### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\public-api.ts /* * Public API Surface of x-framework-components */ // //#region Export Components ... // //#region Component Modules ... export * from './lib/x-ide/x-ide.module'; export * from './lib/x-fab/x-fab.module'; export * from './lib/x-map/x-map.module'; export * from './lib/x-icon/x-icon.module'; export * from './lib/x-card/x-card.module'; export * from './lib/x-list/x-list.module'; export * from './lib/x-form/x-form.module'; export * from './lib/x-grid/x-grid.module'; export * from './lib/x-page/x-page.module'; export * from './lib/x-tabs/x-tabs.module'; export * from './lib/x-tree/x-tree.module'; export * from './lib/x-chart/x-chart.module'; export * from './lib/x-theme/x-theme.module'; export * from './lib/x-table/x-table.module'; export * from './lib/x-frame/x-frame.module'; export * from './lib/x-empty/x-empty.module'; export * from './lib/x-color/x-color.module'; export * from './lib/dialogs/x-dialog.module'; export * from './lib/x-button/x-button.module'; export * from './lib/x-slider/x-slider.module'; export * from './lib/x-slotter/x-slotter.module'; export * from './lib/x-spinner/x-spinner.module'; export * from './lib/x-stepper/x-stepper.module'; export * from './lib/x-counter/x-counter.module'; export * from './lib/x-markdown/x-markdown.module'; export * from './lib/x-thumbnail/x-thumbnail.module'; export * from './lib/x-data-pager/x-data-pager.module'; export * from './lib/x-search-bar/x-search-bar.module'; export * from './lib/x-action-bar/x-action-bar.module'; export * from './lib/x-file-upload/x-file-upload.module'; export * from './lib/x-progress-bar/x-progress-bar.module'; export * from './lib/x-color-picker/x-color-picker.module'; export * from './lib/x-data-scroller/x-data-scroller.module'; export * from './lib/x-image-cropper/x-image-cropper.module'; export * from './lib/x-tab-navigator/x-tab-navigator.module'; export * from './lib/x-avatar-upload/x-avatar-upload.module'; export * from './lib/x-file-drop-area/x-file-drop-area.module'; export * from './lib/x-screen-capture/x-screen-capture.module'; export * from './lib/x-model-presenter/x-model-presenter.module'; export * from './lib/x-expandable-list/x-expandable-list.module'; export * from './lib/x-expandable-panel/x-expandable-panel.module'; export * from './lib/x-description-list/x-description-list.module'; //#endregion // //#region Component ItSelfd ... export * from './lib/x-ide/x-ide.component'; export * from './lib/x-fab/x-fab.component'; export * from './lib/x-map/x-map.component'; export * from './lib/x-form/x-form.component'; export * from './lib/x-icon/x-icon.component'; export * from './lib/x-card/x-card.component'; export * from './lib/x-list/x-list.component'; export * from './lib/x-grid/x-grid.component'; export * from './lib/x-page/x-page.component'; export * from './lib/x-tabs/x-tabs.component'; export * from './lib/x-tree/x-tree.component'; export * from './lib/x-chart/x-chart.component'; export * from './lib/x-color/x-color.component'; export * from './lib/x-empty/x-empty.component'; export * from './lib/x-frame/x-frame.component'; export * from './lib/x-table/x-table.component'; export * from './lib/x-button/x-button.component'; export * from './lib/x-slider/x-slider.component'; export * from './lib/x-tabs/x-tab/x-tab.component'; export * from './lib/x-spinner/x-spinner.component'; export * from './lib/x-slotter/x-slotter.component'; export * from './lib/x-stepper/x-stepper.component'; export * from './lib/x-counter/x-counter.component'; export * from './lib/x-markdown/x-markdown.component'; export * from './lib/x-stepper/x-step/x-step.component'; export * from './lib/x-slotter/x-slot/x-slot.component'; export * from './lib/x-thumbnail/x-thumbnail.component'; export * from './lib/x-slider/x-slide/x-slide.component'; export * from './lib/x-page/x-footer/x-footer.component'; export * from './lib/x-data-pager/x-data-pager.component'; export * from './lib/x-search-bar/x-search-bar.component'; export * from './lib/x-action-bar/x-action-bar.component'; export * from './lib/x-page/x-toolbar/x-toolbar.component'; export * from './lib/dialogs/x-popover/x-popover.component'; export * from './lib/x-file-upload/x-file-upload.component'; export * from './lib/x-progress-bar/x-progress-bar.component'; export * from './lib/x-color-picker/x-color-picker.component'; export * from './lib/x-page/x-navigator/x-navigator.component'; export * from './lib/x-data-scroller/x-data-scroller.component'; export * from './lib/x-map/x-map-dialog/x-map-dialog.component'; export * from './lib/x-image-cropper/x-image-cropper.component'; export * from './lib/x-tab-navigator/x-tab-navigator.component'; export * from './lib/x-avatar-upload/x-avatar-upload.component'; export * from './lib/x-file-drop-area/x-file-drop-area.component'; export * from './lib/x-screen-capture/x-screen-capture.component'; export * from './lib/x-expandable-panel/x-panel/x-panel.component'; export * from './lib/x-expandable-list/x-expandable-list.component'; export * from './lib/x-model-presenter/x-model-presenter.component'; export * from './lib/x-expandable-panel/x-expandable-panel.component'; export * from './lib/x-description-list/x-description-list.component'; export * from './lib/x-theme/x-theme-manager/x-theme-manager.component'; export * from './lib/dialogs/x-selector-dialog/x-selector-dialog.component'; export * from './lib/x-color-picker/x-color-picker-dialog/x-color-picker-dialog.component'; export * from './lib/x-model-presenter/x-model-presenter-item/x-model-presenter-item.component'; export * from './lib/x-description-list/x-description-list-item/x-description-list-item.component'; //#endregion // //#region Component Typings ... export * from './lib/x-ide/x-ide.typings'; export * from './lib/x-fab/x-fab.typings'; export * from './lib/x-map/x-map.typings'; export * from './lib/x-grid/x-grid.typings'; export * from './lib/x-form/x-form.typings'; export * from './lib/x-icon/x-icon.typings'; export * from './lib/x-card/x-card.typings'; export * from './lib/x-list/x-list.typings'; export * from './lib/x-page/x-page.typings'; export * from './lib/x-tabs/x-tabs.typings'; export * from './lib/x-tree/x-tree.typings'; export * from './lib/x-empty/x-empty.typings'; export * from './lib/x-frame/x-frame.typings'; export * from './lib/x-page/x-page.container'; export * from './lib/x-chart/x-chart.typings'; export * from './lib/x-color/x-color.typings'; export * from './lib/x-theme/x-theme-typings'; export * from './lib/x-table/x-table.typings'; export * from './lib/x-button/x-button.typings'; export * from './lib/x-slider/x-slider.typings'; export * from './lib/x-stepper/x-stepper.typings'; export * from './lib/x-slotter/x-slotter.typings'; export * from './lib/x-counter/x-counter.typings'; export * from './lib/x-markdown/x-markdown.typings'; export * from './lib/x-thumbnail/x-thumbnail.typings'; export * from './lib/x-page/x-footer/x-footer.typings'; export * from './lib/x-data-pager/x-data-pager.typings'; export * from './lib/x-action-bar/x-action-bar.typings'; export * from './lib/x-search-bar/x-search-bar.typings'; export * from './lib/x-page/x-toolbar/x-toolbar.typings'; export * from './lib/dialogs/x-popover/x-popover.typings'; export * from './lib/x-file-upload/x-file-upload.typings'; export * from './lib/x-progress-bar/x-progress-bar.typings'; export * from './lib/x-color-picker/x-color-picker.typings'; export * from './lib/x-page/x-navigator/x-navigator.typings'; export * from './lib/x-data-scroller/x-data-scroller.typings'; export * from './lib/x-image-cropper/x-image-cropper.typings'; export * from './lib/x-tab-navigator/x-tab-navigator.typings'; export * from './lib/x-avatar-upload/x-avatar-upload.typings'; export * from './lib/x-map/x-map-dialog/x-map-dialog.typings'; export * from './lib/x-file-drop-area/x-file-drop-area.typings'; export * from './lib/x-screen-capture/x-screen-capture.typings'; export * from './lib/x-screen-capture/x-screen-capture.container'; export * from './lib/x-expandable-list/x-expandable-list.typings'; export * from './lib/x-model-presenter/x-model-presenter.typings'; export * from './lib/x-expandable-panel/x-expandable-panel.typings'; export * from './lib/x-description-list/x-description-list.typings'; export * from './lib/x-theme/x-theme-manager/x-theme-manager.typings'; export * from './lib/dialogs/x-selector-dialog/x-selector-dialog.typings'; export * from './lib/x-color-picker/x-color-picker-dialog/x-color-picker-dialog.typings'; export * from './lib/x-model-presenter/x-model-presenter-item/x-model-presenter-item.typings'; export * from './lib/x-description-list/x-description-list-item/x-description-list-item.typings'; //#endregion // //#region Component Tools ... export * from './lib/x-map/x-map.tools'; export * from './lib/x-form/x-form.tools'; export * from './lib/x-theme/x-theme.tools'; export * from './lib/dialogs/x-popover/x-popover.tools'; export * from './lib/x-form/validators/x-form-validators'; export * from './lib/dialogs/x-popover/x-popover.service'; export * from './lib/x-slider/x-slide.animation.providers'; export * from './lib/x-page/x-navigator/x-navigator.tools'; export * from './lib/x-tab-navigator/x-tab-navigator.tools'; export * from './lib/x-map/x-map-dialog/x-map-dialog.service'; export * from './lib/x-image-cropper/x-image-cropper.service'; export * from './lib/x-screen-capture/x-screen-capture.service'; export * from './lib/x-expandable-list/x-expandable-list.tools'; export * from './lib/x-color-picker/directives/x-color-text.directive'; export * from './lib/dialogs/x-selector-dialog/x-selector-dialog.service'; export * from './lib/x-color-picker/x-color-picker-dialog/x-color-picker-dialog.service'; //#endregion //#endregion // //#region Export Classes ... // export * from './lib/classes/x-base-page'; export * from './lib/classes/x-base-component'; export * from './lib/classes/i-x-base.container'; export * from './lib/classes/i-x-file.container'; export * from './lib/classes/i-x-toolbar-footer'; export * from './lib/classes/x-base-action.model'; export * from './lib/classes/x-base-dialog.service'; export * from './lib/classes/x-base.dialog.component'; export * from './lib/classes/x-base.observable.tools'; export * from './lib/classes/x-base.dialog.component'; export * from './lib/classes/i-x-card-empty.container'; export * from './lib/classes/i-x-base-dialog.container'; export * from './lib/classes/i-x-next-prev-reset.container'; // export * from './lib/dialogs/x-dialog/x-dialog.typings'; export * from './lib/dialogs/x-dialog/x-dialog.component'; //#endregion // //#region Tokens ... export * from './lib/tokens/x-injectable-tokens'; //#endregion // //#region Export Config ... export * from './lib/config/x-framework-components.config'; //#endregion // //#region Export Modules ... export * from './lib/modules/x-material.module'; export * from './lib/x-framework-components.module'; export * from './lib/modules/x-base-component.module'; //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\test.ts // This file is required by karma.conf.js and loads recursively all the .spec and framework files import 'zone.js'; import 'zone.js/testing'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; declare const require: { context(path: string, deep?: boolean, filter?: RegExp): { keys(): string[]; (id: string): T; }; }; // First, initialize the Angular testing environment. getTestBed().initTestEnvironment( BrowserDynamicTestingModule, platformBrowserDynamicTesting() ); // Then we find all the tests. const context = require.context('./', true, /\.spec\.ts$/); // And load the modules. context.keys().map(context); ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-framework-components.module.ts import { NgModule } from '@angular/core'; import { IonicModule } from '@ionic/angular'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { XIDEModule } from './x-ide/x-ide.module'; import { XFabModule } from './x-fab/x-fab.module'; import { XMapModule } from './x-map/x-map.module'; import { XIconModule } from './x-icon/x-icon.module'; import { XCardModule } from './x-card/x-card.module'; import { XListModule } from './x-list/x-list.module'; import { XFormModule } from './x-form/x-form.module'; import { XGridModule } from './x-grid/x-grid.module'; import { XPageModule } from './x-page/x-page.module'; import { XTabsModule } from './x-tabs/x-tabs.module'; import { XFrameModule } from './x-frame/x-frame.module'; import { XEmptyModule } from './x-empty/x-empty.module'; import { XTableModule } from './x-table/x-table.module'; import { XFrameworkCoreModule } from 'x-framework-core'; import { XThemeModule } from './x-theme/x-theme.module'; import { XColorModule } from './x-color/x-color.module'; import { XChartModule } from './x-chart/x-chart.module'; import { XSliderModule } from './x-slider/x-slider.module'; import { XButtonModule } from './x-button/x-button.module'; import { XDialogsModule } from './dialogs/x-dialog.module'; import { XMaterialModule } from './modules/x-material.module'; import { XSlotterModule } from './x-slotter/x-slotter.module'; import { XSpinnerModule } from './x-spinner/x-spinner.module'; import { XStepperModule } from './x-stepper/x-stepper.module'; import { XCounterModule } from './x-counter/x-counter.module'; import { XFrameworkServicesModule } from 'x-framework-services'; import { XMarkdownModule } from './x-markdown/x-markdown.module'; import { XThumbnailModule } from './x-thumbnail/x-thumbnail.module'; import { XActionBarModule } from './x-action-bar/x-action-bar.module'; import { XSearchBarModule } from './x-search-bar/x-search-bar.module'; import { XDataPagerModule } from './x-data-pager/x-data-pager.module'; import { XBaseComponentModule } from './modules/x-base-component.module'; import { XFileUploadModule } from './x-file-upload/x-file-upload.module'; import { XColorPickerModule } from './x-color-picker/x-color-picker.module'; import { XProgressBarModule } from './x-progress-bar/x-progress-bar.module'; import { XImageCropperModule } from './x-image-cropper/x-image-cropper.module'; import { XTabNavigatorModule } from './x-tab-navigator/x-tab-navigator.module'; import { XAvatarUploadModule } from './x-avatar-upload/x-avatar-upload.module'; import { XDataScrollerModule } from './x-data-scroller/x-data-scroller.module'; import { XFileDropAreaModule } from './x-file-drop-area/x-file-drop-area.module'; import { XScreenCaptureModule } from './x-screen-capture/x-screen-capture.module'; import { XExpandableListModule } from './x-expandable-list/x-expandable-list.module'; import { XModelPresenterModule } from './x-model-presenter/x-model-presenter.module'; import { XExpandablePanelModule } from './x-expandable-panel/x-expandable-panel.module'; import { XDescriptionListModule } from './x-description-list/x-description-list.module'; @NgModule({ declarations: [], imports: [ // IonicModule, RouterModule, CommonModule, // XDialogsModule, // XMaterialModule, XBaseComponentModule, // XFrameworkCoreModule, XFrameworkServicesModule, // XIDEModule, XFabModule, XMapModule, XPageModule, XIconModule, XFormModule, XCardModule, XListModule, XTabsModule, XGridModule, XChartModule, XFrameModule, XEmptyModule, XColorModule, XTableModule, XThemeModule, XButtonModule, XSliderModule, XSlotterModule, XSpinnerModule, XStepperModule, XCounterModule, XMarkdownModule, XDataPagerModule, XSearchBarModule, XThumbnailModule, XActionBarModule, XFileUploadModule, XProgressBarModule, XColorPickerModule, XDataScrollerModule, XTabNavigatorModule, XImageCropperModule, XFileDropAreaModule, XAvatarUploadModule, XScreenCaptureModule, XExpandableListModule, XModelPresenterModule, XExpandablePanelModule, XDescriptionListModule, ], exports: [ // IonicModule, RouterModule, CommonModule, // XDialogsModule, // XMaterialModule, XBaseComponentModule, // XFrameworkCoreModule, XFrameworkServicesModule, // XIDEModule, XFabModule, XMapModule, XPageModule, XIconModule, XFormModule, XCardModule, XListModule, XTabsModule, XGridModule, XEmptyModule, XChartModule, XFrameModule, XColorModule, XTableModule, XThemeModule, XButtonModule, XSliderModule, XSlotterModule, XSpinnerModule, XStepperModule, XCounterModule, XMarkdownModule, XDataPagerModule, XSearchBarModule, XActionBarModule, XThumbnailModule, XFileUploadModule, XProgressBarModule, XColorPickerModule, XDataScrollerModule, XTabNavigatorModule, XImageCropperModule, XFileDropAreaModule, XAvatarUploadModule, XScreenCaptureModule, XExpandableListModule, XModelPresenterModule, XExpandablePanelModule, XDescriptionListModule, ], }) export class XFrameworkComponentsModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-base-dialog.container.ts import { XResourceIdentifier, XStandardType } from 'x-framework-core'; export interface XBaseDialogConfig { title?: XStandardType; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-base.container.ts import { Observable } from 'rxjs'; import { Component } from '@angular/core'; import { XBaseComponent } from './x-base-component'; // //#region Container ... export interface IXBaseContainer {} export abstract class XBaseContainer implements IXBaseContainer {} @Component({ template: '', }) export abstract class XBaseContainerComponent extends XBaseComponent { // //#region Abstracts ... public abstract extractProps(container?: any): Observable; //#endregion // //#region Props Actions ... public async extractPropsAsync(container?: any): Promise { return await this.getValueAsync(this.extractProps(container)); } //#endregion } //#endregion // //#region ComponentContainer ... export interface IXBaseComponentContainer {} export abstract class XBaseComponentContainer implements IXBaseComponentContainer {} @Component({ template: '', }) export abstract class XBaseComponentContainerComponent extends XBaseComponent { // //#region Abstracts ... public abstract extractProps(container?: any): Observable; //#endregion // //#region Props Actions ... public async extractPropsAsync(container?: any): Promise { return await this.getValueAsync(this.extractProps(container)); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-card-empty.container.ts import { Input, Inject, NgZone, Output, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, } from 'x-framework-core'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from './i-x-base.container'; import { XCardActionModel, XComponentCardContainer, IXComponentCardContainer, } from '../x-card/x-card.typings'; import { XEmptyContainer, XEmptyActionModel, IXComponentEmptyContainer, } from '../x-empty/x-empty.typings'; import { XActionBarItem, XActionBarActionModel, XActionBarActionFiredModel, XComponentActionBarContainer, IXComponentActionBarContainer, } from '../x-action-bar/x-action-bar.typings'; import { XSearchBarActionModel, XSearchBarTypeIdentifier, XSearchBarEventIdentifier, XComponentSearchBarContainer, IXComponentSearchBarContainer, } from '../x-search-bar/x-search-bar.typings'; import { concatMap, map } from 'rxjs/operators'; import { Observable, Subject, forkJoin } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region XCardEmptyContainer ... // type TXCardEmptyContainer = IXComponentCardContainer & IXComponentEmptyContainer; export interface IXCardEmptyContainer extends TXCardEmptyContainer { } // @Injectable({ providedIn: 'root', }) export class XCardEmptyContainer extends XBaseContainer implements IXCardEmptyContainer { // //#region XComponentCard ... readonly isInPage: XStandardType = this.cardPropertyProvider.isInPage; readonly wrapWithCard: XStandardType = this.cardPropertyProvider.wrapWithCard; readonly cardShowFooter: XStandardType = this.cardPropertyProvider.cardShowFooter; readonly cardShowActions: XStandardType = this.cardPropertyProvider.cardShowActions; readonly cardColor: XStandardType = this.cardPropertyProvider.cardColor; readonly cardForegroundColor: XStandardType = this.cardPropertyProvider.cardForegroundColor; readonly cardTitle: XStandardType = this.cardPropertyProvider.cardTitle; readonly cardActionProvider: Subject = this.cardPropertyProvider.cardActionProvider; readonly cardSubTitle: XStandardType = this.cardPropertyProvider.cardSubTitle; readonly cardCssClass: XStandardType> = this.cardPropertyProvider.cardCssClass; //#endregion // //#region XComponentEmpty ... // readonly showEmpty: XStandardType = true; readonly emptyHasRefresh: XStandardType = this.emptyPropertyProvider.hasRefresh; // readonly emptyActionProvider: Subject = this.emptyPropertyProvider.actionProvider; readonly emptyCssClass: XStandardType> = this.emptyPropertyProvider.cssClass; readonly emptyColor: XStandardType = this.emptyPropertyProvider.color; readonly emptyForegroundColor: XStandardType = this.emptyPropertyProvider.foregroundColor; readonly emptyMessageColor: XStandardType = this.emptyPropertyProvider.messageColor; readonly emptyForegroundMessageColor: XStandardType = this.emptyPropertyProvider.foregroundMessageColor; readonly emptyRefreshButtonColor: XStandardType = this.emptyPropertyProvider.refreshButtonColor; readonly emptyForegroundRefreshButtonColor: XStandardType = this.emptyPropertyProvider.foregroundRefreshButtonColor; readonly emptyMessage: XStandardType = this.emptyPropertyProvider.message; readonly emptyRefreshIcon: XStandardType = this.emptyPropertyProvider.refreshIcon; readonly emptyRefresh: EventEmitter = this.emptyPropertyProvider.refresh; //#endregion // //#region Constructor ... constructor( protected cardPropertyProvider: XComponentCardContainer, protected emptyPropertyProvider: XEmptyContainer ) { super(); } //#endregion } // @Injectable() @Component({ template: ``, }) export class XCardEmptyContainerComponent extends XBaseContainerComponent implements IXCardEmptyContainer { // //#region Props ... // //#region XComponentCard ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; //#endregion // //#region XComponentEmpty ... // @Input() showEmpty: XStandardType = this.propertyProvider.showEmpty; @Input() emptyHasRefresh: XStandardType = this.propertyProvider.emptyHasRefresh; @Input() emptyActionProvider: Subject = this.propertyProvider.emptyActionProvider; @Input() emptyCssClass: XStandardType> = this.propertyProvider.emptyCssClass; @Input() emptyColor: XStandardType = this.propertyProvider.emptyColor; @Input() emptyForegroundColor: XStandardType = this.propertyProvider.emptyForegroundColor; @Input() emptyMessageColor: XStandardType = this.propertyProvider.emptyMessageColor; @Input() emptyForegroundMessageColor: XStandardType = this.propertyProvider.emptyForegroundMessageColor; @Input() emptyRefreshButtonColor: XStandardType = this.propertyProvider.emptyRefreshButtonColor; @Input() emptyForegroundRefreshButtonColor: XStandardType = this.propertyProvider.emptyForegroundRefreshButtonColor; @Input() emptyMessage: XStandardType = this.propertyProvider.emptyMessage; @Input() emptyRefreshIcon: XStandardType = this.propertyProvider.emptyRefreshIcon; @Output() emptyRefresh: EventEmitter = new EventEmitter(); //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XCardEmptyContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXCardEmptyContainer ): Observable { return forkJoin({ // //#region XComponentCard ... cardCssClass: this.getArrayValue( container ? container.cardCssClass : this.cardCssClass ), isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), //#endregion // //#region XComponentEmpty ... // showEmpty: this.getValue( container ? container.showEmpty : this.showEmpty ), emptyHasRefresh: this.getValue( container ? container.emptyHasRefresh : this.emptyHasRefresh ), // emptyCssClass: this.getValue( container ? container.emptyCssClass : this.emptyCssClass ), emptyColor: this.getValue( container ? container.emptyColor : this.emptyColor ), emptyForegroundColor: this.getValue( container ? container.emptyForegroundColor : this.emptyForegroundColor ), emptyMessageColor: this.getValue( container ? container.emptyMessageColor : this.emptyMessageColor ), emptyForegroundMessageColor: this.getValue( container ? container.emptyForegroundMessageColor : this.emptyForegroundMessageColor ), emptyRefreshButtonColor: this.getValue( container ? container.emptyRefreshButtonColor : this.emptyRefreshButtonColor ), emptyForegroundRefreshButtonColor: this.getValue( container ? container.emptyForegroundRefreshButtonColor : this.emptyForegroundRefreshButtonColor ), emptyMessage: this.getValue( container ? container.emptyMessage : this.emptyMessage ), emptyRefreshIcon: this.getValue( container ? container.emptyRefreshIcon : this.emptyRefreshIcon ), //#endregion }).pipe( map((data) => { return { // ...data, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, // emptyActionProvider: container ? container.emptyActionProvider : this.emptyActionProvider, // emptyRefresh: this.emptyRefresh, }; }) ); } //#endregion } //#endregion // //#region XCardActionBarContainer ... type TXCardActionBarContainer = IXComponentCardContainer & IXComponentActionBarContainer; export interface IXCardActionBarContainer extends TXCardActionBarContainer { } @Injectable({ providedIn: 'root', }) export class XCardActionBarContainer extends XBaseContainer implements IXCardActionBarContainer { // //#region Props ... // //#region ComponentCard Props ... readonly isInPage: XStandardType = this.cardPropertyProvider.isInPage; readonly wrapWithCard: XStandardType = this.cardPropertyProvider.wrapWithCard; readonly cardActionProvider: Subject = this.cardPropertyProvider.cardActionProvider; readonly cardCssClass: XStandardType> = this.cardPropertyProvider.cardCssClass; readonly cardColor: XStandardType = this.cardPropertyProvider.cardColor; readonly cardForegroundColor: XStandardType = this.cardPropertyProvider.cardForegroundColor; readonly cardTitle: XStandardType = this.cardPropertyProvider.cardTitle; readonly cardSubTitle: XStandardType = this.cardPropertyProvider.cardSubTitle; readonly cardShowFooter: XStandardType = this.cardPropertyProvider.cardShowFooter; readonly cardShowActions: XStandardType = this.cardPropertyProvider.cardShowActions; //#endregion // //#region ComponentActionBar Props ... readonly showActionBar: XStandardType = this.actionBarPropertyProvider.showActionBar; readonly actionBarActionProvider: Subject = this.actionBarPropertyProvider.actionBarActionProvider; readonly actionBarCssClass: XStandardType> = this.actionBarPropertyProvider.actionBarCssClass; readonly actionBarColor: XStandardType = this.actionBarPropertyProvider.actionBarColor; readonly actionBarForegroundColor: XStandardType = this.actionBarPropertyProvider.actionBarForegroundColor; readonly actionBarActions: XStandardType> = this.actionBarPropertyProvider.actionBarActions; readonly actionBarActionFired: EventEmitter = this.actionBarPropertyProvider.actionBarActionFired; //#endregion //#endregion // //#region Constructor ... constructor( protected cardPropertyProvider: XComponentCardContainer, protected actionBarPropertyProvider: XComponentActionBarContainer ) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export class XCardActionBarContainerComponent extends XBaseContainerComponent implements IXCardActionBarContainer { // //#region Props ... // //#region ComponentCard Props ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; //#endregion // //#region ComponentActionBar Props ... @Input() showActionBar: XStandardType = this.propertyProvider.showActionBar; @Input() actionBarCssClass: XStandardType> = this.propertyProvider.actionBarCssClass; @Input() actionBarColor: XStandardType = this.propertyProvider.actionBarColor; @Input() actionBarForegroundColor: XStandardType = this.propertyProvider.actionBarForegroundColor; @Input() actionBarActionProvider: Subject = this.propertyProvider.actionBarActionProvider; @Output() actionBarActionFired: EventEmitter = this.propertyProvider.actionBarActionFired; actionBarActions: XStandardType> = this.propertyProvider.actionBarActions; //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XCardActionBarContainer, ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstracts ... public extractProps(container?: IXCardActionBarContainer): Observable { return forkJoin({ // //#region XComponentCard ... cardCssClass: this.getArrayValue( container ? container.cardCssClass : this.cardCssClass ), isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), //#endregion // //#region XComponentActionBar ... showActionBar: this.getValue( container ? container.showActionBar : this.showActionBar ), actionBarCssClass: this.getValue( container ? container.actionBarCssClass : this.actionBarCssClass ), actionBarColor: this.getValue( container ? container.actionBarColor : this.actionBarColor ), actionBarForegroundColor: this.getValue( container ? container.actionBarForegroundColor : this.actionBarForegroundColor ), actionBarActions: this.getValue( container ? container.actionBarActions : this.actionBarActions ), //#endregion }).pipe( map((data) => { return { // ...data, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, // actionBarActionProvider: container ? container.actionBarActionProvider : this.actionBarActionProvider, // actionBarActionFired: this.actionBarActionFired, }; }) ); } //#endregion } //#endregion // //#region XCardEmptyActionSearchBarContainer ... // type TXCardEmptyActionSearchBarContainer = IXCardEmptyContainer & IXComponentActionBarContainer & IXComponentSearchBarContainer; export interface IXCardEmptyActionSearchBarContainer extends IXBaseContainer, TXCardEmptyActionSearchBarContainer { } // @Injectable({ providedIn: 'root', }) export class XCardEmptyActionSearchBarContainer extends XCardEmptyContainer implements IXCardEmptyActionSearchBarContainer { // //#region Props ... // //#region ActionBar ... // readonly showActionBar: XStandardType = this.actionBarPropertyProvider.showActionBar; // readonly actionBarActionProvider: Subject = this.actionBarPropertyProvider.actionBarActionProvider; readonly actionBarCssClass: XStandardType> = this.actionBarPropertyProvider.actionBarCssClass; // readonly actionBarColor: XStandardType = this.actionBarPropertyProvider.actionBarColor; readonly actionBarForegroundColor: XStandardType = this.actionBarPropertyProvider.actionBarForegroundColor; // readonly actionBarActions: XStandardType> = this.actionBarPropertyProvider.actionBarActions; // readonly actionBarActionFired: EventEmitter = this.actionBarPropertyProvider.actionBarActionFired; //#endregion // //#region SearchBar ... // readonly showSearchBar: XStandardType = this.searchBarPropertyProvider.showSearchBar; // readonly searchBarActionProvider: Subject = this.searchBarPropertyProvider.searchBarActionProvider; readonly searchBarCssClass: XStandardType> = this.searchBarPropertyProvider.searchBarCssClass; // readonly searchBarColor: XStandardType = this.searchBarPropertyProvider.searchBarColor; readonly searchBarForegroundColor: XStandardType = this.searchBarPropertyProvider.searchBarForegroundColor; // readonly searchBarSearchInputColor: XStandardType = this.searchBarPropertyProvider.searchBarSearchInputColor; readonly searchBarForegroundSearchInputColor: XStandardType = this.searchBarPropertyProvider.searchBarForegroundSearchInputColor; // readonly searchBarType: XStandardType = this.searchBarPropertyProvider.searchBarType; readonly searchBarTitle: XStandardType = this.searchBarPropertyProvider.searchBarTitle; readonly searchBarValue: XStandardType = this.searchBarPropertyProvider.searchBarValue; readonly searchBarEnterKeyHint: XStandardType = this.searchBarPropertyProvider.searchBarEnterKeyHint; readonly searchBarKeyboardType: XStandardType = this.searchBarPropertyProvider.searchBarKeyboardType; readonly searchBarSpellcheck: XStandardType = this.searchBarPropertyProvider.searchBarSpellcheck; readonly searchBarDebounce: XStandardType = this.searchBarPropertyProvider.searchBarDebounce; // readonly searchBarShowCancelButton: XStandardType = this.searchBarPropertyProvider.searchBarShowCancelButton; readonly searchBarCancelButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonIcon; readonly searchBarCancelButtonTitle: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonTitle; readonly searchBarCancelButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonIconColor; // readonly searchBarShowClearButton: XStandardType = this.searchBarPropertyProvider.searchBarShowClearButton; readonly searchBarClearButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarClearButtonIcon; readonly searchBarClearButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarClearButtonIconColor; // readonly searchBarSearchButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarSearchButtonIcon; readonly searchBarSearchButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarSearchButtonIconColor; // readonly searchBarQueryChange: EventEmitter = this.searchBarPropertyProvider.searchBarQueryChange; readonly searchBarOnEvent: EventEmitter = this.searchBarPropertyProvider.searchBarOnEvent; //#endregion //#endregion // //#region Constructor ... constructor( protected cardPropertyProvider: XComponentCardContainer, protected emptyPropertyProvider: XEmptyContainer, protected actionBarPropertyProvider: XComponentActionBarContainer, protected searchBarPropertyProvider: XComponentSearchBarContainer ) { super(cardPropertyProvider, emptyPropertyProvider); } //#endregion } // @Injectable() @Component({ template: ``, }) export class XCardEmptyActionSearchBarContainerComponent extends XCardEmptyContainerComponent implements IXCardEmptyActionSearchBarContainer { // //#region Props ... // //#region ActionBar ... // @Input() showActionBar: XStandardType = this.propertyProvider.showActionBar; // @Input() actionBarActionProvider: Subject = this.propertyProvider.actionBarActionProvider; @Input() actionBarCssClass: XStandardType> = this.propertyProvider.actionBarCssClass; // @Input() actionBarColor: XStandardType = this.propertyProvider.actionBarColor; @Input() actionBarForegroundColor: XStandardType = this.propertyProvider.actionBarForegroundColor; // @Input() actionBarActions: XStandardType> = this.propertyProvider.actionBarActions; // @Output() actionBarActionFired: EventEmitter = new EventEmitter(); //#endregion // //#region SearchBar ... // @Input() showSearchBar: XStandardType = this.propertyProvider.showSearchBar; // @Input() searchBarActionProvider: Subject = this.propertyProvider.searchBarActionProvider; @Input() searchBarCssClass: XStandardType> = this.propertyProvider.searchBarCssClass; // @Input() searchBarColor: XStandardType = this.propertyProvider.searchBarColor; @Input() searchBarForegroundColor: XStandardType = this.propertyProvider.searchBarForegroundColor; // @Input() searchBarSearchInputColor: XStandardType = this.propertyProvider.searchBarSearchInputColor; @Input() searchBarForegroundSearchInputColor: XStandardType = this.propertyProvider.searchBarForegroundSearchInputColor; // @Input() searchBarType: XStandardType = this.propertyProvider.searchBarType; @Input() searchBarTitle: XStandardType = this.propertyProvider.searchBarTitle; @Input() searchBarValue: XStandardType = this.propertyProvider.searchBarValue; @Input() searchBarEnterKeyHint: XStandardType = this.propertyProvider.searchBarEnterKeyHint; @Input() searchBarKeyboardType: XStandardType = this.propertyProvider.searchBarKeyboardType; @Input() searchBarSpellcheck: XStandardType = this.propertyProvider.searchBarSpellcheck; @Input() searchBarDebounce: XStandardType = this.propertyProvider.searchBarDebounce; // @Input() searchBarShowCancelButton: XStandardType = this.propertyProvider.searchBarShowCancelButton; @Input() searchBarCancelButtonIcon: XStandardType = this.propertyProvider.searchBarCancelButtonIcon; @Input() searchBarCancelButtonTitle: XStandardType = this.propertyProvider.searchBarCancelButtonTitle; @Input() searchBarCancelButtonIconColor: XStandardType = this.propertyProvider.searchBarCancelButtonIconColor; // @Input() searchBarClearButtonIcon: XStandardType = this.propertyProvider.searchBarClearButtonIcon; @Input() searchBarClearButtonIconColor: XStandardType = this.propertyProvider.searchBarClearButtonIconColor; // @Input() searchBarShowClearButton: XStandardType = this.propertyProvider.searchBarShowClearButton; @Input() searchBarSearchButtonIcon: XStandardType = this.propertyProvider.searchBarSearchButtonIcon; @Input() searchBarSearchButtonIconColor: XStandardType = this.propertyProvider.searchBarSearchButtonIconColor; // @Output() searchBarQueryChange: EventEmitter = new EventEmitter(); @Output() searchBarOnEvent: EventEmitter = new EventEmitter(); //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XCardEmptyActionSearchBarContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXCardEmptyActionSearchBarContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // // //#region ActionBar ... // showActionBar: this.getValue( container ? container.showActionBar : this.showActionBar ), actionBarCssClass: this.getValue( container ? container.actionBarCssClass : this.actionBarCssClass ), actionBarColor: this.getValue( container ? container.actionBarColor : this.actionBarColor ), actionBarForegroundColor: this.getValue( container ? container.actionBarForegroundColor : this.actionBarForegroundColor ), actionBarActions: this.getValue( container ? container.actionBarActions : this.actionBarActions ), //#endregion // //#region SearchBar ... // showSearchBar: this.getValue( container ? container.showSearchBar : this.showSearchBar ), searchBarCssClass: this.getValue( container ? container.searchBarCssClass : this.searchBarCssClass ), searchBarColor: this.getValue( container ? container.searchBarColor : this.searchBarColor ), searchBarForegroundColor: this.getValue( container ? container.searchBarForegroundColor : this.searchBarForegroundColor ), searchBarSearchInputColor: this.getValue( container ? container.searchBarSearchInputColor : this.searchBarSearchInputColor ), searchBarForegroundSearchInputColor: this.getValue( container ? container.searchBarForegroundSearchInputColor : this.searchBarForegroundSearchInputColor ), // searchBarType: this.getValue( container ? container.searchBarType : this.searchBarType ), searchBarTitle: this.getValue( container ? container.searchBarTitle : this.searchBarTitle ), searchBarValue: this.getValue( container ? container.searchBarValue : this.searchBarValue ), searchBarEnterKeyHint: this.getValue( container ? container.searchBarEnterKeyHint : this.searchBarEnterKeyHint ), searchBarKeyboardType: this.getValue( container ? container.searchBarKeyboardType : this.searchBarKeyboardType ), searchBarSpellcheck: this.getValue( container ? container.searchBarSpellcheck : this.searchBarSpellcheck ), searchBarDebounce: this.getValue( container ? container.searchBarDebounce : this.searchBarDebounce ), // searchBarShowCancelButton: this.getValue( container ? container.searchBarShowCancelButton : this.searchBarShowCancelButton ), searchBarCancelButtonIcon: this.getValue( container ? container.searchBarCancelButtonIcon : this.searchBarCancelButtonIcon ), searchBarCancelButtonTitle: this.getValue( container ? container.searchBarCancelButtonTitle : this.searchBarCancelButtonTitle ), searchBarCancelButtonIconColor: this.getValue( container ? container.searchBarCancelButtonIconColor : this.searchBarCancelButtonIconColor ), // searchBarShowClearButton: this.getValue( container ? container.searchBarShowClearButton : this.searchBarShowClearButton ), searchBarClearButtonIcon: this.getValue( container ? container.searchBarClearButtonIcon : this.searchBarClearButtonIcon ), searchBarClearButtonIconColor: this.getValue( container ? container.searchBarClearButtonIconColor : this.searchBarClearButtonIconColor ), // searchBarSearchButtonIcon: this.getValue( container ? container.searchBarSearchButtonIcon : this.searchBarSearchButtonIcon ), searchBarSearchButtonIconColor: this.getValue( container ? container.searchBarSearchButtonIconColor : this.searchBarSearchButtonIconColor ), //#endregion }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionBarActionProvider: container ? container.actionBarActionProvider : this.actionBarActionProvider, actionBarActionFired: this.actionBarActionFired, // searchBarActionProvider: container ? container.searchBarActionProvider : this.searchBarActionProvider, // searchBarQueryChange: this.searchBarQueryChange, searchBarOnEvent: this.searchBarOnEvent, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-file.container.ts import { Input, Inject, NgZone, Output, Component, Renderer2, Injectable, ElementRef, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XExceptionIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XExceptionIdentifier, } from 'x-framework-core'; import { XCardActionModel, XComponentCardContainer, IXComponentCardContainer, } from '../x-card/x-card.typings'; import { map } from 'rxjs/operators'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XFileDropAreaActionModel, XComponentFileDropAreaContainer, IXComponentFileDropAreaContainer, } from '../x-file-drop-area/x-file-drop-area.typings'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XBaseContainer, XBaseContainerComponent } from './i-x-base.container'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Max Allowed Files ... export interface IXMaxAllowedFilesContainer { maxAllowedFiles: XStandardType; maxAllowedFilesException: XStandardType; } @Injectable({ providedIn: 'root', }) export class XMaxAllowedFilesContainer implements Readonly { // //#region Props ... readonly maxAllowedFiles: XStandardType = this.config.maxUploadFiles; readonly maxAllowedFilesException: XStandardType = XExceptionIDs.MaxAllowedFilesExceeded; //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) private config: XFrameworkComponentsConfig ) {} //#endregion } //#endregion // //#region Max Allowed File Size ... export interface IXMaxAllowedSizeContainer { maxAllowedSize: XStandardType; maxAllowedSizeException: XStandardType; } @Injectable({ providedIn: 'root', }) export class XMaxAllowedSizeContainer implements Readonly { // //#region Props ... readonly maxAllowedSize: XStandardType = this.config.maxAllowedSize; readonly maxAllowedSizeException: XStandardType = XExceptionIDs.MaxFilesSizeExceeded; //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) private config: XFrameworkComponentsConfig ) {} //#endregion } //#endregion // //#region Min Allowed File Size ... export interface IXMinAllowedFileSizeContainer { minAllowedFileSize: XStandardType; minAllowedFileSizeException: XStandardType; } @Injectable({ providedIn: 'root', }) export class XMinAllowedFileSizeContainer implements Readonly { // //#region Props ... readonly minAllowedFileSize: XStandardType = this.config.minAllowedFileSize; readonly minAllowedFileSizeException: XStandardType = XExceptionIDs.MinFilesSizeExceeded; //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) private config: XFrameworkComponentsConfig ) {} //#endregion } //#endregion // //#region Max Allowed Size ... export interface IXMaxAllowedFileSizeContainer { maxAllowedFileSize: XStandardType; maxAllowedFileSizeException: XStandardType; } @Injectable({ providedIn: 'root', }) export class XMaxAllowedFileSizeContainer implements Readonly { // //#region Props ... readonly maxAllowedFileSize: XStandardType = this.config.maxAllowedFileSize; readonly maxAllowedFileSizeException: XStandardType = XExceptionIDs.MaxFilesSizeExceeded; //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) private config: XFrameworkComponentsConfig ) {} //#endregion } //#endregion // //#region Regular File ... export interface IXFileRegularContainer { emptyFileException: XStandardType; notAllowedFileException: XStandardType; allowedExtensions: XStandardType>; } @Injectable({ providedIn: 'root', }) export class XFileRegularContainer implements Readonly { // //#region Props ... readonly emptyFileException: XStandardType = XExceptionIDs.EmptyFile; readonly notAllowedFileException: XStandardType = XExceptionIDs.InavlidFile; readonly allowedExtensions: XStandardType> = []; //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) private config: XFrameworkComponentsConfig ) {} //#endregion } //#endregion // //#region Combine ... type XCombinedType = IXFileRegularContainer & IXMaxAllowedFilesContainer & IXMaxAllowedSizeContainer & IXMinAllowedFileSizeContainer & IXMaxAllowedFileSizeContainer; // tslint:disable-next-line:no-empty-interface export interface IXFileContainer extends XCombinedType {} @Injectable({ providedIn: 'root', }) export class XFileContainer implements Readonly { // //#region Props ... // readonly emptyFileException: XStandardType = XExceptionIDs.EmptyFile; readonly notAllowedFileException: XStandardType = XExceptionIDs.InavlidFile; readonly allowedExtensions: XStandardType> = []; // readonly maxAllowedFiles: XStandardType = this.config.maxUploadFiles; readonly maxAllowedFilesException: XStandardType = XExceptionIDs.MaxAllowedFilesExceeded; // readonly maxAllowedSize: XStandardType = this.config.maxAllowedSize; readonly maxAllowedSizeException: XStandardType = XExceptionIDs.MaxFilesSizeExceeded; // readonly minAllowedFileSize: XStandardType = this.config.minAllowedFileSize; readonly minAllowedFileSizeException: XStandardType = XExceptionIDs.MinFilesSizeExceeded; // readonly maxAllowedFileSize: XStandardType = this.config.maxAllowedFileSize; readonly maxAllowedFileSizeException: XStandardType = XExceptionIDs.MaxFilesSizeExceeded; //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) private config: XFrameworkComponentsConfig ) {} //#endregion } //#endregion // //#region XFileContainerComponent ... @Injectable({ providedIn: 'root', }) @Component({ template: ` `, }) export abstract class XFileContainerComponent extends XBaseContainerComponent implements IXFileContainer { // //#region Props ... // @Input() emptyFileException: XStandardType = this.propertyProvider.emptyFileException; @Input() notAllowedFileException: XStandardType = this.propertyProvider.notAllowedFileException; @Input() allowedExtensions: XStandardType> = this.propertyProvider.allowedExtensions; // @Input() maxAllowedFiles: XStandardType = this.propertyProvider.maxAllowedFiles; @Input() maxAllowedFilesException: XStandardType = this.propertyProvider.maxAllowedFilesException; // @Input() maxAllowedSize: XStandardType = this.propertyProvider.maxAllowedSize; @Input() maxAllowedSizeException: XStandardType = this.propertyProvider.maxAllowedSizeException; // @Input() minAllowedFileSize: XStandardType = this.propertyProvider.minAllowedFileSize; @Input() minAllowedFileSizeException: XStandardType = this.propertyProvider.minAllowedFileSizeException; // @Input() maxAllowedFileSize: XStandardType = this.propertyProvider.maxAllowedFileSize; @Input() maxAllowedFileSizeException: XStandardType = this.propertyProvider.maxAllowedFileSizeException; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XFileContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXFileContainer ): Observable { return forkJoin({ // emptyFileException: this.getValue( container ? container.emptyFileException : this.emptyFileException ), notAllowedFileException: this.getValue( container ? container.notAllowedFileException : this.notAllowedFileException ), allowedExtensions: this.getValue( container ? container.allowedExtensions : this.allowedExtensions ), maxAllowedFiles: this.getValue( container ? container.maxAllowedFiles : this.maxAllowedFiles ), maxAllowedFilesException: this.getValue( container ? container.maxAllowedFilesException : this.maxAllowedFilesException ), maxAllowedSize: this.getValue( container ? container.maxAllowedSize : this.maxAllowedSize ), maxAllowedSizeException: this.getValue( container ? container.maxAllowedSizeException : this.maxAllowedSizeException ), minAllowedFileSize: this.getValue( container ? container.minAllowedFileSize : this.minAllowedFileSize ), minAllowedFileSizeException: this.getValue( container ? container.minAllowedFileSizeException : this.minAllowedFileSizeException ), maxAllowedFileSize: this.getValue( container ? container.maxAllowedFileSize : this.maxAllowedFileSize ), maxAllowedFileSizeException: this.getValue( container ? container.maxAllowedFileSizeException : this.maxAllowedFileSizeException ), }).pipe( map((data) => { return { // ...data, // }; }) ); } //#endregion } //#endregion // //#region XCardFileContainer ... // type TXCardFileContainer = IXComponentCardContainer & IXFileContainer; export interface IXCardFileContainer extends TXCardFileContainer {} // @Injectable({ providedIn: 'root', }) export class XCardFileContainer extends XBaseContainer implements Readonly { // //#region XComponentCard ... readonly isInPage: XStandardType = this.cardPropertyProvider.isInPage; readonly wrapWithCard: XStandardType = this.cardPropertyProvider.wrapWithCard; readonly cardShowFooter: XStandardType = this.cardPropertyProvider.cardShowFooter; readonly cardShowActions: XStandardType = this.cardPropertyProvider.cardShowActions; readonly cardColor: XStandardType = this.cardPropertyProvider.cardColor; readonly cardForegroundColor: XStandardType = this.cardPropertyProvider.cardForegroundColor; readonly cardTitle: XStandardType = this.cardPropertyProvider.cardTitle; readonly cardActionProvider: Subject = this.cardPropertyProvider.cardActionProvider; readonly cardSubTitle: XStandardType = this.cardPropertyProvider.cardSubTitle; readonly cardCssClass: XStandardType> = this.cardPropertyProvider.cardCssClass; //#endregion // //#region XFile ... // readonly emptyFileException: XStandardType = this.filePropertyProvider.emptyFileException; readonly notAllowedFileException: XStandardType = this.filePropertyProvider.notAllowedFileException; readonly allowedExtensions: XStandardType> = this.filePropertyProvider.allowedExtensions; // readonly maxAllowedFiles: XStandardType = this.filePropertyProvider.maxAllowedFiles; readonly maxAllowedFilesException: XStandardType = this.filePropertyProvider.maxAllowedFilesException; // readonly maxAllowedSize: XStandardType = this.filePropertyProvider.maxAllowedSize; readonly maxAllowedSizeException: XStandardType = this.filePropertyProvider.maxAllowedSizeException; // readonly minAllowedFileSize: XStandardType = this.filePropertyProvider.minAllowedFileSize; readonly minAllowedFileSizeException: XStandardType = this.filePropertyProvider.minAllowedFileSizeException; // readonly maxAllowedFileSize: XStandardType = this.filePropertyProvider.maxAllowedFileSize; readonly maxAllowedFileSizeException: XStandardType = this.filePropertyProvider.maxAllowedFileSizeException; //#endregion // //#region Constructor ... constructor( protected cardPropertyProvider: XComponentCardContainer, protected filePropertyProvider: XFileContainer ) { super(); } //#endregion } // @Injectable() @Component({ template: ``, }) export class XCardFileContainerComponent extends XBaseContainerComponent implements IXCardFileContainer { // //#region Props ... // //#region XComponentCard ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; //#endregion // //#region File ... // @Input() emptyFileException: XStandardType = this.propertyProvider.emptyFileException; @Input() notAllowedFileException: XStandardType = this.propertyProvider.notAllowedFileException; @Input() allowedExtensions: XStandardType> = this.propertyProvider.allowedExtensions; // @Input() maxAllowedFiles: XStandardType = this.propertyProvider.maxAllowedFiles; @Input() maxAllowedFilesException: XStandardType = this.propertyProvider.maxAllowedFilesException; // @Input() maxAllowedSize: XStandardType = this.propertyProvider.maxAllowedSize; @Input() maxAllowedSizeException: XStandardType = this.propertyProvider.maxAllowedSizeException; // @Input() minAllowedFileSize: XStandardType = this.propertyProvider.minAllowedFileSize; @Input() minAllowedFileSizeException: XStandardType = this.propertyProvider.minAllowedFileSizeException; // @Input() maxAllowedFileSize: XStandardType = this.propertyProvider.maxAllowedFileSize; @Input() maxAllowedFileSizeException: XStandardType = this.propertyProvider.maxAllowedFileSizeException; //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XCardFileContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXCardFileContainer ): Observable { return forkJoin({ // //#region XComponentCard ... cardCssClass: this.getArrayValue( container ? container.cardCssClass : this.cardCssClass ), isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), //#endregion // //#region File ... emptyFileException: this.getValue( container ? container.emptyFileException : this.emptyFileException ), notAllowedFileException: this.getValue( container ? container.notAllowedFileException : this.notAllowedFileException ), allowedExtensions: this.getValue( container ? container.allowedExtensions : this.allowedExtensions ), maxAllowedFiles: this.getValue( container ? container.maxAllowedFiles : this.maxAllowedFiles ), maxAllowedFilesException: this.getValue( container ? container.maxAllowedFilesException : this.maxAllowedFilesException ), maxAllowedSize: this.getValue( container ? container.maxAllowedSize : this.maxAllowedSize ), maxAllowedSizeException: this.getValue( container ? container.maxAllowedSizeException : this.maxAllowedSizeException ), minAllowedFileSize: this.getValue( container ? container.minAllowedFileSize : this.minAllowedFileSize ), minAllowedFileSizeException: this.getValue( container ? container.minAllowedFileSizeException : this.minAllowedFileSizeException ), maxAllowedFileSize: this.getValue( container ? container.maxAllowedFileSize : this.maxAllowedFileSize ), maxAllowedFileSizeException: this.getValue( container ? container.maxAllowedFileSizeException : this.maxAllowedFileSizeException ), //#endregion }).pipe( map((data) => { return { // ...data, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, }; }) ); } //#endregion } //#endregion // //#region XCardFileFileDropAreaContainer ... // type TXCardFileFileDropContainer = IXComponentCardContainer & IXFileContainer & IXComponentFileDropAreaContainer; export interface IXCardFileFileDropContainer extends TXCardFileFileDropContainer {} // @Injectable({ providedIn: 'root', }) export class XCardFileFileDropContainer extends XBaseContainer implements Readonly { // //#region Props ... // //#region ComponentCard ... readonly isInPage: XStandardType = this.cardPropertyProvider.isInPage; readonly wrapWithCard: XStandardType = this.cardPropertyProvider.wrapWithCard; readonly cardShowFooter: XStandardType = this.cardPropertyProvider.cardShowFooter; readonly cardShowActions: XStandardType = this.cardPropertyProvider.cardShowActions; readonly cardColor: XStandardType = this.cardPropertyProvider.cardColor; readonly cardForegroundColor: XStandardType = this.cardPropertyProvider.cardForegroundColor; readonly cardTitle: XStandardType = this.cardPropertyProvider.cardTitle; readonly cardActionProvider: Subject = this.cardPropertyProvider.cardActionProvider; readonly cardSubTitle: XStandardType = this.cardPropertyProvider.cardSubTitle; readonly cardCssClass: XStandardType> = this.cardPropertyProvider.cardCssClass; //#endregion // //#region File ... // readonly emptyFileException: XStandardType = this.filePropertyProvider.emptyFileException; readonly notAllowedFileException: XStandardType = this.filePropertyProvider.notAllowedFileException; readonly allowedExtensions: XStandardType> = this.filePropertyProvider.allowedExtensions; // readonly maxAllowedFiles: XStandardType = this.filePropertyProvider.maxAllowedFiles; readonly maxAllowedFilesException: XStandardType = this.filePropertyProvider.maxAllowedFilesException; // readonly maxAllowedSize: XStandardType = this.filePropertyProvider.maxAllowedSize; readonly maxAllowedSizeException: XStandardType = this.filePropertyProvider.maxAllowedSizeException; // readonly minAllowedFileSize: XStandardType = this.filePropertyProvider.minAllowedFileSize; readonly minAllowedFileSizeException: XStandardType = this.filePropertyProvider.minAllowedFileSizeException; // readonly maxAllowedFileSize: XStandardType = this.filePropertyProvider.maxAllowedFileSize; readonly maxAllowedFileSizeException: XStandardType = this.filePropertyProvider.maxAllowedFileSizeException; //#endregion // //#region File Drop ... // readonly showFileDropArea: XStandardType = this.fileDropPropertyProvider.showFileDropArea; // readonly fileDropAreaActionProvider: Subject = this.fileDropPropertyProvider.fileDropAreaActionProvider; readonly fileDropAreaCssClass: XStandardType> = this.fileDropPropertyProvider.fileDropAreaCssClass; // readonly fileDropAreaColor: XStandardType = this.fileDropPropertyProvider.fileDropAreaColor; readonly fileDropAreaForegroundColor: XStandardType = this.fileDropPropertyProvider.fileDropAreaForegroundColor; // readonly fileDropAreaIcon: XStandardType = this.fileDropPropertyProvider.fileDropAreaIcon; readonly fileDropAreaMessage: XStandardType = this.fileDropPropertyProvider.fileDropAreaMessage; // readonly fileDropAreaDisableFileCheck: XStandardType = this.fileDropPropertyProvider.fileDropAreaDisableFileCheck; // readonly fileDropAreaSupportsMultipleFiles: XStandardType = this.fileDropPropertyProvider.fileDropAreaSupportsMultipleFiles; readonly fileDropAreaAllowedExtensions: XStandardType< XOneOrManyType > = this.fileDropPropertyProvider.fileDropAreaAllowedExtensions; // readonly fileDropAreaDragDisabled: XStandardType = this.fileDropPropertyProvider.fileDropAreaDragDisabled; readonly fileDropAreaContentTemplate: TemplateRef = this.fileDropPropertyProvider.fileDropAreaContentTemplate; readonly fileDropAreaFilesChangeEmiter: EventEmitter> = this.fileDropPropertyProvider.fileDropAreaFilesChangeEmiter; // readonly fileDropAreaSuccessColor: XStandardType = this.fileDropPropertyProvider.fileDropAreaSuccessColor; readonly fileDropAreaErrorColor: XStandardType = this.fileDropPropertyProvider.fileDropAreaErrorColor; readonly fileDropAreaAccentColor: XStandardType = this.fileDropPropertyProvider.fileDropAreaAccentColor; // //#region ComponentsCard ... readonly fileDropAreaIsInPage: XStandardType = this.fileDropPropertyProvider.fileDropAreaIsInPage; readonly fileDropAreaWrapWithCard: XStandardType = this.fileDropPropertyProvider.fileDropAreaWrapWithCard; readonly fileDropAreaCardShowFooter: XStandardType = this.fileDropPropertyProvider.fileDropAreaCardShowFooter; readonly fileDropAreaCardShowActions: XStandardType = this.fileDropPropertyProvider.fileDropAreaCardShowActions; readonly fileDropAreaCardColor: XStandardType = this.fileDropPropertyProvider.fileDropAreaCardColor; readonly fileDropAreaCardForegroundColor: XStandardType = this.fileDropPropertyProvider.fileDropAreaCardForegroundColor; readonly fileDropAreaCardTitle: XStandardType = this.fileDropPropertyProvider.fileDropAreaCardTitle; readonly fileDropAreaCardActionProvider: Subject = this.fileDropPropertyProvider.fileDropAreaCardActionProvider; readonly fileDropAreaCardSubTitle: XStandardType = this.fileDropPropertyProvider.fileDropAreaCardSubTitle; readonly fileDropAreaCardCssClass: XStandardType> = this.fileDropPropertyProvider.fileDropAreaCardCssClass; //#endregion //#endregion //#endregion // //#region Constructor ... constructor( protected cardPropertyProvider: XComponentCardContainer, protected fileDropPropertyProvider: XComponentFileDropAreaContainer, protected filePropertyProvider: XFileContainer ) { super(); } //#endregion } // @Injectable() @Component({ template: ``, }) export class XCardFileFileDropContainerComponent extends XBaseContainerComponent implements IXCardFileContainer { // //#region Props ... // //#region XComponentCard ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; //#endregion // //#region File ... // @Input() emptyFileException: XStandardType = this.propertyProvider.emptyFileException; @Input() notAllowedFileException: XStandardType = this.propertyProvider.notAllowedFileException; @Input() allowedExtensions: XStandardType> = this.propertyProvider.allowedExtensions; // @Input() maxAllowedFiles: XStandardType = this.propertyProvider.maxAllowedFiles; @Input() maxAllowedFilesException: XStandardType = this.propertyProvider.maxAllowedFilesException; // @Input() maxAllowedSize: XStandardType = this.propertyProvider.maxAllowedSize; @Input() maxAllowedSizeException: XStandardType = this.propertyProvider.maxAllowedSizeException; // @Input() minAllowedFileSize: XStandardType = this.propertyProvider.minAllowedFileSize; @Input() minAllowedFileSizeException: XStandardType = this.propertyProvider.minAllowedFileSizeException; // @Input() maxAllowedFileSize: XStandardType = this.propertyProvider.maxAllowedFileSize; @Input() maxAllowedFileSizeException: XStandardType = this.propertyProvider.maxAllowedFileSizeException; //#endregion // //#region FileDrop ... // @Input() fileDropAreaActionProvider: Subject = this.propertyProvider.fileDropAreaActionProvider; @Input() fileDropAreaCssClass: XStandardType> = this.propertyProvider.fileDropAreaCssClass; // @Input() fileDropAreaColor: XStandardType = this.propertyProvider.fileDropAreaColor; @Input() fileDropAreaForegroundColor: XStandardType = this.propertyProvider.fileDropAreaForegroundColor; // @Input() fileDropAreaIcon: XStandardType = this.propertyProvider.fileDropAreaIcon; @Input() fileDropAreaMessage: XStandardType = this.propertyProvider.fileDropAreaMessage; // @Input() fileDropAreaDisableFileCheck: XStandardType = this.propertyProvider.fileDropAreaDisableFileCheck; // @Input() fileDropAreaSupportsMultipleFiles: XStandardType = this.propertyProvider.fileDropAreaSupportsMultipleFiles; @Input() fileDropAreaAllowedExtensions: XStandardType> = this.propertyProvider.fileDropAreaAllowedExtensions; // @Input() fileDropAreaDragDisabled: XStandardType = this.propertyProvider.fileDropAreaDragDisabled; @Input() fileDropAreaContentTemplate: TemplateRef = this.propertyProvider.fileDropAreaContentTemplate; @Output() fileDropAreaFilesChangeEmiter: EventEmitter> = new EventEmitter(); // @Input() fileDropAreaSuccessColor: XStandardType = this.propertyProvider.fileDropAreaSuccessColor; @Input() fileDropAreaErrorColor: XStandardType = this.propertyProvider.fileDropAreaErrorColor; @Input() fileDropAreaAccentColor: XStandardType = this.propertyProvider.fileDropAreaAccentColor; // @Input() showFileDropArea: XStandardType = this.propertyProvider.showFileDropArea; // //#region ComponentsCard ... @Input() fileDropAreaIsInPage: XStandardType = this.propertyProvider.fileDropAreaIsInPage; @Input() fileDropAreaWrapWithCard: XStandardType = this.propertyProvider.fileDropAreaWrapWithCard; @Input() fileDropAreaCardShowFooter: XStandardType = this.propertyProvider.fileDropAreaCardShowFooter; @Input() fileDropAreaCardShowActions: XStandardType = this.propertyProvider.fileDropAreaCardShowActions; @Input() fileDropAreaCardColor: XStandardType = this.propertyProvider.fileDropAreaCardColor; @Input() fileDropAreaCardForegroundColor: XStandardType = this.propertyProvider.fileDropAreaCardForegroundColor; @Input() fileDropAreaCardTitle: XStandardType = this.propertyProvider.fileDropAreaCardTitle; @Input() fileDropAreaCardActionProvider: Subject = this.propertyProvider.fileDropAreaCardActionProvider; @Input() fileDropAreaCardSubTitle: XStandardType = this.propertyProvider.fileDropAreaCardSubTitle; @Input() fileDropAreaCardCssClass: XStandardType> = this.propertyProvider.fileDropAreaCardCssClass; //#endregion //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XCardFileFileDropContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXCardFileFileDropContainer ): Observable { return forkJoin({ // //#region XComponentCard ... cardCssClass: this.getArrayValue( container ? container.cardCssClass : this.cardCssClass ), isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), //#endregion // //#region File ... emptyFileException: this.getValue( container ? container.emptyFileException : this.emptyFileException ), notAllowedFileException: this.getValue( container ? container.notAllowedFileException : this.notAllowedFileException ), allowedExtensions: this.getValue( container ? container.allowedExtensions : this.allowedExtensions ), maxAllowedFiles: this.getValue( container ? container.maxAllowedFiles : this.maxAllowedFiles ), maxAllowedFilesException: this.getValue( container ? container.maxAllowedFilesException : this.maxAllowedFilesException ), maxAllowedSize: this.getValue( container ? container.maxAllowedSize : this.maxAllowedSize ), maxAllowedSizeException: this.getValue( container ? container.maxAllowedSizeException : this.maxAllowedSizeException ), minAllowedFileSize: this.getValue( container ? container.minAllowedFileSize : this.minAllowedFileSize ), minAllowedFileSizeException: this.getValue( container ? container.minAllowedFileSizeException : this.minAllowedFileSizeException ), maxAllowedFileSize: this.getValue( container ? container.maxAllowedFileSize : this.maxAllowedFileSize ), maxAllowedFileSizeException: this.getValue( container ? container.maxAllowedFileSizeException : this.maxAllowedFileSizeException ), //#endregion // //#region FileDrop ... // fileDropAreaCssClass: this.getValue( container ? container.fileDropAreaCssClass : this.fileDropAreaCssClass ), fileDropAreaColor: this.getValue( container ? container.fileDropAreaColor : this.fileDropAreaColor ), fileDropAreaForegroundColor: this.getValue( container ? container.fileDropAreaForegroundColor : this.fileDropAreaForegroundColor ), fileDropAreaIcon: this.getValue( container ? container.fileDropAreaIcon : this.fileDropAreaIcon ), fileDropAreaMessage: this.getValue( container ? container.fileDropAreaMessage : this.fileDropAreaMessage ), fileDropAreaDisableFileCheck: this.getValue( container ? container.fileDropAreaDisableFileCheck : this.fileDropAreaDisableFileCheck ), fileDropAreaSupportsMultipleFiles: this.getValue( container ? container.fileDropAreaSupportsMultipleFiles : this.fileDropAreaSupportsMultipleFiles ), fileDropAreaAllowedExtensions: this.getValue( container ? container.fileDropAreaAllowedExtensions : this.fileDropAreaAllowedExtensions ), fileDropAreaDragDisabled: this.getValue( container ? container.fileDropAreaDragDisabled : this.fileDropAreaDragDisabled ), fileDropAreaContentTemplate: this.getValue( container ? container.fileDropAreaContentTemplate : this.fileDropAreaContentTemplate ), fileDropAreaSuccessColor: this.getValue( container ? container.fileDropAreaSuccessColor : this.fileDropAreaSuccessColor ), fileDropAreaErrorColor: this.getValue( container ? container.fileDropAreaErrorColor : this.fileDropAreaErrorColor ), fileDropAreaAccentColor: this.getValue( container ? container.fileDropAreaAccentColor : this.fileDropAreaAccentColor ), showFileDropArea: this.getValue( container ? container.showFileDropArea : this.showFileDropArea ), fileDropAreaIsInPage: this.getValue( container ? container.fileDropAreaIsInPage : this.fileDropAreaIsInPage ), fileDropAreaWrapWithCard: this.getValue( container ? container.fileDropAreaWrapWithCard : this.fileDropAreaWrapWithCard ), fileDropAreaCardShowFooter: this.getValue( container ? container.fileDropAreaCardShowFooter : this.fileDropAreaCardShowFooter ), fileDropAreaCardShowActions: this.getValue( container ? container.fileDropAreaCardShowActions : this.fileDropAreaCardShowActions ), fileDropAreaCardColor: this.getValue( container ? container.fileDropAreaCardColor : this.fileDropAreaCardColor ), fileDropAreaCardForegroundColor: this.getValue( container ? container.fileDropAreaCardForegroundColor : this.fileDropAreaCardForegroundColor ), fileDropAreaCardTitle: this.getValue( container ? container.fileDropAreaCardTitle : this.fileDropAreaCardTitle ), fileDropAreaCardSubTitle: this.getValue( container ? container.fileDropAreaCardSubTitle : this.fileDropAreaCardSubTitle ), fileDropAreaCardCssClass: this.getValue( container ? container.fileDropAreaCardCssClass : this.fileDropAreaCardCssClass ), //#endregion }).pipe( map((data) => { return { // ...data, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, // fileDropAreaActionProvider: container ? container.fileDropAreaActionProvider : this.fileDropAreaActionProvider, // fileDropAreaCardActionProvider: container ? container.fileDropAreaCardActionProvider : this.fileDropAreaCardActionProvider, // fileDropAreaFilesChangeEmiter: this.fileDropAreaFilesChangeEmiter, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-next-prev-reset.container.ts import { Input, Inject, Output, NgZone, Renderer2, Component, Injectable, ElementRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from './i-x-base.container'; import { XCardActionModel, XComponentCardContainer, IXComponentCardContainer, } from '../x-card/x-card.typings'; import { map } from 'rxjs/operators'; import { Observable, forkJoin, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { IXButtonContainer, XButtonType } from '../x-button/x-button.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XSlotNameIdentifier, XSlotName } from '../x-slotter/x-slotter.typings'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // export enum XNPRButtonType { Next = 'next', Prev = 'prev', Reset = 'reset', } // export type XNPRButtonTypeIdentifier = XNPRButtonType | string; // //#region Next ... export interface IXNextHost { canNext: XStandardType; onNext: EventEmitter; } export interface IXNextContainer extends IXBaseContainer { // //#region Next ... hasNext: XStandardType; disableNext: XStandardType; nextConfirmer: () => XStandardType; nextPosition: XStandardType; nextCssClass: XStandardType>; nextButton: XStandardType>; //#endregion } export const defaultNextButton: Partial = { title: XResourceIDs.next, type: XButtonType.Raised, color: XColorWithBrightness.Primary, }; @Injectable({ providedIn: 'root', }) export abstract class XNextContainer extends XBaseContainer implements Readonly { // //#region Next ... readonly hasNext: XStandardType; readonly disableNext: XStandardType; readonly nextConfirmer: () => XStandardType; readonly nextPosition: XStandardType = XSlotName.START; readonly nextCssClass: XStandardType> = 'ion-text-start'; readonly nextButton: XStandardType> = { ...defaultNextButton, }; //#endregion } //#endregion // //#region Prev ... export interface IXPrevHost { canPrev: XStandardType; onPrev: EventEmitter; } export interface IXPrevContainer extends IXBaseContainer { // //#region Prev ... hasPrev: XStandardType; disablePrev: XStandardType; prevConfirmer: () => XStandardType; prevPosition: XStandardType; prevCssClass: XStandardType>; prevButton: XStandardType>; //#endregion } export const defaultPrevButton: Partial = { type: XButtonType.Raised, title: XResourceIDs.previous, color: XColorWithBrightness.Primary, }; @Injectable({ providedIn: 'root', }) export abstract class XPrevContainer extends XBaseContainer implements Readonly { // //#region Prev ... readonly hasPrev: XStandardType; readonly disablePrev: XStandardType; readonly prevConfirmer: () => XStandardType; readonly prevPosition: XStandardType = XSlotName.END; readonly prevCssClass: XStandardType> = 'ion-text-end'; readonly prevButton: XStandardType> = { ...defaultPrevButton, }; //#endregion } //#endregion // //#region Reset ... export interface IXResetHost { canReset: XStandardType; onReset: EventEmitter; } export interface IXResetContainer extends IXBaseContainer { // //#region Reset ... hasReset: XStandardType; disableReset: XStandardType; resetConfirmer: () => XStandardType; resetPosition: XStandardType; resetCssClass: XStandardType>; resetButton: XStandardType>; //#endregion } export const defaultResetButton: Partial = { type: XButtonType.Raised, title: XResourceIDs.reset, color: XColorWithBrightness.Warning, }; @Injectable({ providedIn: 'root', }) export abstract class XResetContainer extends XBaseContainer implements Readonly { // //#region Reset ... readonly hasReset: XStandardType; readonly disableReset: XStandardType; readonly resetConfirmer: () => XStandardType; readonly resetPosition: XStandardType = XSlotName.CENTER; readonly resetCssClass: XStandardType> = 'ion-text-center'; readonly resetButton: XStandardType> = { ...defaultResetButton, }; //#endregion } //#endregion // //#region Combined ... // //#region Host ... // type XCompleteHostInterface = IXNextHost & IXPrevHost & IXResetHost; // tslint:disable-next-line:no-empty-interface export interface IXNextPrevResetHostContainer extends XCompleteHostInterface {} @Injectable({ providedIn: 'root', }) export class XNextPrevResetHostContainer extends XBaseContainer implements Readonly { // //#region Props ... // //#region Next ... readonly canNext: XStandardType = true; readonly onNext: EventEmitter = new EventEmitter(); //#endregion // //#region Prev ... readonly canPrev: XStandardType = true; readonly onPrev: EventEmitter = new EventEmitter(); //#endregion // //#region Reset ... readonly canReset: XStandardType = true; readonly onReset: EventEmitter = new EventEmitter(); //#endregion //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XNextPrevResetHostContainerComponent extends XBaseContainerComponent implements IXNextPrevResetHostContainer { // //#region Props ... // //#region Next ... @Input() canNext: XStandardType = this.propertyProvider.canNext; @Output() onNext: EventEmitter = new EventEmitter(); //#endregion // //#region Prev ... @Input() canPrev: XStandardType = this.propertyProvider.canPrev; @Output() onPrev: EventEmitter = new EventEmitter(); //#endregion // //#region Reset ... @Input() canReset: XStandardType = this.propertyProvider.canReset; @Output() onReset: EventEmitter = new EventEmitter(); //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XNextPrevResetHostContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXNextPrevResetHostContainer ): Observable { return forkJoin({ // canNext: this.getValue(container ? container.canNext : this.canNext), canPrev: this.getValue(container ? container.canPrev : this.canPrev), canReset: this.getValue(container ? container.canReset : this.canReset), }).pipe( map((data) => { return { // ...data, // onNext: this.onNext, onPrev: this.onPrev, onReset: this.onReset, }; }) ); } //#endregion } //#endregion // //#region XCardHost // type TXCardEmptyContainer = IXComponentCardContainer & IXNextPrevResetHostContainer; export interface IXCardNextPrevResetHostContainer extends TXCardEmptyContainer {} // @Injectable({ providedIn: 'root', }) export class XCardNextPrevResetHostContainer extends XBaseContainer implements IXCardNextPrevResetHostContainer { // //#region Props ... // //#region XComponentCard ... readonly isInPage: XStandardType = this.cardPropertyProvider.isInPage; readonly wrapWithCard: XStandardType = this.cardPropertyProvider.wrapWithCard; readonly cardShowFooter: XStandardType = this.cardPropertyProvider.cardShowFooter; readonly cardShowActions: XStandardType = this.cardPropertyProvider.cardShowActions; readonly cardColor: XStandardType = this.cardPropertyProvider.cardColor; readonly cardForegroundColor: XStandardType = this.cardPropertyProvider.cardForegroundColor; readonly cardTitle: XStandardType = this.cardPropertyProvider.cardTitle; readonly cardActionProvider: Subject = this.cardPropertyProvider.cardActionProvider; readonly cardSubTitle: XStandardType = this.cardPropertyProvider.cardSubTitle; readonly cardCssClass: XStandardType> = this.cardPropertyProvider.cardCssClass; //#endregion // //#region XNextPrevResetHost ... // //#region Next ... readonly canNext: XStandardType = this.nextPrevResetHostPropertyProvider.canNext; readonly onNext: EventEmitter = this.nextPrevResetHostPropertyProvider.onNext; //#endregion // //#region Prev ... readonly canPrev: XStandardType = this.nextPrevResetHostPropertyProvider.canPrev; readonly onPrev: EventEmitter = this.nextPrevResetHostPropertyProvider.onPrev; //#endregion // //#region Reset ... readonly canReset: XStandardType = this.nextPrevResetHostPropertyProvider.canReset; readonly onReset: EventEmitter = this.nextPrevResetHostPropertyProvider.onReset; //#endregion //#endregion //#endregion // //#region Constructor ... constructor( protected cardPropertyProvider: XComponentCardContainer, protected nextPrevResetHostPropertyProvider: XNextPrevResetHostContainer ) { super(); } //#endregion } // @Injectable() @Component({ template: ``, }) export class XCardNextPrevResetHostContainerComponent extends XBaseContainerComponent implements IXCardNextPrevResetHostContainer { // //#region Props ... // //#region XComponentCard ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; //#endregion // //#region XNextPrevResetHost ... // //#region Next ... @Input() canNext: XStandardType = this.propertyProvider.canNext; @Output() onNext: EventEmitter = new EventEmitter(); //#endregion // //#region Prev ... @Input() canPrev: XStandardType = this.propertyProvider.canPrev; @Output() onPrev: EventEmitter = new EventEmitter(); //#endregion // //#region Reset ... @Input() canReset: XStandardType = this.propertyProvider.canReset; @Output() onReset: EventEmitter = new EventEmitter(); //#endregion //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XCardNextPrevResetHostContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXCardNextPrevResetHostContainer ): Observable { return forkJoin({ // //#region XComponentCard ... cardCssClass: this.getArrayValue( container ? container.cardCssClass : this.cardCssClass ), isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), //#endregion // //#region XNextPrevResetHost ... // canNext: this.getValue(container ? container.canNext : this.canNext), canPrev: this.getValue(container ? container.canPrev : this.canPrev), canReset: this.getValue(container ? container.canReset : this.canReset), //#endregion }).pipe( map((data) => { return { // ...data, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, // onNext: this.onNext, onPrev: this.onPrev, onReset: this.onReset, }; }) ); } //#endregion } //#endregion // //#region Interface ... // type TXNextPrevResetContainer = IXNextContainer & IXPrevContainer & IXResetContainer; // tslint:disable-next-line:no-empty-interface export interface IXNextPrevResetContainer extends IXBaseContainer, TXNextPrevResetContainer {} @Injectable({ providedIn: 'root', }) export class XNextPrevResetContainer extends XBaseContainer implements Readonly { // //#region Props ... // //#region Next ... hasNext: XStandardType = this.nextPropertyProvider.hasNext; disableNext: XStandardType = this.nextPropertyProvider.disableNext; nextConfirmer: () => XStandardType = this.nextPropertyProvider.nextConfirmer; nextPosition: XStandardType = this.nextPropertyProvider.nextPosition; nextCssClass: XStandardType> = this.nextPropertyProvider.nextCssClass; nextButton: XStandardType> = this.nextPropertyProvider.nextButton; //#endregion // //#region Prev ... hasPrev: XStandardType = this.prevPropertyProvider.hasPrev; disablePrev: XStandardType = this.prevPropertyProvider.disablePrev; prevConfirmer: () => XStandardType = this.prevPropertyProvider.prevConfirmer; prevPosition: XStandardType = this.prevPropertyProvider.prevPosition; prevCssClass: XStandardType> = this.prevPropertyProvider.prevCssClass; prevButton: XStandardType> = this.prevPropertyProvider.prevButton; //#endregion // //#region Reset ... hasReset: XStandardType = this.resetpropertyProvider.hasReset; disableReset: XStandardType = this.resetpropertyProvider.disableReset; resetConfirmer: () => XStandardType = this.resetpropertyProvider.resetConfirmer; resetPosition: XStandardType = this.resetpropertyProvider.resetPosition; resetCssClass: XStandardType> = this.resetpropertyProvider.resetCssClass; resetButton: XStandardType> = this.resetpropertyProvider.resetButton; //#endregion //#endregion // //#region Constructor ... constructor( protected prevPropertyProvider: XPrevContainer, protected nextPropertyProvider: XNextContainer, protected resetpropertyProvider: XResetContainer ) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XNextPrevResetContainerComponent extends XBaseContainerComponent implements IXNextPrevResetContainer { // //#region Props ... // //#region Next ... @Input() hasNext: XStandardType = this.propertyProvider.hasNext; @Input() disableNext: XStandardType = this.propertyProvider.disableNext; @Input() nextConfirmer: () => XStandardType = this.propertyProvider.nextConfirmer; @Input() nextPosition: XStandardType = this.propertyProvider.nextPosition; @Input() nextCssClass: XStandardType> = this.propertyProvider.nextCssClass; @Input() nextButton: XStandardType> = this.propertyProvider.nextButton; //#endregion // //#region Prev ... @Input() hasPrev: XStandardType = this.propertyProvider.hasPrev; @Input() disablePrev: XStandardType = this.propertyProvider.disablePrev; @Input() prevConfirmer: () => XStandardType = this.propertyProvider.prevConfirmer; @Input() prevPosition: XStandardType = this.propertyProvider.prevPosition; @Input() prevCssClass: XStandardType> = this.propertyProvider.prevCssClass; @Input() prevButton: XStandardType> = this.propertyProvider.prevButton; //#endregion // //#region Reset ... @Input() hasReset: XStandardType = this.propertyProvider.hasReset; @Input() disableReset: XStandardType = this.propertyProvider.disableReset; @Input() resetConfirmer: () => XStandardType = this.propertyProvider.resetConfirmer; @Input() resetPosition: XStandardType = this.propertyProvider.resetPosition; @Input() resetCssClass: XStandardType> = this.propertyProvider.resetCssClass; @Input() resetButton: XStandardType> = this.propertyProvider.resetButton; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XNextPrevResetContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXNextPrevResetContainer ): Observable { return forkJoin({ // hasNext: this.getValue(container ? container.hasNext : this.hasNext), disableNext: this.getValue( container ? container.disableNext : this.disableNext ), nextConfirmer: this.getValue( container ? container.nextConfirmer : this.nextConfirmer ), nextPosition: this.getValue( container ? container.nextPosition : this.nextPosition ), nextCssClass: this.getValue( container ? container.nextCssClass : this.nextCssClass ), nextButton: this.getValue( container ? container.nextButton : this.nextButton ), hasPrev: this.getValue(container ? container.hasPrev : this.hasPrev), disablePrev: this.getValue( container ? container.disablePrev : this.disablePrev ), prevConfirmer: this.getValue( container ? container.prevConfirmer : this.prevConfirmer ), prevPosition: this.getValue( container ? container.prevPosition : this.prevPosition ), prevCssClass: this.getValue( container ? container.prevCssClass : this.prevCssClass ), prevButton: this.getValue( container ? container.prevButton : this.prevButton ), hasReset: this.getValue(container ? container.hasReset : this.hasReset), disableReset: this.getValue( container ? container.disableReset : this.disableReset ), resetConfirmer: this.getValue( container ? container.resetConfirmer : this.resetConfirmer ), resetPosition: this.getValue( container ? container.resetPosition : this.resetPosition ), resetCssClass: this.getValue( container ? container.resetCssClass : this.resetCssClass ), resetButton: this.getValue( container ? container.resetButton : this.resetButton ), }).pipe( map((data) => { return { // ...data, // }; }) ); } //#endregion } //#endregion // //#region IXNextPrevResetAndHostContainer ... type TXNextPrevResetAndHostContainer = IXNextPrevResetContainer & IXCardNextPrevResetHostContainer; export interface IXNextPrevResetAndHostContainer extends IXBaseContainer, TXNextPrevResetAndHostContainer {} @Injectable({ providedIn: 'root', }) export class XNextPrevResetAndHostContainer extends XBaseContainer implements Readonly { // //#region Props ... // //#region Inteface ... // //#region Next ... hasNext: XStandardType = this.nextPrevResetPropertyProvider.hasNext; disableNext: XStandardType = this.nextPrevResetPropertyProvider.disableNext; nextConfirmer: () => XStandardType = this.nextPrevResetPropertyProvider.nextConfirmer; nextPosition: XStandardType = this.nextPrevResetPropertyProvider.nextPosition; nextCssClass: XStandardType> = this.nextPrevResetPropertyProvider.nextCssClass; nextButton: XStandardType> = this.nextPrevResetPropertyProvider.nextButton; //#endregion // //#region Prev ... hasPrev: XStandardType = this.nextPrevResetPropertyProvider.hasPrev; disablePrev: XStandardType = this.nextPrevResetPropertyProvider.disablePrev; prevConfirmer: () => XStandardType = this.nextPrevResetPropertyProvider.prevConfirmer; prevPosition: XStandardType = this.nextPrevResetPropertyProvider.prevPosition; prevCssClass: XStandardType> = this.nextPrevResetPropertyProvider.prevCssClass; prevButton: XStandardType> = this.nextPrevResetPropertyProvider.prevButton; //#endregion // //#region Reset ... hasReset: XStandardType = this.nextPrevResetPropertyProvider.hasReset; disableReset: XStandardType = this.nextPrevResetPropertyProvider.disableReset; resetConfirmer: () => XStandardType = this.nextPrevResetPropertyProvider.resetConfirmer; resetPosition: XStandardType = this.nextPrevResetPropertyProvider.resetPosition; resetCssClass: XStandardType> = this.nextPrevResetPropertyProvider.resetCssClass; resetButton: XStandardType> = this.nextPrevResetPropertyProvider.resetButton; //#endregion //#endregion // //#region Host ... // //#region Next ... readonly canNext: XStandardType = this.cardNextPrevResetPropertyProvider.canNext; readonly onNext: EventEmitter = this.cardNextPrevResetPropertyProvider.onNext; //#endregion // //#region Prev ... readonly canPrev: XStandardType = this.cardNextPrevResetPropertyProvider.canPrev; readonly onPrev: EventEmitter = this.cardNextPrevResetPropertyProvider.onPrev; //#endregion // //#region Reset ... readonly canReset: XStandardType = this.cardNextPrevResetPropertyProvider.canReset; readonly onReset: EventEmitter = this.cardNextPrevResetPropertyProvider.onReset; //#endregion //#endregion // //#region XComponentCard ... readonly isInPage: XStandardType = this.cardNextPrevResetPropertyProvider.isInPage; readonly wrapWithCard: XStandardType = this.cardNextPrevResetPropertyProvider.wrapWithCard; readonly cardShowFooter: XStandardType = this.cardNextPrevResetPropertyProvider.cardShowFooter; readonly cardShowActions: XStandardType = this.cardNextPrevResetPropertyProvider.cardShowActions; readonly cardColor: XStandardType = this.cardNextPrevResetPropertyProvider.cardColor; readonly cardForegroundColor: XStandardType = this.cardNextPrevResetPropertyProvider.cardForegroundColor; readonly cardTitle: XStandardType = this.cardNextPrevResetPropertyProvider.cardTitle; readonly cardActionProvider: Subject = this.cardNextPrevResetPropertyProvider.cardActionProvider; readonly cardSubTitle: XStandardType = this.cardNextPrevResetPropertyProvider.cardSubTitle; readonly cardCssClass: XStandardType> = this.cardNextPrevResetPropertyProvider.cardCssClass; //#endregion //#endregion // //#region Constructor ... constructor( protected nextPrevResetPropertyProvider: XNextPrevResetContainer, protected cardNextPrevResetPropertyProvider: XCardNextPrevResetHostContainer ) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export class XNextPrevResetAndHostContainerComponent extends XBaseContainerComponent implements IXNextPrevResetAndHostContainer { // //#region Props ... // //#region XComponentCard ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; //#endregion // //#region XNextPrevResetHost ... // //#region Next ... @Input() canNext: XStandardType = this.propertyProvider.canNext; @Output() onNext: EventEmitter = new EventEmitter(); //#endregion // //#region Prev ... @Input() canPrev: XStandardType = this.propertyProvider.canPrev; @Output() onPrev: EventEmitter = new EventEmitter(); //#endregion // //#region Reset ... @Input() canReset: XStandardType = this.propertyProvider.canReset; @Output() onReset: EventEmitter = new EventEmitter(); //#endregion //#endregion // //#region Props ... // //#region Next ... @Input() hasNext: XStandardType = this.propertyProvider.hasNext; @Input() disableNext: XStandardType = this.propertyProvider.disableNext; @Input() nextConfirmer: () => XStandardType = this.propertyProvider.nextConfirmer; @Input() nextPosition: XStandardType = this.propertyProvider.nextPosition; @Input() nextCssClass: XStandardType> = this.propertyProvider.nextCssClass; @Input() nextButton: XStandardType> = this.propertyProvider.nextButton; //#endregion // //#region Prev ... @Input() hasPrev: XStandardType = this.propertyProvider.hasPrev; @Input() disablePrev: XStandardType = this.propertyProvider.disablePrev; @Input() prevConfirmer: () => XStandardType = this.propertyProvider.prevConfirmer; @Input() prevPosition: XStandardType = this.propertyProvider.prevPosition; @Input() prevCssClass: XStandardType> = this.propertyProvider.prevCssClass; @Input() prevButton: XStandardType> = this.propertyProvider.prevButton; //#endregion // //#region Reset ... @Input() hasReset: XStandardType = this.propertyProvider.hasReset; @Input() disableReset: XStandardType = this.propertyProvider.disableReset; @Input() resetConfirmer: () => XStandardType = this.propertyProvider.resetConfirmer; @Input() resetPosition: XStandardType = this.propertyProvider.resetPosition; @Input() resetCssClass: XStandardType> = this.propertyProvider.resetCssClass; @Input() resetButton: XStandardType> = this.propertyProvider.resetButton; //#endregion //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XNextPrevResetAndHostContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXNextPrevResetAndHostContainer ): Observable { return forkJoin({ // //#region XComponentCard ... cardCssClass: this.getArrayValue( container ? container.cardCssClass : this.cardCssClass ), isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), //#endregion // //#region XNextPrevResetHost ... // canNext: this.getValue(container ? container.canNext : this.canNext), canPrev: this.getValue(container ? container.canPrev : this.canPrev), canReset: this.getValue(container ? container.canReset : this.canReset), //#endregion // //#region Interface ... // hasNext: this.getValue(container ? container.hasNext : this.hasNext), disableNext: this.getValue( container ? container.disableNext : this.disableNext ), nextConfirmer: this.getValue( container ? container.nextConfirmer : this.nextConfirmer ), nextPosition: this.getValue( container ? container.nextPosition : this.nextPosition ), nextCssClass: this.getValue( container ? container.nextCssClass : this.nextCssClass ), nextButton: this.getValue( container ? container.nextButton : this.nextButton ), hasPrev: this.getValue(container ? container.hasPrev : this.hasPrev), disablePrev: this.getValue( container ? container.disablePrev : this.disablePrev ), prevConfirmer: this.getValue( container ? container.prevConfirmer : this.prevConfirmer ), prevPosition: this.getValue( container ? container.prevPosition : this.prevPosition ), prevCssClass: this.getValue( container ? container.prevCssClass : this.prevCssClass ), prevButton: this.getValue( container ? container.prevButton : this.prevButton ), hasReset: this.getValue(container ? container.hasReset : this.hasReset), disableReset: this.getValue( container ? container.disableReset : this.disableReset ), resetConfirmer: this.getValue( container ? container.resetConfirmer : this.resetConfirmer ), resetPosition: this.getValue( container ? container.resetPosition : this.resetPosition ), resetCssClass: this.getValue( container ? container.resetCssClass : this.resetCssClass ), resetButton: this.getValue( container ? container.resetButton : this.resetButton ), //#endregion }).pipe( map((data) => { return { // ...data, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, // onNext: this.onNext, onPrev: this.onPrev, onReset: this.onReset, }; }) ); } //#endregion } //#endregion //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\i-x-toolbar-footer.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, } from 'x-framework-core'; import { XBackSlotIdentifier, XLogoSlotIdentifier, XMenuSlotIdentifier, XTitleSlotIdentifier, XContentSlotIdentifier, } from '../x-page/x-page.typings'; import { map } from 'rxjs/operators'; import { XFooterActionModel, XComponentFooterContainer, IXComponentFooterContainer, } from '../x-page/x-footer/x-footer.typings'; import { XToolbarActionModel, XComponentToolbarContainer, IXComponentToolbarContainer, } from '../x-page/x-toolbar/x-toolbar.typings'; import { ViewportRuler } from '@angular/cdk/overlay'; import { forkJoin, Observable, Subject } from 'rxjs'; import { XManagerService } from 'x-framework-services'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XBaseContainer, XBaseContainerComponent } from './i-x-base.container'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Container ... type TXToolbarFooterContainer = IXComponentToolbarContainer & IXComponentFooterContainer; export interface IXToolbarFooterContainer extends TXToolbarFooterContainer {} @Injectable({ providedIn: 'root', }) export class XToolbarFooterContainer extends XBaseContainer implements Readonly { // //#region Props ... // //#region Toolbar ... // readonly showToolbar: XStandardType = this.toolbarPropertyProvider.showToolbar; // readonly toolbarActionProvider: Subject = this.toolbarPropertyProvider.toolbarActionProvider; readonly toolbarCssClass: XStandardType> = this.toolbarPropertyProvider.toolbarCssClass; // readonly toolbarColor: XStandardType = this.toolbarPropertyProvider.toolbarColor; // readonly toolbarShowProgressBar: XStandardType = this.toolbarPropertyProvider.toolbarShowProgressBar; readonly toolbarProgressBarColor: XStandardType = this.toolbarPropertyProvider.toolbarProgressBarColor; // readonly toolbarShowTitle: XStandardType = this.toolbarPropertyProvider.toolbarShowTitle; readonly toolbarTitleSlot: XStandardType = this.toolbarPropertyProvider.toolbarTitleSlot; readonly toolbarTitle: XStandardType = this.toolbarPropertyProvider.toolbarTitle; // readonly toolbarShowSubTitle: XStandardType = this.toolbarPropertyProvider.toolbarShowSubTitle; readonly toolbarSubTitle: XStandardType = this.toolbarPropertyProvider.toolbarSubTitle; // readonly toolbarShowLogo: XStandardType = this.toolbarPropertyProvider.toolbarShowLogo; readonly toolbarLogoSlot: XStandardType = this.toolbarPropertyProvider.toolbarLogoSlot; readonly toolbarLogoUrl: XStandardType = this.toolbarPropertyProvider.toolbarLogoUrl; // readonly toolbarHasBack: XStandardType = this.toolbarPropertyProvider.toolbarHasBack; readonly toolbarShowBack: XStandardType = this.toolbarPropertyProvider.toolbarShowBack; readonly toolbarBackSlot: XStandardType = this.toolbarPropertyProvider.toolbarBackSlot; readonly toolbarBackHandler?: () => XStandardType = this.toolbarPropertyProvider.toolbarBackHandler; readonly toolbarDefaultHref: string = this.toolbarPropertyProvider.toolbarDefaultHref; // readonly toolbarHasMenu: XStandardType = this.toolbarPropertyProvider.toolbarHasMenu; readonly toolbarShowMenu: XStandardType = this.toolbarPropertyProvider.toolbarShowMenu; readonly toolbarAutoHideMenu: XStandardType = this.toolbarPropertyProvider.toolbarAutoHideMenu; readonly toolbarMenuSlot: XStandardType = this.toolbarPropertyProvider.toolbarMenuSlot; // readonly toolbarStartSlotButtonsTemplate: TemplateRef = this.toolbarPropertyProvider.toolbarStartSlotButtonsTemplate; readonly toolbarEndSlotButtonsTemplate: TemplateRef = this.toolbarPropertyProvider.toolbarEndSlotButtonsTemplate; // readonly toolbarContentSlot: XStandardType = this.toolbarPropertyProvider.toolbarContentSlot; readonly toolbarContentTemplate: TemplateRef = this.toolbarPropertyProvider.toolbarContentTemplate; //#endregion // //#region Footer ... // readonly showFooter: XStandardType = this.footerPropertyProvider.showFooter; // readonly footerActionProvider: Subject = this.footerPropertyProvider.footerActionProvider; readonly footerCssClass: XStandardType> = this.footerPropertyProvider.footerCssClass; // readonly footerColor: XStandardType = this.footerPropertyProvider.footerColor; readonly footerContentTemplate: TemplateRef = this.footerPropertyProvider.footerContentTemplate; //#endregion //#endregion // //#region Constructor ... constructor( protected toolbarPropertyProvider: XComponentToolbarContainer, protected footerPropertyProvider: XComponentFooterContainer ) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XToolbarFooterContainerComponent extends XBaseContainerComponent implements IXToolbarFooterContainer { // //#region Props ... // //#region Toolbar ... // @Input() showToolbar: XStandardType = this.propertyProvider.showToolbar; // @Input() toolbarActionProvider: Subject = this.propertyProvider.toolbarActionProvider; @Input() toolbarCssClass: XStandardType> = this.propertyProvider.toolbarCssClass; // @Input() toolbarColor: XStandardType = this.propertyProvider.toolbarColor; // @Input() toolbarShowProgressBar: XStandardType = this.propertyProvider.toolbarShowProgressBar; @Input() toolbarProgressBarColor: XStandardType = this.propertyProvider.toolbarProgressBarColor; // @Input() toolbarShowTitle: XStandardType = this.propertyProvider.toolbarShowTitle; @Input() toolbarTitleSlot: XStandardType = this.propertyProvider.toolbarTitleSlot; @Input() toolbarTitle: XStandardType = this.propertyProvider.toolbarTitle; // @Input() toolbarShowSubTitle: XStandardType = this.propertyProvider.toolbarShowSubTitle; @Input() toolbarSubTitle: XStandardType = this.propertyProvider.toolbarSubTitle; // @Input() toolbarShowLogo: XStandardType = this.propertyProvider.toolbarShowLogo; @Input() toolbarLogoSlot: XStandardType = this.propertyProvider.toolbarLogoSlot; @Input() toolbarLogoUrl: XStandardType = this.propertyProvider.toolbarLogoUrl; // @Input() toolbarHasBack: XStandardType = this.propertyProvider.toolbarHasBack; @Input() toolbarShowBack: XStandardType = this.propertyProvider.toolbarShowBack; @Input() toolbarBackSlot: XStandardType = this.propertyProvider.toolbarBackSlot; @Input() toolbarBackHandler?: () => XStandardType = this.propertyProvider.toolbarBackHandler; @Input() toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref; // @Input() toolbarHasMenu: XStandardType = this.propertyProvider.toolbarHasMenu; @Input() toolbarShowMenu: XStandardType = this.propertyProvider.toolbarShowMenu; @Input() toolbarAutoHideMenu: XStandardType = this.propertyProvider.toolbarAutoHideMenu; @Input() toolbarMenuSlot: XStandardType = this.propertyProvider.toolbarMenuSlot; // @Input() toolbarStartSlotButtonsTemplate: TemplateRef = this.propertyProvider.toolbarStartSlotButtonsTemplate; @Input() toolbarEndSlotButtonsTemplate: TemplateRef = this.propertyProvider.toolbarEndSlotButtonsTemplate; // @Input() toolbarContentSlot: XStandardType = this.propertyProvider.toolbarContentSlot; @Input() toolbarContentTemplate: TemplateRef = this.propertyProvider.toolbarContentTemplate; //#endregion // //#region Footer ... // @Input() showFooter: XStandardType = this.propertyProvider.showFooter; // @Input() footerActionProvider: Subject = this.propertyProvider.footerActionProvider; @Input() footerCssClass: XStandardType> = this.propertyProvider.footerCssClass; // @Input() footerColor: XStandardType = this.propertyProvider.footerColor; @Input() footerContentTemplate: TemplateRef = this.propertyProvider.footerContentTemplate; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XToolbarFooterContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXToolbarFooterContainer ): Observable { return forkJoin({ // //#region Toolbar ... showToolbar: this.getValue( container ? container.showToolbar : this.showToolbar ), toolbarCssClass: this.getValue( container ? container.toolbarCssClass : this.toolbarCssClass ), toolbarColor: this.getValue( container ? container.toolbarColor : this.toolbarColor ), toolbarShowProgressBar: this.getValue( container ? container.toolbarShowProgressBar : this.toolbarShowProgressBar ), toolbarProgressBarColor: this.getValue( container ? container.toolbarProgressBarColor : this.toolbarProgressBarColor ), toolbarShowTitle: this.getValue( container ? container.toolbarShowTitle : this.toolbarShowTitle ), toolbarTitleSlot: this.getValue( container ? container.toolbarTitleSlot : this.toolbarTitleSlot ), toolbarTitle: this.getValue( container ? container.toolbarTitle : this.toolbarTitle ), toolbarShowSubTitle: this.getValue( container ? container.toolbarShowSubTitle : this.toolbarShowSubTitle ), toolbarSubTitle: this.getValue( container ? container.toolbarSubTitle : this.toolbarSubTitle ), toolbarShowLogo: this.getValue( container ? container.toolbarShowLogo : this.toolbarShowLogo ), toolbarLogoSlot: this.getValue( container ? container.toolbarLogoSlot : this.toolbarLogoSlot ), toolbarLogoUrl: this.getValue( container ? container.toolbarLogoUrl : this.toolbarLogoUrl ), toolbarHasBack: this.getValue( container ? container.toolbarHasBack : this.toolbarHasBack ), toolbarShowBack: this.getValue( container ? container.toolbarShowBack : this.toolbarShowBack ), toolbarBackSlot: this.getValue( container ? container.toolbarBackSlot : this.toolbarBackSlot ), toolbarBackHandler: this.getValue( container ? container.toolbarBackHandler : this.toolbarBackHandler ), toolbarDefaultHref: this.getValue( container ? container.toolbarDefaultHref : this.toolbarDefaultHref ), toolbarHasMenu: this.getValue( container ? container.toolbarHasMenu : this.toolbarHasMenu ), toolbarShowMenu: this.getValue( container ? container.toolbarShowMenu : this.toolbarShowMenu ), toolbarAutoHideMenu: this.getValue( container ? container.toolbarAutoHideMenu : this.toolbarAutoHideMenu ), toolbarMenuSlot: this.getValue( container ? container.toolbarMenuSlot : this.toolbarMenuSlot ), toolbarStartSlotButtonsTemplate: this.getValue( container ? container.toolbarStartSlotButtonsTemplate : this.toolbarStartSlotButtonsTemplate ), toolbarEndSlotButtonsTemplate: this.getValue( container ? container.toolbarEndSlotButtonsTemplate : this.toolbarEndSlotButtonsTemplate ), toolbarContentSlot: this.getValue( container ? container.toolbarContentSlot : this.toolbarContentSlot ), toolbarContentTemplate: this.getValue( container ? container.toolbarContentTemplate : this.toolbarContentTemplate ), //#endregion // //#region Footer ... showFooter: this.getValue( container ? container.showFooter : this.showFooter ), footerCssClass: this.getValue( container ? container.footerCssClass : this.footerCssClass ), footerColor: this.getValue( container ? container.footerColor : this.footerColor ), footerContentTemplate: this.getValue( container ? container.footerContentTemplate : this.footerContentTemplate ), //#endregion }).pipe( map((data) => { return { // ...data, // toolbarActionProvider: container ? container.toolbarActionProvider : this.toolbarActionProvider, // footerActionProvider: container ? container.footerActionProvider : this.footerActionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base-action.model.ts export interface XBaseActionModel { action: T; payload?: any; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base-component.ts import { Input, OnInit, Inject, Output, NgZone, OnDestroy, Component, Renderer2, OnChanges, ElementRef, EventEmitter, AfterViewInit, SimpleChanges, AfterContentInit, AfterViewChecked, ChangeDetectorRef, AfterContentChecked, } from '@angular/core'; import { tap, map, first, filter, takeUntil, concatMap, catchError, } from 'rxjs/operators'; import { keys, XTask, XColor, XParam, toArray, getValue, notValue, isNumber, XUiEvent, hasChild, XRenderer, isFunction, XException, formatDate, isValueDate, applyLocale, toObservable, XResourceIDs, XExceptionIDs, XStandardType, fromUtcString, XOneOrManyType, toNormalString, stringFormatter, getDefaultValue, XFormControlState, isNullOrUndefined, getErrorException, getDateFormatString, isNullOrEmptyString, XResourceIdentifier, XExceptionIdentifier, XModalButtonRoleIdentifier, nameof, generateUuid, XKey, } from 'x-framework-core'; import { NgModel } from '@angular/forms'; import { NavigationExtras } from '@angular/router'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { IXBaseObservableTools } from './x-base.observable.tools'; import { Subject, of, Observable, throwError, forkJoin } from 'rxjs'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; import { XBaseActionModel } from './x-base-action.model'; @Component({ template: '', }) export abstract class XBaseComponent extends XRenderer implements OnInit, OnDestroy, OnChanges, AfterViewInit, AfterViewChecked, AfterContentInit, AfterContentChecked, IXBaseObservableTools { // //#region Props ... // public readonly isMobileUi$ = this.managerService.isMobileUi$; public readonly isNotMobileUi$ = this.managerService.isNotMobileUi$; // public readonly ResourceIDs = Object.assign({}, XResourceIDs); public readonly ExceptionIDs = Object.assign({}, XExceptionIDs); // public TaskRepo: XTask[] = []; public RunningTasks: XTask[] = []; // public unsubscriber = new Subject(); // protected applyThemeColors = false; /** * Unique Component Identifier ... */ readonly uuid = generateUuid('X[' + this.constructor.name + ']'); // //#region Component reload ... private SHOW_COMPONENT: boolean = true; set showComponent(v: boolean) { // if (this.SHOW_COMPONENT !== v) { this.onComponentVisibilityChanged(v); } // this.SHOW_COMPONENT = v; } get showComponent() { return this.SHOW_COMPONENT; } async reloadComponent(delay?: number) { // if (!isNullOrUndefined(delay) && delay < 100) { delay = 100; } // this.showComponent = false; this.detectChanges(); return this.waitForElement(this.element.nativeElement.tagName).then( (el) => { // setTimeout(() => { // this.showComponent = true; this.detectChanges(); }, delay); } ); } onComponentVisibilityChanged(visible: boolean) {} //#endregion // //#region Loading ... /** * Notifiy Loading Changed ... */ @Output() loadingNotifier = new EventEmitter<{ id: string; state: boolean }>(); private LOADING: boolean = false; /** * Loading State of Component Representation ... */ @Input() set loading(v: boolean) { // this.LOADING = v; this.onLoading(v); this.loadingNotifier.emit({ id: this.uuid, state: v }); } get loading() { return this.LOADING; } onLoading(state: boolean) {} //#endregion // //#region Ui Disabled ... /** * Notifiy Ui Disabled Changed ... */ @Output() uiDisabledNotifier = new EventEmitter<{ id: string; state: boolean }>(); private UI_DISABLED: boolean = false; /** * Set UI State Disables / Enabled of Component ... */ @Input() set uiDisabled(v: boolean) { // this.UI_DISABLED = v; this.onUiDisabled(v); this.uiDisabledNotifier.emit({ id: this.uuid, state: v }); } get uiDisabled() { return this.UI_DISABLED; } onUiDisabled(state: boolean) {} //#endregion // //#region Error ... /** * Notify Error Changed ... */ errorNotifier = new EventEmitter<{ id: string; state: boolean }>(); private ERROR: XException = undefined; /** * Set Specified Error of Component if Exists ... */ @Input() set error(v: XException) { // this.ERROR = v; this.onError(v); // const hasError = isNullOrUndefined(v); this.errorNotifier.emit({ id: this.uuid, state: hasError }); } get error() { return this.ERROR; } onError(error: XException) {} //#endregion // //#region Lock ... /** * Notify Lock Changed ... */ @Output() lockNotifier = new EventEmitter<{ id: string; state: boolean }>(); private LOCK: boolean = false; /** * Specified Component Locked or not ... */ @Input() set lock(v: boolean) { // this.LOCK = v; this.onLock(v); this.lockNotifier.emit({ id: this.uuid, state: v }); } get lock() { return this.LOCK; } onLock(state: boolean) {} //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef ) { super(config, element, renderer, ruler, zone); } //#endregion // //#region Abstracted ... //#endregion // //#region LifeCycle ... ngOnInit(): void { // this.clearTasks(); this.registerComponentHandlers(); // this.onInit(); } ngAfterViewInit(): void { // this.registerViewHandlers(); // // Apply theme Colors only when it's required ... if (this.applyThemeColors) { this.managerService.themeManagerService .applyCurrentTheme(this.element) .then(() => this.detectChanges()); } // // Handle Apply Manager Service UI State Changed Events is Base Components ... this.applyTakeUntilWrapper( this.managerService.uiStateChanged.asObservable() ).subscribe((state) => { // if (state === XUiEvent.StartLoading && !this.loading) { this.loading = true; } else if (state === XUiEvent.StopLoading && this.loading) { this.loading = false; } else if (state === XUiEvent.Disabled && !this.uiDisabled) { this.uiDisabled = true; } else if (state === XUiEvent.Enabled && this.uiDisabled) { this.uiDisabled = false; } // this.detectChanges(); }); // // Set UUID attribute ... this.setAttribute('xFramework', this.uuid); // this.afterViewInit(); } ngAfterViewChecked(): void { this.afterViewChecked(); } ngAfterContentInit(): void { this.afterContentInit(); } ngAfterContentChecked(): void { this.afterContentChecked(); } ngOnDestroy(): void { // this.clearTasks(); this.unregisterHandlers(); // this.onDestroy(); } ngOnChanges(changes: SimpleChanges): void { // const changeKeys = keys(changes); // let isChanged = false; let applyChanges = false; // // Error Changes ... isChanged = changeKeys.includes(nameof('error')); if (isChanged) { // const hasError = !isNullOrUndefined(this.error); if (hasError) { this.addClass('x-has-error'); } else { this.removeClass('x-has-error'); } // applyChanges = true; this.onError(this.error); this.errorNotifier.emit({ id: this.uuid, state: hasError }); } // // Loading Changes ... isChanged = changeKeys.includes(nameof('loading')); if (isChanged) { // if (this.loading) { this.addClass('x-loading'); } else { this.removeClass('x-loading'); } // applyChanges = true; this.onLoading(this.loading); this.loadingNotifier.emit({ id: this.uuid, state: this.loading }); } // // uiDisabled Changes ... isChanged = changeKeys.includes(nameof('uiDisabled')); if (isChanged) { // if (this.uiDisabled) { this.addClass('x-disabled'); } else { this.removeClass('x-disabled'); } // applyChanges = true; this.onUiDisabled(this.uiDisabled); this.uiDisabledNotifier.emit({ id: this.uuid, state: this.uiDisabled }); } // // Lock Change ... isChanged = changeKeys.includes(nameof('lock')); if (isChanged) { // if (this.lock) { this.addClass('x-locked'); } else { this.removeClass('x-locked'); } // applyChanges = true; this.onLock(this.lock); this.lockNotifier.emit({ id: this.uuid, state: this.lock }); } // if (applyChanges) { this.detectChanges(); } // this.onChange(changeKeys); } // //#region Ionic LifeCycles ... ionViewWillEnter() { this.willEnter(); } ionViewDidEnter() { this.didEnter(); } ionViewWillLeave() { this.willLeave(); } ionViewDidLeave() { this.didLeave(); } //#endregion // //#region Abstracted LifeCycles ... public onInit() {} public willEnter() {} public didEnter() {} public afterViewInit() {} public afterViewChecked() {} public afterContentInit() {} public afterContentChecked() {} public onChange(changeKeys: string[]) {} public willLeave() {} public didLeave() {} public onDestroy() {} //#endregion //#endregion // //#region Providers ... public registerInstanceHandlers(): void {} public registerViewHandlers(): void {} /** * Retrieve Specified Property Names ... */ getFieldName(obj: T, name: XKey): string { return name.toString(); } //#endregion // //#region Notifier Handlers ... public onResize(event?: Event) {} /** * notify a Task Start ... * * @param name task name */ public onTaskStart(name: string, task: XTask) {} /** * notify an error on running task ... * * @param name task name * @param task task object */ public onTaskFailed(name: string, task: XTask) {} /** * notify a task finished successfully ... * * @param name task name * @param task task object */ public onTaskFinished(name: string, task: XTask) {} //#endregion // //#region Handlers ... /** * Clear Error of Component ... */ public clearError() { // setTimeout(() => { // this.error = null; this.managerService.error = null; }, 500); } /** * show error ... */ public showError( exception: | Error | string | XException | XExceptionIDs | XExceptionIdentifier | any = undefined, next?: () => void ) { // let mException: any = getErrorException(exception); if (isNullOrUndefined(mException) && !isNullOrUndefined(this.error)) { mException = this.error; } else if (isNullOrUndefined(mException)) { mException = XExceptionIDs.ActionFailed; } // this.managerService.notificationService.presentErrorNotification({ exception: mException, dissmissable: true, onWillDismiss: () => { // this.clearError(); // if (next && isFunction(next)) { next(); } }, }); } /** * handle error state ... */ public async handleErrorState( exception?: XExceptionIdentifier, presentNotification: boolean = true, redirectToUrl?: string, returnUrl?: string, params?: NavigationExtras, duration: number = this.config.defaultNotificationDelay, replaceUrl = true ) { // //#region Inside Content ... let errorMessage = this.managerService.localizationService.getErrorMessage(exception); // if ( exception.hasOwnProperty('payload') && hasChild((exception as any)['payload']) ) { // const payload = (exception as any)['payload'] as Array; // const localizedPayload = payload.map((pl) => { // if (isValueDate(pl)) { // const plDate = fromUtcString(pl); const locale = this.managerService.currentLocale; // const result = formatDate( plDate, locale, getDateFormatString(locale) ); // return result; } else { return this.applyLocale(pl); } }); // errorMessage = stringFormatter(errorMessage, localizedPayload); } // if (!params || !params.state) { params = { ...params, state: {}, }; } // params.state[XParam.ReturnUrl] = returnUrl; params.state[XParam.Exception] = exception; // if (presentNotification) { // if (duration < 500 || duration > 10000) { duration = this.config.defaultNotificationDelay; } // await this.managerService.notificationService.presentDangerNotification({ message: errorMessage, dissmissable: true, opt: { duration, }, }); } // if (redirectToUrl && !isNullOrEmptyString(redirectToUrl)) { await this.managerService.navigateByUrlReplace( redirectToUrl, params, replaceUrl ); } //#endregion } /** * show success ... */ public showSuccess(message?: XResourceIdentifier, next?: () => void) { // if (!message) { message = XResourceIDs.success_msg; } // this.managerService.notificationService.presentSuccessNotification({ message, dissmissable: true, onWillDismiss: () => { // if (next && isFunction(next)) { next(); } }, }); } /** * present an action modal with yes and no button ... * * @param header the action title resource/msg ... * @param yesHandler the handler which must run when user accept action ... * @param yesRole the yes button role ... * @param noHandler the handler which must run when user reject action ... * @param noRole the no button role ... */ public async presentYesNoDialog( header: XResourceIdentifier, yesHandler: () => void, yesRole?: XModalButtonRoleIdentifier, noHandler?: () => void, noRole?: XModalButtonRoleIdentifier ) { // if (isNullOrUndefined(header)) { header = this.ResourceIDs.are_you_sure; } // await this.managerService.dialogService.presentActionModal({ header, buttons: [], keyboardClose: true, backdropDismiss: true, hasNo: true, noRole, noHandler, hasYes: true, yesRole, yesHandler, }); } /** * present an action modal with yes and no button ... * * @param yesHandler the handler which must run when user accept action ... * @param yesRole the yes button role ... * @param noHandler the handler which must run when user reject action ... * @param noRole the no button role ... */ public async presentDefaultYesNoDialog( yesHandler: () => void, yesRole?: XModalButtonRoleIdentifier, noHandler?: () => void, noRole?: XModalButtonRoleIdentifier ) { // await this.managerService.dialogService.presentActionModal({ header: this.ResourceIDs.are_you_sure, buttons: [], keyboardClose: true, backdropDismiss: true, hasNo: true, noRole, noHandler, hasYes: true, yesRole, yesHandler, }); } /** * lock page for an action * * @param isLoading specify state */ public async setLoadingState(isLoading: boolean) { // this.loading = isLoading; this.uiDisabled = isLoading; // this.detectChanges(); } /** * handle Default Action for Closing open Dialog ... */ public handleDefaultDialogCloseAction() { // this.managerService.dialogService.modalController.dismiss({ dismissed: true, }); } /** * Release all Subscription ... */ public releaseUnsubscriber() { this.unregisterHandlers(); } /** * apply localization on numbers of a text ... * * @param content the text */ public applyLocale(content: string | any) { return applyLocale( content || isNumber(content) ? content.toString() : '', this.managerService.localizationService.locale ); } /** * apply locale and get current resource translated value ... * * @param id tes resource id */ public resourceProvider(id: XResourceIdentifier): string { return ( this.managerService.localizationService.getValue(id) || id.toString() ); } /** * default join strings ... */ public combinedResourceProvider(...ids: XResourceIdentifier[]) { return this.managerService.localizationService.combine( this.managerService.currentLocale, ' ', ...ids ); } /** * get translation of exception id ... * * @param id exception id */ public exceptionResourceProvider(id: XExceptionIdentifier) { return this.managerService.localizationService.getErrorMessage(id); } /** * retrieve property value ... * * @param object the context object ... * @param prop the property name ... */ public getPropValue(object: T, prop: keyof T) { return getValue(object, prop); } /** * retrieve desiered color name based on form control state ... * * @param status form status */ public getIconColor(status: XFormControlState) { switch (status) { case 'DISABLED': case 'PENDING': default: return XColor.Warning; case 'VALID': return XColor.Primary; case 'INVALID': return XColor.Danger; } } /** * determines an element contains child nodes or not ... * * @param ref the element refrence */ public hasChildNodes(ref: ElementRef) { return ref && (ref.nativeElement as HTMLElement).children.length > 0; } public getLengthError(model: NgModel, identifier: string) { // if (!model || !model.errors) { return ''; } // const errorObject = model.getError(identifier); const requiredLength = errorObject.requiredLength; const actualLength = errorObject.actualLength; // return `(${actualLength}/${requiredLength})`; } /** * usefull for doing nothing ... */ public nothing() {} //#endregion // //#region Task Methods ... /** * check a task is Exists or not ... * * @param name task name */ public async hasTask(name: string) { // const hasTask = this.TaskRepo.findIndex((t) => t.name === name) > -1; return hasTask; } /** * retrieve a task by it's name ... * * @param name task name */ public async getTask(name: string) { // const isExists = await this.hasTask(name); if (!isExists) { return null; } // const task = this.TaskRepo.find((t) => t.name === name); return task; } /** * add or update a task in Task Repo ... * * @param task the task object */ public async addOrUpdateTask(task: XTask) { // if (!task) { return; } // const isExists = await this.hasTask(task.name); if (!isExists) { this.TaskRepo.push(task); } else { await this.updateTask(task); } } /** * Add a New Task to Task Repo ... * * @param task task object */ public async addTask(task: XTask) { // if (!task) { return; } // const isExists = await this.hasTask(task.name); if (isExists) { return; } // this.TaskRepo.push(task); } /** * Update a Task in Task Repo ... * * @param task the task object */ public async updateTask(task: XTask) { // const isExists = await this.hasTask(task.name); if (!isExists) { return; } // await this.removeTask(task.name); this.TaskRepo.push(task); } /** * remove a task by it's name ... * * @param name the task name */ public async removeTask(name: string) { // const isExists = await this.hasTask(name); if (!isExists) { return; } // if (this.managerService.taskManagerService.has(name)) { this.managerService.taskManagerService.delete(name); } // this.TaskRepo = this.TaskRepo.filter((t) => t.name !== name); } /** * call a task for running on task manager ... * * @param name task name */ public async dispatchTask(name: string) { // if (isNullOrEmptyString(name)) { return; } // const task = await this.getTask(name); if (!task) { return; } // this.managerService.taskManagerService.add(task); } /** * check a Task is running or not by it's name * * @param name task name */ public async isTaskRunning(name: string) { // if (isNullOrEmptyString(name)) { return false; } // name = toNormalString(name); // return ( this.RunningTasks.findIndex((rt) => name === toNormalString(rt.name)) > -1 ); } /** * clear all tasks for component ... */ public async clearTasks() { // this.TaskRepo = []; this.RunningTasks = []; } /** * do some actions related to Task Repo when a Task Start ... * * @param name task name * @param task task object */ private async handlTaskStart(name: string, task: XTask) { // const isRunning = await this.isTaskRunning(name); if (isRunning) { return; } // this.RunningTasks.push(task); } /** * do some actions related to Task Repo when a Task Failed ... * * @param name task name * @param task task object */ private async handleTaskFailed(name: string, task: XTask) { // const isRunning = await this.isTaskRunning(name); if (!isRunning) { return; } // const tName = toNormalString(task.name); this.RunningTasks = this.RunningTasks.filter( (t) => tName !== toNormalString(t.name) ); } /** * do some actions related to Task Repo when a Task Finished ... * * @param name task name * @param task task object */ private async handleTaskFinished(name: string, task: XTask) { // const isRunning = await this.isTaskRunning(name); if (!isRunning) { return; } // const tName = toNormalString(task.name); this.TaskRepo = this.TaskRepo.filter( (t) => tName !== toNormalString(t.name) ); this.RunningTasks = this.RunningTasks.filter( (t) => tName !== toNormalString(t.name) ); } //#endregion // //#region Observable Actions ... /** * Check if items has childs or not ... * * @param items a list item ... */ public hasChild(items: XOneOrManyType) { return hasChild(items); } /** * convert an standard UI Value to Observable for consuming ... * * @param value the standard UI Value */ public getValue(value: XStandardType) { return toObservable(value); } /** * get stream Observble of specified standard value */ public getValueStream(value: XStandardType) { return this.applyTakeUntilWrapper(this.getValue(value)); } /** * retrieve an standard type var in promise * * @param value an standard type var */ public async getValueAsync(value: XStandardType) { // if (!value) { return null; } // return await this.toPromise(this.getValue(value)); } /** * convert to array ... * * @param value an standard type one or many arg ... */ public getArrayValue(value: XStandardType>) { return this.getValue(value).pipe(map((valueType) => toArray(valueType))); } /** * convert to array ... * * @param value an standard type one or many arg ... */ public async getArrayValueAsync(value: XStandardType>) { return await this.getValueAsync(this.getArrayValue(value)); } /** * check a value has child or not ... * * @param value an standard one or many of type */ public hasChildValue(value: XStandardType>) { // return this.getValue(value).pipe( map((valueType) => hasChild(toArray(valueType))) ); } /** * check a value has child or not ... * * @param value an standard one or many of type */ public async hasChildValueAsync(value: XStandardType>) { // const valueType = await this.getValueAsync(value); if (!valueType) { return false; } // return hasChild(toArray(valueType)); } /** * count a value's child ... * * @param value an standard one or many of type */ public countChildsValue(value: XStandardType>) { return this.getValue(value).pipe( map((valueType) => toArray(valueType).length) ); } /** * count a value's child ... * * @param value an standard one or many of type */ public async countChildsValueAsync( value: XStandardType> ) { // const valueType = await this.getValueAsync(value); if (!valueType) { return 0; } // return toArray(valueType).length; } /** * providing string resources ... * * @param value an standard one or many of type */ public getResourceValue(value: XStandardType) { // return !value ? of('') : this.getValue(value).pipe( map((val) => { return this.resourceProvider(val) || (value as string); }) ); } /** * providing string resources ... * * @param value an standard one or many of type */ public async getResourceValueAsync( value: XStandardType ) { // if (!value) { return ''; } // const val = await this.getValueAsync(value); return this.resourceProvider(val) || (val as string); } /** * determines a given value has content and not empty * * @param value an Standard type of string */ public notEmptyValue(value: XStandardType) { return this.getValue(value).pipe(map((val) => !isNullOrEmptyString(val))); } /** * determines a given value has content and not empty * * @param value an Standard type of string */ public async notEmptyValueAsync(value: any) { return await this.toPromise(this.notEmptyValue(value)); } /** * determines a given value has not content and empty * * @param value an Standard type of string */ public emptyValue(value: XStandardType) { return this.getValue(value).pipe(map((val) => isNullOrEmptyString(val))); } /** * determines a given value has not content and empty * * @param value an Standard type of string */ public async emptyValueAsync(value: XStandardType) { return await this.toPromise(this.emptyValue(value)); } /** * apply not operator to a boolean ... */ public notValue(value: XStandardType) { return notValue(this.getValue(value)); } /** * apply not operator to a boolean ... */ public async notValueAsync(value: XStandardType) { return await this.getValueAsync(this.notValue(value)); } /** * check all input args be same as value ... * * @param value any value which going to check with all args to be same as them ... * @param values the input args which be checked by value ... */ public mustBeValue(value: any, ...values: XStandardType[]) { // return forkJoin(values.map((v) => toObservable(v))).pipe( map((res) => { return res.every((i) => i === value); }) ); } /** * check all input args be same as value ... * * @param value any value which going to check with all args to be same as them ... * @param values the input args which be checked by value ... */ public async mustBeValueAsync(value: any, ...values: XStandardType[]) { // return ( await Promise.all(values.map(async (v) => await this.getValueAsync(v))) ).every((v) => v === value); } /** * check all input args contains at least one value ... * * @param value any value which going to check with all args to find one same ... * @param values the input args which be checked by value ... */ public atLeastHasOneValue(value: any, ...values: XStandardType[]) { // return forkJoin(values.map((v) => toObservable(v))).pipe( map((res) => { return res.includes(value); }) ); } /** * check all input args contains at least one value ... * * @param value any value which going to check with all args to find one same ... * @param values the input args which be checked by value ... */ public async atLeastHasOneValueAsync( value: any, ...values: XStandardType[] ) { // return ( await Promise.all(values.map(async (v) => await this.getValueAsync(v))) ).includes(value); } /** * determines a given value has content and not empty * * @param value an Standard type of any */ public notNullOrUndefinedValue(value: XStandardType) { return this.getValue(value).pipe(map((val) => !isNullOrUndefined(val))); } /** * determines a given value has content and not empty * * @param value an Standard type of any */ public async notNullOrUndefinedValueAsync(value: XStandardType) { return await this.toPromise(this.notNullOrUndefinedValue(value)); } /** * determines a given value content must empty * * @param value an Standard type of any */ public nullOrUndefinedValue(value: XStandardType) { return this.getValue(value).pipe(map((val) => isNullOrUndefined(val))); } /** * determines a given value content must empty * * @param value an Standard type of any */ public async nullOrUndefinedValueAsync(value: XStandardType) { return await this.toPromise(this.nullOrUndefinedValue(value)); } /** * retrieve an optional value ... * * @param value the optional standard value ... */ public getOptionalValue(value?: XStandardType): Observable { // if (value) { return this.getValue(value); } // return this.getValue(getDefaultValue(value)); } /** * retrieve an optional value ... * * @param value the optional standard value ... */ public async getOptionalValueAsync(value?: XStandardType) { return await this.toPromise(this.getOptionalValue(value)); } /** * convert all values as observable of them ... * * @param values the standard list of specific type ... * @returns observable of values array of specific type ... */ public getValues(values?: XOneOrManyType>) { // interface ForkSourceType { [index: number]: XStandardType; } // return this.getArrayValue(values).pipe( concatMap((values) => { // if (!hasChild(values)) { return this.getValue([] as T[]); } else { // const forkSource: ForkSourceType = {}; values.forEach((value, index) => { forkSource[index] = this.getValue(value); }); // return forkJoin(forkSource).pipe( map((forkResult) => { // const respObj = forkResult as any; const mKeys = Object.keys(forkResult) .map((key) => key) .sort((a, b) => +a - +b); const result = mKeys.map((mKey: any) => respObj[mKey] as T); // return result; }) ); } }) ); } /** * convert all values as observable of them ... * * @param values the standard list of specific type ... * @returns observable of values array of specific type ... */ public async getValuesAsync(values?: XOneOrManyType>) { return await this.toPromise(this.getValues(values)); } /** * apply take until wrapper arround an observable ... * * @param task the observable object */ public applyTakeUntilWrapper(task: Observable): Observable { return task.pipe(takeUntil(this.unsubscriber)); } /** * apply inside component loading wrapper arround an observable ... * * @param task the observable object */ public applyLoadingWrapper(task: Observable): Observable { return of(null).pipe( tap((_) => { this.uiDisabled = true; this.loading = true; }), concatMap((_) => task.pipe( tap(() => { this.uiDisabled = false; this.loading = false; }) ) ), catchError((err) => { // this.uiDisabled = false; this.loading = false; return throwError(err); }) ); } /** * apply get first result of an observable ... * * @param task the observable object */ public applyFirstWrapper(task: Observable): Observable { return task.pipe(first()); } /** * convert an observable to promise object ... * * @param task the observable object */ public toPromise(task: Observable): Promise { return this.applyFirstWrapper(task).toPromise(); } //#endregion // //#region Actions ... /** * Call Change Detector's Detect Change method ... */ detectChanges() { this.changeDetector.detectChanges(); } //#endregion // //#region Private ... /** * Register All Required Subscriptions ... */ private registerComponentHandlers() { // this.registerUiHandlers(); this.registerTaskManager(); this.registerInstanceHandlers(); } /** * Release all Subscriptions based on the Component ... */ private unregisterHandlers() { // this.unsubscriber.next(); this.unsubscriber.complete(); } /** * register Ui Event Handlers ... */ private registerUiHandlers() { // this.applyTakeUntilWrapper(this.ruler.change()).subscribe((resizeEvent) => this.onResize(resizeEvent) ); // this.applyTakeUntilWrapper( this.managerService.themeManagerService.notifyChanges.asObservable() ).subscribe(() => { this.detectChanges(); }); } /** * Register Task Handlers for Finish and Error of Tasks ... */ private registerTaskManager() { // // Task Start ... this.applyTakeUntilWrapper( this.managerService.taskManagerService.taskStart.asObservable() ) .pipe(filter((task) => !isNullOrUndefined(task))) .subscribe((task) => { // this.onTaskStart(task.name, task); // this.handlTaskStart(task.name, task); }); // // Task Error ... this.applyTakeUntilWrapper( this.managerService.taskManagerService.taskError.asObservable() ) .pipe(filter((task) => !isNullOrUndefined(task))) .subscribe((task) => { // this.onTaskFailed(task.name, task); // this.handleTaskFailed(task.name, task); }); // // Task Finished ... this.applyTakeUntilWrapper( this.managerService.taskManagerService.taskFinished.asObservable() ) .pipe(filter((task) => !isNullOrUndefined(task))) .subscribe((task) => { // this.onTaskFinished(task.name, task); // this.handleTaskFinished(task.name, task); }); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base-dialog.service.ts import { XBaseService, XDialogResult, isNullOrUndefined, XResourceIdentifier, } from 'x-framework-core'; import { MatDialog, MatDialogRef, MatDialogConfig, } from '@angular/material/dialog'; import { IXBaseDialogConfig, IXBaseDialogResult, XBaseDialogComponent, IXBaseDialogActionModel, } from './x-base.dialog.component'; import { XManagerService } from 'x-framework-services'; import { EventEmitter, Inject, Injectable, Output } from '@angular/core'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; @Injectable({ providedIn: 'root' }) export abstract class XBaseDialogService< TItem, TActionProviderModel extends IXBaseDialogActionModel, TConfig extends IXBaseDialogConfig, TDialogCompnent extends XBaseDialogComponent< TItem, TActionProviderModel, TConfig > > extends XBaseService { // //#region Props ... private MOBILE_CLASS_NAME = 'mobile'; private DIALOG_REF: MatDialogRef; // isMobile$ = this.managerService.isMobileUi$; // tslint:disable-next-line:no-output-on-prefix @Output() onResult = new EventEmitter(); //#endregion // //#region Abstract ... abstract defaultTitleResourceIdentifier: XResourceIdentifier; abstract openDialogAndReturnRef( config: MatDialogConfig ): MatDialogRef; //#endregion // //#region Constructor ... constructor( protected dialog: MatDialog, protected managerService: XManagerService, @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig ) { super(config); } //#endregion // //#region Actions ... /** * Open Select Map Dialog ... */ async openDialog(config?: TConfig) { // // Prevent Double Bubble ... if (this.DIALOG_REF) { return; } // // Prepare Config ... if (!config) { config = {} as TConfig; } // //#region Default Config for Map Component ... // // Set Default Title ... if (config && !config.title) { config.title = this.defaultTitleResourceIdentifier; } //#endregion // // Prepare Dialog Config ... const data: MatDialogConfig = { data: config, }; // data.panelClass = 'fullscreen-dialog'; // // Show Cropper inside a Dialog ... this.DIALOG_REF = this.openDialogAndReturnRef(data); this.DIALOG_REF.disableClose = true; // // Attach Mobile Class ... this.isMobile$.subscribe((isMobile) => { // if (isMobile) { if (this.DIALOG_REF) { this.DIALOG_REF.addPanelClass(this.MOBILE_CLASS_NAME); } } else { if (this.DIALOG_REF) { this.DIALOG_REF.removePanelClass(this.MOBILE_CLASS_NAME); } } }); // // Handle Backdrop ... this.DIALOG_REF.backdropClick().subscribe(() => { // // Cancel Dialog ... this.onResult.emit({ result: XDialogResult.Cancel }); // this.closeDialog(); }); // // Handle Dialog Result ... this.DIALOG_REF.afterClosed().subscribe((model: IXBaseDialogResult) => { // if (isNullOrUndefined(model) || model.result !== XDialogResult.Ok) { // // Cancel Dialog ... this.onResult.emit({ result: XDialogResult.Cancel }); } else { // // Handle Results ... this.onResult.emit(model); } // this.closeDialog(); }); } /** * Close Select Map Dialog ... */ closeDialog() { // // Prevent Go Forward ... if (!this.DIALOG_REF) { return; } // // Close Dialog ... this.DIALOG_REF.close(); this.DIALOG_REF = null; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base-page.ts import { NgZone, Inject, Output, Renderer2, Component, ElementRef, EventEmitter, HostListener, ChangeDetectorRef, } from '@angular/core'; import { nameof, XResourceIDs, XStandardType, XCanDeactivate, XResourceIdentifier, XBehaviourEventType, isNullOrUndefined, } from 'x-framework-core'; import { Subject, Observable } from 'rxjs'; import { XBaseComponent } from './x-base-component'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; @Component({ template: '', }) export abstract class XBasePage extends XBaseComponent implements XCanDeactivate { /** * Since Page Components Manipulate Angular Router ... * and Angular Router has Deactivate Guards ... * and it Works where component is Locked ... * this Param Specified for Deactivation Guard to Do Unlock by Confirmation or not ... */ protected confirmUnlock: boolean = true; /** * Specified when Page Component is Locked, make Guards available for Prevent Back ... */ protected preventBackHandlingWhenHasLock: boolean = true; // @Output() backPreventNotifier = new EventEmitter<{ id: string; state: boolean }>(); // private PREVENT_BACK = false; get isBackPreveted() { return this.PREVENT_BACK; } set preventBack(v: boolean) { // if (v && !this.PREVENT_BACK) { this.managerService.historyService.pushEmptyState(); } else if (v && this.PREVENT_BACK) { this.managerService.historyService.replaceEmptyState(); } // this.PREVENT_BACK = v; // if (v) { this.addClass('x-back-prevented'); } else { this.addClass('x-back-prevented'); } // this.detectChanges(); this.onBackPrevent(v); this.backPreventNotifier.emit({ id: this.uuid, state: v }); } // onBackPrevent(state: boolean) {} // private IS_PARSING_PARAMS = false; private NOT_PREVENT_REFRESH = true; // public titleRes?: XResourceIdentifier; // public scrollEventSimulator = new Subject(); // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Guards ... public canDeactivate( component: XCanDeactivate, route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): boolean | Observable | Promise { return this.handleCanDeactivateGuard(component, route, state); } @HostListener('window:beforeunload', ['$event']) beforeUnloadHandler($event: any) { // if (!this.NOT_PREVENT_REFRESH) { $event.returnValue = true; } } //#endregion // //#region LifeCycle ... onInit() { super.onInit(); // this.handleParseParams(); this.registerPageHandlers(); } public afterViewInit(): void { super.afterViewInit(); // // Register Lock Notifier for Prevent Handling ... this.applyTakeUntilWrapper(this.lockNotifier.asObservable()).subscribe( (event) => { // if (isNullOrUndefined(event)) { return; } // if (this.preventBackHandlingWhenHasLock) { this.preventBack = event.state; } // this.detectChanges(); } ); } public onChange(changeKeys: string[]): void { super.onChange(changeKeys); // let isChanged = false; let applyChanges = false; // // Looking for Lock Changes ... isChanged = changeKeys.includes(nameof('lock')); if (isChanged) { // applyChanges = true; if (this.preventBackHandlingWhenHasLock) { this.preventBack = this.lock; } } // if (applyChanges) { this.detectChanges(); } } public onBack() {} didEnter() { super.didEnter(); // this.handleResourcePresenting(); } willLeave() { super.willLeave(); // this.clearError(); this.clearTasks(); } public parseParams() {} //#endregion // //#region Notifiers ... public simulateScrollStart() { this.scrollEventSimulator.next('scrollStart'); } public simulateScrollEnd() { this.scrollEventSimulator.next('scrollEnd'); } public simulateScrolling() { this.scrollEventSimulator.next('scrolling'); } //#endregion // //#region Protected ... /** * Do Lock Breakes Works ... * * @param acceptCb * @param cancelCb */ protected async presentDeactiveGuardDialog( acceptCb?: () => XStandardType, cancelCb?: () => XStandardType ) { if (this.lock) { // const a = await this.managerService.dialogService.presentActionModal({ header: XResourceIDs.locked_msg, hasAccept: true, acceptHandler: () => { // if (acceptCb) { acceptCb(); } // this.lock = false; }, hasCancel: true, cancelHandler: () => { // if (cancelCb) { cancelCb(); } // this.lock = true; }, buttons: [], }); // await a.onDidDismiss(); } } //#endregion // //#region Private ... private handleParseParams() { // if (this.IS_PARSING_PARAMS) { return; } // this.IS_PARSING_PARAMS = true; // this.getValueAsync(this.parseParams()) .then(() => (this.IS_PARSING_PARAMS = false)) .catch( () => // (this.IS_PARSING_PARAMS = false) ); } private registerPageHandlers() { // this.registerBackHandler(); this.registerParamsHandler(); } private handleResourcePresenting() { // if (!this.titleRes) { return; } // this.managerService.settingsService.setTitle( this.managerService.localizationService.getValue(this.titleRes) ); } private async handleCanDeactivateGuard( component: XCanDeactivate, route: ActivatedRouteSnapshot, state: RouterStateSnapshot ) { // let result = !this.lock; if (this.lock && this.confirmUnlock) { // await this.presentDeactiveGuardDialog( () => { result = true; }, () => { result = false; } ); } // return result; } private registerBackHandler() { // this.managerService.historyService.platformLocation.onPopState(() => { // if (this.PREVENT_BACK) { this.managerService.historyService.pushEmptyState(); } }); // this.applyTakeUntilWrapper( this.managerService.historyService.backHandler.asObservable() ).subscribe(() => { this.onBack(); }); } private registerParamsHandler() { // this.applyTakeUntilWrapper(this.managerService.routeDataChanged$).subscribe( (res) => { this.handleParseParams(); } ); // this.applyTakeUntilWrapper(this.managerService.routeParmChanged$).subscribe( (res) => { this.handleParseParams(); } ); // this.applyTakeUntilWrapper( this.managerService.routeQueryParmChanged$ ).subscribe((res) => { this.handleParseParams(); }); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base.dialog.component.html

{{ title | async }}

{{ item.data | json }} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base.dialog.component.scss ::ng-deep.fullscreen-dialog { // width: 80vw !important; max-width: 80vw !important; // height: 80vh !important; max-height: 80vh !important; // &.mobile { // width: 100vw !important; max-width: 100vw !important; // height: 100vh !important; max-height: 100vh !important; } // .mat-dialog-container { padding: 0 !important; } } .x-dialog-wrapper { width: 100% !important; height: 100% !important; position: relative !important; } .x-dialog-header { position: sticky !important; top: 0; z-index: 1000; } .x-dialog-content-wrapper { height: calc(100%); &.has-toolbar { height: calc(100% - 56px); } } x-icon { --size: 24px; } .toolbar-area { margin: 0px; } .toolbar-item { width: auto; height: 48px; } .toolbar-inline-item { display: inline-flex !important; } .toolbar-button { width: 32px; margin: { left: 4px; right: 4px; } } h1, h2, h3, h4, h5, h6 { margin: 0 !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base.dialog.component.ts import { Inject, NgZone, Output, Renderer2, Component, ElementRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XTask, XColor, toArray, isFunction, getTaskName, XStandardType, XDialogResult, XOneOrManyType, XColorIdentifier, isNullOrUndefined, isNullOrEmptyString, XResourceIdentifier, } from 'x-framework-core'; import { of, Subject } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { XBaseComponent } from './x-base-component'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XIconNames } from '../x-icon/x-icon.typings'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from './x-base-action.model'; import { XButtonType } from '../x-button/x-button.typings'; import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XBaseDialogAction { Refresh = 'refresh', } export type XBaseDialogActionIdentifier = XBaseDialogAction | string; export interface IXBaseDialogActionModel extends XBaseActionModel {} export interface IXBaseDialogConfig< TActionProviderModel extends IXBaseDialogActionModel > { // showToolbar?: boolean; // title?: XResourceIdentifier; cssClass?: XOneOrManyType; progressBarColor?: XColorIdentifier; // showSearchBar?: boolean; searchBarColor?: XColorIdentifier; searchBarInputColor?: XColorIdentifier; // actionProvider?: Subject; // canMultipleSelect?: boolean; // onItemSelect?: (item: XOneOrManyType) => XStandardType; // onTaskStart?: (name: string) => XStandardType; onTaskFinished?: (name: string) => XStandardType; onTaskFailed?: (name: string) => XStandardType; } export interface IXBaseDialogResult { payload?: any; result: XDialogResult; } @Component({ template: '', }) export abstract class XBaseDialogComponent< TItem, TActionProviderModel extends IXBaseDialogActionModel, TConfig extends IXBaseDialogConfig > extends XBaseComponent { // //#region Props ... // public cancelIcon = XIconNames.close; public selectIcon = XIconNames.checked; public backIcon = XIconNames.arrow_back; // readonly SlotNames = Object.assign({}, XSlotName); readonly ButtonTypes = Object.assign({}, XButtonType); readonly SlotLayouts = Object.assign({}, XSlotLayout); // readonly isMobile$ = this.managerService.isMobileUi$; readonly isNotMobile$ = this.managerService.isNotMobileUi$; // public selectedItem: XOneOrManyType; // //#region Prevent Back ... @Output() backPreventNotifier = new EventEmitter<{ id: string; state: boolean }>(); // private PREVENT_BACK = false; get isBackPreveted() { return this.PREVENT_BACK; } set preventBack(v: boolean) { // if (v && !this.PREVENT_BACK) { this.managerService.historyService.pushEmptyState(); } else if (v && this.PREVENT_BACK) { this.managerService.historyService.replaceEmptyState(); } // this.PREVENT_BACK = v; // if (v) { this.addClass('x-back-prevented'); } else { this.addClass('x-back-prevented'); } // this.detectChanges(); this.onBackPrevent(v); this.backPreventNotifier.emit({ id: this.uuid, state: v }); } // onBackPrevent(state: boolean) {} //#endregion // public baseActionProvider = new Subject(); //#endregion // //#region Constructor ... constructor( public zone: NgZone, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public managerService: XManagerService, public changeDetector: ChangeDetectorRef, @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, @Inject(MAT_DIALOG_DATA) public data: any, public dialogRef: MatDialogRef< XBaseDialogComponent > ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // this.preventBack = true; } public afterViewInit(): void { super.afterViewInit(); // // Register Lock Notifier for Prevent Handling ... this.applyTakeUntilWrapper(this.lockNotifier.asObservable()).subscribe( (event) => { // if (isNullOrUndefined(event)) { return; } // this.preventBack = event.state; this.detectChanges(); } ); } //#endregion // //#region Task Handlers ... async onTaskStart(name: string, task: XTask) { super.onTaskStart(name, task); // const isDialogTask = await this.isDialogTask(name); // if (isDialogTask) { // this.setLoadingState(true); await this.notifyTaskStartEvent(name); } } async onTaskFinished(name: string, task: XTask) { super.onTaskFinished(name, task); // const isDialogTask = await this.isDialogTask(name); // if (isDialogTask) { // this.setLoadingState(false); await this.notifyTaskFinishedEvent(name); } } async onTaskFailed(name: string, task: XTask) { super.onTaskFailed(name, task); // const isDialogTask = await this.isDialogTask(name); // if (isDialogTask) { // this.showError(task.error); this.setLoadingState(false); await this.notifyTaskFailedEvent(name); } } //#endregion // //#region Handlers ... registerViewHandlers() { super.registerViewHandlers(); // this.registerBackHandler(); } //#endregion // //#region UI Providers ... /** * retrieve map dialog config ... */ public getData() { return this.getValue(this.data as TConfig); } /** * determines map dialog config exists or not ... */ public hasData() { return !isNullOrUndefined(this.getData()); } /** * determines dialog can select result or not ... */ public dialogCanSelect() { return this.hasChild(this.selectedItem); } /** * retrieve dialog title ... */ public get title() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config ? config.title : '')) ); } /** * retrieve dialog showTollbar ... */ public get showToolbar() { return this.getData().pipe( concatMap((config) => !config || isNullOrUndefined(config.showToolbar) ? of(true) : this.getOptionalValue(config.showToolbar) ) ); } public get cssClass() { return this.getData().pipe( concatMap((config) => this.getArrayValue(config ? config.cssClass : [])) ); } public get progressBarColor() { return this.getData().pipe( concatMap((config) => this.getValue(config ? config.progressBarColor : XColor.Warning) ), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Warning)) ); } public get actionProvider() { return this.getData().pipe( map((config) => config ? config.actionProvider : this.baseActionProvider ), map((actionProvider) => !isNullOrUndefined(actionProvider) ? actionProvider : this.baseActionProvider ) ); } public get canMultipleSelect() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config ? config.canMultipleSelect : false) ) ); } // //#region SearchBar ... public get showSearchBar() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config ? config.showSearchBar : false) ) ); } public get searchBarColor() { return this.getData().pipe( concatMap((config) => this.getValue(config ? config.searchBarColor : XColor.Primary) ), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Primary)) ); } public get searchBarInputColor() { return this.getData().pipe( concatMap((config) => this.getValue(config ? config.searchBarInputColor : XColor.Primary) ), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Primary)) ); } //#endregion //#endregion // //#region UI Handlers ... async handleBack() { this.dialogRef.close(); } async handleSelect() { // if (!this.dialogCanSelect()) { return; } // this.dialogRef.close({ result: XDialogResult.Ok, payload: this.selectedItem, }); } async handleDeselect() { // if (!this.dialogCanSelect()) { return; } // const canSelectMultipleItems = await this.getValueAsync( this.canMultipleSelect ); if (canSelectMultipleItems) { await this.deselectAllListItems(); } else { // const selectedItem = toArray(this.selectedItem)[0]; if (!isNullOrUndefined(selectedItem)) { await this.deselectItemInList(selectedItem); } } // this.selectedItem = undefined; this.detectChanges(); } //#endregion // //#region Abstract ... abstract getTaskNames(): Promise>; abstract deselectAllListItems(): Promise; abstract deselectItemInList(item: TItem): Promise; abstract handleSearchbarQuryChanged(query: string): Promise; //#endregion // //#region Protected ... public async onBack() {} //#endregion // //#region Private ... private async isDialogTask(name: string) { // const pageTasks = await this.getTaskNames(); const mTaskKey = getTaskName(name); const result = pageTasks.includes(mTaskKey); // return result; } private async notifyTaskStartEvent(name: string) { // if (isNullOrEmptyString(name)) { return; } // const config = await this.getValueAsync(this.getData()); if (config && config.onTaskStart && isFunction(config.onTaskStart)) { await this.getValueAsync(config.onTaskStart(name)); } } private async notifyTaskFinishedEvent(name: string) { // if (isNullOrEmptyString(name)) { return; } // const config = await this.getValueAsync(this.getData()); if (config && config.onTaskFinished && isFunction(config.onTaskFinished)) { await this.getValueAsync(config.onTaskFinished(name)); } } private async notifyTaskFailedEvent(name: string) { // if (isNullOrEmptyString(name)) { return; } // const config = await this.getValueAsync(this.getData()); if (config && config.onTaskFailed && isFunction(config.onTaskFailed)) { await this.getValueAsync(config.onTaskFailed(name)); } } private registerBackHandler() { // this.managerService.historyService.platformLocation.onPopState(() => { // if (this.PREVENT_BACK) { this.managerService.historyService.pushEmptyState(); } }); // this.applyTakeUntilWrapper( this.managerService.historyService.backHandler.asObservable() ).subscribe(async () => { await this.onBack(); }); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\classes\x-base.observable.tools.ts import { toArray, hasChild, notValue, toPromise, toObservable, XStandardType, XOneOrManyType, getDefaultValue, isNullOrUndefined, XResourceIdentifier, isNullOrEmptyString, } from 'x-framework-core'; import { concatMap, map } from 'rxjs/operators'; import { Observable, forkJoin, of } from 'rxjs'; export interface IXBaseObservableTools { // //#region Action ... hasChild: (items: XOneOrManyType) => boolean; //#endregion // //#region Observables ... getValue: (value: XStandardType) => Observable; getArrayValue: ( value: XStandardType> ) => Observable; hasChildValue: ( value: XStandardType> ) => Observable; countChildsValue: ( value: XStandardType> ) => Observable; getResourceValue: ( value: XStandardType ) => Observable; notEmptyValue: (value: XStandardType) => Observable; emptyValue: (value: XStandardType) => Observable; notValue: (value: XStandardType) => Observable; mustBeValue: ( value: any, ...values: XStandardType[] ) => Observable; atLeastHasOneValue: ( value: any, ...values: XStandardType[] ) => Observable; notNullOrUndefinedValue: (value: XStandardType) => Observable; nullOrUndefinedValue: (value: XStandardType) => Observable; getOptionalValue: (value?: XStandardType) => Observable; getValues: (values?: XOneOrManyType>) => Observable; //#endregion // //#region Async of Observables ... getValueAsync: (value: XStandardType) => Promise; getArrayValueAsync: ( value: XStandardType> ) => Promise; hasChildValueAsync: ( value: XStandardType> ) => Promise; countChildsValueAsync: ( value: XStandardType> ) => Promise; getResourceValueAsync: ( value: XStandardType ) => Promise; notEmptyValueAsync: (value: XStandardType) => Promise; emptyValueAsync: (value: XStandardType) => Promise; notValueAsync: (value: XStandardType) => Promise; mustBeValueAsync: ( value: any, ...values: XStandardType[] ) => Promise; atLeastHasOneValueAsync: ( value: any, ...values: XStandardType[] ) => Promise; notNullOrUndefinedValueAsync: (value: XStandardType) => Promise; nullOrUndefinedValueAsync: (value: XStandardType) => Promise; getOptionalValueAsync: (value?: XStandardType) => Promise; getValuesAsync: ( values?: XOneOrManyType> ) => Promise; //#endregion } export abstract class XBaseObservableTools implements IXBaseObservableTools { // //#region Actions ... // //#region Observable Actions ... /** * Check if items has childs or not ... * * @param items a list item ... */ public hasChild(items: XOneOrManyType) { return hasChild(items); } /** * convert an standard UI Value to Observable for consuming ... * * @param value the standard UI Value */ public getValue(value: XStandardType) { return toObservable(value); } /** * retrieve an standard type var in promise * * @param value an standard type var */ public async getValueAsync(value: XStandardType) { // if (!value) { return null; } // return await toPromise(this.getValue(value)); } /** * convert to array ... * * @param value an standard type one or many arg ... */ public getArrayValue(value: XStandardType>) { return this.getValue(value).pipe(map((valueType) => toArray(valueType))); } /** * convert to array ... * * @param value an standard type one or many arg ... */ public async getArrayValueAsync(value: XStandardType>) { return this.getValueAsync(value).then((valueType) => toArray(valueType)); } /** * check a value has child or not ... * * @param value an standard one or many of type */ public hasChildValue(value: XStandardType>) { // return this.getValue(value).pipe( map((valueType) => hasChild(toArray(valueType))) ); } /** * check a value has child or not ... * * @param value an standard one or many of type */ public async hasChildValueAsync(value: XStandardType>) { // const valueType = await this.getValueAsync(value); if (!valueType) { return false; } // return hasChild(toArray(valueType)); } /** * count a value's child ... * * @param value an standard one or many of type */ public countChildsValue(value: XStandardType>) { return this.getValue(value).pipe( map((valueType) => toArray(valueType).length) ); } /** * count a value's child ... * * @param value an standard one or many of type */ public async countChildsValueAsync( value: XStandardType> ) { // const valueType = await this.getValueAsync(value); if (!valueType) { return 0; } // return toArray(valueType).length; } /** * providing string resources ... * * @param value an standard one or many of type */ public getResourceValue(value: XStandardType) { // return !value ? of('') : this.getValue(value).pipe( map((val) => { return val.toString(); // return this.resourceProvider(val) || (value as string); }) ); } /** * providing string resources ... * * @param value an standard one or many of type */ public async getResourceValueAsync( value: XStandardType ) { // if (!value) { return ''; } // const val = await this.getValueAsync(value); return val.toString(); } /** * determines a given value has content and not empty * * @param value an Standard type of string */ public notEmptyValue(value: XStandardType) { return this.getValue(value).pipe(map((val) => !isNullOrEmptyString(val))); } /** * determines a given value has content and not empty * * @param value an Standard type of string */ public async notEmptyValueAsync(value: any) { return await toPromise(this.notEmptyValue(value)); } /** * determines a given value has not content and empty * * @param value an Standard type of string */ public emptyValue(value: XStandardType) { return this.getValue(value).pipe(map((val) => isNullOrEmptyString(val))); } /** * determines a given value has not content and empty * * @param value an Standard type of string */ public async emptyValueAsync(value: XStandardType) { return await toPromise(this.emptyValue(value)); } /** * apply not operator to a boolean ... */ public notValue(value: XStandardType) { return notValue(this.getValue(value)); } /** * apply not operator to a boolean ... */ public async notValueAsync(value: XStandardType) { return await this.getValueAsync(this.notValue(value)); } /** * check all input args be same as value ... * * @param value any value which going to check with all args to be same as them ... * @param values the input args which be checked by value ... */ public mustBeValue(value: any, ...values: XStandardType[]) { // return forkJoin(values.map((v) => toObservable(v))).pipe( map((res) => { return res.every((i) => i === value); }) ); } /** * check all input args be same as value ... * * @param value any value which going to check with all args to be same as them ... * @param values the input args which be checked by value ... */ public async mustBeValueAsync(value: any, ...values: XStandardType[]) { // return ( await Promise.all(values.map(async (v) => await this.getValueAsync(v))) ).every((v) => v === value); } /** * check all input args contains at least one value ... * * @param value any value which going to check with all args to find one same ... * @param values the input args which be checked by value ... */ public atLeastHasOneValue(value: any, ...values: XStandardType[]) { // return forkJoin(values.map((v) => toObservable(v))).pipe( map((res) => { return res.includes(value); }) ); } /** * check all input args contains at least one value ... * * @param value any value which going to check with all args to find one same ... * @param values the input args which be checked by value ... */ public async atLeastHasOneValueAsync( value: any, ...values: XStandardType[] ) { // return ( await Promise.all(values.map(async (v) => await this.getValueAsync(v))) ).includes(value); } /** * determines a given value has content and not empty * * @param value an Standard type of any */ public notNullOrUndefinedValue(value: XStandardType) { return this.getValue(value).pipe(map((val) => !isNullOrUndefined(val))); } /** * determines a given value has content and not empty * * @param value an Standard type of any */ public async notNullOrUndefinedValueAsync(value: XStandardType) { return await toPromise(this.notNullOrUndefinedValue(value)); } /** * determines a given value content must empty * * @param value an Standard type of any */ public nullOrUndefinedValue(value: XStandardType) { return this.getValue(value).pipe(map((val) => isNullOrUndefined(val))); } /** * determines a given value content must empty * * @param value an Standard type of any */ public async nullOrUndefinedValueAsync(value: XStandardType) { return await toPromise(this.nullOrUndefinedValue(value)); } /** * retrieve an optional value ... * * @param value the optional standard value ... */ public getOptionalValue(value?: XStandardType): Observable { // if (value) { return this.getValue(value); } // return this.getValue(getDefaultValue(value)); } /** * retrieve an optional value ... * * @param value the optional standard value ... */ public async getOptionalValueAsync(value?: XStandardType) { return await toPromise(this.getOptionalValue(value)); } /** * convert all values as observable of them ... * * @param values the standard list of specific type ... * @returns observable of values array of specific type ... */ public getValues(values?: XOneOrManyType>) { // interface ForkSourceType { [index: number]: XStandardType; } // return this.getArrayValue(values).pipe( concatMap((values) => { // if (!hasChild(values)) { return this.getValue([] as T[]); } else { // const forkSource: ForkSourceType = {}; values.forEach((value, index) => { forkSource[index] = this.getValue(value); }); // return forkJoin(forkSource).pipe( map((forkResult) => { // const respObj = forkResult as any; const mKeys = Object.keys(forkResult) .map((key) => key) .sort((a, b) => +a - +b); const result = mKeys.map((mKey: any) => respObj[mKey] as T); // return result; }) ); } }) ); } /** * convert all values as observable of them ... * * @param values the standard list of specific type ... * @returns observable of values array of specific type ... */ public async getValuesAsync(values?: XOneOrManyType>) { return await toPromise(this.getValues(values)); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\component-templates.module.ts import { XCardTestComponent, XComponentCardTestComponent, } from './x-card.component.templates'; import { XListTestComponent, XComponentListTestComponent, } from './x-list.component.templates'; import { XTabTestComponent, XTabsTestComponent, } from './x-tabs.component.templates'; import { XEmptyTestComponent, XComponentEmptyTestComponent, } from './x-empty.component.templates'; import { XSlideTestComponent, XSliderTestComponent, } from './x-slider.component.templates'; import { XSlotTestComponent, XSlotterTestComponent, } from './x-slotter.component.templates'; import { XStepTestComponent, XStepperTestComponent, } from './x-stepper.component.templates'; import { NgModule } from '@angular/core'; import { XActionBarTestComponent, XComponentActionBarTestComponent, } from './x-action-bar.component.templates'; import { XSearchBarTestComponent, XComponentSearchBarTestComponent, } from './x-search-bar.component.templates'; import { CommonModule } from '@angular/common'; import { XDescriptionListTestComponent, XDescriptionListItemTestComponent, } from './x-description-list.component.templates'; import { XMapModule } from '../x-map/x-map.module'; import { XFabModule } from '../x-fab/x-fab.module'; import { XIDEModule } from '../x-ide/x-ide.module'; import { XFormModule } from '../x-form/x-form.module'; import { XGridModule } from '../x-grid/x-grid.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XListModule } from '../x-list/x-list.module'; import { XPageModule } from '../x-page/x-page.module'; import { XTabsModule } from '../x-tabs/x-tabs.module'; import { XCardModule } from '../x-card/x-card.module'; import { XTableModule } from '../x-table/x-table.module'; import { XThemeModule } from '../x-theme/x-theme.module'; import { XColorModule } from '../x-color/x-color.module'; import { XEmptyModule } from '../x-empty/x-empty.module'; import { XChartModule } from '../x-chart/x-chart.module'; import { XSliderModule } from '../x-slider/x-slider.module'; import { XButtonModule } from '../x-button/x-button.module'; import { XIdeTestComponent } from './x-ide.component.template'; import { XCounterModule } from '../x-counter/x-counter.module'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XSpinnerModule } from '../x-spinner/x-spinner.module'; import { XStepperModule } from '../x-stepper/x-stepper.module'; import { XMapTestComponent } from './x-map.component.templates'; import { XFabTestComponent } from './x-fab.component.templates'; import { XPageTestComponent } from './x-page.component.templates'; import { XMarkdownModule } from '../x-markdown/x-markdown.module'; import { XFormTestComponent } from './x-form.component.templates'; import { XGridTestComponent } from './x-grid.component.templates'; import { XIconTestComponent } from './x-icon.component.templates'; import { XChartTestComponent } from './x-chart.component.template'; import { XTableTestComponent } from './x-table.component.templates'; import { XColorTestComponent } from './x-color.component.templates'; import { XThumbnailModule } from '../x-thumbnail/x-thumbnail.module'; import { XFooterTestComponent } from './x-footer.component.templates'; import { XButtonTestComponent } from './x-button.component.templates'; import { XSearchBarModule } from '../x-search-bar/x-search-bar.module'; import { XActionBarModule } from '../x-action-bar/x-action-bar.module'; import { XToolbarTestComponent } from './x-toolbar.component.templates'; import { XSpinnerTestComponent } from './x-spinner.component.templates'; import { XCounterTestComponent } from './x-counter.component.templates'; import { XDataPagerModule } from './../x-data-pager/x-data-pager.module'; import { XMarkdownTestComponent } from './x-markdown.component.templates'; import { XFileUploadModule } from '../x-file-upload/x-file-upload.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XThumbnailTestComponent } from './x-thumbnail.component.templates'; import { XNavigatorTestComponent } from './x-navigator.component.templates'; import { XDataPagerTestComponent } from './x-data-pager.component.templates'; import { XColorPickerModule } from '../x-color-picker/x-color-picker.module'; import { XFileUploadTestComponent } from './x-file-upload.component.templates'; import { XImageCropperModule } from '../x-image-cropper/x-image-cropper.module'; import { XAvatarUploadModule } from '../x-avatar-upload/x-avatar-upload.module'; import { XTabNavigatorModule } from '../x-tab-navigator/x-tab-navigator.module'; import { XDataScrollerModule } from '../x-data-scroller/x-data-scroller.module'; import { XColorPickerTestComponent } from './x-color-picker.component.templates'; import { XFileDropAreaModule } from '../x-file-drop-area/x-file-drop-area.module'; import { XTabNavigatorTestComponent } from './x-tab-navigator.component.templates'; import { XThemeManagerTestComponent } from './x-theme-manager.component.templates'; import { XAvatarUploadTestComponent } from './x-avatar-upload.component.templates'; import { XImageCropperTestComponent } from './x-image-cropper.component.templates'; import { XDataScrollerTestComponent } from './x-data-scroller.component.templates'; import { XFileDropAreaTestComponent } from './x-file-drop-area.component.templates'; import { XScreenCaptureTestComponent } from './x-screen-capture.component.templates'; import { XModelPresenterModule } from '../x-model-presenter/x-model-presenter.module'; import { XExpandableListModule } from '../x-expandable-list/x-expandable-list.module'; import { XExpandableListTestComponent } from './x-expandable-list.component.templates'; import { XModelPresenterTestComponent } from './x-model-presenter.component.templates'; import { XDescriptionListModule } from '../x-description-list/x-description-list.module'; import { XExpandablePanelModule } from '../x-expandable-panel/x-expandable-panel.module'; import { XExpandablePandelTestComponent } from './x-expandable-panel.component.templates'; @NgModule({ declarations: [ // // x-action-bar ... XActionBarTestComponent, XComponentActionBarTestComponent, // // x-avatar-upload ... XAvatarUploadTestComponent, // // x-button ... XButtonTestComponent, // // x-ide ... XIdeTestComponent, // // x-chart ... XChartTestComponent, // // x-card ... XCardTestComponent, XComponentCardTestComponent, // // x-color ... XColorTestComponent, // // x-color-picker ... XColorPickerTestComponent, // // x-counter ... XCounterTestComponent, // // x-data-pager ... XDataPagerTestComponent, // // x-data-scroller ... XDataScrollerTestComponent, // // x-description-list ... XDescriptionListTestComponent, XDescriptionListItemTestComponent, // // x-empty ... XEmptyTestComponent, XComponentEmptyTestComponent, // // x-expandable-list ... XExpandableListTestComponent, // // x-expandable-panel ... XExpandablePandelTestComponent, // // x-fab ... XFabTestComponent, // // x-file-drop-area ... XFileDropAreaTestComponent, // // x-file-upload ... XFileUploadTestComponent, // // x-form ... XFormTestComponent, // // x-grid ... XGridTestComponent, // // x-icon ... XIconTestComponent, // // x-image-cropper ... XImageCropperTestComponent, // // x-list ... XListTestComponent, XComponentListTestComponent, // // x-map ... XMapTestComponent, // // x-markdown ... XMarkdownTestComponent, // // x-model-presenter ... XModelPresenterTestComponent, // // x-page ... XPageTestComponent, // // x-footer ... XFooterTestComponent, // // x-navigator ... XNavigatorTestComponent, // // x-toolbar ... XToolbarTestComponent, // // x-screen-capture ... XScreenCaptureTestComponent, // // x-search-bar ... XSearchBarTestComponent, XComponentSearchBarTestComponent, // // x-slider ... XSlideTestComponent, XSliderTestComponent, // // x-slotter ... XSlotTestComponent, XSlotterTestComponent, // // x-spinner ... XSpinnerTestComponent, // // x-stepper ... XStepTestComponent, XStepperTestComponent, // // x-tab-navigator ... XTabNavigatorTestComponent, // // x-table ... XTableTestComponent, // // x-tabs ... XTabTestComponent, XTabsTestComponent, // // x-theme-manager ... XThemeManagerTestComponent, // // x-thumbnail ... XThumbnailTestComponent, ], imports: [ // CommonModule, // XEmptyModule, XBaseComponentModule, // XIDEModule, XFabModule, XMapModule, XPageModule, XCardModule, XIconModule, XFormModule, XTabsModule, XTabsModule, XListModule, XGridModule, XChartModule, XColorModule, XTableModule, XThemeModule, XButtonModule, XSliderModule, XSpinnerModule, XStepperModule, XSlotterModule, XCounterModule, XMarkdownModule, XDataPagerModule, XSearchBarModule, XThumbnailModule, XActionBarModule, XFileUploadModule, XColorPickerModule, XImageCropperModule, XFileDropAreaModule, XDataScrollerModule, XTabNavigatorModule, XAvatarUploadModule, XExpandableListModule, XModelPresenterModule, XExpandablePanelModule, XDescriptionListModule, ], exports: [], }) export class XComponentTemplatesModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-action-bar.component.templates.ts import { Component } from '@angular/core'; import { XActionBarContainerComponent, XComponentActionBarContainerComponent, } from '../x-action-bar/x-action-bar.typings'; @Component({ template: ` `, }) export class XActionBarTestComponent extends XActionBarContainerComponent {} @Component({ template: ` `, }) export class XComponentActionBarTestComponent extends XComponentActionBarContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-avatar-upload.component.templates.ts import { Component } from '@angular/core'; import { XAvatarUploadContainerComponent } from '../x-avatar-upload/x-avatar-upload.typings'; @Component({ template: ` `, }) export class XAvatarUploadTestComponent extends XAvatarUploadContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-button.component.templates.ts import { Component } from '@angular/core'; import { XButtonContainerComponent } from '../x-button/x-button.typings'; @Component({ template: ` `, }) export class XButtonTestComponent extends XButtonContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-card.component.templates.ts import { Component } from '@angular/core'; import { XCardContainerComponent, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; @Component({ template: ` `, }) export class XCardTestComponent extends XCardContainerComponent {} @Component({ template: `
`, }) export class XComponentCardTestComponent extends XComponentCardContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-chart.component.template.ts import { Component } from '@angular/core'; import { XChartContainerComponent } from '../x-chart/x-chart.typings'; @Component({ template: ` `, }) export class XChartTestComponent extends XChartContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-color-picker.component.templates.ts import { Component } from '@angular/core'; import { XColorPickerContainerComponent } from '../x-color-picker/x-color-picker.typings'; @Component({ template: ` `, }) export class XColorPickerTestComponent extends XColorPickerContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-color.component.templates.ts import { Component } from "@angular/core"; import { XColorContainerComponent } from "../x-color/x-color.typings"; @Component({ template: ` ` }) export class XColorTestComponent extends XColorContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-counter.component.templates.ts import { Component } from "@angular/core"; import { XCounterContainerComponent } from "../x-counter/x-counter.typings"; @Component({ template: ` ` }) export class XCounterTestComponent extends XCounterContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-data-pager.component.templates.ts import { Component } from '@angular/core'; import { XDataPagerContainerComponent } from '../x-data-pager/x-data-pager.typings'; @Component({ template: ` `, }) export class XDataPagerTestComponent extends XDataPagerContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-data-scroller.component.templates.ts import { Component } from '@angular/core'; import { XDataScrollerContainerComponent } from '../x-data-scroller/x-data-scroller.typings'; @Component({ template: ` `, }) export class XDataScrollerTestComponent extends XDataScrollerContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-description-list.component.templates.ts import { Component } from '@angular/core'; import { XDescriptionListContainerComponent } from '../x-description-list/x-description-list.typings'; import { XDescriptionListItemContainerComponent } from '../x-description-list/x-description-list-item/x-description-list-item.typings'; @Component({ template: ` `, }) export class XDescriptionListTestComponent extends XDescriptionListContainerComponent {} @Component({ template: ` `, }) export class XDescriptionListItemTestComponent extends XDescriptionListItemContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-empty.component.templates.ts import { Component } from '@angular/core'; import { XComponentEmptyContainerComponent, XEmptyContainerComponent, } from '../x-empty/x-empty.typings'; @Component({ template: ` `, }) export class XEmptyTestComponent extends XEmptyContainerComponent {} @Component({ template: ` `, }) export class XComponentEmptyTestComponent extends XComponentEmptyContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-expandable-list.component.templates.ts import { Component } from '@angular/core'; import { XExpandableListContainerComponent } from '../x-expandable-list/x-expandable-list.typings'; @Component({ template: ` `, }) export class XExpandableListTestComponent extends XExpandableListContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-expandable-panel.component.templates.ts import { Component } from '@angular/core'; import { XExpandablePandelContainerComponent } from '../x-expandable-panel/x-expandable-panel.typings'; @Component({ template: ` `, }) export class XExpandablePandelTestComponent extends XExpandablePandelContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-fab.component.templates.ts import { Component } from '@angular/core'; import { XFabContainerComponent } from '../x-fab/x-fab.typings'; @Component({ template: ` `, }) export class XFabTestComponent extends XFabContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-file-drop-area.component.templates.ts import { Component } from '@angular/core'; import { XFileDropAreaContainerComponent } from '../x-file-drop-area/x-file-drop-area.typings'; @Component({ template: ` `, }) export class XFileDropAreaTestComponent extends XFileDropAreaContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-file-upload.component.templates.ts import { Component } from '@angular/core'; import { XFileUploadContainerComponent } from '../x-file-upload/x-file-upload.typings'; @Component({ template: ` `, }) export class XFileUploadTestComponent extends XFileUploadContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-footer.component.templates.ts import { Component } from '@angular/core'; import { XFooterContainerComponent } from '../x-page/x-footer/x-footer.typings'; @Component({ template: ` `, }) export class XFooterTestComponent extends XFooterContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-form.component.templates.ts import { Component } from '@angular/core'; import { XFormContainerComponent } from '../x-form/x-form.typings'; @Component({ template: ` `, }) export class XFormTestComponent extends XFormContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-grid.component.templates.ts import { Component } from '@angular/core'; import { XGridContainerComponent } from '../x-grid/x-grid.typings'; @Component({ template: ` `, }) export class XGridTestComponent extends XGridContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-icon.component.templates.ts import { Component } from '@angular/core'; import { XIconContainerComponent } from '../x-icon/x-icon.typings'; @Component({ template: ` `, }) export class XIconTestComponent extends XIconContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-ide.component.template.ts import { Component } from '@angular/core'; import { XIDEContainerComponent } from '../x-ide/x-ide.typings'; @Component({ template: ` `, }) export class XIdeTestComponent extends XIDEContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-image-cropper.component.templates.ts import { Component } from '@angular/core'; import { XImageCropperContainerComponent } from '../x-image-cropper/x-image-cropper.typings'; @Component({ template: ` `, }) export class XImageCropperTestComponent extends XImageCropperContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-list.component.templates.ts import { Component } from '@angular/core'; import { XComponentListContainerComponent, XListContainerComponent, } from '../x-list/x-list.typings'; @Component({ template: ` `, }) export class XListTestComponent extends XListContainerComponent {} @Component({ template: ` `, }) export class XComponentListTestComponent extends XComponentListContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-map.component.templates.ts import { Component } from '@angular/core'; import { XMapContainerComponent } from '../x-map/x-map.typings'; @Component({ template: ` `, }) export class XMapTestComponent extends XMapContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-markdown.component.templates.ts import { Component } from '@angular/core'; import { XMarkdownContainerComponent } from '../x-markdown/x-markdown.typings'; @Component({ template: ` `, }) export class XMarkdownTestComponent extends XMarkdownContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-model-presenter.component.templates.ts import { Component } from '@angular/core'; import { XModelPresenterContainerComponent } from '../x-model-presenter/x-model-presenter.typings'; @Component({ template: ` `, }) export class XModelPresenterTestComponent extends XModelPresenterContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-navigator.component.templates.ts import { Component } from '@angular/core'; import { XNavigatorContainerComponent } from '../x-page/x-navigator/x-navigator.typings'; @Component({ template: ` `, }) export class XNavigatorTestComponent extends XNavigatorContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-page.component.templates.ts import { Component } from "@angular/core"; import { XPageContainerComponent } from "../x-page/x-page.container"; @Component({ template: ` ` }) export class XPageTestComponent extends XPageContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-screen-capture.component.templates.ts import { Component } from '@angular/core'; import { XScreenCaptureContainerComponent } from '../x-screen-capture/x-screen-capture.container'; @Component({ template: ` `, }) export class XScreenCaptureTestComponent extends XScreenCaptureContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-search-bar.component.templates.ts import { Component } from '@angular/core'; import { XComponentSearchBarContainerComponent, XSearchBarContainerComponent, } from '../x-search-bar/x-search-bar.typings'; @Component({ template: ` `, }) export class XSearchBarTestComponent extends XSearchBarContainerComponent {} @Component({ template: ` `, }) export class XComponentSearchBarTestComponent extends XComponentSearchBarContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-slider.component.templates.ts import { Component } from '@angular/core'; import { XSliderContainerComponent } from '../x-slider/x-slider.typings'; import { XSlideContainerComponent } from '../x-slider/x-slide/x-slide.typings'; @Component({ template: ` `, }) export class XSliderTestComponent extends XSliderContainerComponent {} @Component({ template: ` `, }) export class XSlideTestComponent extends XSlideContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-slotter.component.templates.ts import { Component } from '@angular/core'; import { XSlotterContainerComponent } from '../x-slotter/x-slotter.typings'; import { XSlotContainerComponent } from '../x-slotter/x-slot/x-slot.typings'; @Component({ template: ` `, }) export class XSlotterTestComponent extends XSlotterContainerComponent {} @Component({ template: ` `, }) export class XSlotTestComponent extends XSlotContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-spinner.component.templates.ts import { Component } from '@angular/core'; import { XSpinnerContainerComponent } from '../x-spinner/x-spinner.typings'; @Component({ template: ` `, }) export class XSpinnerTestComponent extends XSpinnerContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-stepper.component.templates.ts import { Component } from '@angular/core'; import { XStepperContainerComponent } from '../x-stepper/x-stepper.typings'; import { XStepContainerComponent } from '../x-stepper/x-step/x-step.typings'; @Component({ template: ` `, }) export class XStepperTestComponent extends XStepperContainerComponent {} @Component({ template: ` `, }) export class XStepTestComponent extends XStepContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-tab-navigator.component.templates.ts import { Component } from '@angular/core'; import { XTabNavigatorContainerComponent } from '../x-tab-navigator/x-tab-navigator.typings'; @Component({ template: ` `, }) export class XTabNavigatorTestComponent extends XTabNavigatorContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-table.component.templates.ts import { Component } from '@angular/core'; import { XTableContainerComponent } from '../x-table/x-table.typings'; @Component({ template: ` `, }) export class XTableTestComponent extends XTableContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-tabs.component.templates.ts import { Component } from '@angular/core'; import { XTabsContainerComponent } from '../x-tabs/x-tabs.typings'; import { XTabContainerComponent } from '../x-tabs/x-tab/x-tab.typings'; @Component({ template: ` `, }) export class XTabsTestComponent extends XTabsContainerComponent {} @Component({ template: ` `, }) export class XTabTestComponent extends XTabContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-theme-manager.component.templates.ts import { Component } from '@angular/core'; import { XThemeManagerContainerComponent } from '../x-theme/x-theme-manager/x-theme-manager.typings'; @Component({ template: ` `, }) export class XThemeManagerTestComponent extends XThemeManagerContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-thumbnail.component.templates.ts import { Component } from '@angular/core'; import { XThumbnailContainerComponent } from '../x-thumbnail/x-thumbnail.typings'; @Component({ template: ` `, }) export class XThumbnailTestComponent extends XThumbnailContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\component-templates\x-toolbar.component.templates.ts import { Component } from '@angular/core'; import { XToolbarContainerComponent } from '../x-page/x-toolbar/x-toolbar.typings'; @Component({ template: ` `, }) export class XToolbarTestComponent extends XToolbarContainerComponent {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\config\x-framework-components.config.ts import { XFrameworkCoreConfig } from 'x-framework-core'; import { XFrameworkServicesConfig } from 'x-framework-services'; export type XSharedConfig = XFrameworkCoreConfig & XFrameworkServicesConfig; // tslint:disable-next-line:no-empty-interface export interface XFrameworkComponentsConfig extends XSharedConfig { // // File Config ... maxAllowedSize: number; maxUploadFiles: number; minAllowedFileSize: number; maxAllowedFileSize: number; // defaultSearchDebounceTime: number; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XListModule } from '../x-list/x-list.module'; import { XPopoverService } from './x-popover/x-popover.service'; import { XSlotterModule } from './../x-slotter/x-slotter.module'; import { XPopoverComponent } from './x-popover/x-popover.component'; import { XSearchBarModule } from '../x-search-bar/x-search-bar.module'; import { XDataPagerModule } from '../x-data-pager/x-data-pager.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XSelectorDialogService } from './x-selector-dialog/x-selector-dialog.service'; import { XSelectorDialogComponent } from './x-selector-dialog/x-selector-dialog.component'; @NgModule({ imports: [ XListModule, CommonModule, XSlotterModule, XSearchBarModule, XDataPagerModule, XBaseComponentModule, ], exports: [ XListModule, CommonModule, XSlotterModule, XSearchBarModule, XDataPagerModule, XBaseComponentModule, ], providers: [XPopoverService, XSelectorDialogService], declarations: [XPopoverComponent, XSelectorDialogComponent], entryComponents: [XPopoverComponent, XSelectorDialogComponent], }) export class XDialogsModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog\x-dialog.component.html

{{ getTitle() | async }}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog\x-dialog.component.scss x-icon { --size: 24px; } h1, h2, h3, h4, h5, h6 { margin: 0 !important; } .x-base-dialog-container { height: 100%; } .x-base-dialog-content { height: 100%; overflow-y: scroll; } .x-base-dialog-toolbar-area { margin: 8px; } .x-base-dialog-toolbar-item { width: auto; height: 48px; } .x-base-dialog-toolbar-button { width: 32px; margin: { left: 4px; right: 4px; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog\x-dialog.component.ts import { XDialogConfig, XDialogContext, defaultBaseDialogConfig, } from './x-dialog.typings'; import { concatMap, map } from 'rxjs/operators'; import { Input, Component, ViewChild, ElementRef } from '@angular/core'; import { XIconNames } from '../../x-icon/x-icon.typings'; import { XSlotName } from '../../x-slotter/x-slotter.typings'; import { XBaseComponent } from '../../classes/x-base-component'; import { XStandardType, isNullOrUndefined } from 'x-framework-core'; @Component({ template: '', }) export abstract class XDialogComponent extends XBaseComponent { // //#region Props ... // //#region Private/Readonly ... readonly SlotNames = Object.assign({}, XSlotName); //#endregion // //#region Self Props ... // @Input() context: XStandardType; //#endregion // //#region ViewChilds ... @ViewChild('xBaseDialogToolbar') dialogToolbar: ElementRef; //#endregion // selectedValue: any; applyThemeColors = true; selectIcon = XIconNames.checked; backIcon = XIconNames.arrow_back; //#endregion // //#region Constructor ... //#endregion // //#region LifeCycles ... //#endregion // //#region Register Handlers ... //#endregion // //#region Task Handlers ... //#endregion // //#region UI Providers ... // //#region Context Options UI Providers ... /** * retrieve id of dialog ... * * @returns Observable of Id ... */ getId() { return this.getData().pipe(map((config) => config.id)); } /** * retrieve map dialog config ... */ getData() { return this.getValue(this.context); } /** * retrieve dialog title ... */ getTitle() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.title)) ); } /** * retrieve dialog can Select values or not ... * * @returns observable of boolean ... */ canSelect() { return this.getData().pipe(map((config) => !!config.canSelect)); } /** * retrieve payload of data for dialog ... * * @returns observable of any ... */ getPayload() { return this.getData().pipe(map((config) => config.payload)); } /** * retrieve toolbar color ... * * @returns observable of XColorIdentifier ... */ getToolbarColor() { return this.getData().pipe( map( (config) => config.toolbarColor || defaultBaseDialogConfig.toolbarColor ) ); } /** * retrieve background color ... * * @returns observable of XColorIdentifier ... */ getBackgroundColor() { return this.getData().pipe( map( (config) => config.backgroundColor || defaultBaseDialogConfig.backgroundColor ) ); } /** * retrieve progressBar color ... * * @returns observable of XColorIdentifier ... */ getProgressBarColor() { return this.getData().pipe( map( (config) => config.progressBarColor || defaultBaseDialogConfig.progressBarColor ) ); } //#endregion // //#region Class Providers ... getDialogToolbarClasses() { return this.getValue(this.getId()).pipe( map((id) => { return ['x-base-dialog-toolbar', `x-base-dialog-${id}-toolbar`]; }) ); } getDialogContainerClasses() { return this.getValue(this.getId()).pipe( map((id) => { return ['x-base-dialog-container', `x-base-dialog-${id}-container`]; }) ); } //#endregion hasSelectedValue() { return this.notNullOrUndefinedValue(this.selectedValue); } canShowProgressBar() { return this.getValue(this.loading || this.uiDisabled); } //#endregion // //#region UI Handlers ... async handleClosePopup(payload: any = undefined) { // const id = await this.getValueAsync(this.getId()); const context = await this.getValueAsync(this.context); if (isNullOrUndefined(context)) { return; } // switch (context.type) { // case XDialogContext.Modal: await this.managerService.dialogService.modalController.dismiss( payload, undefined, id ); break; // case XDialogContext.PopOver: await this.managerService.dialogService.popoverController.dismiss( payload, undefined, id ); break; } } async handleSelect(payload: any) { // if (isNullOrUndefined(payload)) { return; } // const hasSelectedValue = await this.getValueAsync(this.hasSelectedValue()); if (!hasSelectedValue) { return; } // await this.handleClosePopup(payload); } //#endregion // //#region Actions ... //#endregion // //#region Abstracts ... //#endregion // //#region Private ... //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-dialog\x-dialog.typings.ts import { XColorIdentifier, XColorWithBrightness } from 'x-framework-core'; export type XDialogConfigKeys = 'title' | string; export type XDialogConfigType = { [key in XDialogConfigKeys]: any; }; export enum XDialogContext { Modal = 'modal', PopOver = 'pop_over', } export interface XDialogConfig extends XDialogConfigType { id: string; title: string; payload?: any; canSelect?: boolean; type: XDialogContext; toolbarColor?: XColorIdentifier; backgroundColor?: XColorIdentifier; progressBarColor?: XColorIdentifier; } export const defaultBaseDialogConfig: Partial = { // toolbarColor: XColorWithBrightness.Primary, backgroundColor: XColorWithBrightness.Light, progressBarColor: XColorWithBrightness.Warning, }; ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.component.html {{ getResourceValue(title) | async }} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.component.scss :host { --max-popover-height: 260px; --background-color: var(--x-color-light); --divider-color: var(--x-color-dark-shade); } :host::ng-deep { mat-card { background-color: var(--background-color) !important; } } :host::ng-deep.align-self-center { align-self: center !important; } ion-list, ion-item.item, ion-item-divider, ion-list-header { --background: var(--background-color); } ion-item-divider { --color: var(--divider-color); } ion-list-header.x-list-header { text-align: center !important; } h1, h2, h3, h4, h5, h6 { margin: 0; } .x-popover-wrapper { max-height: var(--max-popover-height); overflow-y: scroll; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.component.ts import { Inject, NgZone, Component, Renderer2, ElementRef, ChangeDetectorRef, ChangeDetectionStrategy, } from '@angular/core'; import { nameof, isFunction, parseXColor, XExceptionIDs, XOneOrManyType, XColorIdentifier, isNullOrUndefined, XColorWithBrightness, isNullOrEmptyString, getXColorCssVariableName, } from 'x-framework-core'; import { XPopoverItem, XPopoverCssVar, XPopoverOption, XPopoverResult, } from './x-popover.typings'; import { NavParams } from '@ionic/angular'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XPopoverService } from './x-popover.service'; import { generatePopoverId } from './x-popover.tools'; import { XManagerService } from 'x-framework-services'; import { XBaseComponent } from '../../classes/x-base-component'; import { XSlotLayout, XSlotName } from '../../x-slotter/x-slotter.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-popover', templateUrl: './x-popover.component.html', styleUrls: ['./x-popover.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XPopoverComponent extends XBaseComponent { // //#region Props ... // readonly SlotNames = Object.assign({}, XSlotName); readonly SlotLayouts = Object.assign({}, XSlotLayout); readonly ColorNames = Object.assign({}, XColorWithBrightness); // items: XOneOrManyType; options: XOneOrManyType; // height: string; dividerColor: XColorIdentifier; backgroundColor: XColorIdentifier; //#endregion // //#region Constructor ... constructor( public zone: NgZone, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public navParams: NavParams, @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public changeDetector: ChangeDetectorRef, protected popOverService: XPopoverService ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); // // Options ... const options = this.navParams.get( nameof('options') ) as XPopoverOption[]; this.options = options; // // Items ... const items = this.navParams.get( nameof('items') ) as XPopoverItem[]; this.items = items; // // Error if not Options or Items ... if (!this.hasChild(options) && !this.hasChild(items)) { this.showError(XExceptionIDs.InvalidArgs, () => { this.managerService.dialogService.popoverController.dismiss(); }); } } //#endregion // //#region LifeCycles ... public afterViewInit(): void { super.afterViewInit(); // // Height ... this.height = this.navParams.get(nameof('height')); if (!isNullOrEmptyString(this.height)) { this.applyHeight(); } // // DividerColor ... this.dividerColor = this.navParams.get( nameof('dividerColor') ); if (!isNullOrEmptyString(this.dividerColor)) { this.applyDividerColor(); } // // BackgroundColor ... this.backgroundColor = this.navParams.get( nameof('backgroundColor') ); if (!isNullOrEmptyString(this.backgroundColor)) { this.applyBackgroundColor(); } } //#endregion // //#region UI Providers ... //#endregion // //#region UI Handlers ... handleMenuSelected( isItem: boolean, item: XPopoverItem | XPopoverOption, event: Event ) { // if (!!isItem) { this.handleItemSelected(item as XPopoverItem, event); } else { this.handleOptionSelected(item as XPopoverOption); } } //#endregion // //#region Privates ... private async handleItemSelected(item: XPopoverItem, event: Event) { // const itemResult = !isNullOrUndefined(item) && !isNullOrUndefined(item.handler) && isFunction(item.handler) ? await this.getValueAsync(item.handler()) : undefined; // const optionsResultObj = !this.hasChild(item.options) ? undefined : await this.popOverService.presentContextMenu(item.options, event); // if ( isNullOrUndefined( optionsResultObj || isNullOrUndefined(optionsResultObj.option) ) ) { return; } // const popoverId = generatePopoverId(this.items); // await this.managerService.dialogService.popoverController.dismiss( { item, itemResult, ...optionsResultObj, } as XPopoverResult, undefined, popoverId ); } private async handleOptionSelected(option: XPopoverOption) { // const optionResult = !isNullOrUndefined(option) && !isNullOrUndefined(option.handler) && isFunction(option.handler) ? await this.getValueAsync(option.handler()) : undefined; // await this.managerService.dialogService.popoverController.dismiss({ option, optionResult, } as XPopoverResult); } private applyHeight() { // if (isNullOrEmptyString(this.height)) { return; } // this.setCssVar(XPopoverCssVar.MaxPopoverHeight, this.height); this.detectChanges(); } private applyDividerColor() { // if (isNullOrEmptyString(this.dividerColor)) { return; } // const color = this.dividerColor; if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XPopoverCssVar.DividerColor, `var(${bgColor})`); this.detectChanges(); } private applyBackgroundColor() { // if (isNullOrEmptyString(this.backgroundColor)) { return; } // const color = this.backgroundColor; if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XPopoverCssVar.BackgroundColor, `var(${bgColor})`); this.detectChanges(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.service.ts import { toArray, hasChild, XBaseService, XOneOrManyType, isNullOrUndefined, } from 'x-framework-core'; import { XPopoverItem, XPopoverOption, XPopoverResult, XPopoverComponentProps, XPopoverPresentOptions, XPopoverPresenterOptions, } from './x-popover.typings'; import { Inject, Injectable } from '@angular/core'; import { generatePopoverId } from './x-popover.tools'; import { XManagerService } from 'x-framework-services'; import { XPopoverComponent } from './x-popover.component'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; @Injectable({ providedIn: 'root', }) export class XPopoverService extends XBaseService { // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService ) { super(config); } //#endregion // //#region Actions ... /** * Present Context Menu by Providinf XPopOverOption instance array ... * * @param options menu options which going to show to user ... * @param event click event for positioning ... */ public async presentContextMenu( options: XOneOrManyType, event: Event, props?: XPopoverPresentOptions, presentProps?: XPopoverPresenterOptions ) { // if (!hasChild(options)) { return null; } // const overrideWidth = toArray(options).every((option) => !!option.onlyIcon); if (overrideWidth) { // let currentCssClass = !isNullOrUndefined(presentProps) ? toArray(presentProps.cssClass).join(' ') : ''; currentCssClass += `${ currentCssClass.length > 0 ? ' ' : '' }x-minimal-popover`; // presentProps = { ...presentProps, cssClass: currentCssClass, }; } // const mProps: XPopoverComponentProps = { options, ...props, }; // // Present Popover as Context Menu ... const popOver = await this.managerService.dialogService.presentPopover({ // ...presentProps, // event, translucent: true, showBackdrop: true, componentProps: mProps, component: XPopoverComponent, }); // // Extract Data from PopOver ... const { data } = await popOver.onWillDismiss(); if (!data) { return undefined; } // const result = data as XPopoverResult; return result; } /** * Present Context Menu by Providinf XPopoverItem instance array ... * * @param items * @param event */ public async presentContextMenuItems( items: XOneOrManyType, event: Event, props?: XPopoverPresentOptions, presentProps?: XPopoverPresenterOptions ) { // if (!hasChild(items)) { return null; } // const overrideWidth = toArray(items).every((i) => !!i.onlyIcon); if (overrideWidth) { // let currentCssClass = !isNullOrUndefined(presentProps) ? toArray(presentProps.cssClass).join(' ') : ''; currentCssClass += `${ currentCssClass.length > 0 ? ' ' : '' }x-minimal-popover`; // presentProps = { ...presentProps, cssClass: currentCssClass, }; } // // Generate unique id from items ... const popoverId = generatePopoverId(items); // const mProps: XPopoverComponentProps = { items, ...props, }; // // Present Popover as Context Menu ... const popOver = await this.managerService.dialogService.presentPopover({ // ...presentProps, // event, id: popoverId, translucent: true, showBackdrop: true, componentProps: mProps, component: XPopoverComponent, }); // // Extract Data from PopOver ... const { data } = await popOver.onWillDismiss(); if (!data) { return null; } // const result = data as XPopoverResult; return result; } //#endregion // //#region Private ... //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.tools.ts import { XListItem } from '../../x-list/x-list.typings'; import { toMd5, toArray, hasChild, XOneOrManyType, isNullOrUndefined, } from 'x-framework-core'; import { XPopoverItem, XPopoverOption } from './x-popover.typings'; export const generatePopoverId: ( items: XOneOrManyType ) => string = (items) => { // const itemIds = toArray(items) .map((i) => i.id) .join('|'); const result = toMd5(itemIds); // return result; }; export const toPopoverOptions: ( item: XListItem ) => XOneOrManyType = (item) => { // let result: XPopoverOption[] = []; // if (isNullOrUndefined(item) || !hasChild(item.slideOptions)) { return result; } // result = item.slideOptions.map((so) => { return { id: so.id, onlyIcon: so.onlyIcon, disabled: so.disabled, icon: so.icon, color: so.color, title: so.title, slot: so.slot, handler: so.handler, } as XPopoverOption; }); // return result; }; export const defaultPopoverItem: XPopoverItem = { id: '', icon: '', color: '', title: '', options: [], iconColor: '', iconSlot: 'end', onlyIcon: false, disabled: false, handler: () => {}, showDetailedIcon: false, }; export const defaultPopoverOption: XPopoverOption = { id: '', icon: '', color: '', title: '', slot: 'end', onlyIcon: false, disabled: false, handler: () => {}, }; ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-popover\x-popover.typings.ts import { XStandardType, XOneOrManyType, XPopoverOptions, XColorIdentifier, XResourceIdentifier, } from 'x-framework-core'; import { XPopoverComponent } from './x-popover.component'; import { XIconIdentifier } from '../../x-icon/x-icon.typings'; export type XPopoverItemOptionSlot = 'end' | 'start'; export enum XPopoverCssVar { DividerColor = 'divider-color', BackgroundColor = 'background-color', MaxPopoverHeight = 'max-popover-height', } export type XPopoverCssVarIdentifier = XPopoverCssVar | string; export interface XPopoverOption { id: string; onlyIcon?: boolean; disabled?: boolean; icon?: XIconIdentifier; color?: XColorIdentifier; title?: XResourceIdentifier; slot?: XPopoverItemOptionSlot; handler?: () => XStandardType; } export interface XPopoverItem { id: string; disabled?: boolean; onlyIcon?: boolean; icon?: XIconIdentifier; color: XColorIdentifier; title: XResourceIdentifier; showDetailedIcon?: boolean; iconColor?: XColorIdentifier; options?: XPopoverOption[]; iconSlot?: XPopoverItemOptionSlot; handler?: () => XStandardType; } export interface XPopoverResult { // item?: XPopoverItem; itemResult?: any; // option?: XPopoverOption; optionResult?: any; } type SelectedKeysOfXpopoverComponent = Pick< Partial, 'items' | 'options' | 'height' | 'dividerColor' | 'backgroundColor' >; export type XPopoverComponentPropsType = { [key in keyof SelectedKeysOfXpopoverComponent]: any; }; export interface XPopoverComponentProps extends XPopoverComponentPropsType { height?: string; dividerColor?: XColorIdentifier; backgroundColor?: XColorIdentifier; items?: XOneOrManyType; options?: XOneOrManyType; } export type XPopoverPresentOptions = Pick< Partial, 'height' | 'dividerColor' | 'backgroundColor' >; export type XPopoverPresenterOptions = Partial< Omit< XPopoverOptions, | 'backdropDismiss' | 'componentProps' | 'component' | 'id' | 'translucent' | 'showBackdrop' | 'event' > >; ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.component.html

{{ title | async }}

{{ item.data | json }} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.component.scss ::ng-deep.fullscreen-dialog { // width: 80vw !important; max-width: 80vw !important; // height: 80vh !important; max-height: 80vh !important; // &.mobile { // width: 100vw !important; max-width: 100vw !important; // height: 100vh !important; max-height: 100vh !important; } // .mat-dialog-container { padding: 0 !important; } } .x-dialog-wrapper { width: 100% !important; height: 100% !important; position: relative !important; } .x-dialog-header { position: sticky !important; top: 0; z-index: 1000; } .x-dialog-content-wrapper { height: calc(100%); &.has-toolbar { height: calc(100% - 56px); } } x-icon { --size: 24px; } .toolbar-area { margin: 0px; } .toolbar-item { width: auto; height: 48px; } .toolbar-inline-item { display: inline-flex !important; } .toolbar-button { width: 32px; margin: { left: 4px; right: 4px; } } h1, h2, h3, h4, h5, h6 { margin: 0 !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.component.ts import { Inject, NgZone, Renderer2, Component, ElementRef, ChangeDetectorRef, ChangeDetectionStrategy, } from '@angular/core'; import { XTask, XColor, toArray, isFunction, generateUuid, XOneOrManyType, isNullOrUndefined, isNullOrEmptyString, XBaseDataPagerQuery, XBaseDataPagerQueryResult, } from 'x-framework-core'; import { Observable, Subject } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { XDataPagerActionModel, XDataPagerPresentType, XDataPagerPaginatorPosition, } from '../../x-data-pager/x-data-pager.typings'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XSelectorDialogConfig } from './x-selector-dialog.typings'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { XListItem, XListActionModel } from '../../x-list/x-list.typings'; import { XBaseDialogComponent } from '../../classes/x-base.dialog.component'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-selector-dialog', templateUrl: './x-selector-dialog.component.html', styleUrls: ['./x-selector-dialog.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XSelectorDialogComponent extends XBaseDialogComponent< any, XDataPagerActionModel, XSelectorDialogConfig > { // //#region Props ... // uuid = generateUuid('XFormSelector'); // canSearch: boolean; dataPagerQuery: XBaseDataPagerQuery = { ...this.getDataPagerQuery(), }; showDataPagerPaginator: boolean = true; dataPagerResultListItems: XListItem[] = []; dataPagerResult: XBaseDataPagerQueryResult; dataPagerActionProvider = new Subject(); // pageListActionProvider = new Subject(); // readonly DataPagerPresentTypes = Object.assign({}, XDataPagerPresentType); //#endregion // //#region Constructor ... constructor( public zone: NgZone, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public managerService: XManagerService, public changeDetector: ChangeDetectorRef, @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, @Inject(MAT_DIALOG_DATA) public data: any, public dialogRef: MatDialogRef ) { super( zone, element, renderer, ruler, managerService, changeDetector, config, data, dialogRef ); } //#endregion // //#region Task Handlers ... async onTaskFinished(name: string, task: XTask) { await super.onTaskFinished(name, task); // const tName = await this.getValueAsync(this.taskName); if (name === tName) { // this.setLoadingState(false); await this.handleDataPagerTaskFinished(task.result); } } //#endregion // //#region UI Providers ... // get taskName() { return this.getData().pipe( concatMap((config) => this.getValue(config ? config.taskName : this.uuid) ), map((name) => (!isNullOrEmptyString(name) ? name : this.uuid)) ); } get queryFetcher() { return this.getData().pipe( concatMap((config) => this.getValue(config ? config.queryFetcher : undefined) ) ); } get itemTemplate() { return this.getData().pipe( concatMap((config) => this.getValue(config ? config.itemTemplate : undefined) ) ); } // //#region Data Pager Paginator ... get showPaginator() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config ? config.showPaginator : false) ) ); } get paginatorColor() { return this.getData().pipe( concatMap((config) => this.getValue(config ? config.paginatorColor : XColor.Primary) ), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Primary)) ); } get paginatorPosition() { return this.getData().pipe( concatMap((config) => this.getValue( config ? config.paginatorPosition : XDataPagerPaginatorPosition.Above ) ), map((position) => !isNullOrEmptyString(position) ? position : XDataPagerPaginatorPosition.Above ) ); } //#endregion //#endregion // //#region UI Handlers ... async handleResetDataPagerQuery() { // this.dataPagerQuery = { ...this.getDataPagerQuery(), }; // this.detectChanges(); } async handleDataPagerTaskReady( task: Observable> ) { // // XBaseDataPagerQueryResult ... if (!task || this.uiDisabled || this.loading) { return; } // await this.issueDataPagerTask(task); } async handleDataPagerQueryChanged(query: XBaseDataPagerQuery) { // if (!query) { return; } // const config = await this.getValueAsync(this.getData()); if (config && config.onQueryChanged && isFunction(config.onQueryChanged)) { await this.getValueAsync(config.onQueryChanged(query)); } } async handleListItemSelected(event: XListItem) { // const canSelectMultipleItems = await this.getValueAsync( this.canMultipleSelect ); // if (!event || !event.data || canSelectMultipleItems) { return; } // const index = this.dataPagerResultListItems.findIndex((i) => Object.is(i, event) ); if (index > -1) { // // Cancel Previous Selected Item(s) ... this.dataPagerResultListItems.forEach((i) => { i.disabled = false; }); // // Disable Current Selected Item ... this.dataPagerResultListItems[index].disabled = true; // this.detectChanges(); } // await this.handleSelectedItems(event); } async handleSelectedItems(event: XOneOrManyType>) { // this.selectedItem = toArray(event).map((i) => i.data); // const config = await this.getValueAsync(this.getData()); if (config && config.onItemSelect && isFunction(config.onItemSelect)) { await this.getValueAsync(config.onItemSelect(event)); } // this.detectChanges(); } async handleListItemsSelected(event: XListItem[]) { // const canSelectMultipleItems = await this.getValueAsync( this.canMultipleSelect ); // if (!this.hasChild(event) || !canSelectMultipleItems) { return; } // await this.handleSelectedItems(event); } //#endregion // //#region Abstracts ... async getTaskNames(): Promise { return [await this.getValueAsync(this.taskName)]; } async deselectAllListItems(): Promise { // if (!this.hasChild(this.dataPagerResultListItems)) { return; } // this.dataPagerResultListItems.forEach((i) => { i.disabled = false; }); // this.dataPagerResultListItems = [...this.dataPagerResultListItems]; // this.detectChanges(); } async deselectItemInList(item: any): Promise { // if ( isNullOrUndefined(item) || !this.hasChild(this.dataPagerResultListItems) ) { return; } // const index = this.dataPagerResultListItems.findIndex((i) => Object.is(i.data, item) ); if (index > -1) { // this.dataPagerResultListItems[index].disabled = false; // this.dataPagerResultListItems = [...this.dataPagerResultListItems]; // this.detectChanges(); } } async handleSearchbarQuryChanged(query: string): Promise { // this.dataPagerQuery = { ...this.dataPagerQuery, filter: query, }; // this.detectChanges(); } //#endregion // //#region Private ... private getDataPagerQuery(): XBaseDataPagerQuery { return { filter: '', pageNumber: 1, rowsInPage: this.config.defaultPageSize, } as XBaseDataPagerQuery; } private async issueDataPagerTask( task: Observable> ) { // if (!task) { return; } // const mTaskName = await this.getValueAsync(this.taskName); const mTask = task; // await this.addOrUpdateTask({ priority: 0, affectLoading: true, name: mTaskName, task: mTask, }); // await this.dispatchTask(mTaskName); } private async handleDataPagerTaskFinished( result: XBaseDataPagerQueryResult ) { // this.dataPagerResult = null; this.dataPagerResultListItems = []; this.detectChanges(); // if (!result) { return; } // this.dataPagerResult = { ...result, }; // this.canSearch = (this.hasChild(this.dataPagerResult.items) && this.dataPagerResult.items.length > 1) || !isNullOrEmptyString(this.dataPagerQuery.filter); // this.showDataPagerPaginator = this.hasChild(this.dataPagerResult.items) && this.dataPagerResult.items.length > 1; // const config = await this.getValueAsync(this.getData()); if (config && config.onPageLoad && isFunction(config.onPageLoad)) { await this.getValueAsync(config.onPageLoad(this.dataPagerResult)); } // this.dataPagerResultListItems = await this.prepareListItems(); // this.detectChanges(); } private async prepareListItems() { // if (!this.dataPagerResult || !this.hasChild(this.dataPagerResult.items)) { return []; } // return this.dataPagerResult.items.map((sr) => { return { data: sr, } as XListItem; }); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.service.ts import { MatDialog, MatDialogRef, MatDialogConfig, } from '@angular/material/dialog'; import { Inject, Injectable } from '@angular/core'; import { XResourceIdentifier } from 'x-framework-core'; import { XManagerService } from 'x-framework-services'; import { XSelectorDialogConfig } from './x-selector-dialog.typings'; import { XSelectorDialogComponent } from './x-selector-dialog.component'; import { XBaseDialogService } from '../../classes/x-base-dialog.service'; import { XDataPagerActionModel } from '../../x-data-pager/x-data-pager.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; @Injectable({ providedIn: 'root', }) export class XSelectorDialogService extends XBaseDialogService< any, XDataPagerActionModel, XSelectorDialogConfig, XSelectorDialogComponent > { // defaultTitleResourceIdentifier: XResourceIdentifier; // //#region Constructor ... constructor( protected dialog: MatDialog, protected managerService: XManagerService, @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig ) { super(dialog, managerService, config); } //#endregion // openDialogAndReturnRef( config: MatDialogConfig ): MatDialogRef { return this.dialog.open(XSelectorDialogComponent, config); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\dialogs\x-selector-dialog\x-selector-dialog.typings.ts import { XStandardType, XColorIdentifier, XBaseDataPagerQuery, XBaseDataPagerQueryResult, } from 'x-framework-core'; import { Observable } from 'rxjs'; import { TemplateRef } from '@angular/core'; import { IXBaseDialogConfig, IXBaseDialogResult, } from '../../classes/x-base.dialog.component'; import { XDataPagerActionModel, XDataPagerPaginatorPositionIdentifier, } from '../../x-data-pager/x-data-pager.typings'; export interface XSelectorDialogResult extends IXBaseDialogResult {} export interface XSelectorDialogConfig extends IXBaseDialogConfig { // showPaginator?: XStandardType; paginatorColor?: XStandardType; paginatorPosition?: XStandardType; // queryFetcher?: ( query: XBaseDataPagerQuery ) => Observable>; onQueryChanged?: (query: XBaseDataPagerQuery) => XStandardType; onPageLoad?: (result: XBaseDataPagerQueryResult) => XStandardType; itemTemplate?: XStandardType>; // taskName?: XStandardType; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\modules\x-base-component.module.ts import { NgModule } from '@angular/core'; import { IonicModule } from '@ionic/angular'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { XMaterialModule } from './x-material.module'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { XDirectivesModule as XFrameworkCoreDirectivesModule } from 'x-framework-core'; import { XDirectivesModule as XFrameworkServicesDirectivesModule } from 'x-framework-services'; @NgModule({ imports: [ IonicModule, FormsModule, CommonModule, RouterModule, XMaterialModule, ReactiveFormsModule, XFrameworkCoreDirectivesModule, XFrameworkServicesDirectivesModule, ], exports: [ FormsModule, IonicModule, RouterModule, CommonModule, XMaterialModule, ReactiveFormsModule, XFrameworkCoreDirectivesModule, XFrameworkServicesDirectivesModule, ], }) export class XBaseComponentModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\modules\x-material.module.ts // import { NgModule } from '@angular/core'; // import { DragDropModule } from '@angular/cdk/drag-drop'; import { ScrollingModule } from '@angular/cdk/scrolling'; import { CdkTableModule } from '@angular/cdk/table'; import { CdkTreeModule } from '@angular/cdk/tree'; // // Form Controls ... import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatRadioModule } from '@angular/material/radio'; import { MatSelectModule } from '@angular/material/select'; import { MatSliderModule } from '@angular/material/slider'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; // // Navigations / Menus ... import { MatMenuModule } from '@angular/material/menu'; import { MatSidenavModule } from '@angular/material/sidenav'; import { MatToolbarModule } from '@angular/material/toolbar'; // // Layout ... import { MatCardModule } from '@angular/material/card'; import { MatDividerModule } from '@angular/material/divider'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatGridListModule } from '@angular/material/grid-list'; import { MatListModule } from '@angular/material/list'; import { MatStepperModule } from '@angular/material/stepper'; import { MatTabsModule } from '@angular/material/tabs'; import { MatTreeModule } from '@angular/material/tree'; // // Buttons and Indicators ... import { MatButtonModule } from '@angular/material/button'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatBadgeModule } from '@angular/material/badge'; import { MatChipsModule } from '@angular/material/chips'; import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatRippleModule } from '@angular/material/core'; import { MatNativeDateModule } from '@angular/material/core'; // // Popups and Dialogs ... import { MatBottomSheetModule } from '@angular/material/bottom-sheet'; import { MatDialogModule } from '@angular/material/dialog'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatTooltipModule } from '@angular/material/tooltip'; // // Data Table ... import { MatPaginatorModule } from '@angular/material/paginator'; import { MatSortModule } from '@angular/material/sort'; import { MatTableModule } from '@angular/material/table'; // import { MomentDateModule, MatMomentDateModule, } from '@angular/material-moment-adapter'; import { LayoutModule } from '@angular/cdk/layout'; import { FlexLayoutModule } from '@angular/flex-layout'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule, // CdkTableModule, CdkTreeModule, // DragDropModule, ScrollingModule, // LayoutModule, FlexLayoutModule, // MatAutocompleteModule, MatBadgeModule, MatBottomSheetModule, MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatChipsModule, MatStepperModule, MatDatepickerModule, MatDialogModule, MatDividerModule, MatExpansionModule, MatGridListModule, MatIconModule, MatInputModule, MatListModule, MatNativeDateModule, MatPaginatorModule, MatProgressBarModule, MatProgressSpinnerModule, MatRadioModule, MatRippleModule, MatSelectModule, MatSidenavModule, MatSliderModule, MatSlideToggleModule, MatSnackBarModule, MatSortModule, MatTableModule, MatTabsModule, MatToolbarModule, MatTooltipModule, MatTreeModule, MatFormFieldModule, MatMenuModule, // MomentDateModule, MatMomentDateModule, ], exports: [ // CdkTableModule, CdkTreeModule, // DragDropModule, ScrollingModule, // LayoutModule, FlexLayoutModule, // MatAutocompleteModule, MatBadgeModule, MatBottomSheetModule, MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatChipsModule, MatStepperModule, MatDatepickerModule, MatDialogModule, MatDividerModule, MatExpansionModule, MatGridListModule, MatIconModule, MatInputModule, MatListModule, MatNativeDateModule, MatPaginatorModule, MatProgressBarModule, MatProgressSpinnerModule, MatRadioModule, MatRippleModule, MatSelectModule, MatSidenavModule, MatSliderModule, MatSlideToggleModule, MatSnackBarModule, MatSortModule, MatTableModule, MatTabsModule, MatToolbarModule, MatTooltipModule, MatTreeModule, MatFormFieldModule, MatMenuModule, // MomentDateModule, MatMomentDateModule, ], }) export class XMaterialModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\_tools.scss @import "./animate.scss"; // //#region Tools ... // //#region Dimensions ... // // These are default values which can be used for margins and // paddings ... $d-xsm: 2px; $d-sm: 4px; $d-md: 8px; $d-l: 16px; $d-el: 32px; $d-exl: 48px; // // Box Sizing ... $d-min: 300px; $d-medium: 500px; $d-max: 800px; // // Percentages ... $d-25p: 25%; $d-50p: 50%; $d-75p: 75%; $d-100p: 100%; //#endregion // //#region Margin adnd Padding mixins ... .m-0 { margin: 0 !important; } .p-0 { padding: 0 !important; } @mixin m-rl($size: $d-sm) { margin-left: $size; margin-right: $size; } @mixin p-rl($size: $d-sm) { padding-left: $size; padding-right: $size; } @mixin m-tb($size: $d-sm) { margin-top: $size; margin-bottom: $size; } @mixin p-tb($size: $d-sm) { padding-top: $size; padding-bottom: $size; } @mixin m($size: $d-sm) { margin: $size !important; } @mixin p($size: $d-sm) { padding: $size !important; } @mixin m-full($top: 0px, $left: 0px, $bottom: 0px, $right: 0px) { margin: { top: $top; left: $left; bottom: $bottom; right: $right; } } @mixin p-full($top: 0px, $left: 0px, $bottom: 0px, $right: 0px) { padding: { top: $top; left: $left; bottom: $bottom; right: $right; } } @mixin push-auto { margin: { left: auto; right: auto; } } .push-auto { margin: { left: auto; right: auto; } } // #endregion // //#region Animation mixins and classes ... @mixin animation( $animation-name: ".fadeIn", $animation-duration: 500ms, $animation-delay: "", $animation-repeat: 1 ) { @extend .animated; @extend .#{$animation-name}; animation-delay: $animation-delay; animation-duration: $animation-duration; animation-iteration-count: $animation-repeat; } @mixin transition-duration($duration: 500ms, $delay: 0ms) { // transition-delay: $delay; -webkit-transition-delay: $delay; // transition-duration: $duration; -webkit-transition-duration: $duration; } @mixin transformer($transform, $duration: 500ms, $delay: 0ms) { // transform: $transform; -ms-transform: $transform; -webkit-transform: $transform; // @include transition(transform, $duration, $delay); } @mixin transition($transition, $duration: 500ms, $delay: 0ms) { // transition: $transition; -webkit-transition: $transition; @include transition-duration($duration, $delay); } @mixin show { @include animation("fadeIn", "250ms"); @include transition("height", "250ms"); } @mixin hide { @include animation("fadeOut", "250ms"); height: 0; @include transition("height", "250ms", "250ms"); } .show { @include show(); } .hide { @include hide(); } //#endregion // //#region Width Height and Alignment ... @mixin applyWidthHeight($size: $d-75p, $min-width: $d-min, $max-width: $d-max) { width: calc(#{$size}); max-width: $max-width; min-width: $min-width; } @mixin horizontal-spacer { flex: 1 1 auto; } .horizontal-spacer { @include horizontal-spacer(); } @mixin center-vertical-flex { // display: flex !important; flex-direction: column !important; justify-content: center !important; } .center-vertical-flex { @include center-vertical-flex(); } @mixin center-vertical { position: relative; top: 50%; transform: translateY(-50%); } .center-vertical { @include center-vertical(); } @mixin center { @extend .center; } .center { text-align: center; margin-left: auto; margin-right: auto; } @mixin text-truncate { @extend .text-truncate; } .text-truncate { display: inline-block; overflow-x: hidden !important; text-overflow: ellipsis !important; white-space: nowrap; min-width: 0; } //#endregion // //#region Shadows Tools ... @mixin add-shadow-box($vert, $horz, $blur, $size, $color: $shadow-color) { // $box-shadow-data: $vert $horz $blur $size $shadow-color !important; // box-shadow: $box-shadow-data; -moz-box-shadow: $box-shadow-data; -webkit-box-shadow: $box-shadow-data; } @mixin remove-shadow-box() { // $box-shadow-data: none !important; // box-shadow: $box-shadow-data; -moz-box-shadow: $box-shadow-data; -webkit-box-shadow: $box-shadow-data; } @mixin filterBlur($level: 4px) { -webkit-filter: blur($level); filter: blur($level); } @mixin filterBrightness($level: 0.3) { -webkit-filter: brightness($level); filter: brightness($level); } @mixin filterContrast($level: 180%) { -webkit-filter: contrast($level); filter: contrast($level); } @mixin filterGrayscale($level: 100%) { -webkit-filter: grayscale($level); filter: grayscale($level); } @mixin filterHuerotate($level: 180deg) { -webkit-filter: hue-rotate($level); filter: hue-rotate($level); } @mixin filterInvert($level: 100%) { -webkit-filter: invert($level); filter: invert($level); } @mixin filterOpacity($level: 50%) { -webkit-filter: opacity($level); filter: opacity($level); } @mixin filterSaturate($level: 7) { -webkit-filter: saturate($level); filter: saturate($level); } @mixin filterSepia($level: 100%) { -webkit-filter: sepia($level); filter: sepia(100%); } //#endregion // //#region Other ... @mixin disableLink { pointer-events: none; * { pointer-events: none; } } //#endregion //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\animate.scss @charset "UTF-8"; /*! * animate.css -http://daneden.me/animate * Version - 3.7.0 * Licensed under the MIT license - http://opensource.org/licenses/MIT * * Copyright (c) 2018 Daniel Eden */ @-webkit-keyframes bounce { from, 20%, 53%, 80%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 40%, 43% { -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); -webkit-transform: translate3d(0, -30px, 0); transform: translate3d(0, -30px, 0); } 70% { -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); -webkit-transform: translate3d(0, -15px, 0); transform: translate3d(0, -15px, 0); } 90% { -webkit-transform: translate3d(0, -4px, 0); transform: translate3d(0, -4px, 0); } } @keyframes bounce { from, 20%, 53%, 80%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 40%, 43% { -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); -webkit-transform: translate3d(0, -30px, 0); transform: translate3d(0, -30px, 0); } 70% { -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); -webkit-transform: translate3d(0, -15px, 0); transform: translate3d(0, -15px, 0); } 90% { -webkit-transform: translate3d(0, -4px, 0); transform: translate3d(0, -4px, 0); } } .bounce { -webkit-animation-name: bounce; animation-name: bounce; -webkit-transform-origin: center bottom; transform-origin: center bottom; } @-webkit-keyframes flash { from, 50%, to { opacity: 1; } 25%, 75% { opacity: 0; } } @keyframes flash { from, 50%, to { opacity: 1; } 25%, 75% { opacity: 0; } } .flash { -webkit-animation-name: flash; animation-name: flash; } /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ @-webkit-keyframes pulse { from { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } 50% { -webkit-transform: scale3d(1.05, 1.05, 1.05); transform: scale3d(1.05, 1.05, 1.05); } to { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } @keyframes pulse { from { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } 50% { -webkit-transform: scale3d(1.05, 1.05, 1.05); transform: scale3d(1.05, 1.05, 1.05); } to { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } .pulse { -webkit-animation-name: pulse; animation-name: pulse; } @-webkit-keyframes rubberBand { from { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } 30% { -webkit-transform: scale3d(1.25, 0.75, 1); transform: scale3d(1.25, 0.75, 1); } 40% { -webkit-transform: scale3d(0.75, 1.25, 1); transform: scale3d(0.75, 1.25, 1); } 50% { -webkit-transform: scale3d(1.15, 0.85, 1); transform: scale3d(1.15, 0.85, 1); } 65% { -webkit-transform: scale3d(0.95, 1.05, 1); transform: scale3d(0.95, 1.05, 1); } 75% { -webkit-transform: scale3d(1.05, 0.95, 1); transform: scale3d(1.05, 0.95, 1); } to { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } @keyframes rubberBand { from { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } 30% { -webkit-transform: scale3d(1.25, 0.75, 1); transform: scale3d(1.25, 0.75, 1); } 40% { -webkit-transform: scale3d(0.75, 1.25, 1); transform: scale3d(0.75, 1.25, 1); } 50% { -webkit-transform: scale3d(1.15, 0.85, 1); transform: scale3d(1.15, 0.85, 1); } 65% { -webkit-transform: scale3d(0.95, 1.05, 1); transform: scale3d(0.95, 1.05, 1); } 75% { -webkit-transform: scale3d(1.05, 0.95, 1); transform: scale3d(1.05, 0.95, 1); } to { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } .rubberBand { -webkit-animation-name: rubberBand; animation-name: rubberBand; } @-webkit-keyframes shake { from, to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 10%, 30%, 50%, 70%, 90% { -webkit-transform: translate3d(-10px, 0, 0); transform: translate3d(-10px, 0, 0); } 20%, 40%, 60%, 80% { -webkit-transform: translate3d(10px, 0, 0); transform: translate3d(10px, 0, 0); } } @keyframes shake { from, to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 10%, 30%, 50%, 70%, 90% { -webkit-transform: translate3d(-10px, 0, 0); transform: translate3d(-10px, 0, 0); } 20%, 40%, 60%, 80% { -webkit-transform: translate3d(10px, 0, 0); transform: translate3d(10px, 0, 0); } } .shake { -webkit-animation-name: shake; animation-name: shake; } @-webkit-keyframes headShake { 0% { -webkit-transform: translateX(0); transform: translateX(0); } 6.5% { -webkit-transform: translateX(-6px) rotateY(-9deg); transform: translateX(-6px) rotateY(-9deg); } 18.5% { -webkit-transform: translateX(5px) rotateY(7deg); transform: translateX(5px) rotateY(7deg); } 31.5% { -webkit-transform: translateX(-3px) rotateY(-5deg); transform: translateX(-3px) rotateY(-5deg); } 43.5% { -webkit-transform: translateX(2px) rotateY(3deg); transform: translateX(2px) rotateY(3deg); } 50% { -webkit-transform: translateX(0); transform: translateX(0); } } @keyframes headShake { 0% { -webkit-transform: translateX(0); transform: translateX(0); } 6.5% { -webkit-transform: translateX(-6px) rotateY(-9deg); transform: translateX(-6px) rotateY(-9deg); } 18.5% { -webkit-transform: translateX(5px) rotateY(7deg); transform: translateX(5px) rotateY(7deg); } 31.5% { -webkit-transform: translateX(-3px) rotateY(-5deg); transform: translateX(-3px) rotateY(-5deg); } 43.5% { -webkit-transform: translateX(2px) rotateY(3deg); transform: translateX(2px) rotateY(3deg); } 50% { -webkit-transform: translateX(0); transform: translateX(0); } } .headShake { -webkit-animation-timing-function: ease-in-out; animation-timing-function: ease-in-out; -webkit-animation-name: headShake; animation-name: headShake; } @-webkit-keyframes swing { 20% { -webkit-transform: rotate3d(0, 0, 1, 15deg); transform: rotate3d(0, 0, 1, 15deg); } 40% { -webkit-transform: rotate3d(0, 0, 1, -10deg); transform: rotate3d(0, 0, 1, -10deg); } 60% { -webkit-transform: rotate3d(0, 0, 1, 5deg); transform: rotate3d(0, 0, 1, 5deg); } 80% { -webkit-transform: rotate3d(0, 0, 1, -5deg); transform: rotate3d(0, 0, 1, -5deg); } to { -webkit-transform: rotate3d(0, 0, 1, 0deg); transform: rotate3d(0, 0, 1, 0deg); } } @keyframes swing { 20% { -webkit-transform: rotate3d(0, 0, 1, 15deg); transform: rotate3d(0, 0, 1, 15deg); } 40% { -webkit-transform: rotate3d(0, 0, 1, -10deg); transform: rotate3d(0, 0, 1, -10deg); } 60% { -webkit-transform: rotate3d(0, 0, 1, 5deg); transform: rotate3d(0, 0, 1, 5deg); } 80% { -webkit-transform: rotate3d(0, 0, 1, -5deg); transform: rotate3d(0, 0, 1, -5deg); } to { -webkit-transform: rotate3d(0, 0, 1, 0deg); transform: rotate3d(0, 0, 1, 0deg); } } .swing { -webkit-transform-origin: top center; transform-origin: top center; -webkit-animation-name: swing; animation-name: swing; } @-webkit-keyframes tada { from { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } 10%, 20% { -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); } 30%, 50%, 70%, 90% { -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); } 40%, 60%, 80% { -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); } to { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } @keyframes tada { from { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } 10%, 20% { -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); } 30%, 50%, 70%, 90% { -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); } 40%, 60%, 80% { -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); } to { -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } .tada { -webkit-animation-name: tada; animation-name: tada; } /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ @-webkit-keyframes wobble { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 15% { -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); } 30% { -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); } 45% { -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); } 60% { -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); } 75% { -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes wobble { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 15% { -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); } 30% { -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); } 45% { -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); } 60% { -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); } 75% { -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .wobble { -webkit-animation-name: wobble; animation-name: wobble; } @-webkit-keyframes jello { from, 11.1%, to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 22.2% { -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); transform: skewX(-12.5deg) skewY(-12.5deg); } 33.3% { -webkit-transform: skewX(6.25deg) skewY(6.25deg); transform: skewX(6.25deg) skewY(6.25deg); } 44.4% { -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); transform: skewX(-3.125deg) skewY(-3.125deg); } 55.5% { -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); transform: skewX(1.5625deg) skewY(1.5625deg); } 66.6% { -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); transform: skewX(-0.78125deg) skewY(-0.78125deg); } 77.7% { -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); transform: skewX(0.390625deg) skewY(0.390625deg); } 88.8% { -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); transform: skewX(-0.1953125deg) skewY(-0.1953125deg); } } @keyframes jello { from, 11.1%, to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } 22.2% { -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); transform: skewX(-12.5deg) skewY(-12.5deg); } 33.3% { -webkit-transform: skewX(6.25deg) skewY(6.25deg); transform: skewX(6.25deg) skewY(6.25deg); } 44.4% { -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); transform: skewX(-3.125deg) skewY(-3.125deg); } 55.5% { -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); transform: skewX(1.5625deg) skewY(1.5625deg); } 66.6% { -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); transform: skewX(-0.78125deg) skewY(-0.78125deg); } 77.7% { -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); transform: skewX(0.390625deg) skewY(0.390625deg); } 88.8% { -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); transform: skewX(-0.1953125deg) skewY(-0.1953125deg); } } .jello { -webkit-animation-name: jello; animation-name: jello; -webkit-transform-origin: center; transform-origin: center; } @-webkit-keyframes heartBeat { 0% { -webkit-transform: scale(1); transform: scale(1); } 14% { -webkit-transform: scale(1.3); transform: scale(1.3); } 28% { -webkit-transform: scale(1); transform: scale(1); } 42% { -webkit-transform: scale(1.3); transform: scale(1.3); } 70% { -webkit-transform: scale(1); transform: scale(1); } } @keyframes heartBeat { 0% { -webkit-transform: scale(1); transform: scale(1); } 14% { -webkit-transform: scale(1.3); transform: scale(1.3); } 28% { -webkit-transform: scale(1); transform: scale(1); } 42% { -webkit-transform: scale(1.3); transform: scale(1.3); } 70% { -webkit-transform: scale(1); transform: scale(1); } } .heartBeat { -webkit-animation-name: heartBeat; animation-name: heartBeat; -webkit-animation-duration: 1.3s; animation-duration: 1.3s; -webkit-animation-timing-function: ease-in-out; animation-timing-function: ease-in-out; } @-webkit-keyframes bounceIn { from, 20%, 40%, 60%, 80%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } 0% { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); } 20% { -webkit-transform: scale3d(1.1, 1.1, 1.1); transform: scale3d(1.1, 1.1, 1.1); } 40% { -webkit-transform: scale3d(0.9, 0.9, 0.9); transform: scale3d(0.9, 0.9, 0.9); } 60% { opacity: 1; -webkit-transform: scale3d(1.03, 1.03, 1.03); transform: scale3d(1.03, 1.03, 1.03); } 80% { -webkit-transform: scale3d(0.97, 0.97, 0.97); transform: scale3d(0.97, 0.97, 0.97); } to { opacity: 1; -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } @keyframes bounceIn { from, 20%, 40%, 60%, 80%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } 0% { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); } 20% { -webkit-transform: scale3d(1.1, 1.1, 1.1); transform: scale3d(1.1, 1.1, 1.1); } 40% { -webkit-transform: scale3d(0.9, 0.9, 0.9); transform: scale3d(0.9, 0.9, 0.9); } 60% { opacity: 1; -webkit-transform: scale3d(1.03, 1.03, 1.03); transform: scale3d(1.03, 1.03, 1.03); } 80% { -webkit-transform: scale3d(0.97, 0.97, 0.97); transform: scale3d(0.97, 0.97, 0.97); } to { opacity: 1; -webkit-transform: scale3d(1, 1, 1); transform: scale3d(1, 1, 1); } } .bounceIn { -webkit-animation-duration: 0.75s; animation-duration: 0.75s; -webkit-animation-name: bounceIn; animation-name: bounceIn; } @-webkit-keyframes bounceInDown { from, 60%, 75%, 90%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } 0% { opacity: 0; -webkit-transform: translate3d(0, -3000px, 0); transform: translate3d(0, -3000px, 0); } 60% { opacity: 1; -webkit-transform: translate3d(0, 25px, 0); transform: translate3d(0, 25px, 0); } 75% { -webkit-transform: translate3d(0, -10px, 0); transform: translate3d(0, -10px, 0); } 90% { -webkit-transform: translate3d(0, 5px, 0); transform: translate3d(0, 5px, 0); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes bounceInDown { from, 60%, 75%, 90%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } 0% { opacity: 0; -webkit-transform: translate3d(0, -3000px, 0); transform: translate3d(0, -3000px, 0); } 60% { opacity: 1; -webkit-transform: translate3d(0, 25px, 0); transform: translate3d(0, 25px, 0); } 75% { -webkit-transform: translate3d(0, -10px, 0); transform: translate3d(0, -10px, 0); } 90% { -webkit-transform: translate3d(0, 5px, 0); transform: translate3d(0, 5px, 0); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .bounceInDown { -webkit-animation-name: bounceInDown; animation-name: bounceInDown; } @-webkit-keyframes bounceInLeft { from, 60%, 75%, 90%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } 0% { opacity: 0; -webkit-transform: translate3d(-3000px, 0, 0); transform: translate3d(-3000px, 0, 0); } 60% { opacity: 1; -webkit-transform: translate3d(25px, 0, 0); transform: translate3d(25px, 0, 0); } 75% { -webkit-transform: translate3d(-10px, 0, 0); transform: translate3d(-10px, 0, 0); } 90% { -webkit-transform: translate3d(5px, 0, 0); transform: translate3d(5px, 0, 0); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes bounceInLeft { from, 60%, 75%, 90%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } 0% { opacity: 0; -webkit-transform: translate3d(-3000px, 0, 0); transform: translate3d(-3000px, 0, 0); } 60% { opacity: 1; -webkit-transform: translate3d(25px, 0, 0); transform: translate3d(25px, 0, 0); } 75% { -webkit-transform: translate3d(-10px, 0, 0); transform: translate3d(-10px, 0, 0); } 90% { -webkit-transform: translate3d(5px, 0, 0); transform: translate3d(5px, 0, 0); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .bounceInLeft { -webkit-animation-name: bounceInLeft; animation-name: bounceInLeft; } @-webkit-keyframes bounceInRight { from, 60%, 75%, 90%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } from { opacity: 0; -webkit-transform: translate3d(3000px, 0, 0); transform: translate3d(3000px, 0, 0); } 60% { opacity: 1; -webkit-transform: translate3d(-25px, 0, 0); transform: translate3d(-25px, 0, 0); } 75% { -webkit-transform: translate3d(10px, 0, 0); transform: translate3d(10px, 0, 0); } 90% { -webkit-transform: translate3d(-5px, 0, 0); transform: translate3d(-5px, 0, 0); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes bounceInRight { from, 60%, 75%, 90%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } from { opacity: 0; -webkit-transform: translate3d(3000px, 0, 0); transform: translate3d(3000px, 0, 0); } 60% { opacity: 1; -webkit-transform: translate3d(-25px, 0, 0); transform: translate3d(-25px, 0, 0); } 75% { -webkit-transform: translate3d(10px, 0, 0); transform: translate3d(10px, 0, 0); } 90% { -webkit-transform: translate3d(-5px, 0, 0); transform: translate3d(-5px, 0, 0); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .bounceInRight { -webkit-animation-name: bounceInRight; animation-name: bounceInRight; } @-webkit-keyframes bounceInUp { from, 60%, 75%, 90%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } from { opacity: 0; -webkit-transform: translate3d(0, 3000px, 0); transform: translate3d(0, 3000px, 0); } 60% { opacity: 1; -webkit-transform: translate3d(0, -20px, 0); transform: translate3d(0, -20px, 0); } 75% { -webkit-transform: translate3d(0, 10px, 0); transform: translate3d(0, 10px, 0); } 90% { -webkit-transform: translate3d(0, -5px, 0); transform: translate3d(0, -5px, 0); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes bounceInUp { from, 60%, 75%, 90%, to { -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); } from { opacity: 0; -webkit-transform: translate3d(0, 3000px, 0); transform: translate3d(0, 3000px, 0); } 60% { opacity: 1; -webkit-transform: translate3d(0, -20px, 0); transform: translate3d(0, -20px, 0); } 75% { -webkit-transform: translate3d(0, 10px, 0); transform: translate3d(0, 10px, 0); } 90% { -webkit-transform: translate3d(0, -5px, 0); transform: translate3d(0, -5px, 0); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .bounceInUp { -webkit-animation-name: bounceInUp; animation-name: bounceInUp; } @-webkit-keyframes bounceOut { 20% { -webkit-transform: scale3d(0.9, 0.9, 0.9); transform: scale3d(0.9, 0.9, 0.9); } 50%, 55% { opacity: 1; -webkit-transform: scale3d(1.1, 1.1, 1.1); transform: scale3d(1.1, 1.1, 1.1); } to { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); } } @keyframes bounceOut { 20% { -webkit-transform: scale3d(0.9, 0.9, 0.9); transform: scale3d(0.9, 0.9, 0.9); } 50%, 55% { opacity: 1; -webkit-transform: scale3d(1.1, 1.1, 1.1); transform: scale3d(1.1, 1.1, 1.1); } to { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); } } .bounceOut { -webkit-animation-duration: 0.75s; animation-duration: 0.75s; -webkit-animation-name: bounceOut; animation-name: bounceOut; } @-webkit-keyframes bounceOutDown { 20% { -webkit-transform: translate3d(0, 10px, 0); transform: translate3d(0, 10px, 0); } 40%, 45% { opacity: 1; -webkit-transform: translate3d(0, -20px, 0); transform: translate3d(0, -20px, 0); } to { opacity: 0; -webkit-transform: translate3d(0, 2000px, 0); transform: translate3d(0, 2000px, 0); } } @keyframes bounceOutDown { 20% { -webkit-transform: translate3d(0, 10px, 0); transform: translate3d(0, 10px, 0); } 40%, 45% { opacity: 1; -webkit-transform: translate3d(0, -20px, 0); transform: translate3d(0, -20px, 0); } to { opacity: 0; -webkit-transform: translate3d(0, 2000px, 0); transform: translate3d(0, 2000px, 0); } } .bounceOutDown { -webkit-animation-name: bounceOutDown; animation-name: bounceOutDown; } @-webkit-keyframes bounceOutLeft { 20% { opacity: 1; -webkit-transform: translate3d(20px, 0, 0); transform: translate3d(20px, 0, 0); } to { opacity: 0; -webkit-transform: translate3d(-2000px, 0, 0); transform: translate3d(-2000px, 0, 0); } } @keyframes bounceOutLeft { 20% { opacity: 1; -webkit-transform: translate3d(20px, 0, 0); transform: translate3d(20px, 0, 0); } to { opacity: 0; -webkit-transform: translate3d(-2000px, 0, 0); transform: translate3d(-2000px, 0, 0); } } .bounceOutLeft { -webkit-animation-name: bounceOutLeft; animation-name: bounceOutLeft; } @-webkit-keyframes bounceOutRight { 20% { opacity: 1; -webkit-transform: translate3d(-20px, 0, 0); transform: translate3d(-20px, 0, 0); } to { opacity: 0; -webkit-transform: translate3d(2000px, 0, 0); transform: translate3d(2000px, 0, 0); } } @keyframes bounceOutRight { 20% { opacity: 1; -webkit-transform: translate3d(-20px, 0, 0); transform: translate3d(-20px, 0, 0); } to { opacity: 0; -webkit-transform: translate3d(2000px, 0, 0); transform: translate3d(2000px, 0, 0); } } .bounceOutRight { -webkit-animation-name: bounceOutRight; animation-name: bounceOutRight; } @-webkit-keyframes bounceOutUp { 20% { -webkit-transform: translate3d(0, -10px, 0); transform: translate3d(0, -10px, 0); } 40%, 45% { opacity: 1; -webkit-transform: translate3d(0, 20px, 0); transform: translate3d(0, 20px, 0); } to { opacity: 0; -webkit-transform: translate3d(0, -2000px, 0); transform: translate3d(0, -2000px, 0); } } @keyframes bounceOutUp { 20% { -webkit-transform: translate3d(0, -10px, 0); transform: translate3d(0, -10px, 0); } 40%, 45% { opacity: 1; -webkit-transform: translate3d(0, 20px, 0); transform: translate3d(0, 20px, 0); } to { opacity: 0; -webkit-transform: translate3d(0, -2000px, 0); transform: translate3d(0, -2000px, 0); } } .bounceOutUp { -webkit-animation-name: bounceOutUp; animation-name: bounceOutUp; } @-webkit-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } .fadeIn { -webkit-animation-name: fadeIn; animation-name: fadeIn; } @-webkit-keyframes fadeInDown { from { opacity: 0; -webkit-transform: translate3d(0, -100%, 0); transform: translate3d(0, -100%, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes fadeInDown { from { opacity: 0; -webkit-transform: translate3d(0, -100%, 0); transform: translate3d(0, -100%, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .fadeInDown { -webkit-animation-name: fadeInDown; animation-name: fadeInDown; } @-webkit-keyframes fadeInDownBig { from { opacity: 0; -webkit-transform: translate3d(0, -2000px, 0); transform: translate3d(0, -2000px, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes fadeInDownBig { from { opacity: 0; -webkit-transform: translate3d(0, -2000px, 0); transform: translate3d(0, -2000px, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .fadeInDownBig { -webkit-animation-name: fadeInDownBig; animation-name: fadeInDownBig; } @-webkit-keyframes fadeInLeft { from { opacity: 0; -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes fadeInLeft { from { opacity: 0; -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .fadeInLeft { -webkit-animation-name: fadeInLeft; animation-name: fadeInLeft; } @-webkit-keyframes fadeInLeftBig { from { opacity: 0; -webkit-transform: translate3d(-2000px, 0, 0); transform: translate3d(-2000px, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes fadeInLeftBig { from { opacity: 0; -webkit-transform: translate3d(-2000px, 0, 0); transform: translate3d(-2000px, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .fadeInLeftBig { -webkit-animation-name: fadeInLeftBig; animation-name: fadeInLeftBig; } @-webkit-keyframes fadeInRight { from { opacity: 0; -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes fadeInRight { from { opacity: 0; -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .fadeInRight { -webkit-animation-name: fadeInRight; animation-name: fadeInRight; } @-webkit-keyframes fadeInRightBig { from { opacity: 0; -webkit-transform: translate3d(2000px, 0, 0); transform: translate3d(2000px, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes fadeInRightBig { from { opacity: 0; -webkit-transform: translate3d(2000px, 0, 0); transform: translate3d(2000px, 0, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .fadeInRightBig { -webkit-animation-name: fadeInRightBig; animation-name: fadeInRightBig; } @-webkit-keyframes fadeInUp { from { opacity: 0; -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes fadeInUp { from { opacity: 0; -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .fadeInUp { -webkit-animation-name: fadeInUp; animation-name: fadeInUp; } @-webkit-keyframes fadeInUpBig { from { opacity: 0; -webkit-transform: translate3d(0, 2000px, 0); transform: translate3d(0, 2000px, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes fadeInUpBig { from { opacity: 0; -webkit-transform: translate3d(0, 2000px, 0); transform: translate3d(0, 2000px, 0); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .fadeInUpBig { -webkit-animation-name: fadeInUpBig; animation-name: fadeInUpBig; } @-webkit-keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } .fadeOut { -webkit-animation-name: fadeOut; animation-name: fadeOut; } @-webkit-keyframes fadeOutDown { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); } } @keyframes fadeOutDown { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); } } .fadeOutDown { -webkit-animation-name: fadeOutDown; animation-name: fadeOutDown; } @-webkit-keyframes fadeOutDownBig { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(0, 2000px, 0); transform: translate3d(0, 2000px, 0); } } @keyframes fadeOutDownBig { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(0, 2000px, 0); transform: translate3d(0, 2000px, 0); } } .fadeOutDownBig { -webkit-animation-name: fadeOutDownBig; animation-name: fadeOutDownBig; } @-webkit-keyframes fadeOutLeft { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); } } @keyframes fadeOutLeft { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); } } .fadeOutLeft { -webkit-animation-name: fadeOutLeft; animation-name: fadeOutLeft; } @-webkit-keyframes fadeOutLeftBig { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(-2000px, 0, 0); transform: translate3d(-2000px, 0, 0); } } @keyframes fadeOutLeftBig { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(-2000px, 0, 0); transform: translate3d(-2000px, 0, 0); } } .fadeOutLeftBig { -webkit-animation-name: fadeOutLeftBig; animation-name: fadeOutLeftBig; } @-webkit-keyframes fadeOutRight { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); } } @keyframes fadeOutRight { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); } } .fadeOutRight { -webkit-animation-name: fadeOutRight; animation-name: fadeOutRight; } @-webkit-keyframes fadeOutRightBig { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(2000px, 0, 0); transform: translate3d(2000px, 0, 0); } } @keyframes fadeOutRightBig { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(2000px, 0, 0); transform: translate3d(2000px, 0, 0); } } .fadeOutRightBig { -webkit-animation-name: fadeOutRightBig; animation-name: fadeOutRightBig; } @-webkit-keyframes fadeOutUp { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(0, -100%, 0); transform: translate3d(0, -100%, 0); } } @keyframes fadeOutUp { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(0, -100%, 0); transform: translate3d(0, -100%, 0); } } .fadeOutUp { -webkit-animation-name: fadeOutUp; animation-name: fadeOutUp; } @-webkit-keyframes fadeOutUpBig { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(0, -2000px, 0); transform: translate3d(0, -2000px, 0); } } @keyframes fadeOutUpBig { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(0, -2000px, 0); transform: translate3d(0, -2000px, 0); } } .fadeOutUpBig { -webkit-animation-name: fadeOutUpBig; animation-name: fadeOutUpBig; } @-webkit-keyframes flip { from { -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg); -webkit-animation-timing-function: ease-out; animation-timing-function: ease-out; } 40% { -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); -webkit-animation-timing-function: ease-out; animation-timing-function: ease-out; } 50% { -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } 80% { -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } to { -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } } @keyframes flip { from { -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg); -webkit-animation-timing-function: ease-out; animation-timing-function: ease-out; } 40% { -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg); -webkit-animation-timing-function: ease-out; animation-timing-function: ease-out; } 50% { -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } 80% { -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } to { -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } } .animated.flip { -webkit-backface-visibility: visible; backface-visibility: visible; -webkit-animation-name: flip; animation-name: flip; } @-webkit-keyframes flipInX { from { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); transform: perspective(400px) rotate3d(1, 0, 0, 90deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; opacity: 0; } 40% { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); transform: perspective(400px) rotate3d(1, 0, 0, -20deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } 60% { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); transform: perspective(400px) rotate3d(1, 0, 0, 10deg); opacity: 1; } 80% { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); transform: perspective(400px) rotate3d(1, 0, 0, -5deg); } to { -webkit-transform: perspective(400px); transform: perspective(400px); } } @keyframes flipInX { from { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); transform: perspective(400px) rotate3d(1, 0, 0, 90deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; opacity: 0; } 40% { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); transform: perspective(400px) rotate3d(1, 0, 0, -20deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } 60% { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); transform: perspective(400px) rotate3d(1, 0, 0, 10deg); opacity: 1; } 80% { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); transform: perspective(400px) rotate3d(1, 0, 0, -5deg); } to { -webkit-transform: perspective(400px); transform: perspective(400px); } } .flipInX { -webkit-backface-visibility: visible !important; backface-visibility: visible !important; -webkit-animation-name: flipInX; animation-name: flipInX; } @-webkit-keyframes flipInY { from { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); transform: perspective(400px) rotate3d(0, 1, 0, 90deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; opacity: 0; } 40% { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); transform: perspective(400px) rotate3d(0, 1, 0, -20deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } 60% { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); transform: perspective(400px) rotate3d(0, 1, 0, 10deg); opacity: 1; } 80% { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); transform: perspective(400px) rotate3d(0, 1, 0, -5deg); } to { -webkit-transform: perspective(400px); transform: perspective(400px); } } @keyframes flipInY { from { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); transform: perspective(400px) rotate3d(0, 1, 0, 90deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; opacity: 0; } 40% { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); transform: perspective(400px) rotate3d(0, 1, 0, -20deg); -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } 60% { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); transform: perspective(400px) rotate3d(0, 1, 0, 10deg); opacity: 1; } 80% { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); transform: perspective(400px) rotate3d(0, 1, 0, -5deg); } to { -webkit-transform: perspective(400px); transform: perspective(400px); } } .flipInY { -webkit-backface-visibility: visible !important; backface-visibility: visible !important; -webkit-animation-name: flipInY; animation-name: flipInY; } @-webkit-keyframes flipOutX { from { -webkit-transform: perspective(400px); transform: perspective(400px); } 30% { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); transform: perspective(400px) rotate3d(1, 0, 0, -20deg); opacity: 1; } to { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); transform: perspective(400px) rotate3d(1, 0, 0, 90deg); opacity: 0; } } @keyframes flipOutX { from { -webkit-transform: perspective(400px); transform: perspective(400px); } 30% { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); transform: perspective(400px) rotate3d(1, 0, 0, -20deg); opacity: 1; } to { -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); transform: perspective(400px) rotate3d(1, 0, 0, 90deg); opacity: 0; } } .flipOutX { -webkit-animation-duration: 0.75s; animation-duration: 0.75s; -webkit-animation-name: flipOutX; animation-name: flipOutX; -webkit-backface-visibility: visible !important; backface-visibility: visible !important; } @-webkit-keyframes flipOutY { from { -webkit-transform: perspective(400px); transform: perspective(400px); } 30% { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); transform: perspective(400px) rotate3d(0, 1, 0, -15deg); opacity: 1; } to { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); transform: perspective(400px) rotate3d(0, 1, 0, 90deg); opacity: 0; } } @keyframes flipOutY { from { -webkit-transform: perspective(400px); transform: perspective(400px); } 30% { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); transform: perspective(400px) rotate3d(0, 1, 0, -15deg); opacity: 1; } to { -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); transform: perspective(400px) rotate3d(0, 1, 0, 90deg); opacity: 0; } } .flipOutY { -webkit-animation-duration: 0.75s; animation-duration: 0.75s; -webkit-backface-visibility: visible !important; backface-visibility: visible !important; -webkit-animation-name: flipOutY; animation-name: flipOutY; } @-webkit-keyframes lightSpeedIn { from { -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); transform: translate3d(100%, 0, 0) skewX(-30deg); opacity: 0; } 60% { -webkit-transform: skewX(20deg); transform: skewX(20deg); opacity: 1; } 80% { -webkit-transform: skewX(-5deg); transform: skewX(-5deg); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes lightSpeedIn { from { -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); transform: translate3d(100%, 0, 0) skewX(-30deg); opacity: 0; } 60% { -webkit-transform: skewX(20deg); transform: skewX(20deg); opacity: 1; } 80% { -webkit-transform: skewX(-5deg); transform: skewX(-5deg); } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .lightSpeedIn { -webkit-animation-name: lightSpeedIn; animation-name: lightSpeedIn; -webkit-animation-timing-function: ease-out; animation-timing-function: ease-out; } @-webkit-keyframes lightSpeedOut { from { opacity: 1; } to { -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); transform: translate3d(100%, 0, 0) skewX(30deg); opacity: 0; } } @keyframes lightSpeedOut { from { opacity: 1; } to { -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); transform: translate3d(100%, 0, 0) skewX(30deg); opacity: 0; } } .lightSpeedOut { -webkit-animation-name: lightSpeedOut; animation-name: lightSpeedOut; -webkit-animation-timing-function: ease-in; animation-timing-function: ease-in; } @-webkit-keyframes rotateIn { from { -webkit-transform-origin: center; transform-origin: center; -webkit-transform: rotate3d(0, 0, 1, -200deg); transform: rotate3d(0, 0, 1, -200deg); opacity: 0; } to { -webkit-transform-origin: center; transform-origin: center; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } @keyframes rotateIn { from { -webkit-transform-origin: center; transform-origin: center; -webkit-transform: rotate3d(0, 0, 1, -200deg); transform: rotate3d(0, 0, 1, -200deg); opacity: 0; } to { -webkit-transform-origin: center; transform-origin: center; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } .rotateIn { -webkit-animation-name: rotateIn; animation-name: rotateIn; } @-webkit-keyframes rotateInDownLeft { from { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: rotate3d(0, 0, 1, -45deg); transform: rotate3d(0, 0, 1, -45deg); opacity: 0; } to { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } @keyframes rotateInDownLeft { from { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: rotate3d(0, 0, 1, -45deg); transform: rotate3d(0, 0, 1, -45deg); opacity: 0; } to { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } .rotateInDownLeft { -webkit-animation-name: rotateInDownLeft; animation-name: rotateInDownLeft; } @-webkit-keyframes rotateInDownRight { from { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: rotate3d(0, 0, 1, 45deg); transform: rotate3d(0, 0, 1, 45deg); opacity: 0; } to { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } @keyframes rotateInDownRight { from { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: rotate3d(0, 0, 1, 45deg); transform: rotate3d(0, 0, 1, 45deg); opacity: 0; } to { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } .rotateInDownRight { -webkit-animation-name: rotateInDownRight; animation-name: rotateInDownRight; } @-webkit-keyframes rotateInUpLeft { from { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: rotate3d(0, 0, 1, 45deg); transform: rotate3d(0, 0, 1, 45deg); opacity: 0; } to { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } @keyframes rotateInUpLeft { from { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: rotate3d(0, 0, 1, 45deg); transform: rotate3d(0, 0, 1, 45deg); opacity: 0; } to { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } .rotateInUpLeft { -webkit-animation-name: rotateInUpLeft; animation-name: rotateInUpLeft; } @-webkit-keyframes rotateInUpRight { from { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: rotate3d(0, 0, 1, -90deg); transform: rotate3d(0, 0, 1, -90deg); opacity: 0; } to { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } @keyframes rotateInUpRight { from { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: rotate3d(0, 0, 1, -90deg); transform: rotate3d(0, 0, 1, -90deg); opacity: 0; } to { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); opacity: 1; } } .rotateInUpRight { -webkit-animation-name: rotateInUpRight; animation-name: rotateInUpRight; } @-webkit-keyframes rotateOut { from { -webkit-transform-origin: center; transform-origin: center; opacity: 1; } to { -webkit-transform-origin: center; transform-origin: center; -webkit-transform: rotate3d(0, 0, 1, 200deg); transform: rotate3d(0, 0, 1, 200deg); opacity: 0; } } @keyframes rotateOut { from { -webkit-transform-origin: center; transform-origin: center; opacity: 1; } to { -webkit-transform-origin: center; transform-origin: center; -webkit-transform: rotate3d(0, 0, 1, 200deg); transform: rotate3d(0, 0, 1, 200deg); opacity: 0; } } .rotateOut { -webkit-animation-name: rotateOut; animation-name: rotateOut; } @-webkit-keyframes rotateOutDownLeft { from { -webkit-transform-origin: left bottom; transform-origin: left bottom; opacity: 1; } to { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: rotate3d(0, 0, 1, 45deg); transform: rotate3d(0, 0, 1, 45deg); opacity: 0; } } @keyframes rotateOutDownLeft { from { -webkit-transform-origin: left bottom; transform-origin: left bottom; opacity: 1; } to { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: rotate3d(0, 0, 1, 45deg); transform: rotate3d(0, 0, 1, 45deg); opacity: 0; } } .rotateOutDownLeft { -webkit-animation-name: rotateOutDownLeft; animation-name: rotateOutDownLeft; } @-webkit-keyframes rotateOutDownRight { from { -webkit-transform-origin: right bottom; transform-origin: right bottom; opacity: 1; } to { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: rotate3d(0, 0, 1, -45deg); transform: rotate3d(0, 0, 1, -45deg); opacity: 0; } } @keyframes rotateOutDownRight { from { -webkit-transform-origin: right bottom; transform-origin: right bottom; opacity: 1; } to { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: rotate3d(0, 0, 1, -45deg); transform: rotate3d(0, 0, 1, -45deg); opacity: 0; } } .rotateOutDownRight { -webkit-animation-name: rotateOutDownRight; animation-name: rotateOutDownRight; } @-webkit-keyframes rotateOutUpLeft { from { -webkit-transform-origin: left bottom; transform-origin: left bottom; opacity: 1; } to { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: rotate3d(0, 0, 1, -45deg); transform: rotate3d(0, 0, 1, -45deg); opacity: 0; } } @keyframes rotateOutUpLeft { from { -webkit-transform-origin: left bottom; transform-origin: left bottom; opacity: 1; } to { -webkit-transform-origin: left bottom; transform-origin: left bottom; -webkit-transform: rotate3d(0, 0, 1, -45deg); transform: rotate3d(0, 0, 1, -45deg); opacity: 0; } } .rotateOutUpLeft { -webkit-animation-name: rotateOutUpLeft; animation-name: rotateOutUpLeft; } @-webkit-keyframes rotateOutUpRight { from { -webkit-transform-origin: right bottom; transform-origin: right bottom; opacity: 1; } to { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: rotate3d(0, 0, 1, 90deg); transform: rotate3d(0, 0, 1, 90deg); opacity: 0; } } @keyframes rotateOutUpRight { from { -webkit-transform-origin: right bottom; transform-origin: right bottom; opacity: 1; } to { -webkit-transform-origin: right bottom; transform-origin: right bottom; -webkit-transform: rotate3d(0, 0, 1, 90deg); transform: rotate3d(0, 0, 1, 90deg); opacity: 0; } } .rotateOutUpRight { -webkit-animation-name: rotateOutUpRight; animation-name: rotateOutUpRight; } @-webkit-keyframes hinge { 0% { -webkit-transform-origin: top left; transform-origin: top left; -webkit-animation-timing-function: ease-in-out; animation-timing-function: ease-in-out; } 20%, 60% { -webkit-transform: rotate3d(0, 0, 1, 80deg); transform: rotate3d(0, 0, 1, 80deg); -webkit-transform-origin: top left; transform-origin: top left; -webkit-animation-timing-function: ease-in-out; animation-timing-function: ease-in-out; } 40%, 80% { -webkit-transform: rotate3d(0, 0, 1, 60deg); transform: rotate3d(0, 0, 1, 60deg); -webkit-transform-origin: top left; transform-origin: top left; -webkit-animation-timing-function: ease-in-out; animation-timing-function: ease-in-out; opacity: 1; } to { -webkit-transform: translate3d(0, 700px, 0); transform: translate3d(0, 700px, 0); opacity: 0; } } @keyframes hinge { 0% { -webkit-transform-origin: top left; transform-origin: top left; -webkit-animation-timing-function: ease-in-out; animation-timing-function: ease-in-out; } 20%, 60% { -webkit-transform: rotate3d(0, 0, 1, 80deg); transform: rotate3d(0, 0, 1, 80deg); -webkit-transform-origin: top left; transform-origin: top left; -webkit-animation-timing-function: ease-in-out; animation-timing-function: ease-in-out; } 40%, 80% { -webkit-transform: rotate3d(0, 0, 1, 60deg); transform: rotate3d(0, 0, 1, 60deg); -webkit-transform-origin: top left; transform-origin: top left; -webkit-animation-timing-function: ease-in-out; animation-timing-function: ease-in-out; opacity: 1; } to { -webkit-transform: translate3d(0, 700px, 0); transform: translate3d(0, 700px, 0); opacity: 0; } } .hinge { -webkit-animation-duration: 2s; animation-duration: 2s; -webkit-animation-name: hinge; animation-name: hinge; } @-webkit-keyframes jackInTheBox { from { opacity: 0; -webkit-transform: scale(0.1) rotate(30deg); transform: scale(0.1) rotate(30deg); -webkit-transform-origin: center bottom; transform-origin: center bottom; } 50% { -webkit-transform: rotate(-10deg); transform: rotate(-10deg); } 70% { -webkit-transform: rotate(3deg); transform: rotate(3deg); } to { opacity: 1; -webkit-transform: scale(1); transform: scale(1); } } @keyframes jackInTheBox { from { opacity: 0; -webkit-transform: scale(0.1) rotate(30deg); transform: scale(0.1) rotate(30deg); -webkit-transform-origin: center bottom; transform-origin: center bottom; } 50% { -webkit-transform: rotate(-10deg); transform: rotate(-10deg); } 70% { -webkit-transform: rotate(3deg); transform: rotate(3deg); } to { opacity: 1; -webkit-transform: scale(1); transform: scale(1); } } .jackInTheBox { -webkit-animation-name: jackInTheBox; animation-name: jackInTheBox; } /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ @-webkit-keyframes rollIn { from { opacity: 0; -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes rollIn { from { opacity: 0; -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); } to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .rollIn { -webkit-animation-name: rollIn; animation-name: rollIn; } /* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ @-webkit-keyframes rollOut { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); } } @keyframes rollOut { from { opacity: 1; } to { opacity: 0; -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); } } .rollOut { -webkit-animation-name: rollOut; animation-name: rollOut; } @-webkit-keyframes zoomIn { from { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); } 50% { opacity: 1; } } @keyframes zoomIn { from { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); } 50% { opacity: 1; } } .zoomIn { -webkit-animation-name: zoomIn; animation-name: zoomIn; } @-webkit-keyframes zoomInDown { from { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } 60% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } @keyframes zoomInDown { from { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } 60% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } .zoomInDown { -webkit-animation-name: zoomInDown; animation-name: zoomInDown; } @-webkit-keyframes zoomInLeft { from { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } 60% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } @keyframes zoomInLeft { from { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } 60% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } .zoomInLeft { -webkit-animation-name: zoomInLeft; animation-name: zoomInLeft; } @-webkit-keyframes zoomInRight { from { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } 60% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } @keyframes zoomInRight { from { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } 60% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } .zoomInRight { -webkit-animation-name: zoomInRight; animation-name: zoomInRight; } @-webkit-keyframes zoomInUp { from { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } 60% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } @keyframes zoomInUp { from { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } 60% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } .zoomInUp { -webkit-animation-name: zoomInUp; animation-name: zoomInUp; } @-webkit-keyframes zoomOut { from { opacity: 1; } 50% { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); } to { opacity: 0; } } @keyframes zoomOut { from { opacity: 1; } 50% { opacity: 0; -webkit-transform: scale3d(0.3, 0.3, 0.3); transform: scale3d(0.3, 0.3, 0.3); } to { opacity: 0; } } .zoomOut { -webkit-animation-name: zoomOut; animation-name: zoomOut; } @-webkit-keyframes zoomOutDown { 40% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } to { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); -webkit-transform-origin: center bottom; transform-origin: center bottom; -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } @keyframes zoomOutDown { 40% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } to { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); -webkit-transform-origin: center bottom; transform-origin: center bottom; -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } .zoomOutDown { -webkit-animation-name: zoomOutDown; animation-name: zoomOutDown; } @-webkit-keyframes zoomOutLeft { 40% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); } to { opacity: 0; -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0); transform: scale(0.1) translate3d(-2000px, 0, 0); -webkit-transform-origin: left center; transform-origin: left center; } } @keyframes zoomOutLeft { 40% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); } to { opacity: 0; -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0); transform: scale(0.1) translate3d(-2000px, 0, 0); -webkit-transform-origin: left center; transform-origin: left center; } } .zoomOutLeft { -webkit-animation-name: zoomOutLeft; animation-name: zoomOutLeft; } @-webkit-keyframes zoomOutRight { 40% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); } to { opacity: 0; -webkit-transform: scale(0.1) translate3d(2000px, 0, 0); transform: scale(0.1) translate3d(2000px, 0, 0); -webkit-transform-origin: right center; transform-origin: right center; } } @keyframes zoomOutRight { 40% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); } to { opacity: 0; -webkit-transform: scale(0.1) translate3d(2000px, 0, 0); transform: scale(0.1) translate3d(2000px, 0, 0); -webkit-transform-origin: right center; transform-origin: right center; } } .zoomOutRight { -webkit-animation-name: zoomOutRight; animation-name: zoomOutRight; } @-webkit-keyframes zoomOutUp { 40% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } to { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); -webkit-transform-origin: center bottom; transform-origin: center bottom; -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } @keyframes zoomOutUp { 40% { opacity: 1; -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); } to { opacity: 0; -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); -webkit-transform-origin: center bottom; transform-origin: center bottom; -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); } } .zoomOutUp { -webkit-animation-name: zoomOutUp; animation-name: zoomOutUp; } @-webkit-keyframes slideInDown { from { -webkit-transform: translate3d(0, -100%, 0); transform: translate3d(0, -100%, 0); visibility: visible; } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes slideInDown { from { -webkit-transform: translate3d(0, -100%, 0); transform: translate3d(0, -100%, 0); visibility: visible; } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .slideInDown { -webkit-animation-name: slideInDown; animation-name: slideInDown; } @-webkit-keyframes slideInLeft { from { -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); visibility: visible; } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes slideInLeft { from { -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); visibility: visible; } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .slideInLeft { -webkit-animation-name: slideInLeft; animation-name: slideInLeft; } @-webkit-keyframes slideInRight { from { -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); visibility: visible; } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes slideInRight { from { -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); visibility: visible; } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .slideInRight { -webkit-animation-name: slideInRight; animation-name: slideInRight; } @-webkit-keyframes slideInUp { from { -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); visibility: visible; } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } @keyframes slideInUp { from { -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); visibility: visible; } to { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } } .slideInUp { -webkit-animation-name: slideInUp; animation-name: slideInUp; } @-webkit-keyframes slideOutDown { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { visibility: hidden; -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); } } @keyframes slideOutDown { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { visibility: hidden; -webkit-transform: translate3d(0, 100%, 0); transform: translate3d(0, 100%, 0); } } .slideOutDown { -webkit-animation-name: slideOutDown; animation-name: slideOutDown; } @-webkit-keyframes slideOutLeft { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { visibility: hidden; -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); } } @keyframes slideOutLeft { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { visibility: hidden; -webkit-transform: translate3d(-100%, 0, 0); transform: translate3d(-100%, 0, 0); } } .slideOutLeft { -webkit-animation-name: slideOutLeft; animation-name: slideOutLeft; } @-webkit-keyframes slideOutRight { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { visibility: hidden; -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); } } @keyframes slideOutRight { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { visibility: hidden; -webkit-transform: translate3d(100%, 0, 0); transform: translate3d(100%, 0, 0); } } .slideOutRight { -webkit-animation-name: slideOutRight; animation-name: slideOutRight; } @-webkit-keyframes slideOutUp { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { visibility: hidden; -webkit-transform: translate3d(0, -100%, 0); transform: translate3d(0, -100%, 0); } } @keyframes slideOutUp { from { -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); } to { visibility: hidden; -webkit-transform: translate3d(0, -100%, 0); transform: translate3d(0, -100%, 0); } } .slideOutUp { -webkit-animation-name: slideOutUp; animation-name: slideOutUp; } .animated { -webkit-animation-duration: 1s; animation-duration: 1s; -webkit-animation-fill-mode: both; animation-fill-mode: both; } .animated.infinite { -webkit-animation-iteration-count: infinite; animation-iteration-count: infinite; } .animated.delay-1s { -webkit-animation-delay: 1s; animation-delay: 1s; } .animated.delay-2s { -webkit-animation-delay: 2s; animation-delay: 2s; } .animated.delay-3s { -webkit-animation-delay: 3s; animation-delay: 3s; } .animated.delay-4s { -webkit-animation-delay: 4s; animation-delay: 4s; } .animated.delay-5s { -webkit-animation-delay: 5s; animation-delay: 5s; } .animated.fast { -webkit-animation-duration: 800ms; animation-duration: 800ms; } .animated.faster { -webkit-animation-duration: 500ms; animation-duration: 500ms; } .animated.slow { -webkit-animation-duration: 2s; animation-duration: 2s; } .animated.slower { -webkit-animation-duration: 3s; animation-duration: 3s; } @media (prefers-reduced-motion) { .animated { -webkit-animation: unset !important; animation: unset !important; -webkit-transition: none !important; transition: none !important; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\base-theme.scss // Import all the theming functionality. // We can use relative imports for imports from the cdk because we bundle everything // up into a single flat scss file for material. // We want overlays to always appear over user content, so set a baseline // very high z-index for the overlay container, which is where we create the new // stacking context for all overlays. $cdk-z-index-overlay-container: 1000 !default; $cdk-z-index-overlay: 1000 !default; $cdk-z-index-overlay-backdrop: 1000 !default; // Background color for all of the backdrops $cdk-overlay-dark-backdrop-background: rgba(0, 0, 0, 0.32) !default; // Default backdrop animation is based on the Material Design swift-ease-out. $backdrop-animation-duration: 400ms !default; $backdrop-animation-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default; @mixin cdk-overlay() { .cdk-overlay-container, .cdk-global-overlay-wrapper { // Disable events from being captured on the overlay container. pointer-events: none; // The container should be the size of the viewport. top: 0; left: 0; height: 100%; width: 100%; } // The overlay-container is an invisible element which contains all individual overlays. .cdk-overlay-container { position: fixed; z-index: $cdk-z-index-overlay-container; &:empty { // Hide the element when it doesn't have any child nodes. This doesn't // include overlays that have been detached, rather than disposed. display: none; } } // We use an extra wrapper element in order to use make the overlay itself a flex item. // This makes centering the overlay easy without running into the subpixel rendering // problems tied to using `transform` and without interfering with the other position // strategies. .cdk-global-overlay-wrapper { display: flex; position: absolute; z-index: $cdk-z-index-overlay; } // A single overlay pane. .cdk-overlay-pane { // Note: it's important for this one to start off `absolute`, // in order for us to be able to measure it correctly. position: absolute; pointer-events: auto; box-sizing: border-box; z-index: $cdk-z-index-overlay; // For connected-position overlays, we set `display: flex` in // order to force `max-width` and `max-height` to take effect. display: flex; max-width: 100%; max-height: 100%; } .cdk-overlay-backdrop { // TODO(jelbourn): reuse sidenav fullscreen mixin. position: absolute; top: 0; bottom: 0; left: 0; right: 0; z-index: $cdk-z-index-overlay-backdrop; pointer-events: auto; -webkit-tap-highlight-color: transparent; transition: opacity $backdrop-animation-duration $backdrop-animation-timing-function; opacity: 0; &.cdk-overlay-backdrop-showing { opacity: 1; // In high contrast mode the rgba background will become solid so we need to fall back // to making it opaque using `opacity`. Note that we can't use the `cdk-high-contrast` // mixin, because we can't normalize the import path to the _a11y.scss both for the // source and when this file is distributed. See #10908. @media screen and (-ms-high-contrast: active) { opacity: 0.6; } } } .cdk-overlay-dark-backdrop { background: $cdk-overlay-dark-backdrop-background; } .cdk-overlay-transparent-backdrop { // Note: as of Firefox 57, having the backdrop be `background: none` will prevent it from // capturing the user's mouse scroll events. Since we also can't use something like // `rgba(0, 0, 0, 0)`, we work around the inconsistency by not setting the background at // all and using `opacity` to make the element transparent. &, &.cdk-overlay-backdrop-showing { opacity: 0; } } // Overlay parent element used with the connected position strategy. Used to constrain the // overlay element's size to fit within the viewport. .cdk-overlay-connected-position-bounding-box { position: absolute; z-index: $cdk-z-index-overlay; // We use `display: flex` on this element exclusively for centering connected overlays. // When *not* centering, a top/left/bottom/right will be set which overrides the normal // flex layout. display: flex; // We use the `column` direction here to avoid some flexbox issues in Edge // when using the "grow after open" options. flex-direction: column; // Add some dimensions so the element has an `innerText` which some people depend on in tests. min-width: 1px; min-height: 1px; } // Used when disabling global scrolling. .cdk-global-scrollblock { position: fixed; // Necessary for the content not to lose its width. Note that we're using 100%, instead of // 100vw, because 100vw includes the width plus the scrollbar, whereas 100% is the width // that the element had before we made it `fixed`. width: 100%; // Note: this will always add a scrollbar to whatever element it is on, which can // potentially result in double scrollbars. It shouldn't be an issue, because we won't // block scrolling on a page that doesn't have a scrollbar in the first place. overflow-y: scroll; } } @mixin cdk-a11y { .cdk-visually-hidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; // Avoid browsers rendering the focus ring in some cases. outline: 0; // Avoid some cases where the browser will still render the native controls (see #9049). -webkit-appearance: none; -moz-appearance: none; } } // Applies styles for users in high contrast mode. Note that this only applies // to Microsoft browsers. Chrome can be included by checking for the `html[hc]` // attribute, however Chrome handles high contrast differently. // // @param target Which kind of high contrast setting to target. Defaults to `active`, can be // `white-on-black` or `black-on-white`. @mixin cdk-high-contrast($target: active) { @media (-ms-high-contrast: $target) { @content; } } // Core styles that enable monitoring autofill state of text fields. @mixin cdk-text-field { // Keyframes that apply no styles, but allow us to monitor when an text field becomes autofilled // by watching for the animation events that are fired when they start. Note: the /*!*/ comment is // needed to prevent LibSass from stripping the keyframes out. // Based on: https://medium.com/@brunn/detecting-autofilled-fields-in-javascript-aed598d25da7 @keyframes cdk-text-field-autofill-start {/*!*/} @keyframes cdk-text-field-autofill-end {/*!*/} .cdk-text-field-autofill-monitored:-webkit-autofill { animation-name: cdk-text-field-autofill-start; } .cdk-text-field-autofill-monitored:not(:-webkit-autofill) { animation-name: cdk-text-field-autofill-end; } // Remove the resize handle on autosizing textareas, because whatever height // the user resized to will be overwritten once they start typing again. textarea.cdk-textarea-autosize { resize: none; } // This class is temporarily applied to the textarea when it is being measured. It is immediately // removed when measuring is complete. We use `!important` rules here to make sure user-specified // rules do not interfere with the measurement. textarea.cdk-textarea-autosize-measuring { height: auto !important; overflow: hidden !important; // Having 2px top and bottom padding seems to fix a bug where Chrome gets an incorrect // measurement. We just have to account for it later and subtract it off the final result. padding: 2px 0 !important; box-sizing: content-box !important; } } // Used to generate UIDs for keyframes used to change the text field autofill styles. $cdk-text-field-autofill-color-frame-count: 0; // Mixin used to apply custom background and foreground colors to an autofilled text field. // Based on: https://stackoverflow.com/questions/2781549/ // removing-input-background-colour-for-chrome-autocomplete#answer-37432260 @mixin cdk-text-field-autofill-color($background, $foreground:'') { @keyframes cdk-text-field-autofill-color-#{$cdk-text-field-autofill-color-frame-count} { to { background: $background; @if $foreground != '' { color: $foreground; } } } &:-webkit-autofill { animation-name: cdk-text-field-autofill-color-#{$cdk-text-field-autofill-color-frame-count}; animation-fill-mode: both; } &.cdk-text-field-autofill-monitored:-webkit-autofill { animation-name: cdk-text-field-autofill-start, cdk-text-field-autofill-color-#{$cdk-text-field-autofill-color-frame-count}; } $cdk-text-field-autofill-color-frame-count: $cdk-text-field-autofill-color-frame-count + 1 !global; } // Core styles that can be used to apply material design treatments to any element. // Media queries // TODO(josephperrott): Change $mat-xsmall and $mat-small usages to rely on BreakpointObserver, $mat-xsmall: 'max-width: 599px'; $mat-small: 'max-width: 959px'; // TODO: Revisit all z-indices before beta // z-index master list $z-index-fab: 20 !default; $z-index-drawer: 100 !default; // Global constants $pi: 3.14159265; // Padding between input toggles and their labels $mat-toggle-padding: 8px !default; // Width and height of input toggles $mat-toggle-size: 20px !default; // Easing Curves // TODO(jelbourn): all of these need to be revisited // The default animation curves used by material design. $mat-linear-out-slow-in-timing-function: cubic-bezier(0, 0, 0.2, 0.1) !default; $mat-fast-out-slow-in-timing-function: cubic-bezier(0.4, 0, 0.2, 1) !default; $mat-fast-out-linear-in-timing-function: cubic-bezier(0.4, 0, 1, 1) !default; $ease-in-out-curve-function: cubic-bezier(0.35, 0, 0.25, 1) !default; $swift-ease-out-duration: 400ms !default; $swift-ease-out-timing-function: cubic-bezier(0.25, 0.8, 0.25, 1) !default; $swift-ease-out: all $swift-ease-out-duration $swift-ease-out-timing-function !default; $swift-ease-in-duration: 300ms !default; $swift-ease-in-timing-function: cubic-bezier(0.55, 0, 0.55, 0.2) !default; $swift-ease-in: all $swift-ease-in-duration $swift-ease-in-timing-function !default; $swift-ease-in-out-duration: 500ms !default; $swift-ease-in-out-timing-function: $ease-in-out-curve-function !default; $swift-ease-in-out: all $swift-ease-in-out-duration $swift-ease-in-out-timing-function !default; $swift-linear-duration: 80ms !default; $swift-linear-timing-function: linear !default; $swift-linear: all $swift-linear-duration $swift-linear-timing-function !default; // A collection of mixins and CSS classes that can be used to apply elevation to a material // element. // See: https://material.io/design/environment/elevation.html // Examples: // // // .mat-foo { // @include $mat-elevation(2); // // &:active { // @include $mat-elevation(8); // } // } // //

Some content

// // For an explanation of the design behind how elevation is implemented, see the design doc at // https://goo.gl/Kq0k9Z. // Colors for umbra, penumbra, and ambient shadows. As described in the design doc, each elevation // level is created using a set of 3 shadow values, one for umbra (the shadow representing the // space completely obscured by an object relative to its light source), one for penumbra (the // space partially obscured by an object), and one for ambient (the space which contains the object // itself). For a further explanation of these terms and their meanings, see // https://en.wikipedia.org/wiki/Umbra,_penumbra_and_antumbra. // Maps for the different shadow sets and their values within each z-space. These values were // created by taking a few reference shadow sets created by Google's Designers and interpolating // all of the values between them. @function _get-umbra-map($color, $opacity) { $shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.2), $color); @return ( 0: '0px 0px 0px 0px #{$shadow-color}', 1: '0px 2px 1px -1px #{$shadow-color}', 2: '0px 3px 1px -2px #{$shadow-color}', 3: '0px 3px 3px -2px #{$shadow-color}', 4: '0px 2px 4px -1px #{$shadow-color}', 5: '0px 3px 5px -1px #{$shadow-color}', 6: '0px 3px 5px -1px #{$shadow-color}', 7: '0px 4px 5px -2px #{$shadow-color}', 8: '0px 5px 5px -3px #{$shadow-color}', 9: '0px 5px 6px -3px #{$shadow-color}', 10: '0px 6px 6px -3px #{$shadow-color}', 11: '0px 6px 7px -4px #{$shadow-color}', 12: '0px 7px 8px -4px #{$shadow-color}', 13: '0px 7px 8px -4px #{$shadow-color}', 14: '0px 7px 9px -4px #{$shadow-color}', 15: '0px 8px 9px -5px #{$shadow-color}', 16: '0px 8px 10px -5px #{$shadow-color}', 17: '0px 8px 11px -5px #{$shadow-color}', 18: '0px 9px 11px -5px #{$shadow-color}', 19: '0px 9px 12px -6px #{$shadow-color}', 20: '0px 10px 13px -6px #{$shadow-color}', 21: '0px 10px 13px -6px #{$shadow-color}', 22: '0px 10px 14px -6px #{$shadow-color}', 23: '0px 11px 14px -7px #{$shadow-color}', 24: '0px 11px 15px -7px #{$shadow-color}' ); } @function _get-penumbra-map($color, $opacity) { $shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.14), $color); @return ( 0: '0px 0px 0px 0px #{$shadow-color}', 1: '0px 1px 1px 0px #{$shadow-color}', 2: '0px 2px 2px 0px #{$shadow-color}', 3: '0px 3px 4px 0px #{$shadow-color}', 4: '0px 4px 5px 0px #{$shadow-color}', 5: '0px 5px 8px 0px #{$shadow-color}', 6: '0px 6px 10px 0px #{$shadow-color}', 7: '0px 7px 10px 1px #{$shadow-color}', 8: '0px 8px 10px 1px #{$shadow-color}', 9: '0px 9px 12px 1px #{$shadow-color}', 10: '0px 10px 14px 1px #{$shadow-color}', 11: '0px 11px 15px 1px #{$shadow-color}', 12: '0px 12px 17px 2px #{$shadow-color}', 13: '0px 13px 19px 2px #{$shadow-color}', 14: '0px 14px 21px 2px #{$shadow-color}', 15: '0px 15px 22px 2px #{$shadow-color}', 16: '0px 16px 24px 2px #{$shadow-color}', 17: '0px 17px 26px 2px #{$shadow-color}', 18: '0px 18px 28px 2px #{$shadow-color}', 19: '0px 19px 29px 2px #{$shadow-color}', 20: '0px 20px 31px 3px #{$shadow-color}', 21: '0px 21px 33px 3px #{$shadow-color}', 22: '0px 22px 35px 3px #{$shadow-color}', 23: '0px 23px 36px 3px #{$shadow-color}', 24: '0px 24px 38px 3px #{$shadow-color}' ); } @function _get-ambient-map($color, $opacity) { $shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.12), $color); @return ( 0: '0px 0px 0px 0px #{$shadow-color}', 1: '0px 1px 3px 0px #{$shadow-color}', 2: '0px 1px 5px 0px #{$shadow-color}', 3: '0px 1px 8px 0px #{$shadow-color}', 4: '0px 1px 10px 0px #{$shadow-color}', 5: '0px 1px 14px 0px #{$shadow-color}', 6: '0px 1px 18px 0px #{$shadow-color}', 7: '0px 2px 16px 1px #{$shadow-color}', 8: '0px 3px 14px 2px #{$shadow-color}', 9: '0px 3px 16px 2px #{$shadow-color}', 10: '0px 4px 18px 3px #{$shadow-color}', 11: '0px 4px 20px 3px #{$shadow-color}', 12: '0px 5px 22px 4px #{$shadow-color}', 13: '0px 5px 24px 4px #{$shadow-color}', 14: '0px 5px 26px 4px #{$shadow-color}', 15: '0px 6px 28px 5px #{$shadow-color}', 16: '0px 6px 30px 5px #{$shadow-color}', 17: '0px 6px 32px 5px #{$shadow-color}', 18: '0px 7px 34px 6px #{$shadow-color}', 19: '0px 7px 36px 6px #{$shadow-color}', 20: '0px 8px 38px 7px #{$shadow-color}', 21: '0px 8px 40px 7px #{$shadow-color}', 22: '0px 8px 42px 7px #{$shadow-color}', 23: '0px 9px 44px 8px #{$shadow-color}', 24: '0px 9px 46px 8px #{$shadow-color}' ); } // The default duration value for elevation transitions. $mat-elevation-transition-duration: 280ms !default; // The default easing value for elevation transitions. $mat-elevation-transition-timing-function: $mat-fast-out-slow-in-timing-function; // The default color for elevation shadows. $mat-elevation-color: black !default; // The default opacity scaling value for elevation shadows. $mat-elevation-opacity: 1 !default; // Prefix for elevation-related selectors. $_mat-elevation-prefix: 'mat-elevation-z'; // Applies the correct css rules to an element to give it the elevation specified by $zValue. // The $zValue must be between 0 and 24. @mixin mat-elevation($zValue, $color: $mat-elevation-color, $opacity: $mat-elevation-opacity) { @if type-of($zValue) != number or not unitless($zValue) { @error '$zValue must be a unitless number'; } @if $zValue < 0 or $zValue > 24 { @error '$zValue must be between 0 and 24'; } box-shadow: #{map-get(_get-umbra-map($color, $opacity), $zValue)}, #{map-get(_get-penumbra-map($color, $opacity), $zValue)}, #{map-get(_get-ambient-map($color, $opacity), $zValue)}; } @mixin _mat-theme-elevation($zValue, $theme, $opacity: $mat-elevation-opacity) { $foreground: map-get($theme, foreground); $elevation-color: map-get($foreground, elevation); $elevation-color-or-default: if($elevation-color == null, $mat-elevation-color, $elevation-color); @include mat-elevation($zValue, $elevation-color-or-default, $opacity); } // Applies the elevation to an element in a manner that allows // consumers to override it via the Material elevation classes. @mixin mat-overridable-elevation( $zValue, $color: $mat-elevation-color, $opacity: $mat-elevation-opacity) { &:not([class*='#{$_mat-elevation-prefix}']) { @include mat-elevation($zValue, $color, $opacity); } } @mixin _mat-theme-overridable-elevation($zValue, $theme, $opacity: $mat-elevation-opacity) { $foreground: map-get($theme, foreground); $elevation-color: map-get($foreground, elevation); $elevation-color-or-default: if($elevation-color == null, $mat-elevation-color, $elevation-color); @include mat-overridable-elevation($zValue, $elevation-color-or-default, $opacity); } // Returns a string that can be used as the value for a transition property for elevation. // Calling this function directly is useful in situations where a component needs to transition // more than one property. // // .foo { // transition: mat-elevation-transition-property-value(), opacity 100ms ease; // } @function mat-elevation-transition-property-value( $duration: $mat-elevation-transition-duration, $easing: $mat-elevation-transition-timing-function) { @return box-shadow #{$duration} #{$easing}; } // Applies the correct css rules needed to have an element transition between elevations. // This mixin should be applied to elements whose elevation values will change depending on their // context (e.g. when active or disabled). // // NOTE(traviskaufman): Both this mixin and the above function use default parameters so they can // be used in the same way by clients. @mixin mat-elevation-transition( $duration: $mat-elevation-transition-duration, $easing: $mat-elevation-transition-timing-function) { transition: mat-elevation-transition-property-value($duration, $easing); } // Color palettes from the Material Design spec. // See https://material.io/design/color/ // // Contrast colors are hard-coded because it is too difficult (probably impossible) to // calculate them. These contrast colors are pulled from the public Material Design spec swatches. // While the contrast colors in the spec are not prescriptive, we use them for convenience. // @deprecated renamed to $dark-primary-text. // @breaking-change 8.0.0 $black-87-opacity: rgba(black, 0.87); // @deprecated renamed to $light-primary-text. // @breaking-change 8.0.0 $white-87-opacity: rgba(white, 0.87); // @deprecated use $dark-[secondary-text,disabled-text,dividers,focused] instead. // @breaking-change 8.0.0 $black-12-opacity: rgba(black, 0.12); // @deprecated use $light-[secondary-text,disabled-text,dividers,focused] instead. // @breaking-change 8.0.0 $white-12-opacity: rgba(white, 0.12); // @deprecated use $dark-[secondary-text,disabled-text,dividers,focused] instead. // @breaking-change 8.0.0 $black-6-opacity: rgba(black, 0.06); // @deprecated use $light-[secondary-text,disabled-text,dividers,focused] instead. // @breaking-change 8.0.0 $white-6-opacity: rgba(white, 0.06); $dark-primary-text: rgba(black, 0.87); $dark-secondary-text: rgba(black, 0.54); $dark-disabled-text: rgba(black, 0.38); $dark-dividers: rgba(black, 0.12); $dark-focused: rgba(black, 0.12); $light-primary-text: white; $light-secondary-text: rgba(white, 0.7); $light-disabled-text: rgba(white, 0.5); $light-dividers: rgba(white, 0.12); $light-focused: rgba(white, 0.12); $mat-red: ( 50: #ffebee, 100: #ffcdd2, 200: #ef9a9a, 300: #e57373, 400: #ef5350, 500: #f44336, 600: #e53935, 700: #d32f2f, 800: #c62828, 900: #b71c1c, A100: #ff8a80, A200: #ff5252, A400: #ff1744, A700: #d50000, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $light-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); $mat-pink: ( 50: #fce4ec, 100: #f8bbd0, 200: #f48fb1, 300: #f06292, 400: #ec407a, 500: #e91e63, 600: #d81b60, 700: #c2185b, 800: #ad1457, 900: #880e4f, A100: #ff80ab, A200: #ff4081, A400: #f50057, A700: #c51162, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $light-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); $mat-purple: ( 50: #f3e5f5, 100: #e1bee7, 200: #ce93d8, 300: #ba68c8, 400: #ab47bc, 500: #9c27b0, 600: #8e24aa, 700: #7b1fa2, 800: #6a1b9a, 900: #4a148c, A100: #ea80fc, A200: #e040fb, A400: #d500f9, A700: #aa00ff, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $light-primary-text, 400: $light-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $light-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); $mat-deep-purple: ( 50: #ede7f6, 100: #d1c4e9, 200: #b39ddb, 300: #9575cd, 400: #7e57c2, 500: #673ab7, 600: #5e35b1, 700: #512da8, 800: #4527a0, 900: #311b92, A100: #b388ff, A200: #7c4dff, A400: #651fff, A700: #6200ea, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $light-primary-text, 400: $light-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $light-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); $mat-indigo: ( 50: #e8eaf6, 100: #c5cae9, 200: #9fa8da, 300: #7986cb, 400: #5c6bc0, 500: #3f51b5, 600: #3949ab, 700: #303f9f, 800: #283593, 900: #1a237e, A100: #8c9eff, A200: #536dfe, A400: #3d5afe, A700: #304ffe, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $light-primary-text, 400: $light-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $light-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); $mat-blue: ( 50: #e3f2fd, 100: #bbdefb, 200: #90caf9, 300: #64b5f6, 400: #42a5f5, 500: #2196f3, 600: #1e88e5, 700: #1976d2, 800: #1565c0, 900: #0d47a1, A100: #82b1ff, A200: #448aff, A400: #2979ff, A700: #2962ff, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $light-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); $mat-light-blue: ( 50: #e1f5fe, 100: #b3e5fc, 200: #81d4fa, 300: #4fc3f7, 400: #29b6f6, 500: #03a9f4, 600: #039be5, 700: #0288d1, 800: #0277bd, 900: #01579b, A100: #80d8ff, A200: #40c4ff, A400: #00b0ff, A700: #0091ea, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $light-primary-text, ) ); $mat-cyan: ( 50: #e0f7fa, 100: #b2ebf2, 200: #80deea, 300: #4dd0e1, 400: #26c6da, 500: #00bcd4, 600: #00acc1, 700: #0097a7, 800: #00838f, 900: #006064, A100: #84ffff, A200: #18ffff, A400: #00e5ff, A700: #00b8d4, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $dark-primary-text, ) ); $mat-teal: ( 50: #e0f2f1, 100: #b2dfdb, 200: #80cbc4, 300: #4db6ac, 400: #26a69a, 500: #009688, 600: #00897b, 700: #00796b, 800: #00695c, 900: #004d40, A100: #a7ffeb, A200: #64ffda, A400: #1de9b6, A700: #00bfa5, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $dark-primary-text, ) ); $mat-green: ( 50: #e8f5e9, 100: #c8e6c9, 200: #a5d6a7, 300: #81c784, 400: #66bb6a, 500: #4caf50, 600: #43a047, 700: #388e3c, 800: #2e7d32, 900: #1b5e20, A100: #b9f6ca, A200: #69f0ae, A400: #00e676, A700: #00c853, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $dark-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $dark-primary-text, ) ); $mat-light-green: ( 50: #f1f8e9, 100: #dcedc8, 200: #c5e1a5, 300: #aed581, 400: #9ccc65, 500: #8bc34a, 600: #7cb342, 700: #689f38, 800: #558b2f, 900: #33691e, A100: #ccff90, A200: #b2ff59, A400: #76ff03, A700: #64dd17, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $dark-primary-text, 600: $dark-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $dark-primary-text, ) ); $mat-lime: ( 50: #f9fbe7, 100: #f0f4c3, 200: #e6ee9c, 300: #dce775, 400: #d4e157, 500: #cddc39, 600: #c0ca33, 700: #afb42b, 800: #9e9d24, 900: #827717, A100: #f4ff81, A200: #eeff41, A400: #c6ff00, A700: #aeea00, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $dark-primary-text, 600: $dark-primary-text, 700: $dark-primary-text, 800: $dark-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $dark-primary-text, ) ); $mat-yellow: ( 50: #fffde7, 100: #fff9c4, 200: #fff59d, 300: #fff176, 400: #ffee58, 500: #ffeb3b, 600: #fdd835, 700: #fbc02d, 800: #f9a825, 900: #f57f17, A100: #ffff8d, A200: #ffff00, A400: #ffea00, A700: #ffd600, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $dark-primary-text, 600: $dark-primary-text, 700: $dark-primary-text, 800: $dark-primary-text, 900: $dark-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $dark-primary-text, ) ); $mat-amber: ( 50: #fff8e1, 100: #ffecb3, 200: #ffe082, 300: #ffd54f, 400: #ffca28, 500: #ffc107, 600: #ffb300, 700: #ffa000, 800: #ff8f00, 900: #ff6f00, A100: #ffe57f, A200: #ffd740, A400: #ffc400, A700: #ffab00, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $dark-primary-text, 600: $dark-primary-text, 700: $dark-primary-text, 800: $dark-primary-text, 900: $dark-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $dark-primary-text, ) ); $mat-orange: ( 50: #fff3e0, 100: #ffe0b2, 200: #ffcc80, 300: #ffb74d, 400: #ffa726, 500: #ff9800, 600: #fb8c00, 700: #f57c00, 800: #ef6c00, 900: #e65100, A100: #ffd180, A200: #ffab40, A400: #ff9100, A700: #ff6d00, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $dark-primary-text, 600: $dark-primary-text, 700: $dark-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: black, ) ); $mat-deep-orange: ( 50: #fbe9e7, 100: #ffccbc, 200: #ffab91, 300: #ff8a65, 400: #ff7043, 500: #ff5722, 600: #f4511e, 700: #e64a19, 800: #d84315, 900: #bf360c, A100: #ff9e80, A200: #ff6e40, A400: #ff3d00, A700: #dd2c00, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); $mat-brown: ( 50: #efebe9, 100: #d7ccc8, 200: #bcaaa4, 300: #a1887f, 400: #8d6e63, 500: #795548, 600: #6d4c41, 700: #5d4037, 800: #4e342e, 900: #3e2723, A100: #d7ccc8, A200: #bcaaa4, A400: #8d6e63, A700: #5d4037, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $light-primary-text, 400: $light-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); $mat-grey: ( 50: #fafafa, 100: #f5f5f5, 200: #eeeeee, 300: #e0e0e0, 400: #bdbdbd, 500: #9e9e9e, 600: #757575, 700: #616161, 800: #424242, 900: #212121, A100: #ffffff, A200: #eeeeee, A400: #bdbdbd, A700: #616161, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $dark-primary-text, 500: $dark-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $dark-primary-text, A700: $light-primary-text, ) ); // Alias for alternate spelling. $mat-gray: $mat-grey; $mat-blue-grey: ( 50: #eceff1, 100: #cfd8dc, 200: #b0bec5, 300: #90a4ae, 400: #78909c, 500: #607d8b, 600: #546e7a, 700: #455a64, 800: #37474f, 900: #263238, A100: #cfd8dc, A200: #b0bec5, A400: #78909c, A700: #455a64, contrast: ( 50: $dark-primary-text, 100: $dark-primary-text, 200: $dark-primary-text, 300: $dark-primary-text, 400: $light-primary-text, 500: $light-primary-text, 600: $light-primary-text, 700: $light-primary-text, 800: $light-primary-text, 900: $light-primary-text, A100: $dark-primary-text, A200: $dark-primary-text, A400: $light-primary-text, A700: $light-primary-text, ) ); // Alias for alternate spelling. $mat-blue-gray: $mat-blue-grey; // Background palette for light themes. $mat-light-theme-background: ( status-bar: map_get($mat-grey, 300), app-bar: map_get($mat-grey, 100), background: map_get($mat-grey, 50), hover: rgba(black, 0.04), // TODO(kara): check style with Material Design UX card: white, dialog: white, disabled-button: rgba(black, 0.12), raised-button: white, focused-button: $dark-focused, selected-button: map_get($mat-grey, 300), selected-disabled-button: map_get($mat-grey, 400), disabled-button-toggle: map_get($mat-grey, 200), unselected-chip: map_get($mat-grey, 300), disabled-list-option: map_get($mat-grey, 200), ); // Background palette for dark themes. $mat-dark-theme-background: ( status-bar: black, app-bar: map_get($mat-grey, 900), background: #303030, hover: rgba(white, 0.04), // TODO(kara): check style with Material Design UX card: map_get($mat-grey, 800), dialog: map_get($mat-grey, 800), disabled-button: rgba(white, 0.12), raised-button: map-get($mat-grey, 800), focused-button: $light-focused, selected-button: map_get($mat-grey, 900), selected-disabled-button: map_get($mat-grey, 800), disabled-button-toggle: black, unselected-chip: map_get($mat-grey, 700), disabled-list-option: black, ); // Foreground palette for light themes. $mat-light-theme-foreground: ( base: black, divider: $dark-dividers, dividers: $dark-dividers, disabled: $dark-disabled-text, disabled-button: rgba(black, 0.26), disabled-text: $dark-disabled-text, elevation: black, hint-text: $dark-disabled-text, secondary-text: $dark-secondary-text, icon: rgba(black, 0.54), icons: rgba(black, 0.54), text: rgba(black, 0.87), slider-min: rgba(black, 0.87), slider-off: rgba(black, 0.26), slider-off-active: rgba(black, 0.38), ); // Foreground palette for dark themes. $mat-dark-theme-foreground: ( base: white, divider: $light-dividers, dividers: $light-dividers, disabled: $light-disabled-text, disabled-button: rgba(white, 0.3), disabled-text: $light-disabled-text, elevation: black, hint-text: $light-disabled-text, secondary-text: $light-secondary-text, icon: white, icons: white, text: white, slider-min: white, slider-off: rgba(white, 0.3), slider-off-active: rgba(white, 0.3), ); // For a given hue in a palette, return the contrast color from the map of contrast palettes. // @param $color-map // @param $hue @function mat-contrast($palette, $hue) { @return map-get(map-get($palette, contrast), $hue); } // Creates a map of hues to colors for a theme. This is used to define a theme palette in terms // of the Material Design hues. // @param $color-map // @param $primary // @param $lighter @function mat-palette($base-palette, $default: 500, $lighter: 100, $darker: 700, $text: $default) { $result: map_merge($base-palette, ( default: map-get($base-palette, $default), lighter: map-get($base-palette, $lighter), darker: map-get($base-palette, $darker), text: map-get($base-palette, $text), default-contrast: mat-contrast($base-palette, $default), lighter-contrast: mat-contrast($base-palette, $lighter), darker-contrast: mat-contrast($base-palette, $darker) )); // For each hue in the palette, add a "-contrast" color to the map. @each $hue, $color in $base-palette { $result: map_merge($result, ( '#{$hue}-contrast': mat-contrast($base-palette, $hue) )); } @return $result; } // Gets a color from a theme palette (the output of mat-palette). // The hue can be one of the standard values (500, A400, etc.), one of the three preconfigured // hues (default, lighter, darker), or any of the aforementioned prefixed with "-contrast". // // @param $color-map The theme palette (output of mat-palette). // @param $hue The hue from the palette to use. If this is a value between 0 and 1, it will // be treated as opacity. // @param $opacity The alpha channel value for the color. @function mat-color($palette, $hue: default, $opacity: null) { // If hueKey is a number between zero and one, then it actually contains an // opacity value, so recall this function with the default hue and that given opacity. @if type-of($hue) == number and $hue >= 0 and $hue <= 1 { @return mat-color($palette, default, $hue); } $color: map-get($palette, $hue); @if (type-of($color) != color) { // If the $color resolved to something different from a color (e.g. a CSS variable), // we can't apply the opacity anyway so we return the value as is, otherwise Sass can // throw an error or output something invalid. @return $color; } @return rgba($color, if($opacity == null, opacity($color), $opacity)); } // Creates a container object for a light theme to be given to individual component theme mixins. @function mat-light-theme($primary, $accent, $warn: mat-palette($mat-red)) { @return ( primary: $primary, accent: $accent, warn: $warn, is-dark: false, foreground: $mat-light-theme-foreground, background: $mat-light-theme-background, ); } // Creates a container object for a dark theme to be given to individual component theme mixins. @function mat-dark-theme($primary, $accent, $warn: mat-palette($mat-red)) { @return ( primary: $primary, accent: $accent, warn: $warn, is-dark: true, foreground: $mat-dark-theme-foreground, background: $mat-dark-theme-background, ); } $mat-ripple-color-opacity: 0.1; @mixin mat-ripple() { // The host element of an mat-ripple directive should always have a position of "absolute" or // "relative" so that the ripples inside are correctly positioned relatively to the container. .mat-ripple { overflow: hidden; // By default, every ripple container should have position: relative in favor of creating an // easy API for developers using the MatRipple directive. position: relative; } .mat-ripple.mat-ripple-unbounded { overflow: visible; } .mat-ripple-element { position: absolute; border-radius: 50%; pointer-events: none; transition: opacity, transform 0ms cubic-bezier(0, 0, 0.2, 1); transform: scale(0); // In high contrast mode the ripple is opaque, causing it to obstruct the content. @include cdk-high-contrast { display: none; } } } /* Theme for the ripple elements.*/ @mixin mat-ripple-theme($theme) { $foreground: map_get($theme, foreground); $foreground-base: map_get($foreground, base); .mat-ripple-element { // If the ripple color is resolves to a color *type*, we can use it directly, otherwise // (e.g. it resolves to a CSS variable) we fall back to using the color and setting an opacity. @if (type-of($foreground-base) == color) { background-color: rgba($foreground-base, $mat-ripple-color-opacity); } @else { background-color: $foreground-base; opacity: $mat-ripple-color-opacity; } } } // Utility for fetching a nested value from a typography config. @function _mat-get-type-value($config, $level, $name) { @return map-get(map-get($config, $level), $name); } // Gets the font size for a level inside a typography config. @function mat-font-size($config, $level) { @return _mat-get-type-value($config, $level, font-size); } // Gets the line height for a level inside a typography config. @function mat-line-height($config, $level) { @return _mat-get-type-value($config, $level, line-height); } // Gets the font weight for a level inside a typography config. @function mat-font-weight($config, $level) { @return _mat-get-type-value($config, $level, font-weight); } // Gets the letter spacing for a level inside a typography config. @function mat-letter-spacing($config, $level) { @return _mat-get-type-value($config, $level, letter-spacing); } // Gets the font-family from a typography config and removes the quotes around it. @function mat-font-family($config, $level: null) { $font-family: map-get($config, font-family); @if $level != null { $font-family: _mat-get-type-value($config, $level, font-family); } // Guard against unquoting non-string values, because it's deprecated. @return if(type-of($font-family) == string, unquote($font-family), $font-family); } // Outputs the shorthand `font` CSS property, based on a set of typography values. Falls back to // the individual properties if a value that isn't allowed in the shorthand is passed in. @mixin mat-typography-font-shorthand($font-size, $font-weight, $line-height, $font-family) { // If any of the values are set to `inherit`, we can't use the shorthand // so we fall back to passing in the individual properties. @if ($font-size == inherit or $font-weight == inherit or $line-height == inherit or $font-family == inherit or $font-size == null or $font-weight == null or $line-height == null or $font-family == null) { font-size: $font-size; font-weight: $font-weight; line-height: $line-height; font-family: $font-family; } @else { // Otherwise use the shorthand `font`, because it's the least amount of bytes. Note // that we need to use interpolation for `font-size/line-height` in order to prevent // Sass from dividing the two values. font: $font-weight #{$font-size}/#{$line-height} $font-family; } } // Converts a typography level into CSS styles. @mixin mat-typography-level-to-styles($config, $level) { $font-size: mat-font-size($config, $level); $font-weight: mat-font-weight($config, $level); $line-height: mat-line-height($config, $level); $font-family: mat-font-family($config, $level); @include mat-typography-font-shorthand($font-size, $font-weight, $line-height, $font-family); letter-spacing: mat-letter-spacing($config, $level); } @mixin mat-option-theme($theme) { $foreground: map-get($theme, foreground); $background: map-get($theme, background); $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); .mat-option { color: mat-color($foreground, text); &:hover:not(.mat-option-disabled), &:focus:not(.mat-option-disabled) { background: mat-color($background, hover); } // In multiple mode there is a checkbox to show that the option is selected. &.mat-selected:not(.mat-option-multiple):not(.mat-option-disabled) { background: mat-color($background, hover); } &.mat-active { background: mat-color($background, hover); color: mat-color($foreground, text); } &.mat-option-disabled { color: mat-color($foreground, hint-text); } } .mat-primary .mat-option.mat-selected:not(.mat-option-disabled) { color: mat-color($primary, text); } .mat-accent .mat-option.mat-selected:not(.mat-option-disabled) { color: mat-color($accent, text); } .mat-warn .mat-option.mat-selected:not(.mat-option-disabled) { color: mat-color($warn, text); } } @mixin mat-option-typography($config) { .mat-option { font: { family: mat-font-family($config); size: mat-font-size($config, subheading-2); } } } @mixin mat-optgroup-theme($theme) { $foreground: map-get($theme, foreground); .mat-optgroup-label { color: mat-color($foreground, secondary-text); } .mat-optgroup-disabled .mat-optgroup-label { color: mat-color($foreground, hint-text); } } @mixin mat-optgroup-typography($config) { .mat-optgroup-label { @include mat-typography-level-to-styles($config, body-2); } } @mixin mat-pseudo-checkbox-theme($theme) { $is-dark-theme: map-get($theme, is-dark); $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); // NOTE(traviskaufman): While the spec calls for translucent blacks/whites for disabled colors, // this does not work well with elements layered on top of one another. To get around this we // blend the colors together based on the base color and the theme background. $white-30pct-opacity-on-dark: #686868; $black-26pct-opacity-on-light: #b0b0b0; $disabled-color: if($is-dark-theme, $white-30pct-opacity-on-dark, $black-26pct-opacity-on-light); $colored-box-selector: '.mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate'; .mat-pseudo-checkbox { color: mat-color(map-get($theme, foreground), secondary-text); &::after { color: mat-color($background, background); } } .mat-pseudo-checkbox-disabled { color: $disabled-color; } .mat-primary .mat-pseudo-checkbox-checked, .mat-primary .mat-pseudo-checkbox-indeterminate { background: mat-color(map-get($theme, primary)); } // Default to the accent color. Note that the pseudo checkboxes are meant to inherit the // theme from their parent, rather than implementing their own theming, which is why we // don't attach to the `mat-*` classes. Also note that this needs to be below `.mat-primary` // in order to allow for the color to be overwritten if the checkbox is inside a parent that // has `mat-accent` and is placed inside another parent that has `mat-primary`. .mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate, .mat-accent .mat-pseudo-checkbox-checked, .mat-accent .mat-pseudo-checkbox-indeterminate { background: mat-color(map-get($theme, accent)); } .mat-warn .mat-pseudo-checkbox-checked, .mat-warn .mat-pseudo-checkbox-indeterminate { background: mat-color(map-get($theme, warn)); } .mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate { &.mat-pseudo-checkbox-disabled { background: $disabled-color; } } } // Represents a typography level from the Material design spec. @function mat-typography-level( $font-size, $line-height: $font-size, $font-weight: 400, $font-family: null, $letter-spacing: null) { @return ( font-size: $font-size, line-height: $line-height, font-weight: $font-weight, font-family: $font-family, letter-spacing: $letter-spacing ); } // Represents a collection of typography levels. // Defaults come from https://material.io/guidelines/style/typography.html // Note: The spec doesn't mention letter spacing. The values here come from // eyeballing it until it looked exactly like the spec examples. @function mat-typography-config( $font-family: 'Roboto, "Helvetica Neue", sans-serif', $display-4: mat-typography-level(112px, 112px, 300, $letter-spacing: -0.05em), $display-3: mat-typography-level(56px, 56px, 400, $letter-spacing: -0.02em), $display-2: mat-typography-level(45px, 48px, 400, $letter-spacing: -0.005em), $display-1: mat-typography-level(34px, 40px, 400), $headline: mat-typography-level(24px, 32px, 400), $title: mat-typography-level(20px, 32px, 500), $subheading-2: mat-typography-level(16px, 28px, 400), $subheading-1: mat-typography-level(15px, 24px, 400), $body-2: mat-typography-level(14px, 24px, 500), $body-1: mat-typography-level(14px, 20px, 400), $caption: mat-typography-level(12px, 20px, 400), $button: mat-typography-level(14px, 14px, 500), // Line-height must be unit-less fraction of the font-size. $input: mat-typography-level(inherit, 1.125, 400) ) { // Declare an initial map with all of the levels. $config: ( display-4: $display-4, display-3: $display-3, display-2: $display-2, display-1: $display-1, headline: $headline, title: $title, subheading-2: $subheading-2, subheading-1: $subheading-1, body-2: $body-2, body-1: $body-1, caption: $caption, button: $button, input: $input, ); // Loop through the levels and set the `font-family` of the ones that don't have one to the base. // Note that Sass can't modify maps in place, which means that we need to merge and re-assign. @each $key, $level in $config { @if map-get($level, font-family) == null { $new-level: map-merge($level, (font-family: $font-family)); $config: map-merge($config, ($key: $new-level)); } } // Add the base font family to the config. @return map-merge($config, (font-family: $font-family)); } // Adds the base typography styles, based on a config. @mixin mat-base-typography($config, $selector: '.mat-typography') { .mat-h1, .mat-headline, #{$selector} h1 { @include mat-typography-level-to-styles($config, headline); margin: 0 0 16px; } .mat-h2, .mat-title, #{$selector} h2 { @include mat-typography-level-to-styles($config, title); margin: 0 0 16px; } .mat-h3, .mat-subheading-2, #{$selector} h3 { @include mat-typography-level-to-styles($config, subheading-2); margin: 0 0 16px; } .mat-h4, .mat-subheading-1, #{$selector} h4 { @include mat-typography-level-to-styles($config, subheading-1); margin: 0 0 16px; } // Note: the spec doesn't have anything that would correspond to h5 and h6, but we add these for // consistency. The font sizes come from the Chrome user agent styles which have h5 at 0.83em // and h6 at 0.67em. .mat-h5, #{$selector} h5 { @include mat-typography-font-shorthand( // calc is used here to support css variables calc(#{mat-font-size($config, body-1)} * 0.83), mat-font-weight($config, body-1), mat-line-height($config, body-1), mat-font-family($config, body-1) ); margin: 0 0 12px; } .mat-h6, #{$selector} h6 { @include mat-typography-font-shorthand( // calc is used here to support css variables calc(#{mat-font-size($config, body-1)} * 0.67), mat-font-weight($config, body-1), mat-line-height($config, body-1), mat-font-family($config, body-1) ); margin: 0 0 12px; } .mat-body-strong, .mat-body-2 { @include mat-typography-level-to-styles($config, body-2); } .mat-body, .mat-body-1, #{$selector} { @include mat-typography-level-to-styles($config, body-1); p { margin: 0 0 12px; } } .mat-small, .mat-caption { @include mat-typography-level-to-styles($config, caption); } .mat-display-4, #{$selector} .mat-display-4 { @include mat-typography-level-to-styles($config, display-4); margin: 0 0 56px; } .mat-display-3, #{$selector} .mat-display-3 { @include mat-typography-level-to-styles($config, display-3); margin: 0 0 64px; } .mat-display-2, #{$selector} .mat-display-2 { @include mat-typography-level-to-styles($config, display-2); margin: 0 0 64px; } .mat-display-1, #{$selector} .mat-display-1 { @include mat-typography-level-to-styles($config, display-1); margin: 0 0 64px; } } @mixin mat-autocomplete-theme($theme) { $foreground: map-get($theme, foreground); $background: map-get($theme, background); .mat-autocomplete-panel { @include _mat-theme-overridable-elevation(4, $theme); background: mat-color($background, card); color: mat-color($foreground, text); // Selected options in autocompletes should not be gray, but we // only want to override the background for selected options if // they are *not* in hover or focus state. This change has to be // made here because base option styles are shared between the // autocomplete and the select. .mat-option.mat-selected:not(.mat-active):not(:hover) { background: mat-color($background, card); &:not(.mat-option-disabled) { color: mat-color($foreground, text); } } } } @mixin mat-autocomplete-typography($config) { } // This contains all of the styles for the badge // rather than just the color/theme because of // no style sheet support for directives. $mat-badge-font-size: 12px; $mat-badge-font-weight: 600; $mat-badge-default-size: 22px !default; $mat-badge-small-size: $mat-badge-default-size - 6; $mat-badge-large-size: $mat-badge-default-size + 6; // Mixin for building offset given different sizes @mixin _mat-badge-size($size) { .mat-badge-content { width: $size; height: $size; line-height: $size; } &.mat-badge-above { .mat-badge-content { top: -$size / 2; } } &.mat-badge-below { .mat-badge-content { bottom: -$size / 2; } } &.mat-badge-before { .mat-badge-content { left: -$size; } } [dir='rtl'] &.mat-badge-before { .mat-badge-content { left: auto; right: -$size; } } &.mat-badge-after { .mat-badge-content { right: -$size; } } [dir='rtl'] &.mat-badge-after { .mat-badge-content { right: auto; left: -$size; } } &.mat-badge-overlap { &.mat-badge-before { .mat-badge-content { left: -$size / 2; } } [dir='rtl'] &.mat-badge-before { .mat-badge-content { left: auto; right: -$size / 2; } } &.mat-badge-after { .mat-badge-content { right: -$size / 2; } } [dir='rtl'] &.mat-badge-after { .mat-badge-content { right: auto; left: -$size / 2; } } } } @mixin mat-badge-theme($theme) { $accent: map-get($theme, accent); $warn: map-get($theme, warn); $primary: map-get($theme, primary); $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-badge-content { color: mat-color($primary, default-contrast); background: mat-color($primary); @include cdk-high-contrast { outline: solid 1px; border-radius: 0; } } .mat-badge-accent { .mat-badge-content { background: mat-color($accent); color: mat-color($accent, default-contrast); } } .mat-badge-warn { .mat-badge-content { color: mat-color($warn, default-contrast); background: mat-color($warn); } } .mat-badge { position: relative; } .mat-badge-hidden { .mat-badge-content { display: none; } } .mat-badge-disabled { .mat-badge-content { $app-background: mat-color($background, 'background'); $badge-color: mat-color($foreground, disabled-button); // The disabled color usually has some kind of opacity, but because the badge is overlayed // on top of something else, it won't look good if it's opaque. If it is a color *type*, // we convert it into a solid color by taking the opacity from the rgba value and using // the value to determine the percentage of the background to put into foreground when // mixing the colors together. @if (type-of($badge-color) == color and type-of($app-background) == color) { $badge-opacity: opacity($badge-color); background: mix($app-background, rgba($badge-color, 1), (1 - $badge-opacity) * 100%); } @else { background: $badge-color; } color: mat-color($foreground, disabled-text); } } .mat-badge-content { position: absolute; text-align: center; display: inline-block; border-radius: 50%; transition: transform 200ms ease-in-out; transform: scale(0.6); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; pointer-events: none; } .ng-animate-disabled .mat-badge-content, .mat-badge-content._mat-animation-noopable { transition: none; } // The active class is added after the element is added // so it can animate scale to default .mat-badge-content.mat-badge-active { // Scale to `none` instead of `1` to avoid blurry text in some browsers. transform: none; } .mat-badge-small { @include _mat-badge-size($mat-badge-small-size); } .mat-badge-medium { @include _mat-badge-size($mat-badge-default-size); } .mat-badge-large { @include _mat-badge-size($mat-badge-large-size); } } @mixin mat-badge-typography($config) { .mat-badge-content { font-weight: $mat-badge-font-weight; font-size: $mat-badge-font-size; font-family: mat-font-family($config); } .mat-badge-small .mat-badge-content { // Set the font size to 75% of the original. font-size: $mat-badge-font-size * 0.75; } .mat-badge-large .mat-badge-content { font-size: $mat-badge-font-size * 2; } } @mixin mat-bottom-sheet-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-bottom-sheet-container { @include _mat-theme-elevation(16, $theme); background: mat-color($background, dialog); color: mat-color($foreground, text); } } @mixin mat-bottom-sheet-typography($config) { .mat-bottom-sheet-container { @include mat-typography-level-to-styles($config, body-1); } } $_mat-button-ripple-opacity: 0.1; // Applies a focus style to an mat-button element for each of the supported palettes. @mixin _mat-button-focus-overlay-color($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); &.mat-primary .mat-button-focus-overlay { background-color: mat-color($primary); } &.mat-accent .mat-button-focus-overlay { background-color: mat-color($accent); } &.mat-warn .mat-button-focus-overlay { background-color: mat-color($warn); } &[disabled] .mat-button-focus-overlay { background-color: transparent; } } // Applies the background color for a ripple. If the value provided is not a Sass color, // we assume that we've been given a CSS variable. Since we can't perform alpha-blending // on a CSS variable, we instead add the opacity directly to the ripple element. @mixin _mat-button-ripple-background($palette, $hue, $opacity) { $background-color: mat-color($palette, $hue, $opacity); background-color: $background-color; @if (type-of($background-color) != color) { opacity: $opacity; } } @mixin _mat-button-ripple-color($theme, $hue, $opacity: $_mat-button-ripple-opacity) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); &.mat-primary .mat-ripple-element { @include _mat-button-ripple-background($primary, $hue, $opacity); } &.mat-accent .mat-ripple-element { @include _mat-button-ripple-background($accent, $hue, $opacity); } &.mat-warn .mat-ripple-element { @include _mat-button-ripple-background($warn, $hue, $opacity); } } // Applies a property to an mat-button element for each of the supported palettes. @mixin _mat-button-theme-property($theme, $property, $hue) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); &.mat-primary { #{$property}: mat-color($primary, $hue); } &.mat-accent { #{$property}: mat-color($accent, $hue); } &.mat-warn { #{$property}: mat-color($warn, $hue); } &.mat-primary, &.mat-accent, &.mat-warn, &[disabled] { &[disabled] { $palette: if($property == 'color', $foreground, $background); #{$property}: mat-color($palette, disabled-button); } } } @mixin mat-button-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-button, .mat-icon-button, .mat-stroked-button { // Buttons without a background color should inherit the font color. This is necessary to // ensure that the button is readable on custom background colors. It's wrong to always assume // that those buttons are always placed inside of containers with the default background // color of the theme (e.g. themed toolbars). color: inherit; background: transparent; @include _mat-button-theme-property($theme, 'color', text); @include _mat-button-focus-overlay-color($theme); // Setup the ripple color to be based on the text color. This ensures that the ripples // are matching with the current theme palette and are in contrast to the background color // (e.g in themed toolbars). .mat-ripple-element { opacity: $_mat-button-ripple-opacity; background-color: currentColor; } } .mat-button-focus-overlay { background: map_get($foreground, base); } // Note: this needs a bit extra specificity, because we're not guaranteed the inclusion // order of the theme styles and the button reset may end up resetting this as well. .mat-stroked-button:not([disabled]) { border-color: mat-color($foreground, divider); } .mat-flat-button, .mat-raised-button, .mat-fab, .mat-mini-fab { // Default font and background color when not using any color palette. color: mat-color($foreground, text); background-color: mat-color($background, raised-button); @include _mat-button-theme-property($theme, 'color', default-contrast); @include _mat-button-theme-property($theme, 'background-color', default); @include _mat-button-ripple-color($theme, default-contrast); } .mat-stroked-button, .mat-flat-button { @include _mat-theme-overridable-elevation(0, $theme); } .mat-raised-button { @include _mat-theme-overridable-elevation(2, $theme); &:not([disabled]):active { @include _mat-theme-overridable-elevation(8, $theme); } &[disabled] { @include _mat-theme-overridable-elevation(0, $theme); } } .mat-fab, .mat-mini-fab { @include _mat-theme-overridable-elevation(6, $theme); &:not([disabled]):active { @include _mat-theme-overridable-elevation(12, $theme); } &[disabled] { @include _mat-theme-overridable-elevation(0, $theme); } } } @mixin mat-button-typography($config) { .mat-button, .mat-raised-button, .mat-icon-button, .mat-stroked-button, .mat-flat-button, .mat-fab, .mat-mini-fab { font: { family: mat-font-family($config, button); size: mat-font-size($config, button); weight: mat-font-weight($config, button); } } } @mixin mat-button-toggle-theme($theme) { $foreground: map-get($theme, foreground); $background: map-get($theme, background); $divider-color: mat-color($foreground, divider); .mat-button-toggle-standalone, .mat-button-toggle-group { @include _mat-theme-elevation(2, $theme); } .mat-button-toggle-standalone.mat-button-toggle-appearance-standard, .mat-button-toggle-group-appearance-standard { box-shadow: none; } .mat-button-toggle { color: mat-color($foreground, hint-text); .mat-button-toggle-focus-overlay { background-color: mat-color($background, focused-button); } } .mat-button-toggle-appearance-standard { color: mat-color($foreground, text); background: mat-color($background, card); .mat-button-toggle-focus-overlay { background-color: mat-color($background, focused-button, 1); } } .mat-button-toggle-group-appearance-standard .mat-button-toggle + .mat-button-toggle { border-left: solid 1px $divider-color; } [dir='rtl'] .mat-button-toggle-group-appearance-standard .mat-button-toggle + .mat-button-toggle { border-left: none; border-right: solid 1px $divider-color; } .mat-button-toggle-group-appearance-standard.mat-button-toggle-vertical { .mat-button-toggle + .mat-button-toggle { border-left: none; border-right: none; border-top: solid 1px $divider-color; } } .mat-button-toggle-checked { background-color: mat-color($background, selected-button); color: mat-color($foreground, secondary-text); &.mat-button-toggle-appearance-standard { color: mat-color($foreground, text); } } .mat-button-toggle-disabled { color: mat-color($foreground, disabled-button); background-color: mat-color($background, disabled-button-toggle); &.mat-button-toggle-appearance-standard { background: mat-color($background, card); } &.mat-button-toggle-checked { background-color: mat-color($background, selected-disabled-button); } } .mat-button-toggle-standalone.mat-button-toggle-appearance-standard, .mat-button-toggle-group-appearance-standard { border: solid 1px $divider-color; } } @mixin mat-button-toggle-typography($config) { .mat-button-toggle { font-family: mat-font-family($config); } } @mixin mat-card-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-card { @include _mat-theme-overridable-elevation(1, $theme); background: mat-color($background, card); color: mat-color($foreground, text); // Needs extra specificity to be able to override the elevation selectors. &.mat-card-flat { @include _mat-theme-overridable-elevation(0, $theme); } } .mat-card-subtitle { color: mat-color($foreground, secondary-text); } } @mixin mat-card-typography($config) { .mat-card { font-family: mat-font-family($config); } .mat-card-title { font: { size: mat-font-size($config, headline); weight: mat-font-weight($config, title); } } .mat-card-header .mat-card-title { font-size: mat-font-size($config, title); } .mat-card-subtitle, .mat-card-content { font-size: mat-font-size($config, body-1); } } @mixin mat-checkbox-theme($theme) { $is-dark-theme: map-get($theme, is-dark); $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); // The color of the checkbox's checkmark / mixedmark. $checkbox-mark-color: mat-color($background, background); // NOTE(traviskaufman): While the spec calls for translucent blacks/whites for disabled colors, // this does not work well with elements layered on top of one another. To get around this we // blend the colors together based on the base color and the theme background. $white-30pct-opacity-on-dark: #686868; $black-26pct-opacity-on-light: #b0b0b0; $disabled-color: if($is-dark-theme, $white-30pct-opacity-on-dark, $black-26pct-opacity-on-light); .mat-checkbox-frame { border-color: mat-color($foreground, secondary-text); } .mat-checkbox-checkmark { fill: $checkbox-mark-color; } .mat-checkbox-checkmark-path { // !important is needed here because a stroke must be set as an // attribute on the SVG in order for line animation to work properly. stroke: $checkbox-mark-color !important; @include cdk-high-contrast(black-on-white) { // Having the one above be !important ends up overriding the browser's automatic // color inversion so we need to re-invert it ourselves for black-on-white. stroke: #000 !important; } } .mat-checkbox-mixedmark { background-color: $checkbox-mark-color; } .mat-checkbox-indeterminate, .mat-checkbox-checked { &.mat-primary .mat-checkbox-background { background-color: mat-color($primary); } &.mat-accent .mat-checkbox-background { background-color: mat-color($accent); } &.mat-warn .mat-checkbox-background { background-color: mat-color($warn); } } .mat-checkbox-disabled { &.mat-checkbox-checked, &.mat-checkbox-indeterminate { .mat-checkbox-background { background-color: $disabled-color; } } &:not(.mat-checkbox-checked) { .mat-checkbox-frame { border-color: $disabled-color; } } .mat-checkbox-label { color: mat-color($foreground, secondary-text); } @include cdk-high-contrast { opacity: 0.5; } } // This one is moved down here so it can target both // the theme colors and the disabled state. @include cdk-high-contrast { .mat-checkbox-background { // Needs to be removed because it hides the checkbox outline. background: none; } } // Switch this to a solid color since we're using `opacity` // to control how opaque the ripple should be. .mat-checkbox .mat-ripple-element { background-color: map_get(map-get($theme, foreground), base); } .mat-checkbox-checked:not(.mat-checkbox-disabled), .mat-checkbox:active:not(.mat-checkbox-disabled) { &.mat-primary .mat-ripple-element { background: mat-color($primary); } &.mat-accent .mat-ripple-element { background: mat-color($accent); } &.mat-warn .mat-ripple-element { background: mat-color($warn); } } } @mixin mat-checkbox-typography($config) { .mat-checkbox { font-family: mat-font-family($config); } // TODO(kara): Remove this style when fixing vertical baseline .mat-checkbox-layout .mat-checkbox-label { line-height: mat-line-height($config, body-2); } } $mat-chip-remove-font-size: 18px; @mixin mat-chips-color($foreground, $background) { background-color: $background; color: $foreground; .mat-chip-remove { color: $foreground; opacity: 0.4; } } @mixin mat-chips-theme-color($palette) { @include mat-chips-color(mat-color($palette, default-contrast), mat-color($palette)); .mat-ripple-element { background: mat-color($palette, default-contrast, 0.1); } } @mixin mat-chips-theme($theme) { $is-dark-theme: map-get($theme, is-dark); $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); $unselected-background: mat-color($background, unselected-chip); $unselected-foreground: mat-color($foreground, text); .mat-chip.mat-standard-chip { @include mat-chips-color($unselected-foreground, $unselected-background); &:not(.mat-chip-disabled) { &:active { @include _mat-theme-elevation(3, $theme); } .mat-chip-remove:hover { opacity: 0.54; } } &.mat-chip-disabled { opacity: 0.4; } &::after { background: map_get($foreground, base); } } .mat-chip.mat-standard-chip.mat-chip-selected { &.mat-primary { @include mat-chips-theme-color($primary); } &.mat-warn { @include mat-chips-theme-color($warn); } &.mat-accent { @include mat-chips-theme-color($accent); } } } @mixin mat-chips-typography($config) { .mat-chip { font-size: mat-font-size($config, body-2); font-weight: mat-font-weight($config, body-2); .mat-chip-trailing-icon.mat-icon, .mat-chip-remove.mat-icon { font-size: $mat-chip-remove-font-size; } } } @mixin mat-table-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-table { background: mat-color($background, 'card'); } .mat-table thead, .mat-table tbody, .mat-table tfoot, mat-header-row, mat-row, mat-footer-row, [mat-header-row], [mat-row], [mat-footer-row], .mat-table-sticky { background: inherit; } mat-row, mat-header-row, mat-footer-row, th.mat-header-cell, td.mat-cell, td.mat-footer-cell { border-bottom-color: mat-color($foreground, divider); } .mat-header-cell { color: mat-color($foreground, secondary-text); } .mat-cell, .mat-footer-cell { color: mat-color($foreground, text); } } @mixin mat-table-typography($config) { .mat-table { font-family: mat-font-family($config); } .mat-header-cell { font-size: mat-font-size($config, caption); font-weight: mat-font-weight($config, body-2); } .mat-cell, .mat-footer-cell { font-size: mat-font-size($config, body-1); } } $mat-datepicker-selected-today-box-shadow-width: 1px; $mat-datepicker-selected-fade-amount: 0.6; $mat-datepicker-today-fade-amount: 0.2; $mat-calendar-body-font-size: 13px !default; $mat-calendar-weekday-table-font-size: 11px !default; @mixin _mat-datepicker-color($palette) { .mat-calendar-body-selected { background-color: mat-color($palette); color: mat-color($palette, default-contrast); } .mat-calendar-body-disabled > .mat-calendar-body-selected { $background: mat-color($palette); @if (type-of($background) == color) { background-color: fade-out($background, $mat-datepicker-selected-fade-amount); } @else { // If we couldn't resolve to background to a color (e.g. it's a CSS variable), // fall back to fading the content out via `opacity`. opacity: $mat-datepicker-today-fade-amount; } } .mat-calendar-body-today.mat-calendar-body-selected { box-shadow: inset 0 0 0 $mat-datepicker-selected-today-box-shadow-width mat-color($palette, default-contrast); } } @mixin mat-datepicker-theme($theme) { $foreground: map-get($theme, foreground); $background: map-get($theme, background); .mat-calendar-arrow { border-top-color: mat-color($foreground, icon); } // The prev/next buttons need a bit more specificity to // avoid being overwritten by the .mat-icon-button. .mat-datepicker-toggle, .mat-datepicker-content .mat-calendar-next-button, .mat-datepicker-content .mat-calendar-previous-button { color: mat-color($foreground, icon); } .mat-calendar-table-header { color: mat-color($foreground, hint-text); } .mat-calendar-table-header-divider::after { background: mat-color($foreground, divider); } .mat-calendar-body-label { color: mat-color($foreground, secondary-text); } .mat-calendar-body-cell-content { color: mat-color($foreground, text); border-color: transparent; } .mat-calendar-body-disabled > .mat-calendar-body-cell-content:not(.mat-calendar-body-selected) { color: mat-color($foreground, disabled-text); } .mat-calendar-body-cell:not(.mat-calendar-body-disabled):hover, .cdk-keyboard-focused .mat-calendar-body-active, .cdk-program-focused .mat-calendar-body-active { & > .mat-calendar-body-cell-content:not(.mat-calendar-body-selected) { background-color: mat-color($background, hover); } } .mat-calendar-body-today:not(.mat-calendar-body-selected) { // Note: though it's not text, the border is a hint about the fact that this is today's date, // so we use the hint color. border-color: mat-color($foreground, hint-text); } .mat-calendar-body-disabled > .mat-calendar-body-today:not(.mat-calendar-body-selected) { $color: mat-color($foreground, hint-text); @if (type-of($color) == color) { border-color: fade-out($color, $mat-datepicker-today-fade-amount); } @else { // If the color didn't resolve to a color value, but something like a CSS variable, we can't // fade it out so we fall back to reducing the element opacity. Note that we don't use the // $mat-datepicker-today-fade-amount, because hint text usually has some opacity applied // to it already and we don't want them to stack on top of each other. opacity: 0.5; } } @include _mat-datepicker-color(map-get($theme, primary)); .mat-datepicker-content { @include _mat-theme-elevation(4, $theme); background-color: mat-color($background, card); color: mat-color($foreground, text); &.mat-accent { @include _mat-datepicker-color(map-get($theme, accent)); } &.mat-warn { @include _mat-datepicker-color(map-get($theme, warn)); } } .mat-datepicker-content-touch { @include _mat-theme-elevation(0, $theme); } .mat-datepicker-toggle-active { color: mat-color(map-get($theme, primary), text); &.mat-accent { color: mat-color(map-get($theme, accent), text); } &.mat-warn { color: mat-color(map-get($theme, warn), text); } } } @mixin mat-datepicker-typography($config) { .mat-calendar { font-family: mat-font-family($config); } .mat-calendar-body { font-size: $mat-calendar-body-font-size; } .mat-calendar-body-label, .mat-calendar-period-button { font: { size: mat-font-size($config, button); weight: mat-font-weight($config, button); } } .mat-calendar-table-header th { font: { size: $mat-calendar-weekday-table-font-size; weight: mat-font-weight($config, body-1); } } } @mixin mat-dialog-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-dialog-container { @include _mat-theme-elevation(24, $theme); background: mat-color($background, dialog); color: mat-color($foreground, text); } } @mixin mat-dialog-typography($config) { .mat-dialog-title { @include mat-typography-level-to-styles($config, title); } } @mixin mat-expansion-panel-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-expansion-panel { @include _mat-theme-overridable-elevation(2, $theme); background: mat-color($background, card); color: mat-color($foreground, text); } .mat-action-row { border-top-color: mat-color($foreground, divider); } .mat-expansion-panel { & .mat-expansion-panel-header.cdk-keyboard-focused, & .mat-expansion-panel-header.cdk-program-focused, &:not(.mat-expanded) .mat-expansion-panel-header:hover { &:not([aria-disabled='true']) { background: mat-color($background, hover); } } } // Disable the hover on touch devices since it can appear like it is stuck. We can't use // `@media (hover)` above, because the desktop support browser support isn't great. @media (hover: none) { .mat-expansion-panel:not(.mat-expanded):not([aria-disabled='true']) .mat-expansion-panel-header:hover { background: mat-color($background, card); } } .mat-expansion-panel-header-title { color: mat-color($foreground, text); } .mat-expansion-panel-header-description, .mat-expansion-indicator::after { color: mat-color($foreground, secondary-text); } .mat-expansion-panel-header[aria-disabled='true'] { color: mat-color($foreground, disabled-button); .mat-expansion-panel-header-title, .mat-expansion-panel-header-description { color: inherit; } } } @mixin mat-expansion-panel-typography($config) { .mat-expansion-panel-header { font: { family: mat-font-family($config, subheading-1); size: mat-font-size($config, subheading-1); weight: mat-font-weight($config, subheading-1); } } .mat-expansion-panel-content { @include mat-typography-level-to-styles($config, body-1); } } // This mixin will ensure that lines that overflow the container will hide the overflow and // truncate neatly with an ellipsis. @mixin mat-truncate-line() { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } // Mixin to provide all mat-line styles, changing secondary font size based on whether the list // is in dense mode. @mixin mat-line-base($secondary-font-size) { .mat-line { @include mat-truncate-line(); display: block; box-sizing: border-box; // all lines but the top line should have smaller text &:nth-child(n+2) { font-size: $secondary-font-size; } } } // This mixin normalizes default element styles, e.g. font weight for heading text. @mixin mat-normalize-text() { & > * { margin: 0; padding: 0; font-weight: normal; font-size: inherit; } } // This mixin provides base styles for the wrapper around mat-line elements in a list. @mixin mat-line-wrapper-base() { @include mat-normalize-text(); display: flex; flex-direction: column; width: 100%; box-sizing: border-box; overflow: hidden; // Must remove wrapper when lines are empty or it takes up horizontal // space and pushes other elements to the right. &:empty { display: none; } } // Include this empty mixin for consistency with the other components. @mixin mat-grid-list-theme($theme) { } @mixin mat-grid-list-typography($config) { .mat-grid-tile-header, .mat-grid-tile-footer { @include mat-line-base(mat-font-size($config, caption)); font-size: mat-font-size($config, body-1); } } // Include this empty mixin for consistency with the other components. @mixin mat-icon-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-icon { &.mat-primary { color: mat-color($primary, text); } &.mat-accent { color: mat-color($accent, text); } &.mat-warn { color: mat-color($warn, text); } } } @mixin mat-icon-typography($config) { } // Renders a gradient for showing the dashed line when the input is disabled. // Unlike using a border, a gradient allows us to adjust the spacing of the dotted line // to match the Material Design spec. @mixin mat-control-disabled-underline($color) { background-image: linear-gradient(to right, $color 0%, $color 33%, transparent 0%); background-size: 4px 100%; background-repeat: repeat-x; } // Figures out the color of the placeholder for a form control. // Used primarily to prevent the various form controls from // becoming out of sync since these colors aren't in a palette. @function _mat-control-placeholder-color($theme) { $foreground: map-get($theme, foreground); $is-dark-theme: map-get($theme, is-dark); @return mat-color($foreground, secondary-text, if($is-dark-theme, 0.5, 0.42)); } /* stylelint-disable material/no-prefixes */ @mixin user-select($value) { -webkit-user-select: $value; -moz-user-select: $value; -ms-user-select: $value; user-select: $value; } @mixin input-placeholder { &::placeholder { @content; } &::-moz-placeholder { @content; } &::-webkit-input-placeholder { @content; } &:-ms-input-placeholder { @content; } } @mixin cursor-grab { cursor: -webkit-grab; cursor: grab; } @mixin cursor-grabbing { cursor: -webkit-grabbing; cursor: grabbing; } @mixin backface-visibility($value) { -webkit-backface-visibility: $value; backface-visibility: $value; } /* stylelint-enable */ @mixin mat-input-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $foreground: map-get($theme, foreground); .mat-form-field-type-mat-native-select .mat-form-field-infix::after { color: mat-color($foreground, secondary-text); } .mat-input-element:disabled, .mat-form-field-type-mat-native-select.mat-form-field-disabled .mat-form-field-infix::after { color: mat-color($foreground, disabled-text); } .mat-input-element { caret-color: mat-color($primary, text); @include input-placeholder { color: _mat-control-placeholder-color($theme); } // On dark themes we set the native `select` color to some shade of white, // however the color propagates to all of the `option` elements, which are // always on a white background inside the dropdown, causing them to blend in. // Since we can't change background of the dropdown, we need to explicitly // reset the color of the options to something dark. @if (map-get($theme, is-dark)) { option { color: $dark-primary-text; } option:disabled { color: $dark-disabled-text; } } } .mat-accent .mat-input-element { caret-color: mat-color($accent, text); } .mat-warn .mat-input-element, .mat-form-field-invalid .mat-input-element { caret-color: mat-color($warn, text); } .mat-form-field-type-mat-native-select.mat-form-field-invalid .mat-form-field-infix::after { color: mat-color($warn, text); } } @mixin mat-input-typography($config) { // The unit-less line-height from the font config. $line-height: mat-line-height($config, input); // The amount of space between the top of the line and the top of the actual text // (as a fraction of the font-size). $line-spacing: ($line-height - 1) / 2; // elements seem to have their height set slightly too large on Safari causing the text to // be misaligned w.r.t. the placeholder. Adding this margin corrects it. input.mat-input-element { margin-top: -$line-spacing * 1em; } } @mixin mat-list-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-list-base { .mat-list-item { color: mat-color($foreground, text); } .mat-list-option { color: mat-color($foreground, text); } .mat-subheader { color: mat-color($foreground, secondary-text); } } .mat-list-item-disabled { background-color: mat-color($background, disabled-list-option); } .mat-list-option, .mat-nav-list .mat-list-item, .mat-action-list .mat-list-item { &:hover, &:focus { background: mat-color($background, 'hover'); } } } @mixin mat-list-typography($config) { $font-family: mat-font-family($config); .mat-list-item { font-family: $font-family; } .mat-list-option { font-family: $font-family; } // Default list .mat-list-base { .mat-list-item { font-size: mat-font-size($config, subheading-2); @include mat-line-base(mat-font-size($config, body-1)); } .mat-list-option { font-size: mat-font-size($config, subheading-2); @include mat-line-base(mat-font-size($config, body-1)); } .mat-subheader { font-family: mat-font-family($config, body-2); font-size: mat-font-size($config, body-2); font-weight: mat-font-weight($config, body-2); } } // Dense list .mat-list-base[dense] { .mat-list-item { font-size: mat-font-size($config, caption); @include mat-line-base(mat-font-size($config, caption)); } .mat-list-option { font-size: mat-font-size($config, caption); @include mat-line-base(mat-font-size($config, caption)); } .mat-subheader { font-family: $font-family; font-size: mat-font-size($config, caption); font-weight: mat-font-weight($config, body-2); } } } @mixin mat-menu-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-menu-panel { @include _mat-theme-overridable-elevation(4, $theme); background: mat-color($background, 'card'); } .mat-menu-item { background: transparent; color: mat-color($foreground, 'text'); &[disabled] { &, &::after { color: mat-color($foreground, 'disabled'); } } } .mat-menu-item .mat-icon-no-color, .mat-menu-item-submenu-trigger::after { color: mat-color($foreground, 'icon'); } .mat-menu-item:hover, .mat-menu-item.cdk-program-focused, .mat-menu-item.cdk-keyboard-focused, .mat-menu-item-highlighted { &:not([disabled]) { background: mat-color($background, 'hover'); } } } @mixin mat-menu-typography($config) { .mat-menu-item { font: { family: mat-font-family($config, body-1); size: mat-font-size($config, body-1); weight: mat-font-weight($config, body-1); } } } @mixin mat-paginator-theme($theme) { $foreground: map-get($theme, foreground); $background: map-get($theme, background); .mat-paginator { background: mat-color($background, 'card'); } .mat-paginator, .mat-paginator-page-size .mat-select-trigger { color: mat-color($foreground, secondary-text); } .mat-paginator-decrement, .mat-paginator-increment { border-top: 2px solid mat-color($foreground, 'icon'); border-right: 2px solid mat-color($foreground, 'icon'); } .mat-paginator-first, .mat-paginator-last { border-top: 2px solid mat-color($foreground, 'icon'); } .mat-icon-button[disabled] { .mat-paginator-decrement, .mat-paginator-increment, .mat-paginator-first, .mat-paginator-last { border-color: mat-color($foreground, 'disabled'); } } } @mixin mat-paginator-typography($config) { .mat-paginator, .mat-paginator-page-size .mat-select-trigger { font: { family: mat-font-family($config, caption); size: mat-font-size($config, caption); } } } @mixin mat-progress-bar-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); .mat-progress-bar-background { fill: mat-color($primary, lighter); } .mat-progress-bar-buffer { background-color: mat-color($primary, lighter); } .mat-progress-bar-fill::after { background-color: mat-color($primary); } .mat-progress-bar.mat-accent { .mat-progress-bar-background { fill: mat-color($accent, lighter); } .mat-progress-bar-buffer { background-color: mat-color($accent, lighter); } .mat-progress-bar-fill::after { background-color: mat-color($accent); } } .mat-progress-bar.mat-warn { .mat-progress-bar-background { fill: mat-color($warn, lighter); } .mat-progress-bar-buffer { background-color: mat-color($warn, lighter); } .mat-progress-bar-fill::after { background-color: mat-color($warn); } } } @mixin mat-progress-bar-typography($config) { } @mixin mat-progress-spinner-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); .mat-progress-spinner, .mat-spinner { circle { stroke: mat-color($primary); } &.mat-accent circle { stroke: mat-color($accent); } &.mat-warn circle { stroke: mat-color($warn); } } } @mixin mat-progress-spinner-typography($config) { } @mixin _mat-radio-color($palette) { &.mat-radio-checked .mat-radio-outer-circle { border-color: mat-color($palette); } .mat-radio-inner-circle, .mat-radio-ripple .mat-ripple-element:not(.mat-radio-persistent-ripple), &.mat-radio-checked .mat-radio-persistent-ripple, &:active .mat-radio-persistent-ripple { background-color: mat-color($palette); } } @mixin mat-radio-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-radio-outer-circle { border-color: mat-color($foreground, secondary-text); } .mat-radio-button { &.mat-primary { @include _mat-radio-color($primary); } &.mat-accent { @include _mat-radio-color($accent); } &.mat-warn { @include _mat-radio-color($warn); } // This needs extra specificity, because the classes above are combined // (e.g. `.mat-radio-button.mat-accent`) which increases their specificity a lot. // TODO: consider making the selectors into descendants (`.mat-primary .mat-radio-button`). &.mat-radio-disabled { &.mat-radio-checked .mat-radio-outer-circle, .mat-radio-outer-circle { border-color: mat-color($foreground, disabled); } .mat-radio-ripple .mat-ripple-element, .mat-radio-inner-circle { background-color: mat-color($foreground, disabled); } .mat-radio-label-content { color: mat-color($foreground, disabled); } } // Switch this to a solid color since we're using `opacity` // to control how opaque the ripple should be. .mat-ripple-element { background-color: map_get($foreground, base); } } } @mixin mat-radio-typography($config) { .mat-radio-button { font-family: mat-font-family($config); } } @mixin mat-select-theme($theme) { $foreground: map-get($theme, foreground); $background: map-get($theme, background); $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); .mat-select-value { color: mat-color($foreground, text); } .mat-select-placeholder { color: _mat-control-placeholder-color($theme); } .mat-select-disabled .mat-select-value { color: mat-color($foreground, disabled-text); } .mat-select-arrow { color: mat-color($foreground, secondary-text); } .mat-select-panel { background: mat-color($background, card); @include _mat-theme-overridable-elevation(4, $theme); .mat-option.mat-selected:not(.mat-option-multiple) { background: mat-color($background, hover, 0.12); } } .mat-form-field { &.mat-focused { &.mat-primary .mat-select-arrow { color: mat-color($primary, text); } &.mat-accent .mat-select-arrow { color: mat-color($accent, text); } &.mat-warn .mat-select-arrow { color: mat-color($warn, text); } } .mat-select.mat-select-invalid .mat-select-arrow { color: mat-color($warn, text); } .mat-select.mat-select-disabled .mat-select-arrow { color: mat-color($foreground, disabled-text); } } } @mixin mat-select-typography($config) { // The unit-less line-height from the font config. $line-height: mat-line-height($config, input); .mat-select { font-family: mat-font-family($config); } .mat-select-trigger { height: $line-height * 1em; } } @mixin mat-sidenav-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); $drawer-background-color: mat-color($background, dialog); $drawer-container-background-color: mat-color($background, background); $drawer-push-background-color: mat-color($background, dialog); $drawer-side-border: solid 1px mat-color($foreground, divider); .mat-drawer-container { background-color: $drawer-container-background-color; color: mat-color($foreground, text); } .mat-drawer { background-color: $drawer-background-color; color: mat-color($foreground, text); &.mat-drawer-push { background-color: $drawer-push-background-color; } &:not(.mat-drawer-side) { // The elevation of z-16 is noted in the design specifications. // See https://material.io/design/components/navigation-drawer.html @include _mat-theme-elevation(16, $theme); } } .mat-drawer-side { border-right: $drawer-side-border; &.mat-drawer-end { border-left: $drawer-side-border; border-right: none; } } [dir='rtl'] .mat-drawer-side { border-left: $drawer-side-border; border-right: none; &.mat-drawer-end { border-left: none; border-right: $drawer-side-border; } } .mat-drawer-backdrop.mat-drawer-shown { $opacity: 0.6; $backdrop-color: mat-color($background, card, $opacity); @if (type-of($backdrop-color) == color) { // We use invert() here to have the darken the background color expected to be used. If the // background is light, we use a dark backdrop. If the background is dark, // we use a light backdrop. background-color: invert($backdrop-color); } @else { // If we couldn't resolve the backdrop color to a color value, fall back to using // `opacity` to make it opaque since its end value could be a solid color. background-color: $backdrop-color; opacity: $opacity; } } } @mixin mat-sidenav-typography($config) { } @mixin _mat-slide-toggle-checked($palette, $thumb-checked-hue) { &.mat-checked { .mat-slide-toggle-thumb { background-color: mat-color($palette, $thumb-checked-hue); } .mat-slide-toggle-bar { // Opacity is determined from the specs for the selection controls. // See: https://material.io/design/components/selection-controls.html#specs background-color: mat-color($palette, $thumb-checked-hue, 0.54); } .mat-ripple-element { // Set no opacity for the ripples because the ripple opacity will be adjusted dynamically // based on the type of interaction with the slide-toggle (e.g. for hover, focus) background-color: mat-color($palette, $thumb-checked-hue); } } } @mixin mat-slide-toggle-theme($theme) { $is-dark: map_get($theme, is-dark); $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); // Color hues are based on the specs which briefly show the hues that are applied to a switch. // The 2018 specs no longer describe how dark switches should look like. Due to the lack of // information for dark themed switches, we partially keep the old behavior that is based on // the previous specifications. For the checked color we always use the `default` hue because // that follows MDC and also makes it easier for people to create a custom theme without needing // to specify each hue individually. $thumb-unchecked-hue: if($is-dark, 400, 50); $thumb-checked-hue: default; $bar-unchecked-color: mat-color($foreground, disabled); $ripple-unchecked-color: mat-color($foreground, base); .mat-slide-toggle { @include _mat-slide-toggle-checked($accent, $thumb-checked-hue); &.mat-primary { @include _mat-slide-toggle-checked($primary, $thumb-checked-hue); } &.mat-warn { @include _mat-slide-toggle-checked($warn, $thumb-checked-hue); } &:not(.mat-checked) .mat-ripple-element { // Set no opacity for the ripples because the ripple opacity will be adjusted dynamically // based on the type of interaction with the slide-toggle (e.g. for hover, focus) background-color: $ripple-unchecked-color; } } .mat-slide-toggle-thumb { @include _mat-theme-elevation(1, $theme); background-color: mat-color($mat-grey, $thumb-unchecked-hue); } .mat-slide-toggle-bar { background-color: $bar-unchecked-color; } } @mixin mat-slide-toggle-typography($config) { .mat-slide-toggle-content { font-family: mat-font-family($config); } } @mixin _mat-slider-inner-content-theme($palette) { .mat-slider-track-fill, .mat-slider-thumb, .mat-slider-thumb-label { background-color: mat-color($palette); } .mat-slider-thumb-label-text { color: mat-color($palette, default-contrast); } } @mixin mat-slider-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); $mat-slider-off-color: mat-color($foreground, slider-off); $mat-slider-off-focused-color: mat-color($foreground, slider-off-active); $mat-slider-disabled-color: mat-color($foreground, slider-off); $mat-slider-labeled-min-value-thumb-color: mat-color($foreground, slider-min); $mat-slider-labeled-min-value-thumb-label-color: mat-color($foreground, slider-off); $mat-slider-focus-ring-color: mat-color($accent, default, 0.2); $mat-slider-focus-ring-min-value-color: mat-color($foreground, base, 0.12); $mat-slider-tick-color: mat-color($foreground, base, 0.7); $mat-slider-tick-size: 2px; .mat-slider-track-background { background-color: $mat-slider-off-color; } .mat-primary { @include _mat-slider-inner-content-theme($primary); } .mat-accent { @include _mat-slider-inner-content-theme($accent); } .mat-warn { @include _mat-slider-inner-content-theme($warn); } .mat-slider-focus-ring { background-color: $mat-slider-focus-ring-color; } .mat-slider:hover, .cdk-focused { .mat-slider-track-background { background-color: $mat-slider-off-focused-color; } } .mat-slider-disabled { .mat-slider-track-background, .mat-slider-track-fill, .mat-slider-thumb { background-color: $mat-slider-disabled-color; } &:hover { .mat-slider-track-background { background-color: $mat-slider-disabled-color; } } } .mat-slider-min-value { .mat-slider-focus-ring { background-color: $mat-slider-focus-ring-min-value-color; } &.mat-slider-thumb-label-showing { .mat-slider-thumb, .mat-slider-thumb-label { background-color: $mat-slider-labeled-min-value-thumb-color; } &.cdk-focused { .mat-slider-thumb, .mat-slider-thumb-label { background-color: $mat-slider-labeled-min-value-thumb-label-color; } } } &:not(.mat-slider-thumb-label-showing) { .mat-slider-thumb { border-color: $mat-slider-off-color; background-color: transparent; } &:hover, &.cdk-focused { .mat-slider-thumb { border-color: $mat-slider-off-focused-color; } &.mat-slider-disabled .mat-slider-thumb { border-color: $mat-slider-disabled-color; } } } } .mat-slider-has-ticks .mat-slider-wrapper::after { border-color: $mat-slider-tick-color; } .mat-slider-horizontal .mat-slider-ticks { background-image: repeating-linear-gradient(to right, $mat-slider-tick-color, $mat-slider-tick-color $mat-slider-tick-size, transparent 0, transparent); // Firefox doesn't draw the gradient correctly with 'to right' // (see https://bugzilla.mozilla.org/show_bug.cgi?id=1314319). background-image: -moz-repeating-linear-gradient(0.0001deg, $mat-slider-tick-color, $mat-slider-tick-color $mat-slider-tick-size, transparent 0, transparent); } .mat-slider-vertical .mat-slider-ticks { background-image: repeating-linear-gradient(to bottom, $mat-slider-tick-color, $mat-slider-tick-color $mat-slider-tick-size, transparent 0, transparent); } } @mixin mat-slider-typography($config) { .mat-slider-thumb-label-text { font: { family: mat-font-family($config); size: mat-font-size($config, caption); weight: mat-font-weight($config, body-2); } } } @mixin mat-stepper-theme($theme) { $foreground: map-get($theme, foreground); $background: map-get($theme, background); $primary: map-get($theme, primary); $warn: map-get($theme, warn); .mat-step-header { &.cdk-keyboard-focused, &.cdk-program-focused, &:hover { background-color: mat-color($background, hover); } // On touch devices the :hover state will linger on the element after a tap. // Reset it via `@media` after the declaration, because the media query isn't // supported by all browsers yet. @media (hover: none) { &:hover { background: none; } } .mat-step-label, .mat-step-optional { // TODO(josephperrott): Update to using a corrected disabled-text contrast // instead of secondary-text. color: mat-color($foreground, secondary-text); } .mat-step-icon { // TODO(josephperrott): Update to using a corrected disabled-text contrast // instead of secondary-text. background-color: mat-color($foreground, secondary-text); color: mat-color($primary, default-contrast); } .mat-step-icon-selected, .mat-step-icon-state-done, .mat-step-icon-state-edit { background-color: mat-color($primary); color: mat-color($primary, default-contrast); } .mat-step-icon-state-error { background-color: transparent; color: mat-color($warn, text); } .mat-step-label.mat-step-label-active { color: mat-color($foreground, text); } .mat-step-label.mat-step-label-error { color: mat-color($warn, text); } } .mat-stepper-horizontal, .mat-stepper-vertical { background-color: mat-color($background, card); } .mat-stepper-vertical-line::before { border-left-color: mat-color($foreground, divider); } .mat-horizontal-stepper-header::before, .mat-horizontal-stepper-header::after, .mat-stepper-horizontal-line { border-top-color: mat-color($foreground, divider); } } @mixin mat-stepper-typography($config) { .mat-stepper-vertical, .mat-stepper-horizontal { font-family: mat-font-family($config); } .mat-step-label { font: { size: mat-font-size($config, body-1); weight: mat-font-weight($config, body-1); }; } .mat-step-sub-label-error { font-weight: normal; } .mat-step-label-error { font-size: mat-font-size($config, body-2); } .mat-step-label-selected { font: { size: mat-font-size($config, body-2); weight: mat-font-weight($config, body-2); }; } } @mixin mat-sort-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-sort-header-arrow { $table-background: mat-color($background, 'card'); $text-color: mat-color($foreground, secondary-text); // Because the arrow is made up of multiple elements that are stacked on top of each other, // we can't use the semi-trasparent color from the theme directly. If the value is a color // *type*, we convert it into a solid color by taking the opacity from the rgba value and // using the value to determine the percentage of the background to put into foreground // when mixing the colors together. Otherwise, if it resolves to something different // (e.g. it resolves to a CSS variable), we use the color directly. @if (type-of($table-background) == color and type-of($text-color) == color) { $text-opacity: opacity($text-color); color: mix($table-background, rgba($text-color, 1), (1 - $text-opacity) * 100%); } @else { color: $text-color; } } } @mixin mat-sort-typography($config) { } @mixin mat-tabs-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); $header-border: 1px solid mat-color($foreground, divider); .mat-tab-nav-bar, .mat-tab-header { border-bottom: $header-border; } .mat-tab-group-inverted-header { .mat-tab-nav-bar, .mat-tab-header { border-top: $header-border; border-bottom: none; } } .mat-tab-label, .mat-tab-link { color: mat-color($foreground, text); &.mat-tab-disabled { color: mat-color($foreground, disabled-text); } } .mat-tab-header-pagination-chevron { border-color: mat-color($foreground, text); } .mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron { border-color: mat-color($foreground, disabled-text); } // Remove header border when there is a background color .mat-tab-group[class*='mat-background-'] .mat-tab-header, .mat-tab-nav-bar[class*='mat-background-'] { border-bottom: none; border-top: none; } .mat-tab-group, .mat-tab-nav-bar { $theme-colors: ( primary: $primary, accent: $accent, warn: $warn ); @each $name, $color in $theme-colors { // Set the foreground color of the tabs &.mat-#{$name} { @include _mat-tab-label-focus($color); @include _mat-ink-bar($color); // Override ink bar when background color is the same &.mat-background-#{$name} { @include _mat-ink-bar($color, default-contrast); } } } @each $name, $color in $theme-colors { // Set background color of the tabs and override focus color &.mat-background-#{$name} { @include _mat-tab-label-focus($color); @include _mat-tabs-background($color); } } } } @mixin _mat-ink-bar($color, $hue: default) { .mat-ink-bar { background-color: mat-color($color, $hue); } } @mixin _mat-tab-label-focus($tab-focus-color) { .mat-tab-label, .mat-tab-link { &.cdk-keyboard-focused, &.cdk-program-focused { &:not(.mat-tab-disabled) { background-color: mat-color($tab-focus-color, lighter, 0.3); } } } } @mixin _mat-tabs-background($background-color) { // Set background color for the tab group .mat-tab-header, .mat-tab-links, .mat-tab-header-pagination { background-color: mat-color($background-color); } // Set labels to contrast against background .mat-tab-label, .mat-tab-link { color: mat-color($background-color, default-contrast); &.mat-tab-disabled { color: mat-color($background-color, default-contrast, 0.4); } } // Set pagination chevrons to contrast background .mat-tab-header-pagination-chevron { border-color: mat-color($background-color, default-contrast); } .mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron { border-color: mat-color($background-color, default-contrast, 0.4); } // Set ripples color to be the contrast color of the new background. Otherwise the ripple // color will be based on the app background color. .mat-ripple-element { background-color: mat-color($background-color, default-contrast, 0.12); } } @mixin mat-tabs-typography($config) { .mat-tab-group { font-family: mat-font-family($config); } .mat-tab-label, .mat-tab-link { font: { family: mat-font-family($config, button); size: mat-font-size($config, button); weight: mat-font-weight($config, button); } } } @mixin _mat-toolbar-color($palette) { background: mat-color($palette); color: mat-color($palette, default-contrast); } @mixin _mat-toolbar-form-field-overrides { .mat-form-field-underline, .mat-form-field-ripple, .mat-focused .mat-form-field-ripple { background-color: currentColor; } .mat-form-field-label, .mat-focused .mat-form-field-label, .mat-select-value, .mat-select-arrow, .mat-form-field.mat-focused .mat-select-arrow { color: inherit; } .mat-input-element { caret-color: currentColor; } } @mixin mat-toolbar-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-toolbar { background: mat-color($background, app-bar); color: mat-color($foreground, text); &.mat-primary { @include _mat-toolbar-color($primary); } &.mat-accent { @include _mat-toolbar-color($accent); } &.mat-warn { @include _mat-toolbar-color($warn); } @include _mat-toolbar-form-field-overrides; } } @mixin mat-toolbar-typography($config) { .mat-toolbar, .mat-toolbar h1, .mat-toolbar h2, .mat-toolbar h3, .mat-toolbar h4, .mat-toolbar h5, .mat-toolbar h6 { @include mat-typography-level-to-styles($config, title); margin: 0; } } $mat-tooltip-target-height: 22px; $mat-tooltip-font-size: 10px; $mat-tooltip-vertical-padding: ($mat-tooltip-target-height - $mat-tooltip-font-size) / 2; $mat-tooltip-handset-target-height: 30px; $mat-tooltip-handset-font-size: 14px; $mat-tooltip-handset-vertical-padding: ($mat-tooltip-handset-target-height - $mat-tooltip-handset-font-size) / 2; @mixin mat-tooltip-theme($theme) { .mat-tooltip { background: mat-color($mat-grey, 700, 0.9); } } @mixin mat-tooltip-typography($config) { .mat-tooltip { font-family: mat-font-family($config); font-size: $mat-tooltip-font-size; padding-top: $mat-tooltip-vertical-padding; padding-bottom: $mat-tooltip-vertical-padding; } .mat-tooltip-handset { font-size: $mat-tooltip-handset-font-size; padding-top: $mat-tooltip-handset-vertical-padding; padding-bottom: $mat-tooltip-handset-vertical-padding; } } @mixin mat-snack-bar-theme($theme) { $is-dark-theme: map-get($theme, is-dark); $accent: map-get($theme, accent); .mat-snack-bar-container { // Use the primary text on the dark theme, even though the lighter one uses // a secondary, because the contrast on the light primary text is poor. color: if($is-dark-theme, $dark-primary-text, $light-secondary-text); background: if($is-dark-theme, map-get($mat-grey, 50), #323232); @include _mat-theme-elevation(6, $theme); } .mat-simple-snackbar-action { color: if($is-dark-theme, inherit, mat-color($accent, text)); } } @mixin mat-snack-bar-typography($config) { .mat-simple-snackbar { font: { family: mat-font-family($config, body-1); size: mat-font-size($config, body-1); } } .mat-simple-snackbar-action { line-height: 1; font: { family: inherit; size: inherit; weight: mat-font-weight($config, button); } } } // Theme styles that only apply to the fill appearance of the form-field. @mixin mat-form-field-fill-theme($theme) { $foreground: map-get($theme, foreground); $is-dark-theme: map-get($theme, is-dark); $fill-background: mat-color($foreground, base, if($is-dark-theme, 0.1, 0.04)); $fill-disabled-background: mat-color($foreground, base, if($is-dark-theme, 0.05, 0.02)); $underline-color: mat-color($foreground, divider, if($is-dark-theme, 0.5, 0.42)); $label-disabled-color: mat-color($foreground, disabled-text); .mat-form-field-appearance-fill { .mat-form-field-flex { background-color: $fill-background; } &.mat-form-field-disabled .mat-form-field-flex { background-color: $fill-disabled-background; } .mat-form-field-underline::before { background-color: $underline-color; } &.mat-form-field-disabled { .mat-form-field-label { color: $label-disabled-color; } .mat-form-field-underline::before { background-color: transparent; } } } } // Used to make instances of the _mat-form-field-label-floating mixin negligibly different, // and prevent Google's CSS Optimizer from collapsing the declarations. This is needed because some // of the selectors contain pseudo-classes not recognized in all browsers. If a browser encounters // an unknown pseudo-class it will discard the entire rule set. $mat-form-field-fill-dedupe: 0; // Applies a floating label above the form field control itself. @mixin _mat-form-field-fill-label-floating($font-scale, $infix-padding, $infix-margin-top) { transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-fill-dedupe) scale($font-scale); width: 100% / $font-scale + $mat-form-field-fill-dedupe; $mat-form-field-fill-dedupe: $mat-form-field-fill-dedupe + 0.00001 !global; } @mixin mat-form-field-fill-typography($config) { // The unit-less line-height from the font config. $line-height: mat-line-height($config, input); // The amount to scale the font for the floating label and subscript. $subscript-font-scale: 0.75; // The padding on top of the infix. $infix-padding-top: 0.25em; // The padding below the infix. $infix-padding-bottom: 0.75em; // The margin applied to the form-field-infix to reserve space for the floating label. $infix-margin-top: 1em * $line-height * $subscript-font-scale; // The amount we offset the label from the input text in the fill appearance. $fill-appearance-label-offset: -0.5em; .mat-form-field-appearance-fill { .mat-form-field-infix { padding: $infix-padding-top 0 $infix-padding-bottom 0; } .mat-form-field-label { top: $infix-margin-top + $infix-padding-top; margin-top: $fill-appearance-label-offset; } &.mat-form-field-can-float { &.mat-form-field-should-float .mat-form-field-label, .mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-fill-label-floating( $subscript-font-scale, $infix-padding-top + $fill-appearance-label-offset, $infix-margin-top); } // Server-side rendered matInput with a label attribute but label not shown // (used as a pure CSS stand-in for mat-form-field-should-float). .mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-fill-label-floating( $subscript-font-scale, $infix-padding-top + $fill-appearance-label-offset, $infix-margin-top); } } } } // Theme styles that only apply to the legacy appearance of the form-field. @mixin mat-form-field-legacy-theme($theme) { $foreground: map-get($theme, foreground); $is-dark-theme: map-get($theme, is-dark); $label-color: mat-color($foreground, secondary-text); $underline-color: mat-color($foreground, divider, if($is-dark-theme, 0.7, 0.42)); .mat-form-field-appearance-legacy { .mat-form-field-label { color: $label-color; } .mat-hint { color: $label-color; } .mat-form-field-underline { background-color: $underline-color; } &.mat-form-field-disabled .mat-form-field-underline { @include mat-control-disabled-underline($underline-color); } } } // Used to make instances of the _mat-form-field-label-floating mixin negligibly different, // and prevent Google's CSS Optimizer from collapsing the declarations. This is needed because some // of the selectors contain pseudo-classes not recognized in all browsers. If a browser encounters // an unknown pseudo-class it will discard the entire rule set. $mat-form-field-legacy-dedupe: 0; // Applies a floating label above the form field control itself. @mixin _mat-form-field-legacy-label-floating($font-scale, $infix-padding, $infix-margin-top) { // We use perspective to fix the text blurriness as described here: // http://www.useragentman.com/blog/2014/05/04/fixing-typography-inside-of-2-d-css-transforms/ // This results in a small jitter after the label floats on Firefox, which the // translateZ fixes. transform: translateY(-$infix-margin-top - $infix-padding) scale($font-scale) perspective(100px) translateZ(0.001px + $mat-form-field-legacy-dedupe); // The tricks above used to smooth out the animation on chrome and firefox actually make things // worse on IE, so we don't include them in the IE version. -ms-transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-legacy-dedupe) scale($font-scale); width: 100% / $font-scale + $mat-form-field-legacy-dedupe; $mat-form-field-legacy-dedupe: $mat-form-field-legacy-dedupe + 0.00001 !global; } // Same as mixin above, but omits the translateZ for printing purposes. @mixin _mat-form-field-legacy-label-floating-print($font-scale, $infix-padding, $infix-margin-top) { // This results in a small jitter after the label floats on Firefox, which the // translateZ fixes. transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-legacy-dedupe) scale($font-scale); // The tricks above used to smooth out the animation on chrome and firefox actually make things // worse on IE, so we don't include them in the IE version. $mat-form-field-legacy-dedupe: $mat-form-field-legacy-dedupe + 0.00001 !global; } @mixin mat-form-field-legacy-typography($config) { // The unit-less line-height from the font config. $line-height: mat-line-height($config, input); // The amount to scale the font for the floating label and subscript. $subscript-font-scale: 0.75; // The amount of space between the top of the line and the top of the actual text // (as a fraction of the font-size). $line-spacing: ($line-height - 1) / 2; // The padding on the infix. Mocks show half of the text size, but seem to measure from the edge // of the text itself, not the edge of the line; therefore we subtract off the line spacing. $infix-padding: 0.5em - $line-spacing; // The margin applied to the form-field-infix to reserve space for the floating label. $infix-margin-top: 1em * $line-height * $subscript-font-scale; // The space between the bottom of the .mat-form-field-flex area and the subscript wrapper. // Mocks show half of the text size, but this margin is applied to an element with the subscript // text font size, so we need to divide by the scale factor to make it half of the original text // size. We again need to subtract off the line spacing since the mocks measure to the edge of the // text, not the edge of the line. $subscript-margin-top: 0.5em / $subscript-font-scale - ($line-spacing * 2); // The padding applied to the form-field-wrapper to reserve space for the subscript, since it's // absolutely positioned. This is a combination of the subscript's margin and line-height, but we // need to multiply by the subscript font scale factor since the wrapper has a larger font size. $wrapper-padding-bottom: ($subscript-margin-top + $line-height) * $subscript-font-scale; .mat-form-field-appearance-legacy { .mat-form-field-wrapper { padding-bottom: $wrapper-padding-bottom; } .mat-form-field-infix { padding: $infix-padding 0; } &.mat-form-field-can-float { &.mat-form-field-should-float .mat-form-field-label, .mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-legacy-label-floating( $subscript-font-scale, $infix-padding, $infix-margin-top); } // @breaking-change 8.0.0 will rely on AutofillMonitor instead. .mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-legacy-label-floating( $subscript-font-scale, $infix-padding, $infix-margin-top); } // Server-side rendered matInput with a label attribute but label not shown // (used as a pure CSS stand-in for mat-form-field-should-float). .mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-legacy-label-floating( $subscript-font-scale, $infix-padding, $infix-margin-top); } } .mat-form-field-label { top: $infix-margin-top + $infix-padding; } .mat-form-field-underline { // We want the underline to start at the end of the content box, not the padding box, // so we move it up by the padding amount. bottom: $wrapper-padding-bottom; } .mat-form-field-subscript-wrapper { margin-top: $subscript-margin-top; // We want the subscript to start at the end of the content box, not the padding box, // so we move it up by the padding amount (adjusted for the smaller font size); top: calc(100% - #{$wrapper-padding-bottom / $subscript-font-scale}); } } // translateZ causes the label to not appear while printing, so we override it to not // apply translateZ while printing @media print { .mat-form-field-appearance-legacy { &.mat-form-field-can-float { &.mat-form-field-should-float .mat-form-field-label, .mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-legacy-label-floating-print( $subscript-font-scale, $infix-padding, $infix-margin-top); } // @breaking-change 8.0.0 will rely on AutofillMonitor instead. .mat-form-field-autofill-control:-webkit-autofill + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-legacy-label-floating-print( $subscript-font-scale, $infix-padding, $infix-margin-top); } // Server-side rendered matInput with a label attribute but label not shown // (used as a pure CSS stand-in for mat-form-field-should-float). .mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-legacy-label-floating-print( $subscript-font-scale, $infix-padding, $infix-margin-top); } } } } } // Theme styles that only apply to the outline appearance of the form-field. @mixin mat-form-field-outline-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $foreground: map-get($theme, foreground); $is-dark-theme: map-get($theme, is-dark); $label-disabled-color: mat-color($foreground, disabled-text); $outline-color: mat-color($foreground, divider, if($is-dark-theme, 0.3, 0.12)); $outline-color-hover: mat-color($foreground, divider, if($is-dark-theme, 1, 0.87)); $outline-color-primary: mat-color($primary); $outline-color-accent: mat-color($accent); $outline-color-warn: mat-color($warn); $outline-color-disabled: mat-color($foreground, divider, if($is-dark-theme, 0.15, 0.06)); .mat-form-field-appearance-outline { .mat-form-field-outline { color: $outline-color; } .mat-form-field-outline-thick { color: $outline-color-hover; } &.mat-focused { .mat-form-field-outline-thick { color: $outline-color-primary; } &.mat-accent .mat-form-field-outline-thick { color: $outline-color-accent; } &.mat-warn .mat-form-field-outline-thick { color: $outline-color-warn; } } // Class repeated so that rule is specific enough to override focused accent color case. &.mat-form-field-invalid.mat-form-field-invalid { .mat-form-field-outline-thick { color: $outline-color-warn; } } &.mat-form-field-disabled { .mat-form-field-label { color: $label-disabled-color; } .mat-form-field-outline { color: $outline-color-disabled; } } } } // Used to make instances of the _mat-form-field-label-floating mixin negligibly different, // and prevent Google's CSS Optimizer from collapsing the declarations. This is needed because some // of the selectors contain pseudo-classes not recognized in all browsers. If a browser encounters // an unknown pseudo-class it will discard the entire rule set. $mat-form-field-outline-dedupe: 0; // Applies a floating label above the form field control itself. @mixin _mat-form-field-outline-label-floating($font-scale, $infix-padding, $infix-margin-top) { transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-outline-dedupe) scale($font-scale); width: 100% / $font-scale + $mat-form-field-outline-dedupe; $mat-form-field-outline-dedupe: $mat-form-field-outline-dedupe + 0.00001 !global; } @mixin mat-form-field-outline-typography($config) { // The unit-less line-height from the font config. $line-height: mat-line-height($config, input); // The amount to scale the font for the floating label and subscript. $subscript-font-scale: 0.75; // The padding above and below the infix. $infix-padding: 1em; // The margin applied to the form-field-infix to reserve space for the floating label. $infix-margin-top: 1em * $line-height * $subscript-font-scale; // The space between the bottom of the .mat-form-field-flex area and the subscript wrapper. // Mocks show half of the text size, but this margin is applied to an element with the subscript // text font size, so we need to divide by the scale factor to make it half of the original text // size. $subscript-margin-top: 0.5em / $subscript-font-scale; // The padding applied to the form-field-wrapper to reserve space for the subscript, since it's // absolutely positioned. This is a combination of the subscript's margin and line-height, but we // need to multiply by the subscript font scale factor since the wrapper has a larger font size. $wrapper-padding-bottom: ($subscript-margin-top + $line-height) * $subscript-font-scale; // The amount we offset the label from the input text in the outline appearance. $outline-appearance-label-offset: -0.25em; .mat-form-field-appearance-outline { .mat-form-field-infix { padding: $infix-padding 0 $infix-padding 0; } .mat-form-field-label { top: $infix-margin-top + $infix-padding; margin-top: $outline-appearance-label-offset; } &.mat-form-field-can-float { &.mat-form-field-should-float .mat-form-field-label, .mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-outline-label-floating( $subscript-font-scale, $infix-padding + $outline-appearance-label-offset, $infix-margin-top); } // Server-side rendered matInput with a label attribute but label not shown // (used as a pure CSS stand-in for mat-form-field-should-float). .mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-outline-label-floating( $subscript-font-scale, $infix-padding + $outline-appearance-label-offset, $infix-margin-top); } } } } // Theme styles that only apply to the standard appearance of the form-field. @mixin mat-form-field-standard-theme($theme) { $foreground: map-get($theme, foreground); $is-dark-theme: map-get($theme, is-dark); $underline-color: mat-color($foreground, divider, if($is-dark-theme, 0.7, 0.42)); .mat-form-field-appearance-standard { .mat-form-field-underline { background-color: $underline-color; } &.mat-form-field-disabled .mat-form-field-underline { @include mat-control-disabled-underline($underline-color); } } } @mixin mat-form-field-standard-typography($config) {} // Theme styles that apply to all appearances of the form-field. @mixin mat-form-field-theme($theme) { $primary: map-get($theme, primary); $accent: map-get($theme, accent); $warn: map-get($theme, warn); $background: map-get($theme, background); $foreground: map-get($theme, foreground); $is-dark-theme: map-get($theme, is-dark); // Label colors. Required is used for the `*` star shown in the label. $label-color: mat-color($foreground, secondary-text, if($is-dark-theme, 0.7, 0.6)); $focused-label-color: mat-color($primary, text); $required-label-color: mat-color($accent, text); // Underline colors. $underline-color-base: mat-color($foreground, divider, if($is-dark-theme, 1, 0.87)); $underline-color-accent: mat-color($accent, text); $underline-color-warn: mat-color($warn, text); $underline-focused-color: mat-color($primary, text); .mat-form-field-label { color: $label-color; } .mat-hint { color: $label-color; } .mat-form-field.mat-focused .mat-form-field-label { color: $focused-label-color; &.mat-accent { color: $underline-color-accent; } &.mat-warn { color: $underline-color-warn; } } .mat-focused .mat-form-field-required-marker { color: $required-label-color; } .mat-form-field-ripple { background-color: $underline-color-base; } .mat-form-field.mat-focused { .mat-form-field-ripple { background-color: $underline-focused-color; &.mat-accent { background-color: $underline-color-accent; } &.mat-warn { background-color: $underline-color-warn; } } } .mat-form-field-type-mat-native-select.mat-focused:not(.mat-form-field-invalid) { .mat-form-field-infix::after { color: $underline-focused-color; } &.mat-accent .mat-form-field-infix::after { color: $underline-color-accent; } &.mat-warn .mat-form-field-infix::after { color: $underline-color-warn; } } // Styling for the error state of the form field. Note that while the same can be // achieved with the ng-* classes, we use this approach in order to ensure that the same // logic is used to style the error state and to show the error messages. .mat-form-field.mat-form-field-invalid { .mat-form-field-label { color: $underline-color-warn; &.mat-accent, .mat-form-field-required-marker { color: $underline-color-warn; } } .mat-form-field-ripple, .mat-form-field-ripple.mat-accent { background-color: $underline-color-warn; } } .mat-error { color: $underline-color-warn; } @include mat-form-field-legacy-theme($theme); @include mat-form-field-standard-theme($theme); @include mat-form-field-fill-theme($theme); @include mat-form-field-outline-theme($theme); } // Used to make instances of the _mat-form-field-label-floating mixin negligibly different, // and prevent Google's CSS Optimizer from collapsing the declarations. This is needed because some // of the selectors contain pseudo-classes not recognized in all browsers. If a browser encounters // an unknown pseudo-class it will discard the entire rule set. $mat-form-field-dedupe: 0; // Applies a floating label above the form field control itself. @mixin _mat-form-field-label-floating($font-scale, $infix-padding, $infix-margin-top) { transform: translateY(-$infix-margin-top - $infix-padding + $mat-form-field-dedupe) scale($font-scale); width: 100% / $font-scale + $mat-form-field-dedupe; $mat-form-field-dedupe: $mat-form-field-dedupe + 0.00001 !global; } @mixin mat-form-field-typography($config) { // The unit-less line-height from the font config. $line-height: mat-line-height($config, input); // The amount to scale the font for the floating label and subscript. $subscript-font-scale: 0.75; // The amount to scale the font for the prefix and suffix icons. $prefix-suffix-icon-font-scale: 1.5; // The padding on the infix. Mocks show half of the text size. $infix-padding: 0.5em; // The margin applied to the form-field-infix to reserve space for the floating label. $infix-margin-top: 1em * $line-height * $subscript-font-scale; // Font size to use for the label and subscript text. $subscript-font-size: $subscript-font-scale * 100%; // Font size to use for the for the prefix and suffix icons. $prefix-suffix-icon-font-size: $prefix-suffix-icon-font-scale * 100%; // The space between the bottom of the .mat-form-field-flex area and the subscript wrapper. // Mocks show half of the text size, but this margin is applied to an element with the subscript // text font size, so we need to divide by the scale factor to make it half of the original text // size. $subscript-margin-top: 0.5em / $subscript-font-scale; // The padding applied to the form-field-wrapper to reserve space for the subscript, since it's // absolutely positioned. This is a combination of the subscript's margin and line-height, but we // need to multiply by the subscript font scale factor since the wrapper has a larger font size. $wrapper-padding-bottom: ($subscript-margin-top + $line-height) * $subscript-font-scale; .mat-form-field { @include mat-typography-level-to-styles($config, input); } .mat-form-field-wrapper { padding-bottom: $wrapper-padding-bottom; } .mat-form-field-prefix, .mat-form-field-suffix { // Allow icons in a prefix or suffix to adapt to the correct size. .mat-icon { font-size: $prefix-suffix-icon-font-size; line-height: $line-height; } // Allow icon buttons in a prefix or suffix to adapt to the correct size. .mat-icon-button { height: $prefix-suffix-icon-font-scale * 1em; width: $prefix-suffix-icon-font-scale * 1em; .mat-icon { height: $line-height * 1em; line-height: $line-height; } } } .mat-form-field-infix { padding: $infix-padding 0; // Throws off the baseline if we do it as a real margin, so we do it as a border instead. border-top: $infix-margin-top solid transparent; } .mat-form-field-can-float { &.mat-form-field-should-float .mat-form-field-label, .mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-label-floating( $subscript-font-scale, $infix-padding, $infix-margin-top); } // Server-side rendered matInput with a label attribute but label not shown // (used as a pure CSS stand-in for mat-form-field-should-float). .mat-input-server[label]:not(:label-shown) + .mat-form-field-label-wrapper .mat-form-field-label { @include _mat-form-field-label-floating( $subscript-font-scale, $infix-padding, $infix-margin-top); } } .mat-form-field-label-wrapper { top: -$infix-margin-top; padding-top: $infix-margin-top; } .mat-form-field-label { top: $infix-margin-top + $infix-padding; } .mat-form-field-underline { // We want the underline to start at the end of the content box, not the padding box, // so we move it up by the padding amount. bottom: $wrapper-padding-bottom; } .mat-form-field-subscript-wrapper { font-size: $subscript-font-size; margin-top: $subscript-margin-top; // We want the subscript to start at the end of the content box, not the padding box, // so we move it up by the padding amount (adjusted for the smaller font size); top: calc(100% - #{$wrapper-padding-bottom / $subscript-font-scale}); } @include mat-form-field-legacy-typography($config); @include mat-form-field-standard-typography($config); @include mat-form-field-fill-typography($config); @include mat-form-field-outline-typography($config); } @mixin mat-tree-theme($theme) { $background: map-get($theme, background); $foreground: map-get($theme, foreground); .mat-tree { background: mat-color($background, 'card'); } .mat-tree-node, .mat-nested-tree-node { color: mat-color($foreground, text); } } @mixin mat-tree-typography($config) { .mat-tree { font-family: mat-font-family($config); } .mat-tree-node, .mat-nested-tree-node { font-weight: mat-font-weight($config, body-1); font-size: mat-font-size($config, body-1); } } // Includes all of the typographic styles. @mixin angular-material-typography($config: null) { @if $config == null { $config: mat-typography-config(); } @include mat-badge-typography($config); @include mat-base-typography($config); @include mat-autocomplete-typography($config); @include mat-bottom-sheet-typography($config); @include mat-button-typography($config); @include mat-button-toggle-typography($config); @include mat-card-typography($config); @include mat-checkbox-typography($config); @include mat-chips-typography($config); @include mat-table-typography($config); @include mat-datepicker-typography($config); @include mat-dialog-typography($config); @include mat-expansion-panel-typography($config); @include mat-form-field-typography($config); @include mat-grid-list-typography($config); @include mat-icon-typography($config); @include mat-input-typography($config); @include mat-menu-typography($config); @include mat-paginator-typography($config); @include mat-progress-bar-typography($config); @include mat-progress-spinner-typography($config); @include mat-radio-typography($config); @include mat-select-typography($config); @include mat-sidenav-typography($config); @include mat-slide-toggle-typography($config); @include mat-slider-typography($config); @include mat-stepper-typography($config); @include mat-sort-typography($config); @include mat-tabs-typography($config); @include mat-toolbar-typography($config); @include mat-tooltip-typography($config); @include mat-list-typography($config); @include mat-option-typography($config); @include mat-optgroup-typography($config); @include mat-snack-bar-typography($config); @include mat-tree-typography($config); } // Mixin that renders all of the core styles that are not theme-dependent. @mixin mat-core($typography-config: null) { @include angular-material-typography($typography-config); @include mat-ripple(); @include cdk-a11y(); @include cdk-overlay(); @include cdk-text-field(); } // Mixin that renders all of the core styles that depend on the theme. @mixin mat-core-theme($theme) { @include mat-ripple-theme($theme); @include mat-option-theme($theme); @include mat-optgroup-theme($theme); @include mat-pseudo-checkbox-theme($theme); // Provides external CSS classes for each elevation value. Each CSS class is formatted as // `mat-elevation-z$zValue` where `$zValue` corresponds to the z-space to which the element is // elevated. @for $zValue from 0 through 24 { .#{$_mat-elevation-prefix}#{$zValue} { @include _mat-theme-elevation($zValue, $theme); } } // Wrapper element that provides the theme background when the user's content isn't // inside of a `mat-sidenav-container`. Note that we need to exclude the ampersand // selector in case the mixin is included at the top level. .mat-app-background#{if(&, ', &.mat-app-background', '')} { $background: map-get($theme, background); $foreground: map-get($theme, foreground); background-color: mat-color($background, background); color: mat-color($foreground, text); } // Marker that is used to determine whether the user has added a theme to their page. @at-root { .mat-theme-loaded-marker { display: none; } } } @mixin mat-divider-theme($theme) { $foreground: map-get($theme, foreground); .mat-divider { border-top-color: mat-color($foreground, divider); } .mat-divider-vertical { border-right-color: mat-color($foreground, divider); } } // Create a theme. @mixin angular-material-theme($theme) { @include mat-core-theme($theme); @include mat-autocomplete-theme($theme); @include mat-badge-theme($theme); @include mat-bottom-sheet-theme($theme); @include mat-button-theme($theme); @include mat-button-toggle-theme($theme); @include mat-card-theme($theme); @include mat-checkbox-theme($theme); @include mat-chips-theme($theme); @include mat-table-theme($theme); @include mat-datepicker-theme($theme); @include mat-dialog-theme($theme); @include mat-divider-theme($theme); @include mat-expansion-panel-theme($theme); @include mat-form-field-theme($theme); @include mat-grid-list-theme($theme); @include mat-icon-theme($theme); @include mat-input-theme($theme); @include mat-list-theme($theme); @include mat-menu-theme($theme); @include mat-paginator-theme($theme); @include mat-progress-bar-theme($theme); @include mat-progress-spinner-theme($theme); @include mat-radio-theme($theme); @include mat-select-theme($theme); @include mat-sidenav-theme($theme); @include mat-slide-toggle-theme($theme); @include mat-slider-theme($theme); @include mat-stepper-theme($theme); @include mat-sort-theme($theme); @include mat-tabs-theme($theme); @include mat-toolbar-theme($theme); @include mat-tooltip-theme($theme); @include mat-tree-theme($theme); @include mat-snack-bar-theme($theme); } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\custom-effects.scss // button:hover:not([disabled]), ion-button:hover:not([disabled]) { @include animation("flash", 1500ms); } .picker-opt-disabled { opacity: 0.5; } .action-sheet-cancel, .action-sheet-setructive, .action-sheet-group-cancel { color: var(--x-color-danger) !important; } // // Dialog Theme ... ::ng-deep.mat-card, ::ng-deep.mat-expansion-panel, ::ng-deep.mat-dialog-container { color: var(--x-color-light-contrast); background-color: var(--x-color-light); } ::ng-deep.full-with { .x-wrapper { width: 100%; } } .full-with { width: 100%; } .x-minimal-popover { .popover-content { width: 90px !important; max-width: 90px !important; } } .dynamic-slot { flex: 0 auto !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\fab-theme.scss // //#region Fab ... $isRTL: var(--is-rtl); $fabMargin: 16px; x-fab[pageFab] { // ion-fab { // @if $isRTL { left: $fabMargin !important; right: auto !important; } @else { right: $fabMargin !important; left: auto !important; } // position: fixed !important; margin-top: calc(var(--content-offset-bottom) * -1); margin-bottom: calc(var(--content-offset-bottom) * -1); // transition: transform 250ms ease 0s, opacity 250ms ease 0s; } // &.start-scroll { ion-fab { transform: translateY(200px) scale3d(0, 0, 0) !important; } } } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\markdown-theme.scss /** * MIT License * Copyright (c) 2021 Ayush Saini * Holi Theme for prism.js * @author Ayush Saini <@AyushCodes on Twitter> */ code[class*='language-'], pre[class*='language-'] { color: #d6e7ff; background: #030314; text-shadow: none; font-family: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace; font-size: 1em; line-height: 1.5; letter-spacing: .2px; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; text-align: left; -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; -webkit-hyphens: none; -moz-hyphens: none; -ms-hyphens: none; hyphens: none; } pre[class*='language-']::-moz-selection, pre[class*='language-'] ::-moz-selection, code[class*='language-']::-moz-selection, code[class*='language-'] ::-moz-selection, pre[class*='language-']::selection, pre[class*='language-'] ::selection, code[class*='language-']::selection, code[class*='language-'] ::selection { color: inherit; background: #1d3b54; text-shadow: none; } pre[class*='language-'] { border: 1px solid #2a4555; border-radius: 5px; padding: 1.5em 1em; margin: 1em 0; overflow: auto; } :not(pre) > code[class*='language-'] { color: #f0f6f6; background: #2a4555; padding: 0.2em 0.3em; border-radius: 0.2em; box-decoration-break: clone; } .token.comment, .token.prolog, .token.doctype, .token.cdata { color: #446e69; } .token.punctuation { color: #d6b007; } .token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: #d6e7ff; } .token.selector, .token.attr-name, .token.builtin, .token.inserted { color: #e60067; } .token.string, .token.char { color: #49c6ec; } .token.operator, .token.entity, .token.url, .language-css .token.string, .style .token.string { color: #ec8e01; background: transparent; } .token.atrule, .token.attr-value, .token.keyword { color: #0fe468; } .token.function, .token.class-name { color: #78f3e9; } .token.regex, .token.important, .token.variable { color: #d6e7ff; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\material-fonts.scss // //#region Material Fonts ... /* cyrillic-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 300; src: local("Roboto Light"), local("Roboto-Light"), url("../assets/font/KFOlCnqEu92Fr1MmSU5fCRc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 300; src: local("Roboto Light"), local("Roboto-Light"), url("../assets/font/KFOlCnqEu92Fr1MmSU5fABc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 300; src: local("Roboto Light"), local("Roboto-Light"), url("../assets/font/KFOlCnqEu92Fr1MmSU5fCBc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 300; src: local("Roboto Light"), local("Roboto-Light"), url("../assets/font/KFOlCnqEu92Fr1MmSU5fBxc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 300; src: local("Roboto Light"), local("Roboto-Light"), url("../assets/font/KFOlCnqEu92Fr1MmSU5fCxc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 300; src: local("Roboto Light"), local("Roboto-Light"), url("../assets/font/KFOlCnqEu92Fr1MmSU5fChc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 300; src: local("Roboto Light"), local("Roboto-Light"), url("../assets/font/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* Persian */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 300; src: url("../assets/font/irsans.ttf"); unicode-renge: U+0621, U+0623, U+0626, U+0624, U+0627, U+0628, U+067E, U+062A, U+062B, U+062C, U+0686, U+062D, U+062E, U+062F, U+0630, U+0631, U+0632, U+0698, U+0633, U+0634, U+0635, U+0636, U+0637, U+0638, U+0639, U+063A, U+0641, U+0642, U+06A9, U+06AF, U+0644, U+0645, U+0646, U+0648, U+0647, U+06CC, U+0622, U+06C0, U+0644, U+0627, U+0640, U+067E, U+0686, U+0698, U+06AF, U+0660, U+0661, U+0662, U+0663, U+0664, U+0665, U+0666, U+0667, U+0668, U+0669, U+064A, U+0643; } /* cyrillic-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; src: local("Roboto"), local("Roboto-Regular"), url("../assets/font/KFOmCnqEu92Fr1Mu72xKKTU1Kvnz.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; src: local("Roboto"), local("Roboto-Regular"), url("../assets/font/KFOmCnqEu92Fr1Mu5mxKKTU1Kvnz.woff2") format("woff2"); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; src: local("Roboto"), local("Roboto-Regular"), url("../assets/font/KFOmCnqEu92Fr1Mu7mxKKTU1Kvnz.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; src: local("Roboto"), local("Roboto-Regular"), url("../assets/font/KFOmCnqEu92Fr1Mu4WxKKTU1Kvnz.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; src: local("Roboto"), local("Roboto-Regular"), url("../assets/font/KFOmCnqEu92Fr1Mu7WxKKTU1Kvnz.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; src: local("Roboto"), local("Roboto-Regular"), url("../assets/font/KFOmCnqEu92Fr1Mu7GxKKTU1Kvnz.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; src: local("Roboto"), local("Roboto-Regular"), url("../assets/font/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* Persian */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 400; src: url("../assets/font/irsans.ttf"); unicode-renge: U+0621, U+0623, U+0626, U+0624, U+0627, U+0628, U+067E, U+062A, U+062B, U+062C, U+0686, U+062D, U+062E, U+062F, U+0630, U+0631, U+0632, U+0698, U+0633, U+0634, U+0635, U+0636, U+0637, U+0638, U+0639, U+063A, U+0641, U+0642, U+06A9, U+06AF, U+0644, U+0645, U+0646, U+0648, U+0647, U+06CC, U+0622, U+06C0, U+0644, U+0627, U+0640, U+067E, U+0686, U+0698, U+06AF, U+0660, U+0661, U+0662, U+0663, U+0664, U+0665, U+0666, U+0667, U+0668, U+0669, U+064A, U+0643; } /* cyrillic-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; src: local("Roboto Medium"), local("Roboto-Medium"), url("../assets/font/KFOlCnqEu92Fr1MmEU9fCRc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; } /* cyrillic */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; src: local("Roboto Medium"), local("Roboto-Medium"), url("../assets/font/KFOlCnqEu92Fr1MmEU9fABc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; } /* greek-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; src: local("Roboto Medium"), local("Roboto-Medium"), url("../assets/font/KFOlCnqEu92Fr1MmEU9fCBc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+1F00-1FFF; } /* greek */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; src: local("Roboto Medium"), local("Roboto-Medium"), url("../assets/font/KFOlCnqEu92Fr1MmEU9fBxc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0370-03FF; } /* vietnamese */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; src: local("Roboto Medium"), local("Roboto-Medium"), url("../assets/font/KFOlCnqEu92Fr1MmEU9fCxc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0102-0103, U+0110-0111, U+1EA0-1EF9, U+20AB; } /* latin-ext */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; src: local("Roboto Medium"), local("Roboto-Medium"), url("../assets/font/KFOlCnqEu92Fr1MmEU9fChc4AMP6lbBP.woff2") format("woff2"); unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; } /* latin */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; src: local("Roboto Medium"), local("Roboto-Medium"), url("../assets/font/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2") format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; } /* Persian */ @font-face { font-family: "Roboto"; font-style: normal; font-weight: 500; src: url("../assets/font/irsans.ttf"); unicode-renge: U+0621, U+0623, U+0626, U+0624, U+0627, U+0628, U+067E, U+062A, U+062B, U+062C, U+0686, U+062D, U+062E, U+062F, U+0630, U+0631, U+0632, U+0698, U+0633, U+0634, U+0635, U+0636, U+0637, U+0638, U+0639, U+063A, U+0641, U+0642, U+06A9, U+06AF, U+0644, U+0645, U+0646, U+0648, U+0647, U+06CC, U+0622, U+06C0, U+0644, U+0627, U+0640, U+067E, U+0686, U+0698, U+06AF, U+0660, U+0661, U+0662, U+0663, U+0664, U+0665, U+0666, U+0667, U+0668, U+0669, U+064A, U+0643; } //#endregion // //#region Material Design Icons ... @font-face { font-family: "Material Icons"; font-style: normal; font-weight: 400; src: url("../assets/font/flUhRq6tzZclQEJ-Vdg-IuiaDsNcIhQ8tQ.woff2") format("woff2"); } .material-icons { font-family: "Material Icons"; font-weight: normal; font-style: normal; font-size: 24px; line-height: 1; letter-spacing: normal; text-transform: none; display: inline-block; white-space: nowrap; word-wrap: normal; direction: ltr; -webkit-font-feature-settings: "liga"; -webkit-font-smoothing: antialiased; } //#endregion @mixin x-toolbar-typography($config) { .mat-toolbar { @include mat-typography-level-to-styles($config, body-2); margin: 0; } .mat-toolbar h1 { @include mat-typography-level-to-styles($config, headline); margin: 0; } .mat-toolbar h2 { @include mat-typography-level-to-styles($config, title); margin: 0; } .mat-toolbar h3 { @include mat-typography-level-to-styles($config, subheading-2); margin: 0; } .mat-toolbar h4 { @include mat-typography-level-to-styles($config, subheading-1); margin: 0; } .mat-toolbar h5 { @include mat-typography-level-to-styles($config, body-1); margin: 0; } .mat-toolbar h6 { @include mat-typography-level-to-styles($config, caption); margin: 0; } } body { @extend .mat-typography; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\material-icons.scss @font-face { font-family: 'Material Icons'; font-style: normal; font-weight: 400; src: url('../assets/font/MaterialIcons-Regular.eot'); /* For IE6-8 */ src: local('Material Icons'), local('MaterialIcons-Regular'), url('../assets/font/MaterialIcons-Regular.woff2') format('woff2'), url('../assets/font/MaterialIcons-Regular.woff') format('woff'), url('../assets/font/MaterialIcons-Regular.ttf') format('truetype'); } .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; font-size: 24px; /* Preferred icon size */ display: inline-block; line-height: 1; text-transform: none; letter-spacing: normal; word-wrap: normal; white-space: nowrap; direction: ltr; /* Support for all WebKit browsers. */ -webkit-font-smoothing: antialiased; /* Support for Safari and Chrome. */ text-rendering: optimizeLegibility; /* Support for Firefox. */ -moz-osx-font-smoothing: grayscale; /* Support for IE. */ font-feature-settings: 'liga'; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\theme\theme.scss @import "./base-theme.scss"; @import "./material-icons.scss"; @import "./material-fonts.scss"; @import "./markdown-theme.scss"; @import "./fab-theme.scss"; @include mat-core(); $x-primary: mat-palette($mat-blue); $x-accent: mat-palette($mat-cyan); $x-warn: mat-palette($mat-red); // Create the theme object (a Sass map containing all of the palettes). $x-theme: mat-light-theme($x-primary, $x-accent, $x-warn); @include angular-material-theme($x-theme); // @function generate-x-theme($primary, $accent, $warn) { // $x-primary: $primary; $x-accent: $accent; $x-warn: $warn; // $x-theme: mat-light-theme($primary, $accent, $warn); // @return $x-theme; } // @mixin x-theme($theme) { @include angular-material-theme($theme); } // @mixin x-ion-color() { // // XFramework Color Mechanism ... :root { --x-color-primary: var(--ion-color-primary); --x-color-primary-shade: var(--ion-color-primary-shade); --x-color-primary-tint: var(--ion-color-primary-tint); --x-color-secondary: var(--ion-color-secondary); --x-color-secondary-shade: var(--ion-color-secondary-shade); --x-color-secondary-tint: var(--ion-color-secondary-tint); --x-color-tertiary: var(--ion-color-tertiary); --x-color-tertiary-shade: var(--ion-color-tertiary-shade); --x-color-tertiary-tint: var(--ion-color-tertiary-tint); --x-color-success: var(--ion-color-success); --x-color-success-shade: var(--ion-color-success-shade); --x-color-success-tint: var(--ion-color-success-tint); --x-color-warning: var(--ion-color-warning); --x-color-warning-shade: var(--ion-color-warning-shade); --x-color-warning-tint: var(--ion-color-warning-tint); --x-color-danger: var(--ion-color-danger); --x-color-danger-shade: var(--ion-color-danger-shade); --x-color-danger-tint: var(--ion-color-danger-tint); --x-color-dark: var(--ion-color-dark); --x-color-dark-shade: var(--ion-color-dark-shade); --x-color-dark-tint: var(--ion-color-dark-tint); --x-color-medium: var(--ion-color-medium); --x-color-medium-shade: var(--ion-color-medium-shade); --x-color-medium-tint: var(--ion-color-medium-tint); --x-color-light: var(--ion-color-light); --x-color-light-shade: var(--ion-color-light-shade); --x-color-light-tint: var(--ion-color-light-tint); --x-color-primary-contrast: var(--ion-color-primary-contrast); --x-color-primary-shade-contrast: var(--ion-color-primary-contrast); --x-color-primary-tint-contrast: var(--ion-color-primary-contrast); --x-color-secondary-contrast: var(--ion-color-secondary-contrast); --x-color-secondary-shade-contrast: var(--ion-color-secondary-contrast); --x-color-secondary-tint-contrast: var(--ion-color-secondary-contrast); --x-color-tertiary-contrast: var(--ion-color-tertiary-contrast); --x-color-tertiary-shade-contrast: var(--ion-color-tertiary-contrast); --x-color-tertiary-tint-contrast: var(--ion-color-tertiary-contrast); --x-color-success-contrast: var(--ion-color-success-contrast); --x-color-success-shade-contrast: var(--ion-color-success-contrast); --x-color-success-tint-contrast: var(--ion-color-success-contrast); --x-color-warning-contrast: var(--ion-color-warning-contrast); --x-color-warning-shade-contrast: var(--ion-color-warning-contrast); --x-color-warning-tint-contrast: var(--ion-color-warning-contrast); --x-color-danger-contrast: var(--ion-color-danger-contrast); --x-color-danger-shade-contrast: var(--ion-color-danger-contrast); --x-color-danger-tint-contrast: var(--ion-color-danger-contrast); --x-color-dark-contrast: var(--ion-color-dark-contrast); --x-color-dark-shade-contrast: var(--ion-color-dark-contrast); --x-color-dark-tint-contrast: var(--ion-color-dark-contrast); --x-color-medium-contrast: var(--ion-color-medium-contrast); --x-color-medium-shade-contrast: var(--ion-color-medium-contrast); --x-color-medium-tint-contrast: var(--ion-color-medium-contrast); --x-color-light-contrast: var(--ion-color-light-contrast); --x-color-light-shade-contrast: var(--ion-color-light-contrast); --x-color-light-tint-contras: var(--ion-color-light-contrast); } // // Define a Palette Based on Collection ... $m-color-palette: mat-palette($m-color-collection, m-ionic); // // Merge Defined Palette to Theme Object ... $x-theme: map_merge( $x-theme, ( m-ionic: $m-color-palette, ) ); // // Generate a General Object for feauture Usages ... $x-ionic: map-get($x-theme, m-ionic); } // @mixin x-to-ion-color() { // // XFramework Color Mechanism ... :root { --ion-color-primary: var(--x-color-primary); --ion-color-primary-shade: var(--x-color-primary-shade); --ion-color-primary-tint: var(--x-color-primary-tint); --ion-color-primary-contrast: var(--x-color-primary-contrast); --ion-color-primary-contrast: var(--x-color-primary-contrast); --ion-color-primary-contrast: var(--x-color-primary-contrast); --ion-color-secondary: var(--x-color-secondary); --ion-color-secondary-shade: var(--x-color-secondary-shade); --ion-color-secondary-tint: var(--x-color-secondary-tint); --ion-color-secondary-contrast: var(--x-color-secondary-contrast); --ion-color-secondary-contrast: var(--x-color-secondary-contrast); --ion-color-secondary-contrast: var(--x-color-secondary-contrast); --ion-color-tertiary: var(--x-color-tertiary); --ion-color-tertiary-shade: var(--x-color-tertiary-shade); --ion-color-tertiary-tint: var(--x-color-tertiary-tint); --ion-color-tertiary-contrast: var(--x-color-tertiary-contrast); --ion-color-tertiary-contrast: var(--x-color-tertiary-contrast); --ion-color-tertiary-contrast: var(--x-color-tertiary-contrast); --ion-color-success: var(--x-color-success); --ion-color-success-shade: var(--x-color-success-shade); --ion-color-success-tint: var(--x-color-success-tint); --ion-color-success-contrast: var(--x-color-success-contrast); --ion-color-success-contrast: var(--x-color-success-contrast); --ion-color-success-contrast: var(--x-color-success-contrast); --ion-color-warning: var(--x-color-warning); --ion-color-warning-shade: var(--x-color-warning-shade); --ion-color-warning-tint: var(--x-color-warning-tint); --ion-color-warning-contrast: var(--x-color-warning-contrast); --ion-color-warning-contrast: var(--x-color-warning-contrast); --ion-color-warning-contrast: var(--x-color-warning-contrast); --ion-color-danger: var(--x-color-danger); --ion-color-danger-shade: var(--x-color-danger-shade); --ion-color-danger-tint: var(--x-color-danger-tint); --ion-color-danger-contrast: var(--x-color-danger-contrast); --ion-color-danger-contrast: var(--x-color-danger-contrast); --ion-color-danger-contrast: var(--x-color-danger-contrast); --ion-color-dark: var(--x-color-dark); --ion-color-dark-shade: var(--x-color-dark-shade); --ion-color-dark-tint: var(--x-color-dark-tint); --ion-color-dark-contrast: var(--x-color-dark-contrast); --ion-color-dark-contrast: var(--x-color-dark-contrast); --ion-color-dark-contrast: var(--x-color-dark-contrast); --ion-color-medium: var(--x-color-medium); --ion-color-medium-shade: var(--x-color-medium-shade); --ion-color-medium-tint: var(--x-color-medium-tint); --ion-color-medium-contrast: var(--x-color-medium-contrast); --ion-color-medium-contrast: var(--x-color-medium-contrast); --ion-color-medium-contrast: var(--x-color-medium-contrast); --ion-color-light: var(--x-color-light); --ion-color-light-shade: var(--x-color-light-shade); --ion-color-light-tint: var(--x-color-light-tint); --ion-color-light-contrast: var(--x-color-light-contrast); --ion-color-light-contrast: var(--x-color-light-contrast); --ion-color-light-contrast: var(--x-color-light-contrast); } // // Define a Palette Based on Collection ... $m-color-palette: mat-palette($m-color-collection, m-ionic); // // Merge Defined Palette to Theme Object ... $x-theme: map_merge( $x-theme, ( m-ionic: $m-color-palette, ) ); // // Generate a General Object for feauture Usages ... $x-ionic: map-get($x-theme, m-ionic); } // //#region Custom Ionic Based Colors ... // //#region Define a Collection ... $m-color-collection: ( primary: var(--x-color-primary), primary-shade: var(--x-color-primary-shade), primary-tint: var(--x-color-primary-tint), secondary: var(--x-color-secondary), secondary-shade: var(--x-color-secondary-shade), secondary-tint: var(--x-color-secondary-tint), tertiary: var(--x-color-tertiary), tertiary-shade: var(--x-color-tertiary-shade), tertiary-tint: var(--x-color-tertiary-tint), success: var(--x-color-success), success-shade: var(--x-color-success-shade), success-tint: var(--x-color-success-tint), warning: var(--x-color-warning), warning-shade: var(--x-color-warning-shade), warning-tint: var(--x-color-warning-tint), danger: var(--x-color-danger), danger-shade: var(--x-color-danger-shade), danger-tint: var(--x-color-danger-tint), dark: var(--x-color-dark), dark-shade: var(--x-color-dark-shade), dark-tint: var(--x-color-dark-tint), medium: var(--x-color-medium), medium-shade: var(--x-color-medium-shade), medium-tint: var(--x-color-medium-tint), light: var(--x-color-light), light-shade: var(--x-color-light-shade), light-tint: var(--x-color-light-tint), contrast: ( primary: var(--x-color-primary-contrast), primary-shade: var(--x-color-primary-shade-contrast), primary-tint: var(--x-color-primary-tint-contrast), secondary: var(--x-color-secondary-contrast), secondary-shade: var(--x-color-secondary-shade-contrast), secondary-tint: var(--x-color-secondary-tint-contrast), tertiary: var(--x-color-tertiary-contrast), tertiary-shade: var(--x-color-tertiary-shade-contrast), tertiary-tint: var(--x-color-tertiary-tint-contrast), success: var(--x-color-success-contrast), success-shade: var(--x-color-success-shade-contrast), success-tint: var(--x-color-success-tint-contrast), warning: var(--x-color-warning-contrast), warning-shade: var(--x-color-warning-shade-contrast), warning-tint: var(--x-color-warning-tint-contrast), danger: var(--x-color-danger-contrast), danger-shade: var(--x-color-danger-shade-contrast), danger-tint: var(--x-color-danger-tint-contrast), dark: var(--x-color-dark-contrast), dark-shade: var(--x-color-dark-shade-contrast), dark-tint: var(--x-color-dark-tint-contrast), medium: var(--x-color-medium-contrast), medium-shade: var(--x-color-medium-shade-contrast), medium-tint: var(--x-color-medium-tint-contrast), light: var(--x-color-light-contrast), light-shade: var(--x-color-light-shade-contrast), light-tint: var(--x-color-light-tint-contrast), ), ); //#endregion // // Define a Palette Based on Collection ... $m-color-palette: mat-palette($m-color-collection, m-ionic); // // Merge Defined Palette to Theme Object ... $x-theme: map_merge( $x-theme, ( m-ionic: $m-color-palette, ) ); // // Generate a General Object for feauture Usages ... $x-ionic: map-get($x-theme, m-ionic); // //#region Generate General Classes for Support these Colors ... // //#region Primary ... .mat-primary { // color: mat-color($x-ionic, primary-contrast) !important; background-color: mat-color($x-ionic, primary) !important; // --color: mat-color($x-ionic, primary-contrast) !important; --background: mat-color($x-ionic, primary) !important; } .mat-primary-shade { // color: mat-color($x-ionic, primary-shade-contrast) !important; background-color: mat-color($x-ionic, primary-shade) !important; // --color: mat-color($x-ionic, primary-shade-contrast) !important; --background: mat-color($x-ionic, primary-shade) !important; } .mat-primary-tint { // color: mat-color($x-ionic, primary-tint-contrast) !important; background-color: mat-color($x-ionic, primary-tint) !important; // --color: mat-color($x-ionic, primary-tint-contrast) !important; --background: mat-color($x-ionic, primary-tint) !important; } .c-primary { // color: mat-color($x-ionic, primary) !important; // --color: mat-color($x-ionic, primary) !important; } .c-primary-shade { // color: mat-color($x-ionic, primary-shade) !important; // --color: mat-color($x-ionic, primary-shade) !important; } .c-primary-tint { // color: mat-color($x-ionic, primary-tint) !important; // --color: mat-color($x-ionic, primary-tint) !important; } //#endregion // //#region Secondary ... .mat-secondary { // color: mat-color($x-ionic, secondary-contrast) !important; background-color: mat-color($x-ionic, secondary) !important; // --color: mat-color($x-ionic, secondary-contrast) !important; --background: mat-color($x-ionic, secondary) !important; } .mat-secondary-shade { // color: mat-color($x-ionic, secondary-shade-contrast) !important; background-color: mat-color($x-ionic, secondary-shade) !important; // --color: mat-color($x-ionic, secondary-shade-contrast) !important; --background: mat-color($x-ionic, secondary-shade) !important; } .mat-secondary-tint { // color: mat-color($x-ionic, secondary-tint-contrast) !important; background-color: mat-color($x-ionic, secondary-tint) !important; // --color: mat-color($x-ionic, secondary-tint-contrast) !important; --background: mat-color($x-ionic, secondary-tint) !important; } .c-secondary { // color: mat-color($x-ionic, secondary) !important; // --color: mat-color($x-ionic, secondary) !important; } .c-secondary-shade { // color: mat-color($x-ionic, secondary-shade) !important; // --color: mat-color($x-ionic, secondary-shade) !important; } .c-secondary-tint { // color: mat-color($x-ionic, secondary-tint) !important; // --color: mat-color($x-ionic, secondary-tint) !important; } //#endregion // //#region Tertiary ... .mat-tertiary { // color: mat-color($x-ionic, tertiary-contrast) !important; background-color: mat-color($x-ionic, tertiary) !important; // --color: mat-color($x-ionic, tertiary-contrast) !important; --background: mat-color($x-ionic, tertiary) !important; } .mat-tertiary-shade { // color: mat-color($x-ionic, tertiary-shade-contrast) !important; background-color: mat-color($x-ionic, tertiary-shade) !important; // --color: mat-color($x-ionic, tertiary-shade-contrast) !important; --background: mat-color($x-ionic, tertiary-shade) !important; } .mat-tertiary-tint { // color: mat-color($x-ionic, tertiary-tint-contrast) !important; background-color: mat-color($x-ionic, tertiary-tint) !important; // --color: mat-color($x-ionic, tertiary-tint-contrast) !important; --background: mat-color($x-ionic, tertiary-tint) !important; } .c-tertiary { // color: mat-color($x-ionic, tertiary) !important; // --color: mat-color($x-ionic, tertiary) !important; } .c-tertiary-shade { // color: mat-color($x-ionic, tertiary-shade) !important; // --color: mat-color($x-ionic, tertiary-shade) !important; } .c-tertiary-tint { // color: mat-color($x-ionic, tertiary-tint) !important; // --color: mat-color($x-ionic, tertiary-tint) !important; } //#endregion // //#region Success ... .mat-success { // color: mat-color($x-ionic, success-contrast) !important; background-color: mat-color($x-ionic, success) !important; // --color: mat-color($x-ionic, success-contrast) !important; --background: mat-color($x-ionic, success) !important; } .mat-success-shade { // color: mat-color($x-ionic, success-shade-contrast) !important; background-color: mat-color($x-ionic, success-shade) !important; // --color: mat-color($x-ionic, success-shade-contrast) !important; --background: mat-color($x-ionic, success-shade) !important; } .mat-success-tint { // color: mat-color($x-ionic, success-tint-contrast) !important; background-color: mat-color($x-ionic, success-tint) !important; // --color: mat-color($x-ionic, success-tint-contrast) !important; --background: mat-color($x-ionic, success-tint) !important; } .c-success { // color: mat-color($x-ionic, success) !important; // --color: mat-color($x-ionic, success) !important; } .c-success-shade { // color: mat-color($x-ionic, success-shade) !important; // --color: mat-color($x-ionic, success-shade) !important; } .c-success-tint { // color: mat-color($x-ionic, success-tint) !important; // --color: mat-color($x-ionic, success-tint) !important; } //#endregion // //#region Warning ... .mat-warning { // color: mat-color($x-ionic, warning-contrast) !important; background-color: mat-color($x-ionic, warning) !important; // --color: mat-color($x-ionic, warning-contrast) !important; --background: mat-color($x-ionic, warning) !important; } .mat-warning-shade { // color: mat-color($x-ionic, warning-shade-contrast) !important; background-color: mat-color($x-ionic, warning-shade) !important; // --color: mat-color($x-ionic, warning-shade-contrast) !important; --background: mat-color($x-ionic, warning-shade) !important; } .mat-warning-tint { // color: mat-color($x-ionic, warning-tint-contrast) !important; background-color: mat-color($x-ionic, warning-tint) !important; // --color: mat-color($x-ionic, warning-tint-contrast) !important; --background: mat-color($x-ionic, warning-tint) !important; } .c-warning { // color: mat-color($x-ionic, warning) !important; // --color: mat-color($x-ionic, warning) !important; } .c-warning-shade { // color: mat-color($x-ionic, warning-shade) !important; // --color: mat-color($x-ionic, warning-shade) !important; } .c-warning-tint { // color: mat-color($x-ionic, warning-tint) !important; // --color: mat-color($x-ionic, warning-tint) !important; } //#endregion // //#region Danger ... .mat-danger { // color: mat-color($x-ionic, danger-contrast) !important; background-color: mat-color($x-ionic, danger) !important; // --color: mat-color($x-ionic, danger-contrast) !important; --background: mat-color($x-ionic, danger) !important; } .mat-danger-shade { // color: mat-color($x-ionic, danger-shade-contrast) !important; background-color: mat-color($x-ionic, danger-shade) !important; // --color: mat-color($x-ionic, danger-shade-contrast) !important; --background: mat-color($x-ionic, danger-shade) !important; } .mat-danger-tint { // color: mat-color($x-ionic, danger-tint-contrast) !important; background-color: mat-color($x-ionic, danger-tint) !important; // --color: mat-color($x-ionic, danger-tint-contrast) !important; --background: mat-color($x-ionic, danger-tint) !important; } .c-danger { // color: mat-color($x-ionic, danger) !important; // --color: mat-color($x-ionic, danger) !important; } .c-danger-shade { // color: mat-color($x-ionic, danger-shade) !important; // --color: mat-color($x-ionic, danger-shade) !important; } .c-danger-tint { // color: mat-color($x-ionic, danger-tint) !important; // --color: mat-color($x-ionic, danger-tint) !important; } //#endregion // //#region Dark ... .mat-dark { // color: mat-color($x-ionic, dark-contrast) !important; background-color: mat-color($x-ionic, dark) !important; // --color: mat-color($x-ionic, dark-contrast) !important; --background: mat-color($x-ionic, dark) !important; } .mat-dark-shade { // color: mat-color($x-ionic, dark-shade-contrast) !important; background-color: mat-color($x-ionic, dark-shade) !important; // --color: mat-color($x-ionic, dark-shade-contrast) !important; --background: mat-color($x-ionic, dark-shade) !important; } .mat-dark-tint { // color: mat-color($x-ionic, dark-tint-contrast) !important; background-color: mat-color($x-ionic, dark-tint) !important; // --color: mat-color($x-ionic, dark-tint-contrast) !important; --background: mat-color($x-ionic, dark-tint) !important; } .c-dark { // color: mat-color($x-ionic, dark) !important; // --color: mat-color($x-ionic, dark) !important; } .c-dark-shade { // color: mat-color($x-ionic, dark-shade) !important; // --color: mat-color($x-ionic, dark-shade) !important; } .c-dark-tint { // color: mat-color($x-ionic, dark-tint) !important; // --color: mat-color($x-ionic, dark-tint) !important; } //#endregion // //#region Medium ... .mat-medium { // color: mat-color($x-ionic, medium-contrast) !important; background-color: mat-color($x-ionic, medium) !important; // --color: mat-color($x-ionic, medium-contrast) !important; --background: mat-color($x-ionic, medium) !important; } .mat-medium-shade { // color: mat-color($x-ionic, medium-shade-contrast) !important; background-color: mat-color($x-ionic, medium-shade) !important; // --color: mat-color($x-ionic, medium-shade-contrast) !important; --background: mat-color($x-ionic, medium-shade) !important; } .mat-medium-tint { // color: mat-color($x-ionic, medium-tint-contrast) !important; background-color: mat-color($x-ionic, medium-tint) !important; // --color: mat-color($x-ionic, medium-tint-contrast) !important; --background: mat-color($x-ionic, medium-tint) !important; } .c-medium { // color: mat-color($x-ionic, medium) !important; // --color: mat-color($x-ionic, medium) !important; } .c-medium-shade { // color: mat-color($x-ionic, medium-shade) !important; // --color: mat-color($x-ionic, medium-shade) !important; } .c-medium-tint { // color: mat-color($x-ionic, medium-tint) !important; // --color: mat-color($x-ionic, medium-tint) !important; } //#endregion // //#region Light ... .mat-light { // color: mat-color($x-ionic, light-contrast) !important; background-color: mat-color($x-ionic, light) !important; // --color: mat-color($x-ionic, light-contrast) !important; --background: mat-color($x-ionic, light) !important; } .mat-light-shade { // color: mat-color($x-ionic, light-shade-contrast) !important; background-color: mat-color($x-ionic, light-shade) !important; // --color: mat-color($x-ionic, light-shade-contrast) !important; --background: mat-color($x-ionic, light-shade) !important; } .mat-light-tint { // color: mat-color($x-ionic, light-tint-contrast) !important; background-color: mat-color($x-ionic, light-tint) !important; // --color: mat-color($x-ionic, light-tint-contrast) !important; --background: mat-color($x-ionic, light-tint) !important; } .c-light { // color: mat-color($x-ionic, light) !important; // --color: mat-color($x-ionic, light) !important; } .c-light-shade { // color: mat-color($x-ionic, light-shade) !important; // --color: mat-color($x-ionic, light-shade) !important; } .c-light-tint { // color: mat-color($x-ionic, light-tint) !important; // --color: mat-color($x-ionic, light-tint) !important; } //#endregion //#endregion .cb-inherit { // color: inherit !important; --color: inherit !important; // background-color: inherit !important; --background-color: inherit !important; } .transparent { --background: transparent !important; background-color: transparent !important; } //#endregion // //#region Custom Styles ... html, body { height: 100%; } body { margin: 0; padding: 0; overflow-x: hidden; font-family: Roboto, "Helvetica Neue", sans-serif; } * { box-sizing: border-box; } *::-webkit-scrollbar { display: none; } [hidden] { display: none !important; } //#endregion // @import "_tools"; // // Since here we must able to use all Capabilities, // so we import this at the end ... @import "./custom-effects.scss"; // // Implement to ionic them ... @include x-to-ion-color(); ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\tokens\x-injectable-tokens.ts import { InjectionToken } from '@angular/core'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export const X_FRAMEWORK_COMPONENTS_CONFIG = new InjectionToken< XFrameworkComponentsConfig >('x_config'); ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.component.html
{{ getResourceValue(action.title) | async }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.component.scss $action-item-margin: var(--action-items-offset, 2px); $action-item-gutter: var(--action-items-gutter, 8px); .x-actions-bar { padding: { left: $action-item-gutter !important; right: $action-item-gutter !important; } } .x-action-bar-item { margin: { left: $action-item-margin !important; right: $action-item-margin !important; } } .x-action-bar-item-inner { display: flex; align-items: center; > * { margin: { left: 2px !important; right: 2px !important; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.component.ts import { sort, nameof, toArray, isFunction, filterList, isNullOrEmptyString, } from 'x-framework-core'; import { XActionBarItem, XActionBarAction, XActionBarItemSlot, XActionBarActionModel, XActionBarActionIdentifier, XActionBarItemSlotIdentifier, XActionBarContainerComponent, } from './x-action-bar.typings'; import { map } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs'; import { XButtonType } from '../x-button/x-button.typings'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-action-bar', templateUrl: './x-action-bar.component.html', styleUrls: ['./x-action-bar.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XActionBarComponent extends XActionBarContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // private ACTIONS: XActionBarItem[] = []; private ACTIONS_HIDDEN: Map = new Map(); private ACTIONS_DISABLED: Map = new Map(); // readonly ButtonTypes = Object.assign({}, XButtonType); get preparedActions() { return this.ACTIONS; } //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Actions Changed ... // const isActionsChanged = changeKeys.includes( nameof('actions') ); if (isActionsChanged) { await this.prepareActions(); } //#endregion // //#region Action Provider Changed ... // const isActionProviderChaged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChaged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... // //#region Slot Based Items Fetcher ... getSlotItems(slot: XActionBarItemSlotIdentifier) { return filterList(this.actions, (action) => this.getValue(action.slot).pipe(map((iSlot) => iSlot === slot)) ); } getStartSoltItems() { return this.getSlotItems(XActionBarItemSlot.START); } getEndSoltItems() { return this.getSlotItems(XActionBarItemSlot.END); } isOnlyIcon(item: XActionBarItem) { return this.getOptionalValue(item.onlyIcon).pipe( map((onlyIcon) => !!onlyIcon) ); } isDisabledAction(item: XActionBarItem) { // if (!item) { return this.getValue(false); } // return this.getValue(item.id).pipe( map((id) => isNullOrEmptyString(id) ? false : this.ACTIONS_DISABLED.has(id) ? this.ACTIONS_DISABLED.get(id) : false ) ); } isHidedAction(item: XActionBarItem) { // if (!item) { return this.getValue(false); } // return this.getValue(item.id).pipe( map((id) => isNullOrEmptyString(id) ? false : this.ACTIONS_HIDDEN.has(id) ? this.ACTIONS_HIDDEN.get(id) : false ) ); } //#endregion async getActionIds() { // if (!this.hasChild(this.preparedActions)) { return []; } // const IDS = this.preparedActions.map((a) => this.getValueAsync(a.id)); // return await Promise.all(IDS); } //#endregion // //#region UI Handlers ... async handleActionClicked(item: XActionBarItem, event: Event) { // const disabled = await this.getValueAsync(item.disabled); if (disabled || this.uiDisabled || this.loading) { return; } // const id = await this.getValueAsync(item.id); // if (item.handler && isFunction(item.handler)) { await item.handler({ action: id, event, }); } // this.actionFired.emit({ action: id, event, }); } //#endregion // //#region Actions ... /** * check an action with specific id exists in actions or not ... * * @param id required action id ... */ async isActionExists(id: string) { return (await this.getActionIds()).findIndex((i) => i === id) > -1; } /** * retrieve all actions ... */ async getActions() { // const ACTIONS_TYPE = await this.getValueAsync(this.actions); if (!ACTIONS_TYPE) { return []; } // return toArray(ACTIONS_TYPE); } /** * retrieve an action ... * * @param id action id */ async getAction(id: string) { // const isExists = await this.isActionExists(id); if (!isExists) { return null; } // const ACTIONS = await this.getActions(); if (!this.hasChild(ACTIONS)) { return null; } // const existsAction = ACTIONS.find( async (a) => (await this.getValueAsync(a.id)) === id ); // return this.toPreparedAction(existsAction); } /** * manually fire a registered action * * @param id action id */ async fireAction(id: string, event?: Event) { // const isExist = await this.isActionExists(id); if (!isExist) { return; } // const action = await this.getAction(id); if (!action) { return; } // const canFire = !this.uiDisabled && !this.loading && !(await this.getOptionalValueAsync(action.disabled)); if (!canFire) { return; } // await this.handleActionClicked(action, event); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe( async (action) => await this.handleActionProviderAction(action) ); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // private async prepareActions() { // this.ACTIONS = null; if (!this.actions) { // this.detectChanges(); return; } // const ACTIONS_TYPE = await this.getValueAsync(this.actions); if (!ACTIONS_TYPE) { // this.detectChanges(); return; } // const ACTIONS = toArray(ACTIONS_TYPE); if (!this.hasChild(ACTIONS)) { // this.detectChanges(); return; } // this.ACTIONS = [ ...sort(ACTIONS, (a, b) => (a.index && b.index ? a.index - b.index : -1)), ]; // for (const a of this.ACTIONS) { // const id = await this.getValueAsync(a.id); // if (!this.ACTIONS_DISABLED.has(id)) { this.ACTIONS_DISABLED.set(id, false); } // if (!this.ACTIONS_HIDDEN.has(id)) { this.ACTIONS_HIDDEN.set(id, false); } } // this.detectChanges(); } private async actionsCount() { return (await this.getActions()).length || 0; } private async findActionIdex(id: string) { // const isExists = await this.isActionExists(id); if (!isExists) { return -1; } // const ACTIONS_TYPE = await this.getValueAsync(this.actions); if (!ACTIONS_TYPE) { return null; } // const ACTIONS = toArray(ACTIONS_TYPE); if (!this.hasChild(ACTIONS)) { return null; } // return ACTIONS.findIndex( async (a) => (await this.getValueAsync(a.id)) === id ); } private async toPreparedAction(item: XActionBarItem) { // if (!item) { return null; } // return { index: item.index, handler: item.handler, id: await this.getValueAsync(item.id), icon: await this.getValueAsync(item.icon), slot: await this.getValueAsync(item.slot), color: await this.getValueAsync(item.color), title: await this.getValueAsync(item.title), hidden: await this.getValueAsync(item.hidden), onlyIcon: await this.getValueAsync(item.onlyIcon), disabled: await this.getValueAsync(item.disabled), cssClass: await this.getValueAsync(item.cssClass), iconColor: await this.getValueAsync(item.iconColor), titleColor: await this.getValueAsync(item.titleColor), } as XActionBarItem; } private async handleActionProviderAction(model: XActionBarActionModel) { // if (!model || isNullOrEmptyString(model.action)) { return; } // const actionId = await this.getValueAsync(model.id); // switch (model.action) { // case XActionBarAction.Refresh: this.detectChanges(); break; // case XActionBarAction.FireAction: await this.fireAction(model.id, model.event); break; // case XActionBarAction.EnableAction: // if (this.ACTIONS_DISABLED.has(actionId)) { // this.ACTIONS_DISABLED.set(actionId, false); this.detectChanges(); } else { if (!this.hasChild(this.ACTIONS)) { setTimeout(() => this.handleActionProviderAction(model), 500); } } break; // case XActionBarAction.DisbaleAction: // if (this.ACTIONS_DISABLED.has(actionId)) { // this.ACTIONS_DISABLED.set(actionId, true); this.detectChanges(); } else { if (!this.hasChild(this.ACTIONS)) { setTimeout(() => this.handleActionProviderAction(model), 500); } } break; // case XActionBarAction.ShowAction: // if (this.ACTIONS_HIDDEN.has(actionId)) { // this.ACTIONS_HIDDEN.set(actionId, false); this.detectChanges(); } else { if (!this.hasChild(this.ACTIONS)) { setTimeout(() => this.handleActionProviderAction(model), 500); } } break; // case XActionBarAction.HideAction: // if (this.ACTIONS_HIDDEN.has(actionId)) { // this.ACTIONS_HIDDEN.set(actionId, true); this.detectChanges(); } else { if (!this.hasChild(this.ACTIONS)) { setTimeout(() => this.handleActionProviderAction(model), 500); } } break; } } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XButtonModule } from '../x-button/x-button.module'; import { XActionBarComponent } from './x-action-bar.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XActionBarComponent], imports: [XIconModule, CommonModule, XButtonModule, XBaseComponentModule], exports: [ XIconModule, CommonModule, XButtonModule, XActionBarComponent, XBaseComponentModule, ], }) export class XActionBarModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-action-bar\x-action-bar.typings.ts import { XColor, XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { Input, Inject, NgZone, Output, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XBaseContainer, IXBaseContainer, XBaseComponentContainer, XBaseContainerComponent, IXBaseComponentContainer, XBaseComponentContainerComponent, } from '../classes/i-x-base.container'; import { map } from 'rxjs/operators'; import { Observable, forkJoin, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XIconNames, XIconIdentifier } from '../x-icon/x-icon.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region ActionBar Item ... export enum XActionBarItemSlot { START = 'start', END = 'end', } export type XActionBarItemSlotIdentifier = XActionBarItemSlot | string; export interface XActionBarItem { index?: number; id: XStandardType; hidden?: XStandardType; onlyIcon?: XStandardType; disabled?: XStandardType; icon: XStandardType; color?: XStandardType; title?: XStandardType; iconColor?: XStandardType; titleColor?: XStandardType; cssClass?: XStandardType>; slot: XStandardType; handler?: (model?: XActionBarActionFiredModel) => XStandardType; } export interface XActionBarActionFiredModel { action: string; event?: Event; } //#endregion // //#region Action Provider ... export enum XActionBarAction { Refresh = 'refresh', FireAction = 'fire_action', HideAction = 'hide_action', ShowAction = 'show_action', EnableAction = 'enable_action', DisbaleAction = 'disable_action', } export type XActionBarActionIdentifier = XActionBarAction | string; export interface XActionBarActionModel extends XBaseActionModel { id?: string; event?: Event; } //#endregion // //#region Default Actionbar Item IDs ... export enum DefaultActionBarItemIds { Add = 'add', Set = 'set', Edit = 'edit', Remove = 'remove', Upload = 'upload', Download = 'download', SelectAll = 'select_all', DeSelectAll = 'de_select_all', SelectAllGroup = 'select_all_group', InverseSelection = 'inverse_selection', DeSelectAllGroup = 'de_select_all_group', } export type DefaultActionBarItemIdsIdentifier = | DefaultActionBarItemIds | string; //#endregion // //#region Default Items ... export const defaultActionBarRemoveItem: XActionBarItem = { onlyIcon: true, color: XColor.Danger, icon: XIconNames.remove, iconColor: XColor.Danger, title: XResourceIDs.delete, slot: XActionBarItemSlot.START, id: DefaultActionBarItemIds.Remove, }; export const defaultActionBarUploadItem: XActionBarItem = { onlyIcon: true, color: XColor.Tertiary, icon: XIconNames.upload, iconColor: XColor.Tertiary, title: XResourceIDs.upload, slot: XActionBarItemSlot.START, id: DefaultActionBarItemIds.Upload, }; export const defaultActionBarDownloadItem: XActionBarItem = { onlyIcon: true, color: XColor.Tertiary, icon: XIconNames.download, iconColor: XColor.Tertiary, title: XResourceIDs.download, slot: XActionBarItemSlot.START, id: DefaultActionBarItemIds.Download, }; export const defaultActionBarSelectAllItem: XActionBarItem = { onlyIcon: true, color: XColor.Tertiary, iconColor: XColor.Tertiary, icon: XIconNames.select_all, slot: XActionBarItemSlot.END, title: XResourceIDs.select_all, id: DefaultActionBarItemIds.SelectAll, }; export const defaultActionBarDeSelectAllItem: XActionBarItem = { onlyIcon: true, color: XColor.Tertiary, iconColor: XColor.Tertiary, slot: XActionBarItemSlot.END, icon: XIconNames.deselect_all, title: XResourceIDs.deselect_all, id: DefaultActionBarItemIds.DeSelectAll, }; export const defaultActionBarSelectAllGroupItem: XActionBarItem = { onlyIcon: true, color: XColor.Tertiary, iconColor: XColor.Tertiary, slot: XActionBarItemSlot.END, icon: XIconNames.select_all_group, title: XResourceIDs.select_all_group, id: DefaultActionBarItemIds.SelectAllGroup, }; export const defaultActionBarDeSelectAllGroupItem: XActionBarItem = { onlyIcon: true, color: XColor.Tertiary, iconColor: XColor.Tertiary, slot: XActionBarItemSlot.END, icon: XIconNames.deselect_all_group, title: XResourceIDs.deselect_all_group, id: DefaultActionBarItemIds.DeSelectAllGroup, }; export const defaultActionBarInverseSelectionItem: XActionBarItem = { onlyIcon: true, color: XColor.Tertiary, iconColor: XColor.Tertiary, slot: XActionBarItemSlot.END, icon: XIconNames.inverse_selection, title: XResourceIDs.inverse_selection, id: DefaultActionBarItemIds.InverseSelection, }; export const defaultActionBarAddItem: XActionBarItem = { onlyIcon: true, icon: XIconNames.add, color: XColor.Success, title: XResourceIDs.add, iconColor: XColor.Success, slot: XActionBarItemSlot.START, id: DefaultActionBarItemIds.Add, }; export const defaultActionBarSetItem: XActionBarItem = { onlyIcon: true, color: XColor.Success, icon: XIconNames.done, title: XResourceIDs.set, iconColor: XColor.Success, slot: XActionBarItemSlot.START, id: DefaultActionBarItemIds.Set, }; export const defaultActionBarEditItem: XActionBarItem = { onlyIcon: true, icon: XIconNames.edit, color: XColor.Warning, title: XResourceIDs.edit, iconColor: XColor.Warning, slot: XActionBarItemSlot.START, id: DefaultActionBarItemIds.Edit, }; //#endregion // //#region Container ... export interface IXActionBarContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; // actions: XStandardType>; // actionFired: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XActionBarContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly actions: XStandardType>; // readonly actionFired = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XActionBarContainerComponent extends XBaseContainerComponent implements IXActionBarContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Input() actions: XStandardType> = this.propertyProvider.actions; // @Output() actionFired: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XActionBarContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXActionBarContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), // color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), // actions: this.getValue(container ? container.actions : this.actions), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // actionFired: this.actionFired, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentActionBarContainer = { [TKey in keyof IXActionBarContainer as `actionBar${Capitalize< string & TKey >}`]: IXActionBarContainer[TKey]; }; export interface IXComponentActionBarContainer extends TXComponentActionBarContainer, IXBaseComponentContainer { showActionBar: XStandardType; actionBarColor: XStandardType; actionBarForegroundColor: XStandardType; actionBarActionProvider: Subject; actionBarCssClass: XStandardType>; actionBarActionFired: EventEmitter; actionBarActions: XStandardType>; } @Injectable({ providedIn: 'root', }) export class XComponentActionBarContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // readonly showActionBar: XStandardType = true; // readonly actionBarActionProvider: Subject = this.propertyProvider.actionProvider; readonly actionBarCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly actionBarColor: XStandardType = this.propertyProvider.color; readonly actionBarForegroundColor: XStandardType = this.propertyProvider.foregroundColor; // readonly actionBarActions: XStandardType> = this.propertyProvider.actions; // readonly actionBarActionFired: EventEmitter = this.propertyProvider.actionFired; //#endregion // //#region Constructor ... constructor(protected propertyProvider: XActionBarContainer) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XComponentActionBarContainerComponent extends XBaseComponentContainerComponent implements IXComponentActionBarContainer { // //#region Props ... // @Input() showActionBar: XStandardType = this.propertyProvider.showActionBar; // @Input() actionBarActionProvider: Subject = this.propertyProvider.actionBarActionProvider; @Input() actionBarCssClass: XStandardType> = this.propertyProvider.actionBarCssClass; // @Input() actionBarColor: XStandardType = this.propertyProvider.actionBarColor; @Input() actionBarForegroundColor: XStandardType = this.propertyProvider.actionBarForegroundColor; // @Input() actionBarActions: XStandardType> = this.propertyProvider.actionBarActions; // @Output() actionBarActionFired: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XComponentActionBarContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXComponentActionBarContainer ): Observable { return forkJoin({ // showActionBar: this.getValue( container ? container.showActionBar : this.showActionBar ), // actionBarCssClass: this.getValue( container ? container.actionBarCssClass : this.actionBarCssClass ), // actionBarColor: this.getValue( container ? container.actionBarColor : this.actionBarColor ), actionBarForegroundColor: this.getValue( container ? container.actionBarForegroundColor : this.actionBarForegroundColor ), // actionBarActions: this.getValue( container ? container.actionBarActions : this.actionBarActions ), }).pipe( map((data) => { return { // ...data, // actionBarActionProvider: container ? container.actionBarActionProvider : this.actionBarActionProvider, // actionBarActionFired: this.actionBarActionFired, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.component.scss // :host { --avatar-size: 64px; --top-radius: 5px; --padding: 6px; } .x-file-drag-drop-wrapper { padding-bottom: var(--padding); border-top-left-radius: var(--top-radius); border-top-right-radius: var(--top-radius); } .x-avatar-container { padding: 6px; border-radius: 5px; } .thumbnail-wrapper { height: var(--avatar-size, 64px) !important; } x-thumbnail { --thumbnail-size: var(--avatar-size, 64px); } x-file-drop-area { --padding: 0px; } .avatar-actions { // @extend .thumbnail-wrapper; // display: flex; flex-direction: row; align-items: stretch; justify-content: flex-end; // * { flex: 0 0 auto; margin: { top: auto; bottom: auto; } } // * { margin: { left: 3px; right: 3px; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.component.ts import { Component, ViewChild, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { sort, nameof, isArray, toArray, hasChild, toBoolean, getArrayOf, XDialogResult, isExtensionOk, getErrorException, getImageDimensions, XColorWithBrightness, XExceptionIdentifier, } from 'x-framework-core'; import { XAvatarStatus, XAvatarUploadAction, XAvatarUploadActionModel, XAvatarUploadActionButtonName, XAvatarUploadContainerComponent, } from './x-avatar-upload.typings'; import { map } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs'; import { XIconNames } from '../x-icon/x-icon.typings'; import { XButtonType } from '../x-button/x-button.typings'; import { XThumbnailType } from '../x-thumbnail/x-thumbnail.typings'; import { XSlotName, XSlotLayout } from '../x-slotter/x-slotter.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-avatar-upload', templateUrl: './x-avatar-upload.component.html', styleUrls: ['./x-avatar-upload.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XAvatarUploadComponent extends XAvatarUploadContainerComponent { // //#region Props ... // private SELECTED_AVATAR: File; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly SlotNames = Object.assign({}, XSlotName); readonly IconNames = Object.assign({}, XIconNames); readonly SlotLayout = Object.assign({}, XSlotLayout); readonly ButtonTypes = Object.assign({}, XButtonType); readonly ThumbnailTypes = Object.assign({}, XThumbnailType); readonly ColorNames = Object.assign({}, XColorWithBrightness); readonly ActionButtonNames = Object.assign({}, XAvatarUploadActionButtonName); // selectedFileWidth = 0; selectedFileHeight = 0; // @ViewChild('fileInput', { static: false }) private fileInputRef!: ElementRef; set avatar(v: File) { // this.SELECTED_AVATAR = v; // if (!v) { return; } // getImageDimensions(v).then((dimension) => { if (dimension) { // this.selectedFileWidth = dimension.width; this.selectedFileHeight = dimension.height; // this.detectChanges(); } }); } get avatar() { return this.SELECTED_AVATAR; } //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Action Provider ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Task Handlers ... //#endregion // //#region UI Providers ... getActions() { return this.getArrayValue(this.actions).pipe( map((actions) => sort(actions, (a1, a2) => a1.index - a2.index)) ); } isCroppableImage() { return ( this.avatar && this.selectedFileWidth > 0 && this.selectedFileHeight > 0 && this.selectedFileWidth >= this.config.minAllowedImageSize && this.selectedFileHeight >= this.config.minAllowedImageSize ); } //#endregion // //#region UI Handlers ... // handleFilesSelected() { // if (!this.fileInputRef) { return; } // const fileInput = this.fileInputRef.nativeElement; if (!fileInput || !fileInput.files) { return; } // const files = getArrayOf(fileInput.files); // if (!files || files.length === 0) { return; } // const file = files[0]; if (!file) { return; } // fileInput.value = null; // this.handleFileDropped(files); } // async handleFileDropped(files: File | File[]) { // if (!files) { return; } // this.loading = true; // let file: File; if (!isArray(files) && files instanceof File) { file = files as File; } else { // const filesArr = files as File[]; if (hasChild(filesArr)) { file = filesArr[0]; } } // this.loading = false; // if (!file) { return; } // const status = await this.getFileStatus(file); if (status !== XAvatarStatus.OK) { this.loading = false; await this.handleFileStatus(status); return; } // this.avatar = file; this.avatarChange.emit(file); // this.detectChanges(); } // async handleActionButtonClicked(name: XAvatarUploadActionButtonName) { switch (name) { // case XAvatarUploadActionButtonName.Crop: this.loadCropper(); break; // case XAvatarUploadActionButtonName.Clear: await this.clear(); break; // case XAvatarUploadActionButtonName.Select: this.select(); break; } } //#endregion // //#region Actions ... // select() { // if (!this.fileInputRef || !this.fileInputRef.nativeElement) { return; } // this.fileInputRef.nativeElement.click(); } // async clear(force = false) { // if (!this.avatar) { return; } // if (force) { this.clearImage(); return; } // await this.managerService.dialogService.presentAreYouSureYesNoDialog(() => { this.clearImage(); }); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XAvatarUploadAction.Clear: await this.clear(toBoolean(model.payload)); break; // case XAvatarUploadAction.Select: this.select(); break; // case XAvatarUploadAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private loadCropper() { this.imageCropperService.showCropper(this.avatar); // const s = this.applyTakeUntilWrapper( this.imageCropperService.onResult.asObservable() ).subscribe((res) => { // if (res.result === XDialogResult.Ok && res.file) { // this.avatar = null; setTimeout(() => { // this.avatar = res.file; this.avatarChange.emit(res.file); // this.detectChanges(); }, 100); } // s.unsubscribe(); }); } private clearImage() { // if (!this.avatar) { return; } // this.avatar = null; this.selectedFileWidth = 0; this.selectedFileHeight = 0; this.avatarChange.emit(null); // this.detectChanges(); } private async getFileStatus(file: File) { // // Check Not Empty File ... if (!file || file.size === 0) { return XAvatarStatus.EMPTY; } // // Check File Extension Validation ... const isExtensionIsOk = await this.isExtensionOk(file); if (!isExtensionIsOk) { return XAvatarStatus.NOT_ALLOWED_TYPE; } // // Check File Min Size Ok ... const isMinAllowedFileSizeOk = await this.isMinAllowedFileSizeOk(file); if (!isMinAllowedFileSizeOk) { return XAvatarStatus.MIN_SIZE_NOT_REACHED; } // // Check File Max Size Ok ... const isMaxAllowedFileSizeOk = await this.isMaxAllowedFileSizeOk(file); if (!isMaxAllowedFileSizeOk) { return XAvatarStatus.SIZE_EXCEEDED; } // // Everythings Ok ... return XAvatarStatus.OK; } private async handleFileStatus(status: XAvatarStatus) { // let identifier: XExceptionIdentifier = null; switch (status) { // case XAvatarStatus.EMPTY: identifier = await this.getValueAsync(this.emptyFileException); break; // case XAvatarStatus.NOT_ALLOWED_TYPE: identifier = await this.getValueAsync(this.notAllowedFileException); break; // case XAvatarStatus.SIZE_EXCEEDED: identifier = await this.getValueAsync(this.maxAllowedFileSizeException); break; // case XAvatarStatus.MIN_SIZE_NOT_REACHED: identifier = await this.getValueAsync(this.minAllowedFileSizeException); break; } // const exception = getErrorException(identifier); if (exception) { this.managerService.notificationService.presentErrorNotification({ exception, dissmissable: true, }); } } // //#region File Selection Policies ... /** * Check File Extension ... */ private async isExtensionOk(file: File) { // if (!file) { return false; } // const allowedExtensionsType = await this.getValueAsync( this.allowedExtensions ); if (!allowedExtensionsType) { return true; } // const allowedExtensions = toArray(allowedExtensionsType); if (!hasChild(allowedExtensions)) { return true; } // const result = isExtensionOk(file, allowedExtensions); return result; } /** * Check File Size less than or Equals Max Required Size ... */ private async isMaxAllowedFileSizeOk(file: File) { // const maxAllowedFileSize = await this.getValueAsync( this.maxAllowedFileSize ); // const result = maxAllowedFileSize && maxAllowedFileSize > 0 ? file.size <= maxAllowedFileSize : true; // return result; } /** * Check File Size satisfied Min Required Size ... */ private async isMinAllowedFileSizeOk(file: File) { // const minAllowedFileSize = await this.getValueAsync( this.minAllowedFileSize ); // const result = minAllowedFileSize && minAllowedFileSize > 0 ? file.size >= minAllowedFileSize : true; // return result; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XButtonModule } from '../x-button/x-button.module'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XAvatarUploadComponent } from './x-avatar-upload.component'; import { XThumbnailModule } from '../x-thumbnail/x-thumbnail.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XFileDropAreaModule } from '../x-file-drop-area/x-file-drop-area.module'; @NgModule({ declarations: [XAvatarUploadComponent], imports: [ XIconModule, XCardModule, CommonModule, XButtonModule, XSlotterModule, XThumbnailModule, XFileDropAreaModule, XBaseComponentModule, ], exports: [ XIconModule, XCardModule, XButtonModule, XSlotterModule, XThumbnailModule, XFileDropAreaModule, XBaseComponentModule, XAvatarUploadComponent, ], }) export class XAvatarUploadModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-avatar-upload\x-avatar-upload.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XColor, XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XCardFileFileDropContainer, IXCardFileFileDropContainer, XCardFileFileDropContainerComponent, } from '../classes/i-x-file.container'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XIconIdentifier, XIconNames } from '../x-icon/x-icon.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XImageCropperService } from '../x-image-cropper/x-image-cropper.service'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XAvatarUploadAction { // Clear = 'clear', Select = 'select', Refresh = 'refresh', } export type XAvatarUploadActionIdentifier = XAvatarUploadAction | string; export interface XAvatarUploadActionModel extends XBaseActionModel {} export enum XAvatarStatus { OK = 'ok', EMPTY = 'empty', SIZE_EXCEEDED = 'size_exceeded', NOT_ALLOWED_TYPE = 'not_allowed_type', MIN_SIZE_NOT_REACHED = 'min_size_not_reached', } export type XAvatarStatusIdentifier = XAvatarStatus | string; export enum XAvatarUploadActionButtonName { Crop, Clear, Select, } export interface XAvatarUploadActionButton { index?: number; name: XAvatarUploadActionButtonName; icon?: XStandardType; color?: XStandardType; tooltip?: XStandardType; } export const defaultAvatarUploadActionButtons: XAvatarUploadActionButton[] = [ // // Select ... { index: 0, color: XColor.Success, icon: XIconNames.touch, tooltip: XResourceIDs.select, name: XAvatarUploadActionButtonName.Select, }, // // Crop ... { index: 1, icon: XIconNames.crop, color: XColor.Tertiary, tooltip: XResourceIDs.crop, name: XAvatarUploadActionButtonName.Crop, }, // // Clear ... { index: 2, color: XColor.Warning, icon: XIconNames.clear, tooltip: XResourceIDs.clear, name: XAvatarUploadActionButtonName.Clear, }, ]; // //#region Inside Card Container ... export interface IXAvatarUploadContainer extends IXCardFileFileDropContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; // placeHolderAvatar: XStandardType; // actions: XStandardType>; // avatarChange: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XAvatarUploadContainer extends XCardFileFileDropContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly placeHolderAvatar: XStandardType; // readonly actions: XStandardType> = defaultAvatarUploadActionButtons; // readonly avatarChange: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XAvatarUploadContainerComponent extends XCardFileFileDropContainerComponent implements IXAvatarUploadContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Input() placeHolderAvatar: XStandardType = this.propertyProvider.placeHolderAvatar; // @Input() actions: XStandardType> = this.propertyProvider.actions; // @Output() avatarChange: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, public imageCropperService: XImageCropperService, protected propertyProvider: XAvatarUploadContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXAvatarUploadContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), placeHolderAvatar: this.getValue( container ? container.placeHolderAvatar : this.placeHolderAvatar ), actions: this.getValue( container ? container.actions : this.actions ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // avatarChange: this.avatarChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.component.html {{ getResourceValue(title) | async }} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.component.scss :host ::ng-deep .x-button-icon-wrapper { vertical-align: middle; display: inline-grid; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.component.ts import { nameof, isNullOrUndefined, XColorWithBrightness, } from 'x-framework-core'; import { XButtonType, XButtonAction, XButtonActionModel, XButtonIconPosition, XButtonContainerComponent, } from './x-button.typings'; import { concatMap, map, switchMap } from 'rxjs/operators'; import { of, Observable, Subscription, Subject } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-button', templateUrl: './x-button.component.html', styleUrls: ['./x-button.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XButtonComponent extends XButtonContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly XSlotNames = Object.assign({}, XSlotName); readonly XButtonTypes = Object.assign({}, XButtonType); readonly XSlotLayouts = Object.assign({}, XSlotLayout); readonly XButtonIconPositions = Object.assign({}, XButtonIconPosition); //#endregion // //#region LifeCycle ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Action Provider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region is IconPositionChanged ... const isIconPositionChanged = changeKeys.includes( nameof('iconPosition') ); if (isIconPositionChanged && isNullOrUndefined(this.iconPosition)) { // this.iconPosition = XButtonIconPosition.Start; this.detectChanges(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... hasIcon() { return this.notNullOrUndefinedValue(this.icon); } hasTitle() { return this.notNullOrUndefinedValue(this.title); } useSlot() { return this.hasIcon().pipe( concatMap((hasIcon) => this.hasTitle().pipe(map((hasTitle) => hasIcon && hasTitle)) ) ); } isVerticalLayout() { return this.useSlot().pipe( concatMap((useSlot) => { // if (!useSlot) { return of(false); } // return this.getValue(this.iconPosition).pipe( map( (iPos) => iPos === this.XButtonIconPositions.Above || iPos === this.XButtonIconPositions.Below ) ); }) ); } iconSlotName(): Observable { return this.getValue(this.iconPosition).pipe( map((iPos) => { // switch (iPos) { // case this.XButtonIconPositions.Start: return this.XSlotNames.START; // case this.XButtonIconPositions.End: return this.XSlotNames.END; // case this.XButtonIconPositions.Above: return this.XSlotNames.TOP; // case this.XButtonIconPositions.Below: return this.XSlotNames.BOTTOM; // default: return this.XSlotNames.START; } }) ); } titleSlotName(): Observable { return this.iconSlotName().pipe( map((iSlot) => { // switch (iSlot) { // case this.XSlotNames.START: return this.XSlotNames.END; // case this.XSlotNames.END: return this.XSlotNames.START; // case this.XSlotNames.TOP: return this.XSlotNames.BOTTOM; // case this.XSlotNames.BOTTOM: return this.XSlotNames.TOP; // default: return this.XSlotNames.CENTER; } }) ); } getButtonColor() { return this.hasIcon().pipe( switchMap((hasIcon) => this.getValue(hasIcon ? XColorWithBrightness.Transparent : this.color) ) ); } //#endregion // //#region UI Handlers ... handleButtonClicked(event?: Event) { // if (this.uiDisabled || this.loading) { return; } // this.clicked.emit(event); } //#endregion // //#region Actions ... //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XButtonAction.Click: this.clicked.emit(); break; // case XButtonAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XButtonComponent } from './x-button.component'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XButtonComponent], imports: [CommonModule, XIconModule, XSlotterModule, XBaseComponentModule], exports: [ CommonModule, XIconModule, XSlotterModule, XButtonComponent, XBaseComponentModule, ], }) export class XButtonModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-button\x-button.typings.ts import { Input, Output, Inject, NgZone, Renderer2, Component, Injectable, ElementRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { XBaseContainer } from './../classes/i-x-base.container'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XButtonType { Raised = 'raised', Icon = 'icon', } export type XButtonTypeIdentifier = XButtonType | string; export enum XButtonIconPosition { Above = 'above', Start = 'strat', Below = 'below', End = 'end', } export type XButtonIconPositionIdentifier = XButtonIconPosition | string; export enum XButtonAction { Click = 'click', Refresh = 'refresh', } export type XButtonActionIdentifier = XButtonAction | string; export interface XButtonActionModel extends XBaseActionModel {} // //#region Container ... export interface IXButtonContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // type: XStandardType; title: XStandardType; icon: XStandardType; iconPosition: XStandardType; // color: XStandardType; foregroundColor: XStandardType; iconColor: XStandardType; // clicked: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XButtonContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly type: XStandardType = XButtonType.Raised; readonly title: XStandardType; readonly icon: XStandardType; readonly iconPosition: XStandardType = XButtonIconPosition.Start; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; readonly iconColor: XStandardType = XColorWithBrightness.Light; // readonly clicked: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XButtonContainerComponent extends XBaseContainerComponent implements IXButtonContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() type: XStandardType = this.propertyProvider.type; @Input() title: XStandardType = this.propertyProvider.title; @Input() icon: XStandardType = this.propertyProvider.icon; @Input() iconPosition: XStandardType = this.propertyProvider.iconPosition; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; @Input() iconColor: XStandardType = this.propertyProvider.iconColor; // @Output() clicked: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XButtonContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXButtonContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), // type: this.getValue(container ? container.type : this.type), title: this.getValue(container ? container.title : this.title), icon: this.getValue(container ? container.icon : this.icon), iconPosition: this.getValue( container ? container.iconPosition : this.iconPosition ), // color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), iconColor: this.getValue( container ? container.iconColor : this.iconColor ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // clicked: this.clicked, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.component.html
{{ getResourceValue(title) | async }} {{ getResourceValue(subTitle) | async }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.component.scss // @import '../theme/theme.scss'; // :host::ng-deep.x-card.no-text { .mat-card-header-text { display: none; visibility: hidden; } } // .x-card { @extend .p-0; width: inherit; height: var(--height, inherit); } .x-card.page-card { @include push-auto(); @include applyWidthHeight(); @include m-tb($d-l); @include animation('fadeInUp'); &.mobile { box-sizing: border-box; width: $d-100p; max-width: $d-100p; min-width: $d-100p; @include m(0); margin-bottom: $d-l; } } .x-header, .x-content, .x-actions, .x-footer { @include p($d-md); } .x-footer { margin: 0px !important; } .x-image { width: 100% !important; @extend .m-0; } .x-actions { margin: 0 !important; } .x-header:empty, .x-footer:empty, .x-actions:empty { display: none; visibility: hidden; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.component.ts import { XCardAction, XCardActionModel, XCardContainerComponent, } from './x-card.typings'; import { Subject, Subscription } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { nameof, isNullOrEmptyString } from 'x-framework-core'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-card', templateUrl: './x-card.component.html', styleUrls: ['./x-card.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XCardComponent extends XCardContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Action Provider Changed ... // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... isNoTextCard() { return this.getResourceValue(this.title).pipe( concatMap((title) => this.getResourceValue(this.subTitle).pipe( map((subTitle) => { return { title, subTitle, }; }), map((object) => { return ( isNullOrEmptyString(object.title) && isNullOrEmptyString(object.subTitle) ); }) ) ) ); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper( this.actionProvider.asObservable() ).subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XCardAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardComponent } from './x-card.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [ XCardComponent ], imports: [CommonModule, XBaseComponentModule], exports: [XBaseComponentModule, XCardComponent], }) export class XCardModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-card\x-card.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseComponentContainer, XBaseContainerComponent, IXBaseComponentContainer, XBaseComponentContainerComponent, } from '../classes/i-x-base.container'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XCardAction { Refresh = 'refresh', } export type XCardActionIdentifier = XCardAction | string; export interface XCardActionModel extends XBaseActionModel {} // //#region Container ... export interface IXCardContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; // showHeader: XStandardType; title: XStandardType; subTitle: XStandardType; avatarUrl: XStandardType; avatarTemplate: TemplateRef; // imageUrl: XStandardType; imageDescription: XStandardType; // isInPage: XStandardType; // showContent: XStandardType; showActions: XStandardType; showFooter: XStandardType; } @Injectable({ providedIn: 'root', }) export class XCardContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly showHeader: XStandardType = false; readonly title: XStandardType; readonly subTitle: XStandardType; readonly avatarUrl: XStandardType; readonly avatarTemplate: TemplateRef; // readonly imageUrl: XStandardType; readonly imageDescription: XStandardType; // readonly isInPage: XStandardType = false; // readonly showContent: XStandardType = true; readonly showActions: XStandardType = false; readonly showFooter: XStandardType = false; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XCardContainerComponent extends XBaseContainerComponent implements IXCardContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Input() showHeader: XStandardType = this.propertyProvider.showHeader; @Input() title: XStandardType = this.propertyProvider.title; @Input() subTitle: XStandardType = this.propertyProvider.subTitle; @Input() avatarUrl: XStandardType = this.propertyProvider.avatarUrl; @Input() avatarTemplate: TemplateRef = this.propertyProvider.avatarTemplate; // @Input() imageUrl: XStandardType = this.propertyProvider.imageUrl; @Input() imageDescription: XStandardType = this.propertyProvider.imageDescription; // @Input() isInPage: XStandardType = this.propertyProvider.isInPage; // @Input() showContent: XStandardType = this.propertyProvider.showContent; @Input() showActions: XStandardType = this.propertyProvider.showActions; @Input() showFooter: XStandardType = this.propertyProvider.showFooter; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XCardContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXCardContainer ): Observable { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), // showHeader: this.getValue( container ? container.showHeader : this.showHeader ), title: this.getValue(container ? container.title : this.title), subTitle: this.getValue(container ? container.subTitle : this.subTitle), avatarUrl: this.getValue( container ? container.avatarUrl : this.avatarUrl ), avatarTemplate: this.getValue( container ? container.avatarTemplate : this.avatarTemplate ), // imageUrl: this.getValue(container ? container.imageUrl : this.imageUrl), imageDescription: this.getValue( container ? container.imageDescription : this.imageDescription ), // isInPage: this.getValue(container ? container.isInPage : this.isInPage), // showContent: this.getValue( container ? container.showContent : this.showContent ), showActions: this.getValue( container ? container.showActions : this.showActions ), showFooter: this.getValue( container ? container.showFooter : this.showFooter ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentCardContainer = { [TKey in keyof Pick< IXCardContainer, | 'actionProvider' | 'cssClass' | 'color' | 'foregroundColor' | 'title' | 'subTitle' | 'showFooter' | 'showActions' > as `card${Capitalize}`]: IXCardContainer[TKey]; }; export interface IXComponentCardContainer extends TXComponentCardContainer, IXBaseComponentContainer { isInPage: XStandardType; wrapWithCard: XStandardType; } @Injectable({ providedIn: 'root', }) export class XComponentCardContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // readonly isInPage: XStandardType = false; readonly wrapWithCard: XStandardType = false; // readonly cardActionProvider: Subject = this.propertyProvider.actionProvider; readonly cardCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly cardColor: XStandardType = this.propertyProvider.color; readonly cardForegroundColor: XStandardType = this.propertyProvider.foregroundColor; // readonly cardTitle: XStandardType = this.propertyProvider.title; readonly cardSubTitle: XStandardType = this.propertyProvider.subTitle; // readonly cardShowFooter: XStandardType = this.propertyProvider.showFooter; readonly cardShowActions: XStandardType = this.propertyProvider.showActions; //#endregion // //#region Constructor ... constructor(protected propertyProvider: XCardContainer) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XComponentCardContainerComponent extends XBaseComponentContainerComponent implements IXComponentCardContainer { // //#region Props ... // @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; // @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; // @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; // @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; // @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XComponentCardContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXComponentCardContainer ): Observable { return forkJoin({ // isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardCssClass: this.getValue( container ? container.cardCssClass : this.cardCssClass ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), }).pipe( map((data) => { return { // ...data, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.component.scss :host { display: block; width: 100%; height: 100%; } .x-chart-wrapper { width: 100%; height: 100%; min-height: 300px; /* ارتفاع پیش‌فرض برای جلوگیری از فروپاشی layout */ } .x-chart-container { width: 100%; height: 100%; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.component.ts import { Component, ViewChild, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { XChartAction, XChartOptions, XChartSeriesType, XChartContainerComponent, } from './x-chart.typings'; import { Subscription } from 'rxjs'; import ApexCharts from 'apexcharts'; import { isNullOrUndefined, nameof } from 'x-framework-core'; @Component({ selector: 'x-chart', templateUrl: './x-chart.component.html', styleUrls: ['./x-chart.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XChartComponent extends XChartContainerComponent { // //#region Props ... // private CHART_CONTAINER: ElementRef | undefined; @ViewChild('chartContainer', { static: false }) set chartContainer(el: ElementRef | undefined) { // if (isNullOrUndefined(el)) { // this.destroyComponent(); return; } // this.CHART_CONTAINER = el; this.initializeComponent(); } get chartContainer() { return this.CHART_CONTAINER; } // private chartInstance: ApexCharts = null; // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycles ... async afterViewInit() { super.afterViewInit(); // await this.initializeComponent(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // // Auto Update ... const isAutoUpdateChanged = changeKeys.includes( nameof('autoUpdate'), ); if (isAutoUpdateChanged) { // if (isNullOrUndefined(this.autoUpdate)) { this.autoUpdate = this.propertyProvider.autoUpdate; } } // // Action Provider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider'), ); if (isActionProviderChanged) { this.registerActionProvider(); } // // Check Auto Update ... var autoUpdate = await this.getValueAsync(this.autoUpdate); if ( autoUpdate && !isNullOrUndefined(this.chartInstance) && !isNullOrUndefined(this.chartContainer) && !isNullOrUndefined(this.chartContainer.nativeElement) ) { // // Options Changed ... const isOptionsChanged = changeKeys.includes( nameof('options'), ); if (isOptionsChanged) { // if (isNullOrUndefined(this.options)) { this.options = this.propertyProvider.options; } // const options = await this.getValueAsync(this.options); await this.chartInstance.updateOptions(options); } // // Series Changed ... const isSeriesChanged = changeKeys.includes( nameof('series'), ); if (isSeriesChanged) { // if (isNullOrUndefined(this.series)) { this.series = this.propertyProvider.series; } // const series = await this.getValueAsync(this.series); await this.chartInstance.updateSeries(series); } } // this.detectChanges(); } onDestroy() { super.onDestroy(); // this.destroyComponent(); this.unregisterActionProvider(); } //#endregion // //#region Private ... private async initializeComponent() { // if (isNullOrUndefined(this.CHART_CONTAINER)) { return; } // // Reading Requirement Properties ... const chartId = await this.getValueAsync(this.uuid); const series = await this.getValueAsync(this.series); const options = await this.getValueAsync(this.options); // // Validate Options ... if (isNullOrUndefined(options)) { return; } // const computedStyle = getComputedStyle(document.documentElement); const primaryColor = computedStyle.getPropertyValue('--x-color-primary').trim() || '#008ffb'; const textColor = computedStyle.getPropertyValue('--x-color-dark-contrast').trim() || '#373d3f'; const gridColor = computedStyle.getPropertyValue('--x-color-light-shade').trim() || '#e0e0e0'; // const finalOptions: XChartOptions = { ...options, series: series || options.series, chart: { ...options.chart, id: chartId, type: options.chart?.type || 'line', foreColor: textColor, events: { ...options.chart?.events, mounted: (chartContext, config) => { this.chartRendered.emit(); options.chart?.events?.mounted?.(chartContext, config); }, dataPointSelection: (event, chartContext, config) => { this.dataPointSelected.emit({ event, chartContext, config }); options.chart?.events?.dataPointSelection?.( event, chartContext, config, ); }, zoomed: (chartContext, { xaxis, yaxis }) => { this.zoomed.emit({ xaxis, yaxis }); options.chart?.events?.zoomed?.(chartContext, { xaxis, yaxis }); }, }, }, theme: { ...options.theme, palette: options.theme?.palette || 'palette1', }, colors: options.colors || [primaryColor], grid: { ...options.grid, borderColor: gridColor, }, }; // this.chartInstance = new ApexCharts( this.chartContainer.nativeElement, finalOptions, ); // await this.chartInstance.render(); } private destroyComponent() { // if (isNullOrUndefined(this.chartInstance)) { return; } // this.chartInstance.destroy(); this.chartInstance = null; } private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = this.propertyProvider.actionProvider; } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XChartAction.Refresh: this.detectChanges(); break; // case XChartAction.Destroy: this.onDestroy(); break; // case XChartAction.UpdateSeries: // if ( !isNullOrUndefined(model.payload) || !isNullOrUndefined(this.chartInstance) ) { // this.series = await this.getValueAsync( model.payload as XChartSeriesType, ); await this.chartInstance.updateSeries(this.series); this.detectChanges(); } break; // case XChartAction.UpdateOptions: // if ( !isNullOrUndefined(model.payload) || !isNullOrUndefined(this.chartInstance) ) { // this.options = await this.getValueAsync( model.payload as XChartOptions, ); await this.chartInstance.updateOptions(this.options); this.detectChanges(); } break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XChartComponent } from './x-chart.component'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ providers: [], entryComponents: [], declarations: [XChartComponent], imports: [ XCardModule, XIconModule, CommonModule, XSlotterModule, XBaseComponentModule, ], exports: [ XCardModule, XIconModule, CommonModule, XSlotterModule, XChartComponent, XBaseComponentModule, ], }) export class XChartModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-chart\x-chart.typings.ts import { Input, Inject, NgZone, Output, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, } from 'x-framework-core'; import { XCardActionModel, XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Chart ... export type XChartAnnotationStyle = { background?: string; color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; cssClass?: string; padding?: { left?: number; right?: number; top?: number; bottom?: number; }; }; export type XChartAnnotationLabel = { borderColor?: string; borderWidth?: number; borderRadius?: number; text?: string | string[]; textAnchor?: string; offsetX?: number; offsetY?: number; style?: XChartAnnotationStyle; position?: string; orientation?: string; mouseEnter?: (annotation: XChartAnnotationLabel, e: MouseEvent) => void; mouseLeave?: (annotation: XChartAnnotationLabel, e: MouseEvent) => void; click?: (annotation: XChartAnnotationLabel, e: MouseEvent) => void; }; export type XCahrtAxisBaseAnnotations = { id?: number | string; strokeDashArray?: number; fillColor?: string; borderColor?: string; borderWidth?: number; opacity?: number; offsetX?: number; offsetY?: number; label?: XChartAnnotationLabel; draggable?: boolean; }; export type XChartYAxisAnnotations = XCahrtAxisBaseAnnotations & { y?: null | number | string; y2?: null | number | string; width?: number | string; yAxisIndex?: number; }; export type XChartXAxisAnnotations = XCahrtAxisBaseAnnotations & { x?: null | number | string; x2?: null | number | string; }; export type XChartPointAnnotations = { id?: number | string; x?: number | string; y?: null | number; yAxisIndex?: number; seriesIndex?: number; /** * Ink Layer (#7): make this point annotation draggable. Overrides * `chart.ink.enabled`. Requires the `ink` feature. */ draggable?: boolean; mouseEnter?: (annotation: XChartPointAnnotations, e: MouseEvent) => void; mouseLeave?: (annotation: XChartPointAnnotations, e: MouseEvent) => void; click?: (annotation: XChartPointAnnotations, e: MouseEvent) => void; marker?: { size?: number; fillColor?: string; strokeColor?: string; strokeWidth?: number; shape?: string; offsetX?: number; offsetY?: number; cssClass?: string; }; label?: XChartAnnotationLabel; image?: { path?: string; width?: number; height?: number; offsetX?: number; offsetY?: number; }; /** * Show a hover tooltip over the annotation marker, like a regular data * point. Useful for surfacing more detail than fits in the label. */ tooltip?: { enabled?: boolean; /** * Static tooltip content (HTML allowed; an array is joined with line * breaks). Falls back to `label.text` when omitted. */ text?: string | string[]; /** * Returns the tooltip markup (HTML). Takes precedence over `text`. */ formatter?: (opts: { annotation: XChartPointAnnotations; seriesIndex?: number; id?: number | string; w: any; }) => string; /** * Tooltip theme. Falls back to the global `tooltip.theme`. */ theme?: 'light' | 'dark'; offsetX?: number; offsetY?: number; }; /** * Render arbitrary SVG markup at the annotation's position. Deprecated in * favor of `image`/`marker`, but still supported. */ customSVG?: { SVG?: string; cssClass?: string; offsetX?: number; offsetY?: number; }; }; export type XChartTextAnnotations = { x?: number; y?: number; text?: string; textAnchor?: string; foreColor?: string; fontSize?: string | number; fontFamily?: undefined | string; fontWeight?: string | number; /** CSS selector for the parent element the text is appended to. */ appendTo?: string; backgroundColor?: string; borderColor?: string; borderRadius?: number; borderWidth?: number; paddingLeft?: number; paddingRight?: number; paddingTop?: number; paddingBottom?: number; }; export type XChartImageAnnotations = { path?: string; x?: number; y?: number; width?: number; height?: number; }; export type XChartAnnotations = { texts?: XChartTextAnnotations[]; yaxis?: XChartYAxisAnnotations[]; xaxis?: XChartXAxisAnnotations[]; points?: XChartPointAnnotations[]; images?: XChartImageAnnotations[]; }; export type XChartContext = { config: XChartOptions; globals: any; [key: string]: any; }; export type XChartColorFormatterOpts = { value: number; seriesIndex: number; dataPointIndex: number; w: XChartContext; }; export type XChartFormatterOpts = { seriesIndex: number; dataPointIndex: number; series?: any[][]; w: XChartContext; [key: string]: any; }; export type XChartDropShadow = { enabled?: boolean; top?: number; left?: number; blur?: number; opacity?: number; /** * Shadow color. A single string applies to all series; an array applies * per-series (only respected by `chart.dropShadow`). */ color?: string | string[]; }; export type XChartDataLabels = { enabled?: boolean; enabledOnSeries?: undefined | number[]; textAnchor?: 'start' | 'middle' | 'end'; distributed?: boolean; /** * Horizontal offset of the label. Pass a function to vary the offset per * data point, e.g. to separate labels that would otherwise overlap. * The function must be pure, as it may be called more than once per label. */ offsetX?: number | ((opts: XChartFormatterOpts) => number); /** * Vertical offset of the label. Pass a function to vary the offset per * data point, e.g. to separate labels that would otherwise overlap. * The function must be pure, as it may be called more than once per label. */ offsetY?: number | ((opts: XChartFormatterOpts) => number); style?: { fontSize?: string; fontFamily?: string; fontWeight?: string | number; colors?: string[]; }; background?: { enabled?: boolean; foreColor?: string; backgroundColor?: string; borderRadius?: number; padding?: number; opacity?: number; borderWidth?: number; borderColor?: string; dropShadow?: XChartDropShadow; }; dropShadow?: XChartDropShadow; /** * Ride data labels to their new position on a data-change update (e.g. a bar * chart race) instead of snapping. Off by default. Bar/column only; speed and * easing follow chart.animations.dynamicAnimation. */ animate?: { enabled?: boolean; }; /** * Count the numeric value up/down from its previous value on update, like * countUp.js. Off by default. The formatter runs each frame so number * formatting is preserved. Bar/column only. */ countUp?: { enabled?: boolean; }; formatter?( val: string | number | number[], opts?: XChartFormatterOpts, ): string | number | (string | number)[]; }; export type XChartHierarchyNode = { /** The node's label. `name` is accepted as an alias. */ x?: string | number; name?: string; /** The node's value. `value` is accepted as an alias. */ y?: number | null; value?: number | null; color?: string; fillColor?: string; /** A second metric driving colour rather than size (`treemap`). */ colorValue?: number; meta?: unknown; children?: XChartHierarchyNode[]; /** * The `id` of a `drilldown.series` entry, read as another level by the * sunburst (and by the treemap with * `plotOptions.treemap.nested.drilldownAsLevels`). */ drilldown?: string | number; }; export type XChartParsing = { x?: string; y?: string | string[]; z?: string; }; export type XChartColorStop = { offset: number; color: string; opacity: number; }; export type XChartFill = { colors?: string[]; opacity?: number | number[]; type?: string | string[]; gradient?: { shade?: string; type?: string; shadeIntensity?: number; gradientToColors?: string[]; inverseColors?: boolean; opacityFrom?: number | number[]; opacityTo?: number | number[]; stops?: number[]; colorStops?: XChartColorStop[][] | XChartColorStop[]; }; image?: { src?: string | string[]; width?: number; height?: number; }; pattern?: { style?: string | string[]; width?: number; height?: number; strokeWidth?: number; }; }; export type XChartAxisChartSeries = { name?: string; type?: string; color?: string; group?: string; hidden?: boolean; zIndex?: number; parsing?: XChartParsing; data: | (number | null)[] | { /** * A category label, a timestamp, or a `Date`. On a `datetime` axis all * three keep millisecond resolution. */ x: string | number | Date; /** * A plain value for most charts. For `candlestick`/`boxPlot`, the * summary array (`[O,H,L,C]` / `[min,Q1,median,Q3,max]`). For `violin`, an * object carrying the precomputed density profile (`[value, weight]` pairs) * plus the raw observations rendered as jitter. For a `scatter` strip plot * (`plotOptions.scatter.jitter`), the array of observations in this category. */ y: | number | null | number[] | { density: [number, number][]; points?: number[] }; /** * Optional raw observations for a `boxPlot` data point, rendered as jitter * dots when `plotOptions.boxPlot.points.show` is enabled. */ points?: number[]; fill?: XChartFill; fillColor?: string; strokeColor?: string; meta?: unknown; /** * A second metric that drives this point's COLOUR, independent of `y` * which drives its size (`treemap`). See * `plotOptions.treemap.colorScale.colorValue` to read a different key. */ colorValue?: number; /** * Nested hierarchy: this point is a branch containing these children, * to any depth (`treemap`, `sunburst`). A branch normally omits `y` and * takes the sum of its children instead. */ children?: XChartHierarchyNode[]; /** * Drilldown target: the `id` of a `drilldown.series` entry. Clicking this * point drills into that level. Requires the Drilldown feature. */ drilldown?: string | number; goals?: { name?: string; value: number; strokeHeight?: number; strokeWidth?: number; strokeColor?: string; strokeDashArray?: number; strokeLineCap?: 'butt' | 'square' | 'round'; }[]; barHeightOffset?: number; columnWidthOffset?: number; }[] | [number, number | null][] | [number, (number | null)[]][] | number[][] // A `children` hierarchy for the partition charts, where a branch carries no // value of its own. Listed before the catch-all so authors get completion on // the node shape instead of falling through to `Record`. | XChartHierarchyNode[] | Record[]; }[]; export type XChartNonAxisChartSeries = number[] | XChartAxisChartSeries; export type XChartGradientLegend = { enabled?: boolean; /** * Strip length for horizontal placements (top/bottom). Accepts a number * (pixels) or percentage string (e.g. `'70%'`, resolved against the chart's * SVG width). Default `'70%'`. */ width?: number | string; /** * Strip length for vertical placements (left/right). Accepts a number * (pixels) or percentage string (e.g. `'70%'`, resolved against the chart's * SVG height). Default `'70%'`. */ height?: number | string; /** Strip thickness (short axis) in pixels. Default 12. */ thickness?: number; /** * Strip alignment within the legend area. * - top/bottom: 'start' = left, 'center', 'end' = right * - left/right: 'start' = top, 'center', 'end' = bottom * Default `'center'`. */ align?: 'start' | 'center' | 'end'; /** * Number of color stops sampled from the shade function when no explicit * `ranges` (or continuous scale) supply their own. Default 16. */ stops?: number; /** Show min/max labels at the ends of the strip. Default true. */ showLabels?: boolean; /** Show a value tooltip next to the arrow on mark hover. Default true. */ showHoverValue?: boolean; labelStyle?: { fontSize?: string; fontFamily?: string; colors?: string; }; arrow?: { size?: number; color?: string; }; /** Formatter for min/max labels and the hover value tooltip. */ formatter?(value: number): string; }; export type XChartTreemapLevel = { /** Inset between a parent's edge and the children inside it. Default 4. */ padding?: number; /** Container fill. Defaults to a neutral tint that deepens with each level. */ fill?: string; fillOpacity?: number; borderColor?: string; borderWidth?: number; /** Falls back to `plotOptions.treemap.borderRadius`. */ borderRadius?: number; hover?: { /** Outline the container on hover. Default true. */ show?: boolean; color?: string; width?: number; }; header?: { show?: boolean; /** Height of the strip reserved at the top of the container. Default 22. */ height?: number; /** * Skip the strip on tiles narrower than this, where no name could be read * anyway. Default 40. */ minWidth?: number; align?: 'left' | 'center' | 'right'; offsetX?: number; offsetY?: number; /** Append the branch's aggregate to its name. Default false. */ showValue?: boolean; formatter?( name: string, opts: { value: number; depth: number; seriesIndex: number; node: any; w: any; }, ): string; style?: { fontSize?: string; fontFamily?: string; fontWeight?: number | string; color?: string; background?: string; cssClass?: string; }; }; }; export type XChartBreadcrumb = { show?: boolean; position?: 'top-left' | 'top-right'; separator?: string; /** Label of the leftmost crumb, the "everything" level. Default 'All'. */ rootLabel?: string; offsetX?: number; offsetY?: number; formatter?( label: string, opts: { index: number; depth: number; data?: any }, ): string; }; export interface XChartUnitObject { /** * Stable identity. The datum's own `id`/`name` when the per-unit object form * supplies one, so a provider can address a specific unit ("Texas", * "employee 41") rather than a positional slot; otherwise * `":"`. */ id: string; /** Global draw order across every category. */ index: number; /** Category this mark belongs to. */ seriesIndex: number; /** Index within its category. */ dataPointIndex: number; /** Category label. */ label: string; /** The datum's value, when the per-unit object form supplies one. */ value?: number; /** The raw per-unit datum, when supplied. */ datum?: any; /** The radius the engine would use, so a size-aware provider need not redo it. */ r: number; } export interface XChartUnitPosition { /** Must match an `ApexUnitObject.id`; unknown ids are ignored. */ id: string; x: number; y: number; /** Overrides the engine's radius for this mark. */ r?: number; } export type XChartUnitLayout = ( objects: XChartUnitObject[], rect: { x: number; y: number; width: number; height: number }, ) => XChartUnitPosition[]; export type XChartPlotOptions = { line?: { isSlopeChart?: boolean; colors?: { threshold?: number; colorAboveThreshold?: string; colorBelowThreshold?: string; }; }; area?: { fillTo?: 'origin' | 'end'; }; bar?: { horizontal?: boolean; columnWidth?: string | number; barHeight?: string | number; distributed?: boolean; borderRadius?: number; borderRadiusApplication?: 'around' | 'end'; borderRadiusWhenStacked?: 'all' | 'last'; hideZeroBarsWhenGrouped?: boolean; rangeBarOverlap?: boolean; rangeBarGroupRows?: boolean; isDumbbell?: boolean; dumbbellColors?: string[][]; isFunnel?: boolean; isFunnel3d?: boolean; colors?: { ranges?: { from?: number; to?: number; color?: string; }[]; backgroundBarColors?: string[]; backgroundBarOpacity?: number; backgroundBarRadius?: number; }; dataLabels?: { maxItems?: number; hideOverflowingLabels?: boolean; position?: string; orientation?: 'horizontal' | 'vertical'; total?: { enabled?: boolean; formatter?(val?: string, opts?: XChartFormatterOpts): string; offsetX?: number; offsetY?: number; style?: { color?: string; fontSize?: string; fontFamily?: string; fontWeight?: number | string; }; }; }; }; bubble?: { zScaling?: boolean; minBubbleRadius?: number; maxBubbleRadius?: number; }; scatter?: { /** * Spread overlapping points apart ("jitter"). Two uses, one engine: * - Strip plot: supply data as `{ x: 'Category', y: [v1, v2, ...] }`. Each * category becomes a band and the values scatter horizontally within it. * - Overplotting: ordinary `{ x, y }` points get a small random offset so * dense clusters fan out. The underlying data (and tooltip values) stay * exact; only the drawn position moves. * Offsets are in axis units and deterministic (stable across re-renders). */ jitter?: { enabled?: boolean; /** Max ± horizontal offset, in x-axis units (1 = one category step). */ x?: number; /** Max ± vertical offset, in y-axis units. */ y?: number; /** Single series: colour each band differently (by its position). */ distributed?: boolean; /** Per-band cap; values beyond this are stride-thinned. */ maxPoints?: number; }; }; candlestick?: { type?: string; colors?: { upward?: string | string[]; downward?: string | string[]; }; wick?: { useFillColor?: boolean; }; }; boxPlot?: { colors?: { upper?: string | string[]; lower?: string | string[]; }; /** * Where the whiskers reach when the summary is DERIVED from raw * observations: a datum supplying `points` instead of a five-number `y`, * which requires `import 'apexcharts/features/stats'`. A precomputed * summary is drawn exactly as given and ignores this. * * `'minmax'` (default) reaches the extremes, so nothing is hidden. * `'tukey'` stops at the last observation within 1.5 * IQR of each * quartile; points beyond the fence then fall outside the whisker, so pair * it with `points.show` or they become invisible. */ whiskers?: 'minmax' | 'tukey'; /** * Individual observations ("jitter") overlaid on each box. Inert unless a * data point supplies a `points: number[]` array; `show` is false by * default so existing boxPlot charts are unchanged. * * `points` is also the sample the five-number summary is derived from when * a datum has no `y` (see `whiskers`), so the observations live in one * place whether the library summarises them or you do. */ points?: { show?: boolean; shape?: 'circle' | 'square'; /** Marker radius in pixels. */ size?: number; /** 0..1 fraction of the box half-width to scatter within. */ jitter?: number; /** Cap per box; observations beyond this are stride-thinned. */ maxPoints?: number; opacity?: number; /** * Dot fill colour. Defaults to 'series-dark' (a darker shade of the * series colour). Use 'series' for the series colour, or any literal * colour string. */ fillColor?: string; /** Colour of the outline around each dot. Defaults to '#fff'. */ strokeColor?: string; /** Width of the dot's outline in pixels. Defaults to 1; 0 disables it. */ strokeWidth?: number; /** * Colour each dot by its value along a colour ramp (overrides fillColor). * Points are bucketed into `steps` shades to keep rendering performant. */ colorScale?: { colors: string[]; min?: number; max?: number; steps?: number; }; }; }; violin?: { /** * Multiplies the density-derived half-width. 1 maps the density's own * maxWeight to half the category slot. */ bandwidthScale?: number; /** * Kernel density estimation, used only when the density is DERIVED from raw * observations: a datum supplying `points`, or a flat number array as `y`, * which requires `import 'apexcharts/features/stats'`. A precomputed * density profile is drawn exactly as given. */ kde?: { /** * Kernel width in value units. Unset uses Silverman's rule of thumb. * This is the statistical parameter; `bandwidthScale` above only scales * the drawn width. */ bandwidth?: number; /** Density samples per violin (default 64). */ resolution?: number; }; /** * 'individual' (default): each violin is scaled to its own peak density, so * all violins reach the full slot width. 'group': all violins share the * densest violin's scale, keeping widths proportional to density across * categories. */ normalize?: 'individual' | 'group'; /** Individual observations ("jitter") overlaid on the violin shape. */ points?: { show?: boolean; shape?: 'circle' | 'square'; /** Marker radius in pixels. */ size?: number; /** 0..1 fraction of the half-width to scatter within. */ jitter?: number; /** Clamp jitter to the density width at each value so points stay inside. */ constrainToViolin?: boolean; /** Cap per violin; observations beyond this are stride-thinned. */ maxPoints?: number; opacity?: number; /** * Dot fill colour. Defaults to 'series-dark' (a darker shade of each * violin's own colour). Use 'series' for the violin's colour as-is, or * any literal colour string (e.g. '#fff'). */ fillColor?: string; /** Colour of the ring/outline around each dot. Defaults to '#fff'. */ strokeColor?: string; /** Width of the dot's outline in pixels. Defaults to 1; 0 disables it. */ strokeWidth?: number; /** * Colour each dot by its value along a colour ramp (overrides fillColor). * Points are bucketed into `steps` shades to keep rendering performant. */ colorScale?: { /** Hex colour stops, low → high (a sequential colour ramp). */ colors: string[]; /** Value mapped to the first stop. Defaults to the data minimum. */ min?: number; /** Value mapped to the last stop. Defaults to the data maximum. */ max?: number; /** Number of shade buckets. Defaults to 24. */ steps?: number; }; }; }; /** * `chart.type: 'histogram'`. The series carry raw observations (a flat * number array, or `{ y }` objects) and are binned into one column per bin; * all series share one set of edges so overlaid distributions stay * comparable. * * Requires the optional stats feature. Import from `apexcharts/histogram`, * or add `import 'apexcharts/features/stats'` alongside `apexcharts/bar`. * The default `apexcharts` bundle already includes it. Without it the chart * warns and draws nothing, rather than rendering one bar per observation. */ histogram?: { /** * How the bin width is chosen: a rule name, or a fixed bin count. * `'auto'` takes the narrower of Freedman-Diaconis and Sturges, falling * back to Sturges when the IQR is 0. */ bins?: 'auto' | 'fd' | 'sturges' | 'scott' | 'rice' | 'sqrt' | number; /** * Explicit bin width in value units. Wins over `bins`, for when the * boundaries carry meaning (decades, 5-minute buckets) rather than being * a statistical choice. */ binWidth?: number; /** `[min, max]` to bin over instead of the data's own extent. */ range?: number[]; /** * y units: observations per bin, percent of the series total, or * `count / (n * binWidth)` so the total area is 1. */ normalize?: 'count' | 'relative' | 'density'; /** Running total across bins, i.e. a cumulative distribution. */ cumulative?: boolean; /** * With more than one series, draw every distribution across the full bin * so they overlay, instead of dividing the bin between them. Defaults to * `true`: all series already share one set of edges, and comparing two * shapes is the reason to put them on one axis. Set `false` for * side-by-side bars. * * An overlay also softens the fill and drops the bin separator stroke, so * the overlapping region reads. Both remain overridable. */ overlap?: boolean; }; heatmap?: { radius?: number; enableShades?: boolean; shadeIntensity?: number; reverseNegativeShade?: boolean; distributed?: boolean; useFillColorAsStroke?: boolean; colorScale?: { ranges?: { from?: number; to?: number; color?: string; foreColor?: string; name?: string; }[]; inverse?: boolean; min?: number; max?: number; /** * When enabled, replaces the default categorical legend with a * continuous color gradient strip and a hover indicator arrow that * tracks the currently hovered mark's value along the spectrum. * Follows `legend.position` (top / right / bottom / left); the arrow * orientation flips to point at the strip from the chart-facing side. */ gradientLegend?: XChartGradientLegend; }; }; funnel?: { /** * 'rectangle' (default) preserves the existing centered-rectangle funnel * geometry. 'trapezoid' produces continuous sloped sides between * consecutive stages (each stage's bottom width matches the next stage's * top width). */ shape?: 'rectangle' | 'trapezoid'; /** * For `shape: 'trapezoid'` only — last stage's bottom edge: * 'flat' (default, parallel sides) or 'taper' (taper to a point). */ lastShape?: 'flat' | 'taper'; }; treemap?: { enableShades?: boolean; shadeIntensity?: number; distributed?: boolean; reverseNegativeShade?: boolean; useFillColorAsStroke?: boolean; dataLabels?: { format?: 'scale' | 'truncate'; /** * Skip a tile's label when it would render below this size in px. * * With `format: 'scale'` the font size follows the tile's area, so a * dense treemap asks for a lot of text only a few pixels tall. Each such * label still has to be built and measured against the DOM, which on a * large chart dominates the render. Default 4, below the smallest label * any bundled sample draws. Set 0 to label every tile regardless. */ minFontSize?: number; }; borderRadius?: number; colorScale?: { inverse?: boolean; ranges?: { from?: number; to?: number; color?: string; foreColor?: string; name?: string; }[]; min?: number; max?: number; /** * Colour a tile by a SECOND metric, independent of the value that sizes * it: area is how big something is, colour is how it did. Reads * `datum.colorValue` by default; pass a key name to read a different * property, or an accessor to compute one. */ colorValue?: | string | (( datum: any, opts: { seriesIndex: number; dataPointIndex: number; w: any }, ) => number); /** * Continuous interpolation between colour stops, for the metric above. * Active as soon as any datum carries a colour metric; `enabled: false` * opts out and `true` forces it on. `ranges` is unaffected and still * applies wherever it is set. */ gradient?: { enabled?: boolean; /** Domain low. Defaults to the extent of the colour metric. */ min?: number; /** Domain high. Defaults to the extent of the colour metric. */ max?: number; /** * The value the middle colour is pinned to. Defaults to 0 when the * domain straddles zero (a diverging metric), otherwise none. Pass * `null` to force a plain sequential ramp. */ midpoint?: number | null; /** * With a midpoint, balance the domain around it so equal moves in * either direction read as equally saturated. Default true. */ symmetric?: boolean; /** Low -> mid -> high. Two colours make a sequential ramp. */ colors?: string[]; /** Explicit stops; overrides `colors` and `midpoint`. */ stops?: { value: number; color: string }[]; }; /** * Continuous colour legend for the metric above: a gradient strip with * end labels and a hover indicator, in place of the categorical legend. */ gradientLegend?: XChartGradientLegend; }; /** * Arbitrary-depth treemap. A datum may carry `children` to any depth; * every branch is drawn as a real container with a header strip and its * children inset below it. */ nested?: { /** * Parent containers appear on their own as soon as the data is nested. * `false` forces the flat two-level layout. */ enabled?: boolean; /** * Read `drilldown: ''` ids as extra levels instead of as a click * target for the drilldown feature. Default false, because on a treemap * that id has always meant "descend on click". */ drilldownAsLevels?: boolean; }; /** * How a branch is drawn once the data is nested. Per-level overrides go in * `levels`. */ parents?: XChartTreemapLevel & { /** `'auto'` (default): on when the data carries `children`. */ show?: boolean | 'auto'; tooltip?: { formatter?(opts: { name: string; value: number; depth: number; leafCount: number; percentOfParent: number; percentOfTotal: number; node: any; w: any; }): string; }; }; /** * Per-depth overrides of `parents`, indexed from the outermost group * actually drawn (0 = the series, or the first authored level when a * single series is unwrapped). */ levels?: XChartTreemapLevel[]; /** * Click a group to fill the canvas with it; a breadcrumb goes back. * * Ignored when the drilldown feature is active on the same chart: both * navigate the hierarchy, and drilldown owns the click there. */ zoom?: { enabled?: boolean; /** * Overrides `drilldown.breadcrumb` for this chart only, so a zoomed * treemap and a drilled-in chart present the same affordance without * importing the drilldown feature. */ breadcrumb?: XChartBreadcrumb; }; seriesTitle?: { show?: boolean; offsetY?: number; offsetX?: number; borderColor?: string; borderWidth?: number; borderRadius?: number; style?: { background?: string; color?: string; fontSize?: string; fontFamily?: string; fontWeight?: number | string; cssClass?: string; padding?: { left?: number; right?: number; top?: number; bottom?: number; }; }; }; }; unit?: { /** * 'grouped' (default): each category is its own cluster, laid out in a row. * 'packed': one blob; categories are coloured and (with sortByGroup) ordered * smallest-first so the minority group nests in the centre. * 'columns': each category is a vertical bar built from stacked dots (a unit * / waffle column) whose height encodes the count. * 'grid': one lattice of cells filled in category order - a waffle / * part-to-whole square "pie" (`chart.type: 'waffle'` presets this layout). * 'scatter': beeswarm - each unit placed on a real numeric X value axis by * its per-unit value, laned by category on Y (draws its own axis + lanes). * 'arc': parliament / hemicycle - seats in concentric arced rows, filled in * category order so each category is a contiguous wedge (see `arc`). * 'custom': positions come from `positions`. */ layout?: | 'grouped' | 'packed' | 'columns' | 'grid' | 'scatter' | 'arc' | 'custom'; /** * `layout: 'custom'` only. The layout provider: either a function returning * plot-pixel positions, or the name of one registered with * `ApexCharts.registerUnitLayout`. * * A layout is objects in, positions out. It knows nothing about animation, * because the engine already tweens position, radius and colour and already * keeps each mark's identity across a relayout, so an arrangement the * built-in layouts cannot express needs no new transition code. * * A mark whose id the provider omits animates out; ids matching no mark are * ignored. */ positions?: string | XChartUnitLayout; /** * How dots are matched between renders on an update (which previous dot a * new dot tweens from). * 'group' (default): keyed per category, so a dot stays in its group and * category-level enters/exits fade in and out. * 'flow': keyed by global draw order, so the anonymous crowd migrates (and * recolours) across a regroup - the circles-to-bars transition. * 'identity': keyed by each datum's `id`/`name`, so a SPECIFIC unit migrates * across any regroup or relayout keeping its colour and size. Requires the * per-unit object form with unique ids/names. */ transition?: 'group' | 'flow' | 'identity'; /** Mark shape for each unit. `'image'` renders an icon (isotype pictogram). */ shape?: 'circle' | 'square' | 'image'; /** Icon used when `shape: 'image'`. */ image?: { /** Icon URL or data URI. */ src?: string; width?: number; height?: number; /** * Recolour a monochrome icon to the category colour (or a per-unit * `fillColor`) so the pictogram matches the legend. Leave off (default) * for multi-colour icons that should keep their own colours. */ tint?: boolean; }; /** Dot radius in px, or 'auto' to size dots so the largest cluster fits. */ size?: number | 'auto'; /** * The 'columns' layout can size its dots independently of `size` (which the * circle layouts / storyboard beats often pin to a constant so dots do not * resize while migrating). */ columns?: { /** * 'inherit' (default) uses `size`; 'auto' sizes dots to fill the plot * height; a number pins a columns-only size. Circle / square only (image * icons keep their intrinsic size). */ size?: 'inherit' | 'auto' | number; }; /** * The 'grid' (waffle) layout: one lattice of cells filled in category order. */ grid?: { /** Cells per row. Defaults to 10. */ columns?: number; /** * Fixed cell budget (e.g. 100 for a percentage waffle); largest-remainder * allocates the cells to categories. Leave undefined for one cell per unit * (respects unitValue / maxUnits). */ total?: number; /** First row of the fill: 'bottom' (default) or 'top'. */ fillFrom?: 'bottom' | 'top'; /** * Small multiples: render ONE mini-waffle per category in a trellis * instead of a single shared lattice. Each tile has `total` cells * (default 100) and fills value/`max` of them; the rest show as a faint * `trackColor` backdrop, and each tile carries its own label. */ split?: boolean; /** Small-multiple tiles per row; undefined = auto (near-square). */ tileColumns?: number; /** * Small-multiple value -> filled-cell denominator; undefined = the largest * count (leader fills its tile). Set to 100 for true "of 100" percentage tiles. */ max?: number; /** Small-multiple empty ("track") cell colour; undefined = neutral grey. */ trackColor?: string; }; /** * The 'scatter' layout places units on real value axes (needs the object-form * data). `y:'lanes'` (default) is a beeswarm (X value axis, Y category lane); * `y:'value'` is a 2D value-value scatter (each datum's `x`/`y` on two numeric * axes, category = colour). `sizeRange` turns dots into bubbles. */ scatter?: { /** 'lanes' (beeswarm, default) or 'value' (2D value-value scatter). */ y?: 'lanes' | 'value'; /** 'swarm' (anti-overlap pack, default) or 'jitter' (random lane spread). */ spread?: 'swarm' | 'jitter'; /** * Beeswarm orientation (1D `y:'lanes'` mode only). 'horizontal' (default): * value on X, category lanes stacked on Y. 'vertical': value on Y, * category lanes as columns across X. The value-axis config keys * (`xMin`/`xMax`/`xTitle`/`xFormatter`/`tickAmount`) describe the value * axis in both orientations. */ orientation?: 'horizontal' | 'vertical'; /** Approximate number of value-axis ticks. Defaults to 5. */ tickAmount?: number; /** Fixed X-axis min / max; undefined = derived (nice-numbered) from data. */ xMin?: number; xMax?: number; /** X-axis title drawn under the tick labels. */ xTitle?: string; /** X tick-label formatter, `(value) => string`. */ xFormatter?: (value: number) => string; /** Approximate number of Y-axis ticks (2D mode). Defaults to 5. */ yTickAmount?: number; /** Fixed Y-axis min / max (2D mode); undefined = nice-numbered from data. */ yMin?: number; yMax?: number; /** Y-axis title (2D mode), drawn rotated at the left. */ yTitle?: string; /** Y tick-label formatter, `(value) => string`. */ yFormatter?: (value: number) => string; /** Datum key holding the bubble size value. Defaults to 'z'. */ sizeField?: string; /** `[minRadius, maxRadius]` in px: turns dots into area-scaled bubbles. */ sizeRange?: [number, number]; /** Left-gutter width reserved for lane (category) labels (lanes mode). */ laneLabelWidth?: number; /** Draw the faint gridlines. Defaults to true. */ gridlines?: boolean; }; /** * Opt-in bubble sizing: scale each dot's radius by its per-unit value * (requires the object-form data, `series: [{ data: [{ value }] }]`). * Circle shape only; the lattice is spaced for the largest bubble so dots * never overlap. Ignored when there are no per-unit values. */ sizeByValue?: { enabled?: boolean; /** Radius (px) for the largest value, or 'auto' to fit it to the plot. */ maxRadius?: number | 'auto'; /** Radius (px) for the smallest value; defaults to ~35% of maxRadius. */ minRadius?: number; /** 'area' (bubble area proportional to value) or 'linear'. */ scale?: 'area' | 'linear'; }; /** Packing gap factor between spiral shells (1 = dots touch). */ spacing?: number; /** * How marks move between layouts on an update, and where entering marks * come from. */ gather?: { /** * 'spring' settles each mark on a damped spring, so a gather interrupted * by the next update carries the marks' velocity into it instead of * restarting them from a standstill. 'tween' runs the fixed-duration * `easing` below. 'auto' (the default) is spring, unless `easing` was set * to something other than the default. */ motion?: 'auto' | 'spring' | 'tween'; /** * Spring character (`motion: 'spring'` only): 'crisp' (default), * 'gentle' (softer, for large reflows) or 'snappy' (faster, a hint of * settle). Scaled by `chart.animations.speed`. */ spring?: 'crisp' | 'gentle' | 'snappy'; /** Tween curve: 'outCubic' (default: decelerate and stop), 'inOutCubic' (weighted start), or 'outBack' (overshoot + settle). Setting this implies `motion: 'tween'`. */ easing?: 'outCubic' | 'inOutCubic' | 'outBack'; /** Overshoot strength for `easing: 'outBack'`. Defaults to 1.70158 (~10% overshoot). */ overshoot?: number; /** * Where an ENTERING mark animates from (fresh mount, or a category * appearing): 'burst' (default) flies out from the cluster centre, * 'fade' materialises in place, 'rise' fades in while drifting gently * up into its slot. */ enter?: 'burst' | 'fade' | 'rise'; }; /** * Options for `layout: 'arc'` (parliament / hemicycle). Angles use the * radialBar convention: 0 = top, clockwise. The default sweep is a top * semicircle; a full circle is `startAngle: 0, endAngle: 360`. */ arc?: { /** Sweep start angle in degrees (0 = top, clockwise). Default -90. */ startAngle?: number; /** Sweep end angle in degrees. Default 90 (a top semicircle). */ endAngle?: number; /** Donut hole: inner radius as a fraction of the outer radius. Default 0.4. */ innerRadiusRatio?: number; /** Number of concentric seat rows, or 'auto' to size dots as large as fit. */ rows?: number | 'auto'; }; /** Corner radius for shape:'square'. */ borderRadius?: number; /** 1 dot represents this many units of value (waffle scaling). */ unitValue?: number; /** Safety cap on total dots; counts scale down proportionally above it. */ maxUnits?: number; /** Packed layout: order categories smallest-first (minority centred). */ sortByGroup?: boolean; clusterLabels?: { show?: boolean; /** Label placement relative to the cluster/bar. Defaults to 'top'. A 'bottom' label is always straight (the curved arc rides the top crown only). */ position?: 'top' | 'bottom'; curved?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: number | string; /** Defaults to the cluster's own colour when undefined. */ color?: string; offsetY?: number; /** Return "\n"-separated text to split an outer label over several lines. */ formatter?( name: string, opts: { seriesIndex: number; value: number; percent: number; w: any }, ): string; /** * Outer (name) labels, as pie/donut draw them: the label sits in the margin * beside the shape and a leader line joins it to the colour band it names, * so the crowd can be read without a legend. * * `layout: 'custom'` only, and best on a silhouette whose categories stack * vertically (the default row ordering): those alternate down the left and * right gutters. A column-ordered shape sends each label to the side its own * band sits on. The margin is taken off both sides so the shape stays * centred, so turning this on makes the silhouette a little smaller. */ external?: { show?: boolean; connector?: { show?: boolean; width?: number; /** Defaults to the band's own colour when undefined. */ color?: string; /** Air between the band's outermost dot and the leader line's bend. */ gap?: number; /** Length of the run out to the label. */ length?: number; }; offsetX?: number; offsetY?: number; }; }; /** Per-unit (per-dot) tooltip. */ tooltip?: { /** * Return the tooltip body for a single hovered dot. The dot's category is * `seriesIndex` and its index within that category is `dataPointIndex`, so * the formatter can index into per-unit data. Return a string or HTML. * Defaults to `"# of "`. */ formatter?(opts: { seriesName: string; seriesIndex: number; dataPointIndex: number; /** Number of dots drawn for this category (after unitValue + maxUnits). */ count: number; /** Raw category value (before unitValue scaling). */ value: number; unitValue: number; /** * This dot's own datum when the per-unit object form was supplied * (`series: [{ name, data: [...] }]`); otherwise undefined. */ datum: any; color: string; w: any; }): string; }; }; pie?: { startAngle?: number; endAngle?: number; customScale?: number; offsetX?: number; offsetY?: number; expandOnClick?: boolean; /** * How far a clicked slice slides out of the pie (px), measured along its * own mid-angle. The slice is translated, not redrawn at a bigger radius, * so its shape is unchanged and a gap opens between it and the rest of the * pie. Defaults to 10. Ignored for polarArea, and in a drilldown pie/donut * where a slice click navigates instead. Set 0 to keep the slice in place * on click. */ expandOffset?: number; /** * Hover outline: a translucent band traced just outside the rim of the * hovered slice, so the slice keeps its own colour instead of being * lightened. Takes the place of the `states.hover` filter for pie, donut * and polarArea, and is skipped when `states.hover.filter.type` is * `'none'`. */ hoverOutline?: { show?: boolean; /** Band thickness in px. Defaults to 8. */ size?: number; /** * Extra clearance between the slice rim and the band, in px, on top of * the slice stroke (the band always starts at the outer edge of the * stroke, never under it). Defaults to 0, since a stroke is normally * present and already reads as the separation. */ gap?: number; /** Band opacity over the slice colour. Defaults to 0.3. */ opacity?: number; /** Band colour. Defaults to the hovered slice's colour. */ color?: string; }; /** * Rounds the corners of each slice (in px). Applies to pie, donut and * polarArea. Defaults to 0 (sharp corners). The value is clamped per * slice so corner fillets never cross on thin or narrow slices. */ borderRadius?: number; /** * Gap between adjacent slices (in px). Applies to pie, donut and * polarArea. Defaults to 0 (slices touch). Each slice is inset * symmetrically, so its mid-angle (data label and hit region) is kept. */ spacing?: number; dataLabels?: { offset?: number; minAngleToShowLabel?: number; /** * External (outer) labels: render the category/series name outside the * slice, joined by a leader (connector) line, so the chart is readable * without the legend. The percentage keeps rendering inside the slice. * Applies to pie and donut only (ignored for polarArea, where the radial * length already encodes the value). */ external?: { show?: boolean; offsetX?: number; offsetY?: number; fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; /** * Return a string for a single-line label, or an array of strings to * stack multiple lines (e.g. `[name, percent + '%']`). */ formatter?( name: string, opts: { seriesIndex: number; percent: number; value: number; w: XChartContext; }, ): string | string[]; /** Leader line from the slice edge to the label. */ connector?: { show?: boolean; width?: number; color?: string; length?: number; gap?: number; }; }; }; donut?: { size?: string; background?: string; labels?: { show?: boolean; name?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; offsetY?: number; formatter?(val: string): string; }; value?: { show?: boolean; fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; offsetY?: number; formatter?(val: number | string): string; }; total?: { show?: boolean; showAlways?: boolean; fontFamily?: string; fontWeight?: string | number; fontSize?: string; label?: string; color?: string; formatter?(w: XChartContext): string; }; }; }; }; polarArea?: { rings?: { strokeWidth?: number; strokeColor?: string; }; spokes?: { strokeWidth?: number; connectorColors?: string | string[]; }; }; /** * Sunburst / nested pie-donut (hierarchical radial). Rings go from the centre * hole outward, one per hierarchy level; each child arc is nested inside its * parent's angular wedge. Accepts a native `children` hierarchy or an existing * `drilldown` config (adapter). */ sunburst?: { offsetX?: number; offsetY?: number; startAngle?: number; endAngle?: number; /** Centre hole radius as a % of the max radius (e.g. '15%'). */ innerSize?: string; /** Corner rounding of each arc (px), same semantics as pie borderRadius. */ borderRadius?: number; /** Gap between adjacent arcs (px), same semantics as pie spacing. */ spacing?: number; /** Draw a shallow branch's leaf to the rim ('extend') or stop it ('stop'). */ leaf?: 'extend' | 'stop'; /** Angular partition of a parent's wedge among its children. */ partition?: 'normalize' | 'strict'; /** Per-depth lightening of the parent colour (0 = same, 1 = white). */ tint?: number; /** Click a wedge to zoom into its branch (breadcrumb to go back). Default true. */ zoomOnClick?: boolean; dataLabels?: { show?: boolean; /** Hide the label on any arc narrower than this (degrees). */ minAngleToShow?: number; style?: { fontSize?: string; fontFamily?: string; fontWeight?: string | number; colors?: string[]; }; }; }; radar?: { size?: number; offsetX?: number; offsetY?: number; polygons?: { strokeColors?: string | string[]; strokeWidth?: number | number[] | string | string[]; connectorColors?: string | string[]; fill?: { colors?: string[]; }; }; }; radialBar?: { inverseOrder?: boolean; startAngle?: number; endAngle?: number; offsetX?: number; offsetY?: number; /** * Gauge sub-shape. 'arc' (default) renders the existing filled value-arc * gauge; 'needle' replaces the value-arc with a rotating pointer/needle. * Bands and ticks are independent and work for both shapes. */ shape?: 'arc' | 'needle'; /** * Value-to-angle mapping (gauge). Defaults: min: 0, max: 100. Override * for gauges with a custom domain (e.g. min: 0, max: 240 speedometer). */ min?: number; max?: number; /** * Threshold bands rendered as colored arc segments along the gauge arc. * Each band spans [`from`, `to`] in the gauge's `min..max` domain and is * filled with `color`. */ bands?: Array<{ from: number; to: number; color: string; label?: string; }>; bandsStyle?: { strokeWidth?: string; gap?: number; hideTrackWhenPresent?: boolean; linecap?: 'butt' | 'round' | 'square'; }; ticks?: { show?: boolean; major?: { count?: number; length?: number; width?: number; color?: string; placement?: 'inside' | 'outside'; }; minor?: { count?: number; length?: number; width?: number; color?: string; placement?: 'inside' | 'outside'; }; labels?: { show?: boolean; offset?: number; fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; formatter?: (value: number) => string; }; }; needle?: { color?: string; length?: string | number; baseWidth?: number; tipWidth?: number; /** * When true, also render the filled value-arc alongside the needle. * Default false preserves needle-only behavior. */ showValueArc?: boolean; /** * px offset from the geometric arc center on Y. Positive values push * the needle base down (toward the chord midpoint of a ∩-shape * gauge); negative pushes up. The needle rotates around this shifted * point. */ offsetY?: number; animation?: { enabled?: boolean; duration?: number; easing?: string; }; }; hollow?: { margin?: number; size?: string; background?: string; image?: string; imageWidth?: number; imageHeight?: number; imageOffsetX?: number; imageOffsetY?: number; imageClipped?: boolean; position?: 'front' | 'back'; /** * Optional stroke color around the hollow ring. Combined with * `strokeDasharray` this produces a dashed indicator circle around * the value text. */ stroke?: string; strokeWidth?: number; strokeDasharray?: string | number; dropShadow?: XChartDropShadow; }; track?: { show?: boolean; startAngle?: number; endAngle?: number; background?: string | string[]; strokeWidth?: string; opacity?: number; margin?: number; dropShadow?: XChartDropShadow; }; dataLabels?: { show?: boolean; name?: { show?: boolean; fontFamily?: string; fontWeight?: string | number; fontSize?: string; color?: string; offsetY?: number; formatter?(seriesName: string): string; }; value?: { show?: boolean; fontFamily?: string; fontSize?: string; fontWeight?: string | number; color?: string; offsetY?: number; formatter?(val: number): string; }; total?: { show?: boolean; label?: string; color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; formatter?(w: XChartContext): string; }; }; barLabels?: { enabled?: boolean; offsetX?: number; offsetY?: number; useSeriesColors?: boolean; fontFamily?: string; fontWeight?: string | number; fontSize?: string; formatter?: (barName: string, opts?: XChartFormatterOpts) => string; onClick?: (barName: string, opts?: XChartFormatterOpts) => void; }; }; }; export type XChartXAxis = { type?: 'category' | 'datetime' | 'numeric'; /** * X-axis category labels. Pass a flat array for a single row of labels, * or a 2-D array (`[group, label][]`) to render grouped category axes. */ categories?: Array | Array>; overwriteCategories?: number[] | string[] | undefined; offsetX?: number; offsetY?: number; sorted?: boolean; labels?: { show?: boolean; rotate?: number; rotateAlways?: boolean; hideOverlappingLabels?: boolean; showDuplicates?: boolean; trim?: boolean; minHeight?: number; maxHeight?: number; style?: { colors?: string | string[]; fontSize?: string; fontFamily?: string; fontWeight?: string | number; cssClass?: string; }; offsetX?: number; offsetY?: number; format?: string; formatter?( value: string | number, timestamp?: number, opts?: XChartFormatterOpts, ): string | string[]; datetimeUTC?: boolean; datetimeFormatter?: { year?: string; month?: string; day?: string; hour?: string; minute?: string; second?: string; }; }; group?: { groups?: { title: string; cols: number }[]; style?: { colors?: string | string[]; fontSize?: string; fontFamily?: string; fontWeight?: string | number; cssClass?: string; }; }; axisBorder?: { show?: boolean; color?: string; width?: string | number; height?: number; offsetX?: number; offsetY?: number; }; axisTicks?: { show?: boolean; borderType?: 'solid' | 'dotted' | 'dashed'; color?: string; height?: number; offsetX?: number; offsetY?: number; }; tickPlacement?: string; tickAmount?: number | 'dataPoints'; stepSize?: number; min?: number; max?: number; range?: number; floating?: boolean; decimalsInFloat?: number; position?: string; title?: { text?: string; offsetX?: number; offsetY?: number; style?: { color?: string; fontFamily?: string; fontWeight?: string | number; fontSize?: string; cssClass?: string; }; }; crosshairs?: { show?: boolean; width?: number | string; position?: string; opacity?: number; stroke?: { color?: string; width?: number; dashArray?: number; }; fill?: { type?: string; color?: string; gradient?: { colorFrom?: string; colorTo?: string; stops?: number[]; opacityFrom?: number; opacityTo?: number; }; }; dropShadow?: XChartDropShadow; }; tooltip?: { enabled?: boolean; offsetY?: number; formatter?(value: string | number, opts?: XChartFormatterOpts): string; style?: { fontSize?: string; fontFamily?: string; }; }; }; export type XChartYAxis = { show?: boolean; showAlways?: boolean; showForNullSeries?: boolean; seriesName?: string | string[]; opposite?: boolean; reversed?: boolean; logarithmic?: boolean; logBase?: number; tickAmount?: number; stepSize?: number; forceNiceScale?: boolean; alignZero?: boolean; min?: number | ((min: number) => number); max?: number | ((max: number) => number); floating?: boolean; decimalsInFloat?: number; labels?: { show?: boolean; showDuplicates?: boolean; minWidth?: number; maxWidth?: number; offsetX?: number; offsetY?: number; rotate?: number; align?: 'left' | 'center' | 'right'; padding?: number; style?: { colors?: string | string[]; fontSize?: string; fontWeight?: string | number; fontFamily?: string; cssClass?: string; }; formatter?(val: number, opts?: XChartFormatterOpts): string | string[]; }; axisBorder?: { show?: boolean; color?: string; width?: number; offsetX?: number; offsetY?: number; }; axisTicks?: { show?: boolean; color?: string; width?: number; offsetX?: number; offsetY?: number; }; title?: { text?: string; rotate?: number; offsetX?: number; offsetY?: number; style?: { color?: string; fontSize?: string; fontWeight?: string | number; fontFamily?: string; cssClass?: string; }; }; crosshairs?: { show?: boolean; position?: string; stroke?: { color?: string; width?: number; dashArray?: number; }; }; tooltip?: { enabled?: boolean; offsetX?: number; }; }; export type XChartLegendFormatterOpts = { seriesIndex: number; w: XChartContext; }; export type XChartMarkerShapeOptions = | 'circle' | 'square' | 'rect' | 'line' | 'cross' | 'plus' | 'star' | 'sparkle' | 'diamond' | 'triangle'; export type XChartMarkerShape = | XChartMarkerShapeOptions | XChartMarkerShapeOptions[]; export type XChartDiscretePoint = { seriesIndex?: number; dataPointIndex?: number; fillColor?: string; strokeColor?: string; size?: number; shape?: XChartMarkerShape; }; export type XChartMarkers = { size?: number | number[]; colors?: string | string[]; strokeColors?: string | string[]; strokeWidth?: number | number[]; strokeOpacity?: number | number[]; strokeDashArray?: number | number[]; fillOpacity?: number | number[]; discrete?: XChartDiscretePoint[]; shape?: XChartMarkerShape; offsetX?: number; offsetY?: number; showNullDataPoints?: boolean; onClick?(e?: MouseEvent): void; onDblClick?(e?: MouseEvent): void; hover?: { size?: number; sizeOffset?: number; }; }; export type XChartLegend = { show?: boolean; showForSingleSeries?: boolean; showForNullSeries?: boolean; showForZeroSeries?: boolean; floating?: boolean; inverseOrder?: boolean; position?: 'top' | 'right' | 'bottom' | 'left'; horizontalAlign?: 'left' | 'center' | 'right'; fontSize?: string; fontFamily?: string; fontWeight?: string | number; width?: number; height?: number; offsetX?: number; offsetY?: number; formatter?(legendName: string, opts?: XChartLegendFormatterOpts): string; tooltipHoverFormatter?( legendName: string, opts?: XChartLegendFormatterOpts, ): string; customLegendItems?: string[]; clusterGroupedSeries?: boolean; clusterGroupedSeriesOrientation?: 'vertical' | 'horizontal'; labels?: { colors?: string | string[]; useSeriesColors?: boolean; }; markers?: { size?: number; strokeWidth?: number; fillColors?: string[]; shape?: XChartMarkerShape; offsetX?: number; offsetY?: number; customHTML?(): string; onClick?(e: MouseEvent): void; }; itemMargin?: { horizontal?: number; vertical?: number; }; onItemClick?: { toggleDataSeries?: boolean; }; onItemHover?: { highlightDataSeries?: boolean; }; }; export type XChartEasing = | 'linear' | 'easeInSine' | 'easeOutSine' | 'easeInOutSine' | 'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic' | 'easeOutBack' | 'easeInOutBack' | (string & {}) | [number, number, number, number] | ((t: number) => number); export type XChartEventOpts = { seriesIndex: number; dataPointIndex: number; w: XChartContext; [key: string]: any; }; export type XChartLocale = { name?: string; options?: { months?: string[]; shortMonths?: string[]; days?: string[]; shortDays?: string[]; toolbar?: { download?: string; selection?: string; selectionZoom?: string; zoomIn?: string; zoomOut?: string; pan?: string; reset?: string; measure?: string; menu?: string; exportToSVG?: string; exportToPNG?: string; exportToCSV?: string; }; }; }; export interface XChartStoryboardBeatInfo { index: number; key: string | null; el: Element; direction: 'up' | 'down'; } export interface XChartDrilldownSeries { /** Unique id referenced by a data point's `drilldown` field. */ id: string | number; /** Display name used by the breadcrumb and as the (single-series) child series name. */ name?: string; /** Child data points for a single-series level. Use this OR `series`. */ data?: any[]; /** Full multi-series array for a grouped/stacked drilldown level. Use this OR `data`. */ series?: XChartAxisChartSeries; /** Optional chart-type override applied when this level is shown. */ chart?: Pick; plotOptions?: XChartPlotOptions; xaxis?: XChartXAxis; yaxis?: XChartYAxis | XChartYAxis[]; colors?: Array string)>; /** Optional fill override (e.g. a pattern fill to visually distinguish drilled levels). */ fill?: XChartFill; /** Optional legend override (e.g. show a legend when a level is a pie/donut). */ legend?: XChartLegend; } export interface XChartDrilldownEvent { /** The level id navigated away from. */ from: string | number; /** The level id navigated to (`'root'` at the top). */ to: string | number; /** The clicked data point (drill-down only). */ point?: any; seriesIndex?: number; dataPointIndex?: number; } export interface XChartDrilldownContext { /** The requested level id, i.e. the clicked point's `drilldown` value. */ id: string | number | null; point: any; seriesIndex?: number; dataPointIndex?: number; } export interface XChartDrilldown { /** Master switch. When false the feature stays inert even if imported. */ enabled?: boolean; /** Inline child levels referenced by data-point `drilldown` ids. */ series?: XChartDrilldownSeries[]; breadcrumb?: | false | { show?: boolean; position?: 'top-left' | 'top-right'; separator?: string; rootLabel?: string; offsetX?: number; offsetY?: number; formatter?( label: string, opts: { index: number; depth: number }, ): string; }; animation?: { enabled?: boolean; /** * Anchor the drill transition at the clicked point: the child unfolds * outward from it (and settles back on drill-up) instead of the chart * simply re-rendering. A gentle scale layered on the SVG. Opt-in. * Defaults to false. */ zoomFromPoint?: boolean; /** Base transition duration in ms when `zoomFromPoint` is true. Default 260. */ speed?: number; }; /** * The dot marking a drillable point on a line/area chart drawn without * markers. A bar, slice, tile or cell is already a visible, clickable mark; * a line point is not, so without this nothing would show that a point can * be opened. Only drillable points get one. Set `show: false` to supply your * own affordance. Omitted colours inherit the series marker defaults. */ marker?: { /** Default true. */ show?: boolean; /** Radius in px. Default 6. */ size?: number; /** Defaults to the series marker shape. */ shape?: 'circle' | 'square' | 'rect'; /** Defaults to the series colour. */ fillColor?: string; /** Default '#fff'. */ strokeColor?: string; }; /** * Async resolver called when a drillable point has no inline `series` match. * * Failure never changes state: a throw, a rejection, or a resolved value * without a `data` array leaves the chart where it was and fires * `drillDownError`. A second click while one is in flight is ignored rather * than starting a second request. */ onDrillDown?( ctx: XChartDrilldownContext, ): XChartDrilldownSeries | Promise; /** * Overlay shown while an async level resolves. `text` is optional; with * none, the spinner shows alone and carries "Loading" as its accessible * name, so the default ships no user-visible English. */ loading?: | false | { show?: boolean; text?: string; }; /** * Cache levels resolved by `onDrillDown`, keyed by id, so drilling back down * a branch does not re-fetch. Default true. Clear it with the drilldown * module's `clearCache()` when the underlying data changes. */ cache?: boolean; } export type XChartForecastDataPoints = { count?: number; fillOpacity?: number; strokeWidth?: undefined | number; dashArray?: number; }; export type XChartGrid = { show?: boolean; borderColor?: string; strokeDashArray?: number; position?: 'front' | 'back'; xaxis?: { lines?: { show?: boolean; offsetX?: number; offsetY?: number; }; }; yaxis?: { lines?: { show?: boolean; offsetX?: number; offsetY?: number; }; }; row?: { colors?: string[]; opacity?: number; }; column?: { colors?: string[]; opacity?: number; }; padding?: { top?: number; right?: number; bottom?: number; left?: number; }; }; export type XChartNoData = { text?: string; align?: 'left' | 'right' | 'center'; verticalAlign?: 'top' | 'middle' | 'bottom'; offsetX?: number; offsetY?: number; style?: { color?: string; fontSize?: string; fontFamily?: string; }; }; export interface XChartPluginActivation { name: string; options?: Record; order?: number; } export type XChartResponsive = { breakpoint?: number; options?: XChartOptions; }; export type XChartStates = { hover?: { filter?: { type?: 'none' | 'lighten' | 'darken'; /** * Blend strength toward white (lighten) or black (darken), from 0 to 1. * Higher means a stronger effect. The shift is proportional to the base * color's head-room, so already-light colors are lightened only slightly * (and already-dark colors darkened only slightly) and never wash out. * @default 0.15 */ value?: number; }; }; active?: { allowMultipleDataPointsSelection?: boolean; filter?: { type?: 'none' | 'lighten' | 'darken'; /** * Blend strength toward white (lighten) or black (darken), from 0 to 1. * Higher means a stronger effect. * @default 0.35 */ value?: number; }; }; }; export type XChartStroke = { show?: boolean; curve?: | 'smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic' | ('smooth' | 'straight' | 'stepline' | 'linestep' | 'monotoneCubic')[]; lineCap?: 'butt' | 'square' | 'round'; colors?: string[]; width?: number | number[]; dashArray?: number | number[]; fill?: XChartFill; }; export type XChartTitleSubtitle = { text?: string; align?: 'left' | 'center' | 'right'; margin?: number; offsetX?: number; offsetY?: number; floating?: boolean; style?: { fontSize?: string; fontFamily?: string; fontWeight?: string | number; color?: string; }; }; export type XChartTheme = { /** '' (the default) inherits / auto-resolves; 'light' | 'dark' force a mode. */ mode?: 'light' | 'dark' | ''; palette?: string; /** * Facet (#13): read `--apx-*` CSS design tokens from the cascade * (`--apx-accent`, `--apx-fore`, `--apx-grid`, `--apx-surface`, * `--apx-series-1..N`). They top the resolution chain, below explicit config. * true (default) reads any present (absence is a no-op); false disables. * Tokens are re-read on each render; use `chart.refreshTokens()` after a * runtime CSS change that does not itself trigger a render. */ tokens?: boolean; /** * Facet (#13): 'os' follows the operating system's `prefers-color-scheme` * (light/dark) and `prefers-contrast` reactively, with no JS. SSR-safe. */ follow?: 'os' | false; /** Facet (#13): a theme registered via `ApexCharts.registerTheme(name, def)`. */ name?: string; monochrome?: { enabled?: boolean; color?: string; shadeTo?: 'light' | 'dark'; shadeIntensity?: number; }; accessibility?: { colorBlindMode?: | 'deuteranopia' | 'protanopia' | 'tritanopia' | 'highContrast' | ''; }; }; export type XChartTooltipCustomOpts = { series: number[][]; seriesIndex: number; dataPointIndex: number; y1?: number; y2?: number; w: XChartContext; }; export type XChartTooltipY = { title?: { formatter?(seriesName: string, opts?: XChartFormatterOpts): string; }; formatter?(val: number, opts?: XChartFormatterOpts): string; }; export type XChartTooltip = { enabled?: boolean; enabledOnSeries?: undefined | number[]; shared?: boolean; followCursor?: boolean; intersect?: boolean; inverseOrder?: boolean; arrow?: boolean; custom?: | (( opts: XChartTooltipCustomOpts, ) => string | number | Element | { nodeName: string }) | Array< ( opts: XChartTooltipCustomOpts, ) => string | number | Element | { nodeName: string } >; fillSeriesColor?: boolean; theme?: 'light' | 'dark'; cssClass?: string; hideEmptySeries?: boolean; style?: { fontSize?: string; fontFamily?: string; background?: string; }; onDatasetHover?: { highlightDataSeries?: boolean; }; x?: { show?: boolean; format?: string; formatter?(val: string | number, opts?: XChartFormatterOpts): string; }; y?: XChartTooltipY | XChartTooltipY[]; z?: { title?: string; formatter?(val: number): string; }; marker?: { show?: boolean; fillColors?: string[]; }; items?: { display?: string; }; fixed?: { enabled?: boolean; position?: string; // topRight; topLeft; bottomRight; bottomLeft offsetX?: number; offsetY?: number; }; }; export interface XChartOptions { annotations?: XChartAnnotations; chart?: XChart; /** * Series colors. Each entry is either a CSS color string (hex, rgb, hsl, * named) or a function returning one per-datapoint. The list cycles when * there are more series than colors. */ colors?: Array string)>; dataLabels?: XChartDataLabels; /** Opt-in drilldown navigation. Requires `import 'apexcharts/features/drilldown'`. */ drilldown?: XChartDrilldown; fill?: XChartFill; forecastDataPoints?: XChartForecastDataPoints; grid?: XChartGrid; labels?: string[]; legend?: XChartLegend; markers?: XChartMarkers; noData?: XChartNoData; /** Weave (#1) plugin activation list. Requires `import 'apexcharts/features/weave'`. */ plugins?: XChartPluginActivation[]; plotOptions?: XChartPlotOptions; responsive?: XChartResponsive[]; parsing?: XChartParsing; series?: XChartSeriesType; states?: XChartStates; stroke?: XChartStroke; subtitle?: XChartTitleSubtitle; theme?: XChartTheme; title?: XChartTitleSubtitle; tooltip?: XChartTooltip; xaxis?: XChartXAxis; yaxis?: XChartYAxis | XChartYAxis[]; } export type XChart = { width?: string | number; height?: string | number; type?: | 'line' | 'area' | 'bar' | 'pie' | 'donut' | 'radialBar' | 'scatter' | 'bubble' | 'heatmap' | 'candlestick' | 'boxPlot' | 'violin' | 'histogram' | 'radar' | 'polarArea' | 'rangeBar' | 'rangeArea' | 'treemap' | 'unit' | 'waffle' | 'sunburst' | 'funnel' | 'pyramid' | 'gauge'; /** * Internal — populated when `type` is a first-class alias (`'funnel'`, * `'pyramid'`, `'gauge'`, `'waffle'`, `'histogram'`). The original requested * type is preserved here while `type` is normalized to the underlying * renderer (`'bar'`, `'radialBar'` or `'unit'`). Read-only for consumers. */ requestedType?: 'funnel' | 'pyramid' | 'gauge' | 'waffle' | 'histogram'; foreColor?: string; fontFamily?: string; background?: string; offsetX?: number; offsetY?: number; dropShadow?: XChartDropShadow & { enabledOnSeries?: undefined | number[]; }; nonce?: string; events?: { animationEnd?(chart: ApexCharts, options?: XChartEventOpts): void; beforeMount?(chart: ApexCharts, options?: XChartEventOpts): void; mounted?(chart: ApexCharts, options?: XChartEventOpts): void; updated?(chart: ApexCharts, options?: XChartEventOpts): void; mouseMove?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; mouseLeave?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; click?(e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts): void; xAxisLabelClick?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; legendClick?( chart: ApexCharts, seriesIndex?: number, options?: XChartEventOpts, ): void; markerClick?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; selection?( chart: ApexCharts, options?: { xaxis?: { min: number; max: number }; yaxis?: { min: number; max: number }; }, ): void; dataPointSelection?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; dataPointMouseEnter?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; dataPointMouseLeave?( e: MouseEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; beforeZoom?( chart: ApexCharts, options?: { xaxis: { min: number; max: number } }, ): boolean | void; beforeResetZoom?( chart: ApexCharts, options?: XChartEventOpts, ): boolean | void; zoomed?( chart: ApexCharts, options?: { xaxis: { min: number; max: number }; yaxis?: { min: number; max: number }[]; }, ): void; scrolled?( chart: ApexCharts, options?: { xaxis: { min: number; max: number } }, ): void; brushScrolled?( chart: ApexCharts, options?: { xaxis: { min: number; max: number }; yaxis?: { min: number; max: number }[]; }, ): void; /** * Linked Views (#4): fired on the source chart when a brush range drives a * crossfilter across the group. */ crossFilter?( chart: ApexCharts, options?: { xaxis: { min: number; max: number }; sourceChartID?: string }, ): void; /** * Linked Views (#4) FILTER mode: fired on the source chart when a click * toggles a crossfilter bucket. `options` carries the coordinator state * (active filters, filtered/total counts), the source chartID, and the key. */ filterChange?( chart: ApexCharts, options?: { filters: Record; filteredCount: number; total: number; sourceChartID?: string; key?: any; }, ): void; /** * Ink Layer (#7): fired after an annotation is dragged or resized. `options` * carries the annotation type ('point' | 'xaxis' | 'yaxis'), id/index, and * the new data coordinates (x/y, plus x2/y2 for range annotations). */ annotationDragged?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; x: any; y: any; x2?: any; y2?: any; }, ): void; /** * Ink Layer (#7): fired after a point annotation's label is edited inline. * `options` carries the annotation id/index and the new label text. */ annotationEdited?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; text: string; }, ): void; /** * Ink Layer (#7): fired after an annotation is created by clicking the * plot in create mode or from the context menu (note or dashed line). * `options` carries the new annotation type/id/index and its x and/or y. */ annotationCreated?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; x?: any; y?: any; }, ): void; /** * Ink Layer (#7): fired after an annotation is restyled from the floating * note editor (accent color, bold, font size, marker size/shape). `options` * carries the annotation type/id/index and its current label + marker config. */ annotationStyled?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; label?: any; marker?: any; }, ): void; /** * Ink Layer (#7): fired after an annotation is deleted from the floating * note editor. `options` carries the annotation type/id and the index it * occupied before removal. */ annotationDeleted?( chart: ApexCharts, options?: { type?: 'point' | 'xaxis' | 'yaxis'; id?: string; index: number; }, ): void; /** * Measure ruler (#18): fired when a measure ruler is drawn. Requires the * `measure` feature. `options` carries the endpoints and the deltas. */ measured?( chart: ApexCharts, options?: { from: { x: any; y: any }; to: { x: any; y: any }; dx: number; dy: number; percentChange: number; slope: number; }, ): void; /** * Storyboard: fired when scrolling (or goTo) activates a beat. Requires * the `storyboard` feature and an active chart.storyboard.bind(). */ beatChange?(chart: ApexCharts, options?: XChartStoryboardBeatInfo): void; keyDown?( e: KeyboardEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; keyUp?( e: KeyboardEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; /** Fired before a drill-down transition begins. Requires the Drilldown feature. */ drillDownStart?( info: ApexCharts.ApexDrilldownEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; /** Fired after a drill-down transition completes. Requires the Drilldown feature. */ drillDownEnd?( info: ApexCharts.ApexDrilldownEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; /** Fired after navigating back up a drilldown level. Requires the Drilldown feature. */ drillUp?( info: ApexCharts.ApexDrilldownEvent, chart?: ApexCharts, options?: XChartEventOpts, ): void; /** Fired when an async onDrillDown resolver throws or rejects. Requires the Drilldown feature. */ drillDownError?( info: { id: string | number | null; error: any }, chart?: ApexCharts, options?: XChartEventOpts, ): void; }; brush?: { enabled?: boolean; autoScaleYaxis?: boolean; target?: string; targets?: string[]; }; /** * Linked Views (#4): crossfilter / linked highlighting. Requires the `link` * feature (`import 'apexcharts/features/link'`). Two modes: * * HIGHLIGHT (P1): `enabled` with no `dimension`. Charts sharing a * `chart.group` form a set; brushing a range (needs `chart.selection.enabled`) * on any member dims every member's marks whose x is outside the range, in * place (no re-render). * * FILTER (P2): set `dimension` (its presence selects this path). Each chart * declares a dimension + reduction over a shared record set registered with * `ApexCharts.crossfilter({ id, records })`; clicking a bucket re-aggregates * every other participating chart over the filtered subset. */ link?: { /** @default false */ enabled?: boolean; /** Highlight mode (P1) label; filter mode is selected by `dimension`. @default 'highlight' */ mode?: 'highlight' | 'filter'; /** Opacity applied to dimmed (unselected / out-of-range) marks. @default 0.2 */ dimOpacity?: number; /** FILTER mode: crossfilter coordinator id (defaults to `chart.group`). */ id?: string; /** * FILTER mode: `(row) => key`. Its presence selects filter mode. For a * heatmap (matrix) dimension it returns `[xKey, yKey]`. */ dimension?: (row: any) => any; /** FILTER mode: reduction over a bucket's rows. @default 'count' */ reduce?: | 'count' | { sum?: string; avg?: string; min?: string; max?: string } | ((rows: any[]) => number); /** * FILTER mode: bucket kind. Else inferred: `bins` present => 'range', a * heatmap chart => 'matrix' (2D), otherwise 'category'. */ type?: 'category' | 'range' | 'matrix'; /** FILTER mode (range dims): binning spec. */ bins?: { width?: number; count?: number; thresholds?: number[] }; /** FILTER mode (category dims): key ordering. @default 'first-seen' */ order?: 'first-seen' | 'asc' | 'desc' | ((a: any, b: any) => number); /** FILTER mode (axis charts): the derived series name. @default 'Count' */ seriesName?: string; }; /** * Ink Layer (#7): direct-manipulation annotations. When enabled, every point * annotation is draggable (unless it sets `draggable:false`); or opt in per * annotation with `annotations.points[].draggable`. Clicking an ink-managed * annotation opens a floating editor card anchored to it: rename inline, * recolor via accent swatches, toggle bold, step the font size, size/reshape * the marker, or delete the note. Axis-line annotations get separate Label * and Line color rows, so restyling the label chip never touches the stroke. * Requires the `ink` feature (`import 'apexcharts/features/ink'`). Fires the * `annotationDragged`, `annotationEdited`, `annotationStyled` and * `annotationDeleted` events. */ ink?: { /** @default false */ enabled?: boolean; /** * Show a minimal "add note" tool palette; clicking it arms create mode (the * next plot click drops an editable, draggable annotation). @default false */ palette?: boolean; /** * Snap a dragged point / axis-line annotation to the nearest gridline * (numeric x + linear y). @default false */ snap?: boolean; /** * Accent swatches offered by the floating note editor. Defaults to a * built-in 6-color palette when omitted. */ noteColors?: string[]; }; /** * Measure ruler (#18): a measure/delta ruler. Requires the `measure` * feature (`import 'apexcharts/features/measure'`). Hold `key` and drag * A->B on the plot, or call `chart.startMeasure()`, to read * dx/dy/%change/slope in data space; on release the ruler pins as a * data-anchored overlay that re-projects on zoom/resize. Fires `measured`. */ measure?: { /** @default false */ enabled?: boolean; /** * 'span': finance-style vertical band between two x-positions with a * change/%/range readout, endpoints snapped to the first series. 'free': * a diagonal ruler between two arbitrary points. @default 'span' */ mode?: 'span' | 'free'; /** Key held to arm a drag when not in sticky mode. @default 'm' */ key?: string; /** Pin the ruler as a data-anchored overlay on release. @default true */ pinOnRelease?: boolean; /** * Semantic colors. Every element also has a stable CSS class and a * direction class (apexcharts-measure-up|down|flat) for stylesheet theming. */ colors?: { up?: string; down?: string; neutral?: string; guide?: string }; /** Span mode: draw the shaded band between the two x-positions. @default true */ band?: boolean; /** Span mode: draw the vertical dashed reference lines. @default true */ guides?: boolean; /** Draw the endpoint dots on the series line. @default true */ markers?: boolean; /** Value formatters for the readout. */ format?: { x?: (x: number) => string; y?: (y: number) => string; percent?: (pct: number) => string; }; /** * Full readout override. Receives the measure info and returns a string or * an array of lines. Overrides the default readout text. */ label?: (info: { from: { x: any; y: any }; to: { x: any; y: any }; dx: number; dy: number; percentChange: number; slope: number; mode: 'span' | 'free'; }) => string | string[]; }; /** * Radial Actions (#chrome): right-click / long-press context menu. Requires * the `contextMenu` feature (`import 'apexcharts/features/context-menu'`). * Each action receives the clicked data coordinates, so verbs act at that * point rather than chart-wide. 'measure' is shown only when the measure tool * is enabled. When the ink feature is bundled, 'annotate' drops an * ink-managed note that opens its floating editor (rename, restyle, delete), * and 'xline' / 'yline' drop ink-managed dashed lines the same way ('xline' * vertical at the clicked x, 'yline' horizontal at the clicked y). */ contextMenu?: { /** @default false */ enabled?: boolean; /** * Ordered menu items: built-in ids and/or custom entries. @default * ['annotate','xline','yline','measure'] */ items?: Array< | 'annotate' | 'xline' | 'yline' | 'measure' | { id?: string; label?: string; icon?: string; onClick?: ( chart: ApexCharts, context: { x: any; y: any; seriesIndex: number | null; dataPointIndex: number | null; clientX: number; clientY: number; }, ) => void; } >; /** Override the built-in item labels. */ labels?: { annotate?: string; xline?: string; yline?: string; measure?: string; }; /** Text of the annotation dropped by the built-in 'annotate' item. @default 'Note' */ noteText?: string; /** * Shared styling for the built-in 'xline' ("Annotate here", vertical at * the clicked x) and 'yline' ("Mark this level", horizontal at the * clicked y) items. Lines only, never a range rectangle. With the ink * feature bundled the line opens the floating editor, whose Label and * Line color rows restyle the chip and the stroke independently, and is * draggable and undoable, like the note. */ line?: { /** Label drawn on the line. @default '' (no label) */ text?: string; /** @default 4 */ strokeDashArray?: number; /** Line color; omit to keep the annotation default. */ color?: string; }; }; id?: string; injectStyleSheet?: boolean; group?: string; /** * Per-chart license key for the gated premium features (storyboard, link / * crossfilter, ink, measure, contextMenu, perspectives, history). Overrides * ApexCharts.setLicense() and window.Apex.license for this chart. Without a * valid key those features still work but show an "APEXCHARTS" trial * watermark. Shared across the ApexCharts family. */ license?: string; locales?: XChartLocale[]; defaultLocale?: string; perspectives?: { serializeOptions?: string[]; }; history?: { enabled?: boolean; maxDepth?: number; coalesceMs?: number; keyboard?: boolean; }; /** Strata (#2) series renderer. Requires `import 'apexcharts/features/renderer-canvas'` for non-SVG. */ renderer?: 'svg' | 'canvas' | 'auto'; rendererThreshold?: number; layers?: { series?: 'svg' | 'canvas' | 'auto'; grid?: 'svg'; annotations?: 'svg'; dataLabels?: 'svg'; }; parentHeightOffset?: number; redrawOnParentResize?: boolean; redrawOnWindowResize?: boolean | ((...args: any[]) => boolean); sparkline?: { enabled?: boolean; }; stacked?: boolean; stackType?: 'normal' | '100%'; stackOnlyBar?: boolean; /** * Real-time streaming mode. When enabled, appendData() bounds memory * automatically: each series is trimmed to `maxPoints` (when set) or to the * visible `xaxis.range` window plus a small off-screen runway. The * constant-velocity scroll animation for windowed updates needs no opt-in. */ streaming?: { enabled?: boolean; /** Maximum points kept per series by appendData(). Unset: derived from * `xaxis.range` when that is set; otherwise no trimming occurs. */ maxPoints?: number; }; toolbar?: { show?: boolean; offsetX?: number; offsetY?: number; tools?: { download?: boolean | string; selection?: boolean | string; zoom?: boolean | string; zoomin?: boolean | string; zoomout?: boolean | string; pan?: boolean | string; reset?: boolean | string; /** * Measure ruler toggle. Shown only when `chart.measure.enabled` is true * and the `measure` feature is bundled. `false` keeps the ruler * key-driven only; a string supplies a custom SVG icon. */ measure?: boolean | string; customIcons?: { icon?: string; title?: string; index?: number; class?: string; click?( chart: ApexCharts, options?: XChartEventOpts, e?: MouseEvent, ): void; }[]; }; export?: { csv?: { filename?: undefined | string; columnDelimiter?: string; headerCategory?: string; headerValue?: string; categoryFormatter?(value?: string | number): string; valueFormatter?(value?: string | number): string; }; svg?: { filename?: undefined | string; }; png?: { filename?: undefined | string; }; width?: number; scale?: number; /** * Inline the `@font-face` rules for the fonts the chart actually uses * into the exported SVG/PNG as base64 data URIs. * * An exported SVG is a standalone document and cannot reach the page's * `@font-face` rules, so without this a custom font is replaced by a * generic fallback in the export. Cross-origin font files that deny CORS * are skipped and fall back as before. * * @default true */ embedFonts?: boolean; }; autoSelected?: 'zoom' | 'selection' | 'pan' | 'measure'; }; zoom?: { enabled?: boolean; type?: 'x' | 'y' | 'xy'; autoScaleYaxis?: boolean; /** * Cursor-anchored zoom on mouse wheel / trackpad. `'auto'` enables it only * when the toolbar's reset button is present, so an unintended scroll-zoom * is always undoable; `true` forces it on even with the toolbar hidden. * Requires `enabled: true`. * @default 'auto' */ allowMouseWheelZoom?: boolean | 'auto'; /** * Momentum: enable two-finger pinch-zoom on touch devices. Zooms the x-axis * around the pinch centroid, frame-by-frame. `'auto'` enables it only when * the toolbar's reset button is present; `true` forces it on even with the * toolbar hidden. Requires `enabled: true`. * @default 'auto' */ pinch?: boolean | 'auto'; zoomedArea?: { fill?: { color?: string; opacity?: number; }; stroke?: { color?: string; opacity?: number; width?: number; }; }; }; /** * Momentum: kinetic panning on touch. A one-finger pan released with velocity * keeps gliding and decelerates, clamping at the data edges. */ pan?: { /** @default true */ inertia?: boolean; /** Velocity decay applied each animation frame (0-1). @default 0.92 */ friction?: number; }; selection?: { enabled?: boolean; type?: string; fill?: { color?: string; opacity?: number; }; stroke?: { width?: number; color?: string; opacity?: number; dashArray?: number; }; xaxis?: { min?: number; max?: number; }; yaxis?: { min?: number; max?: number; }; }; animations?: { /** * Master switch. Each chart type gets a tailored initial-mount animation * by default (line/area pen-stroke draw, bar grow, scatter pop, heatmap * diagonal wave, treemap largest-first cascade, pie/donut/gauge sweep). * Set false to render charts without any animation. */ enabled?: boolean; /** Animation duration in ms (default 800). */ speed?: number; /** * Cadence (#6): easing for the generic tweens. See `ApexEasing` for the * complete built-in curve list and the accepted forms; register custom * names with `ApexCharts.registerEasing`. * @default 'easeInOutSine' */ easing?: XChartEasing; /** * Drives per-element stagger across all chart types. When enabled, bars, * heatmap cells, scatter points, and treemap tiles reveal in sequence; * line/area markers fade in progressively as the line draws. */ animateGradually?: { enabled?: boolean; /** Requested stagger step in ms; auto-capped per chart so total * stagger ≤ ~half the animation speed. */ delay?: number; }; /** Data-change (updateSeries) animation. Independent from initial mount. */ dynamicAnimation?: { enabled?: boolean; speed?: number; /** * Easing for data-change morphs only (same accepted forms as * `animations.easing`; see `ApexEasing`). Unset: inherits the * chart-wide easing, except detected streaming scrolls (appendData or * a shifted fixed-length window under `xaxis.range`) which default to * 'linear' so the window slides at constant velocity. */ easing?: XChartEasing; }; /** * Cross-type morph (updateOptions changing chart.type). Requires the * optional `apexcharts/features/morph` feature to be registered; without * that import these settings have no effect. Supported pairs include * bar ↔ pie/donut/radialBar/polarArea (and the trivial pie↔donut↔polarArea * cases). Falls back to instant snap when types or data shape are * incompatible. */ chartTypeMorph?: { enabled?: boolean; speed?: number; }; /** * When true (default), honors the OS-level prefers-reduced-motion media * query — all initial-mount animations are skipped and the chart renders * instantly. Set to false to override (e.g. for QA / demo screens). */ respectReducedMotion?: boolean; /** * Above this many data points (default 1000), the per-element morph + * stagger — which spins up one JS-driven animation timeline per path — is * replaced by a single GPU-composited opacity fade of the whole series. * Keeps initial render and zoom transitions smooth on large datasets * (e.g. thousands of candlesticks/bars). Set to 0 to always animate * per-element regardless of dataset size. */ largeDatasetThreshold?: number; }; accessibility?: { enabled?: boolean; description?: string; announcements?: { enabled?: boolean; }; keyboard?: { enabled?: boolean; navigation?: { enabled?: boolean; wrapAround?: boolean; }; }; }; dataReducer?: { enabled?: boolean; algorithm?: 'lttb'; targetPoints?: number; threshold?: number; }; }; //#endregion export enum XChartAction { Refresh = 'refresh', Destroy = 'destroy', UpdateSeries = 'update_series', UpdateOptions = 'update_options', } export type XChartActionIdentifier = XChartAction | string; export interface XChartActionModel extends XBaseActionModel {} export type XChartSeriesType = XChartAxisChartSeries | XChartNonAxisChartSeries; export interface IXChartContainer extends IXComponentCardContainer { // // Commons ... actionProvider: Subject; cssClass: XStandardType>; // // Chart Props ... autoUpdate: XStandardType; options: XStandardType; series: XStandardType; // // Events ... chartRendered: EventEmitter; dataPointSelected: EventEmitter; zoomed: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XChartContainer extends XComponentCardContainer implements Readonly { // readonly chartId: XStandardType; readonly options: XStandardType; readonly autoUpdate: XStandardType = true; readonly cssClass: XStandardType>; readonly actionProvider = new Subject(); readonly series: XStandardType; // readonly zoomed = new EventEmitter(); readonly chartRendered = new EventEmitter(); readonly dataPointSelected = new EventEmitter(); } @Injectable() @Component({ template: `` }) export abstract class XChartContainerComponent extends XComponentCardContainerComponent implements IXChartContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() options: XStandardType = this.propertyProvider.options; @Input() series: XStandardType = this.propertyProvider.series; @Input() autoUpdate: XStandardType = this.propertyProvider.autoUpdate; // // Events ... @Output() chartRendered: EventEmitter = new EventEmitter(); @Output() dataPointSelected: EventEmitter = new EventEmitter(); @Output() zoomed: EventEmitter = new EventEmitter(); // //#region ComponentCard Props ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XChartContainer, ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider, ); } //#endregionّ // //#region Abstract ... public extractProps( container?: IXChartContainer, ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass, ), // options: this.getValue( container ? container.options : this.options, ), series: this.getValue(container ? container.series : this.series), autoUpdate: this.getValue( container ? container.autoUpdate : this.autoUpdate, ), }).pipe( map((data) => { return { superData, data, }; }), ); }), ) .pipe( map((info) => ({ ...info.data, ...info.superData, actionProvider: container ? container.actionProvider : this.actionProvider, chartRendered: this.chartRendered, dataPointSelected: this.dataPointSelected, zoomed: this.zoomed, })), ); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.component.html
{{ item.key }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.component.scss :host { --size: 32px; } .x-color { direction: ltr !important; width: 100%; display: flex; } .x-color-title { flex: 1 1 auto; margin: { top: auto; bottom: auto; } max-width: 230px; } .x-spacer { flex: 1 1 auto; } .x-color-value-button { background-color: transparent; } .x-color-value { opacity: 0.7; width: var(--size); border-radius: 50%; height: var(--size); border-style: var(--border-style); border-color: var(--border-color); border-width: var(--border-width); } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.component.ts import { nameof, parseXColor, isNullOrEmptyString, getXColorCssVariableName, } from 'x-framework-core'; import { XColorAction, XColorCssVars, XColorActionModel, XColorContainerComponent, } from './x-color.typings'; import { Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ selector: 'x-color', templateUrl: './x-color.component.html', styleUrls: ['./x-color.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XColorComponent extends XColorContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.applyDefaults(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Size Changed ... const isSizeChanged = changeKeys.includes(nameof('size')); if (isSizeChanged) { await this.applySize(); } //#endregion // //#region borderWidth Changed ... const isBorderWidthChanged = changeKeys.includes( nameof('borderWidth') ); if (isBorderWidthChanged) { await this.applyBorderWith(); } //#endregion // //#region borderStyle Changed ... const isBorderStyleChanged = changeKeys.includes( nameof('borderStyle') ); if (isBorderStyleChanged) { await this.applyBorderStyle(); } //#endregion // //#region borderColor Changed ... const isBorderColorChanged = changeKeys.includes( nameof('borderColor') ); if (isBorderColorChanged) { await this.applyBorderColor(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Handlers ... async handleCopyToClipboard(value: string) { this.managerService.saveToClipboard(value); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XColorAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // //#region Appliers ... private async applyDefaults() { // await this.applySize(); await this.applyBorderWith(); await this.applyBorderColor(); await this.applyBorderStyle(); } private async applySize() { // let size = await this.getValueAsync(this.size); size = !size || size === 0 ? 32 : size; // this.setCssVar(XColorCssVars.Size, `${size}px`); this.detectChanges(); } private async applyBorderWith() { // let borderWidth = await this.getValueAsync(this.borderWidth); // this.setCssVar(XColorCssVars.BorderWidth, `${borderWidth}px`); this.detectChanges(); } private async applyBorderStyle() { // let borderStyle = await this.getValueAsync(this.borderStyle); // this.setCssVar(XColorCssVars.BorderStyle, `${borderStyle}`); this.detectChanges(); } private async applyBorderColor() { // const color = await this.getValueAsync(this.borderColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XColorCssVars.BorderColor, `var(${bgColor})`); this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XColorComponent } from './x-color.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XColorComponent], imports: [CommonModule, XBaseComponentModule], exports: [CommonModule, XColorComponent, XBaseComponentModule], }) export class XColorModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color\x-color.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { XBorderStyle, XStandardType, XColorKeyValue, XOneOrManyType, XColorIdentifier, XColorWithBrightness, XBorderStyleIdentifier, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XColorAction { Refresh = 'refresh', SetSelectedColor = 'set_selected_color', } export type XColorActionIdentifier = XColorAction | string; export interface XColorActionModel extends XBaseActionModel {} export enum XColorCssVars { Size = 'size', BorderWidth = 'border-width', BorderColor = 'border-color', BorderStyle = 'border-style', } // //#region Container ... export interface IXColorContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // showLabel: XStandardType; labelColor: XStandardType; // size: XStandardType; value: XStandardType; // borderWidth: XStandardType; borderStyle: XStandardType; borderColor: XStandardType; } @Injectable({ providedIn: 'root' }) export class XColorContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly showLabel: XStandardType = true; readonly labelColor: XStandardType = XColorWithBrightness.Dark; // readonly size: XStandardType = 32; // readonly value: XStandardType; // readonly borderWidth: XStandardType = 1; readonly borderStyle: XStandardType = XBorderStyle.Solid; readonly borderColor: XStandardType = XColorWithBrightness.LightShade; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XColorContainerComponent extends XBaseContainerComponent implements IXColorContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() showLabel: XStandardType = this.propertyProvider.showLabel; @Input() labelColor: XStandardType = this.propertyProvider.labelColor; // @Input() size: XStandardType = this.propertyProvider.size; @Input() value: XStandardType = this.propertyProvider.value; // @Input() borderWidth: XStandardType = this.propertyProvider.borderWidth; @Input() borderStyle: XStandardType = this.propertyProvider.borderStyle; @Input() borderColor: XStandardType = this.propertyProvider.borderColor; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XColorContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXColorContainer ): Observable { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // showLabel: this.getValue( container ? container.showLabel : this.showLabel ), labelColor: this.getValue( container ? container.labelColor : this.labelColor ), // size: this.getValue(container ? container.size : this.size), // value: this.getValue(container ? container.value : this.value), // borderWidth: this.getValue( container ? container.borderWidth : this.borderWidth ), borderStyle: this.getValue( container ? container.borderStyle : this.borderStyle ), borderColor: this.getValue( container ? container.borderColor : this.borderColor ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.component.html
{{ hexValue }}
{{ rgbaValue }}
{{ hslaValue }}

{{ getResourceValue(presetColorsLable) | async }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.component.scss :host { display: block; width: inherit; --cursor-color: val(--x-color-dark); } :host ::ng-deep .x-on-top { z-index: 10000; } @mixin boder-radius($radius) { -moz-border-radius: $radius; -webkit-border-radius: $radius; border-radius: $radius; -khtml-border-radius: $radius; } .x-force-ltr { direction: ltr !important; } .x-color-picker { // margin: 0; font-size: 11px; // box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; // height: auto; width: inherit; cursor: default; min-width: 200px; // -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .x-color-palette { // width: 100%; border: none; cursor: pointer; min-height: 130px; margin-bottom: 8px; background-size: 100% 100%; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOYAAACCCAYAAABSD7T3AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwksPWR6lgAAIABJREFUeNrtnVuT47gRrAHN+P//Or/61Y5wONZ7mZ1u3XAeLMjJZGZVgdKsfc5xR3S0RIIUW+CHzCpc2McYo7XGv3ex7UiZd57rjyzzv+v+33X/R/+3r/f7vR386Y+TvKNcf/wdhTLPcv9qU2wZd74uth0t1821jkIZLPcsI/6nWa4XvutquU0Z85mnx80S/ZzgpnLnOtHNt7/ofx1TKXcSNzN/7qbMQ3ju7rNQmMYYd/4s2j9aa+P+gGaMcZrb1M/tdrvf7/d2v99P9/t93O/3cbvdxu12G9frdVwul3E+n8c///nP+2+//Xb66aefxl//+tfx5z//2YK5Al2rgvf4UsbpdGrB52bAvArXpuzjmiqAVSGz5eDmGYXzhbAZmCrnmzddpUU+8Y1dAOYeXCtDUwVwV7YCGH6uAmyMcZ9l5vkUaBPGMUZ7/J5w/792/fvv9Xq93263dr/fTxPECeME8nK5jM/Pz/HTTz/dv337dvrll1/GP/7xj/G3v/1t/OUvfwkVswongjdOp9PzH3U3D3zmWGnZVXn4jCqs7wC2BKP4/8tAzkZsoWx6XrqeHZymvp4ABCBJhTQwKfDT8gzrZCIqi5AhiACjBfEB2rP8/X63MM7f6/V6v9/v7Xa7bYC83W7jcrlsVHIq5ffv30+//fbb+OWXX8ZPP/00/v73v4+ff/75JSvbeu+bL2WMMaFbAlpBNM85QX+ct6qoSqkPAwuQlBVKqGNFSUOAA3Bmu7gC5hNOd15nSwvAOUW7C4giUCV8Sgn5L9hNFIqTsp0GxI0ysioyjAjkY/tGJVEpz+fz+OWXX+7fv38//f777+Pbt2/j119/HT///PP49ddfx8fHRwrmTjV779EXu2px2xhjwtdJZQcAWQIPLPISsMJaSwiD8gzIKrwSyATE5j5nAbR5c1dBUwBlsEWW0h6LqiYsqFPAQxCyRZ3wOSARxmlXMX5k64pQfvv27f75+dk+Pj5OHx8f4/v37+Pbt2/jt99+G9++fRsfHx/jcrmUFLO31gYDWblxRIs/TqfT7ousxJsAxXA2Gc7TA9XdgfdoHbFsj76X2+1WArgI1ageGwA3qupqoHsmcbI6Fu93quggFa9d7LeDtgKfAFHBJ+NEByIkcJ5KervdTmhhGcgJJSZ5vn//fj+fz+18Pp8+Pz/H5+fnmGD+/vvv4/v37+Pj42N8fn6O2+1Ws7JjjP6wraMI5E4RZ8x2vV5TSwkquotV7/d7Tz6HFWsD/qNcdw0CQ3q/321c686TwDVIdbuy73zNldhSHb8I2klZznm+InBS4U6n0302aBFsLhHDAKJVJVglfI9jhvu53W53sLANYNxAiDA6MCeUHx8f9+v12i6XS7tcLqcZW57P5yeY8/fz83Ocz+fnsSmYUyknWEG85WBst9stzSLyMdfr9Qi08iY15UZ0LlDGLhR3o5zK2j7OPUTD0E+nU3tk7Xb/16NFbhloAMuY1zjLUOO3BKeIDe+Z8s3/J4gFo4TM5jPmuRg28foUKKVSwo16TgA5npywcWLHgYl/Pz8/73/605/ab7/91m63W7tcLie0sZj4mao5gTyfz88E0f1+j8EcYzwTPEG2cqjyfHNF0M8fuqEiaOVnRzZZQNh5fwQyHg/HDGfJo89Q1zb/quu5XC6773I2XKfTqd/v9+d3wuqWva/YTdUdEV3fhIv/Viyps6YE3x3r43K5bJQS66zaxVGFsvd+//j4aF+/fm3fv39vt9utff36tf3+++/tdrudvn37ZuNLBaaCMgUzC+rZRiFowxUuJI8YMqcCp9Opq5vagaYU6lGJA1XQqejchw6Cj0Gw5nYBrGw01A2O206n04BGouNNyTfp/FwElhUey6nXrIKw7QQWddxuN2ldL5fL839gSPF8ahu/JvBO48CPSuqMf8Vp9/P53L58+dLu93s7n8/tfr8/39/v9/b5+TkhPJ3P56mQ436/j+/fv+/iSgbzer0+AZx/5+88bv6OMda6S5z6kd21fYC9dxv7cIJJ2d9AOS30fPMzyHiTM8B4DF6XUlYHp4KQW3W+1t77MNB1vGHxWq7Xa7vf78+y5/N5A+H1et29xuP5dbYtyaRu4AksbPq6936fjRzXRxBbPr/b+b18+fKljTHaBBBfn8/n0/1+H1++fBnn8zm0sB8fH5u4cr5GuBhMVk0EEn9RsctgVhM+ixlJtMA23R8B6yysAstBOgFXIKKCMIgToMqNEu2fYMH7ztc732dQKkCj1ytAZtY0Kx8pIr8GGJ+AT3V+2Hirhl++fBmXy2Wz73w+b17P8p+fn8/tUwGVleVkTyUb68DkfayWY4zxNRihU4EpLJPZVrK+u7J4/mgfKqeLW9X2REWlItL1diynbDDb3+jXgYjQqn0rrxWc+NkILP7F7xIbMvx7vV53x40xnlbWJF12ZSag/N0pW6t+ZzmOMzHjajKwDfond78zYTdfq18up97zr2q8v3IioBprRtBl0EZ9og5WBRGOdOHjIjXF7UotFbgOWnXzIJyzYvjG5IYgsmMOxHkz8OsMSrVNWeq5T8DaOcbEv1Od5rbs9aO7YvMet63EkF++fMExq+MRl4/L5bLZN/+ez+fnZ6KazuMqXSQVO5spJXflHAIzes/xJseckRJiDMog9d6VfRrqXMr6KpVV27jRwJacGovOAM1zMdQMnwK1AubK63kdCChvI1C7g0z9nf/D+Xze2Vj8H7Gx4P9duQlsYCrqyN8XqG3Hm/10Oj3jw/n+crlstuM+jPmmxT2dTuPz83Pzt2pn1XsEHX/bnPaVqVmh0xwOt0o6XLLAHePUU203wHfcrspCwmV3TryB5s0Mseeg97x/BwzCjBlbB+pRAPla0BVQuT6V6QHdBlj3d0KG147b+DqxQeUymDO43W4dQar+TIjwmAd0z8/h65vf0/yLv3Pb5XLpru/ydDo9s7ET0I+Pj6dKK9VUEIeKWQWPAOrJ8LKd4vE+t91Y3e7UFlWatg2VwJnb+HPmtvm/sfK59/OaWF3x/eP1UPHvA5DDYDpYXfb0drv1V2DkBkxtw/tEWVVlXWdC9pFYs5/jfh9dS/16vW7s6lTG+TfqsxSJHxkXXq/Xdr1eu4LsfD6P3vsT3N77DkL+zPm5jSdKL4zR3AxQd6rHkLkYlSowsrq7znzu6wSwdsMJOXmA5fBcjxtgMGBYHlr5zokhtsMCTgXLQOW4XC6dEyEMprL8mAQzXRgduix2yZzorxkYsDn3hB1VeMLGsXsVtgl2pW8S3svk0vw7R4hNaHvv4cACl5HFzwIH0Kc6zu4XjDPR/jpAVxWzO1Xk2DDb3vTcxeGU1iWZHkmIDWziWKvirCJ4Dravs6IJ/GG6cTqWdXDy+fArQDVVkLqkVjAoZIITdmmIqXwqa95N3+MGYoZQdRVNO53Y1xRkhO16vY7eu507Ca9lJnbGpxOemQhSw/AQsmmp5zU9BiU8G6wvX76M6/U6Pj4+do0Bz4CpgiknTUeDqwlKBmg3u4OVjrZ1A+rAcgaejWq6eJCvCYFDONSwOgHX4EQRw8lxbzDOdEK6gZ3Hk1b+8g2o1JFtKXyv/fEdTXuWjWXdAZiBp6ADeDrCFiim7B6ZFneeI7Gvm/PMkUDX67W7xI8b0D7/v8dA9qfN5oaCf74WZjH0mf1cmfY1Y0JUFmVrTWu8uzkNcLtEj7u5FXBTkfC6GOA5q8YMxO8KVvF6sAVGdcrUbsKODcQKkLMOMdmlxum642YrPm26AlhZW1YB1R+rrGswE8TaYAWeUMxdf+WjwSvZ2Ef3ytOyfn5+PpVPAaqOn43MtNBqvmjjxbjM4lZjZY4gqNMI5ktaW/sYKNwS+9lFQzGihmMCKPa7+Z0V6Eb0GRmobtpX8JljWu5FMLN5ja6hG9kwQgZqf5+1NH5UxzkFReCdWhJ8XdlGUkxO7HRlYRm4mVO43W7ter12TPJEw/rmEN3L5SKHIWZg9mz+pUoKOYq5bJTJdX2gme1UcxMZQFaEQIlHct32M+Y1BzGkGuzfiyAN9z+ugplZ1symCrDCYYkGxDTpI9RzBy0rHyeDUC1nWaeUaD9n4xkNyYMBDZtzZ3B++fJlY21XFDOcARJlabOyiS3uCpLI9jrZjCDkaVvcCCjwognKShWdzXZWlZMvVTgD8LpqlCLrqgbcB+qYwrgKYpT0ccCqbKyCValkEabn/FynogCrPKfqf51xJ7sGB2ZXcZmxoSOztjx300DZi7a0/2AIR0UlBag9SuDw6KcAzlaB7vHZvWpjK90dyrq6bKyDUZQbR0B05biLQkHIcSUmgIK+SwuqgHCnoio2RQU1yj+BnBy9pphVKLGyC7ZzFK1pxWK+E8IhVCWLN/uLtnUU4ayoYLoaANz8FdtaSvY4pV0BEW2ls61czqllBKpTyKgMAhrZ1cdc1RROtPmvWNkdcKZ7ZKxaWjiPLJMpp7OZKxA+rqG/oJLjxf0pnJlqLoDZo3gyU0mKGys2taKecj/d1C+rJSplBqlTyAqgR+D8KjKlmRL2gtUcAdCtsL+ijCNT1oqqqkH2OHEbG5sDFnUg5Aa+yLou2VU1ptj1S2ZQqv1ORZN9IWzRfgaRBxKoBE8UWyqlJFtrIc0AxNjSjed99CTY/XDfSzCz5M0IZoVEsWnPFNTsl8ooVC1TzbGgqFZNDSgVwKK+1sGDMKqxZCWGVMDysiEr1jVSQJUYwj5iHOlThdHt44SQg9CN+nl8D90NMIgAdgr46JqRiR9I8vRdFvbr17m/yxUMKjNLMiVUADwu2CWGhhi+F55TWM9M9cogzms1dnM4uOF/LAEYWdcqnM7yFmyq3IfwmOROd7Y1iFWtOjoY8To41mTV5IysgFFuRzsbWFGbNIIJCDv1dOo4lZG7jWBwRFtVTKuWyeCByJKOan8oZ3ep9XddNl0tDuaywLz9cXPYeDAA0SpkBO9sbVcTOVWldPv4uyzEkzxHtjvonHoSkFEWNoo1d8DhcQputd2ppNon4BzoAiJ1hBFQg0dVtdbGHHDQWushmNEQukLM2QO1G2Y8bgTXqFhcBJj7EjPgcPts8US8qPpPB/dXznOh5Z438tzH5ec6QgrOKrRRfKmysBmUDB+PhYabMlVPER+GCSITTzr7am2tArH3bgcEzPJm+cr5jJ4NnHNFDVrFXcI5Le9k5Jnw+bedbV+FfRzZIHaOOaOsLY0/7UGs58DjrGwKMIMFIGzOEW1/jGsdAtCN6hEAI4hBe9YXeRROBSVPAVPAqvIM5bx5hVKWAMP6zBRy3iescridVdFBinBxXDnG2GRY2XbCvp1lhvGtO9Bxu5h908XQu42lnSArMFdizMim8uwRCxPGnnOS8lwpnbOiDqTAjsrRN/PcoAScCbaACqVM40ylnjjTBs+bwWlAG23/UKbdkiwKWIQPGzWaczpoSlxPEj822cNWkpS7FyzsDrqpfgpG3jahw2vgbaSQAxuLWZYt7JzyNe8JoZpNAcvDFOdw0wqYT9AK1rZz/DdbSlLPp0ryIxgQJlK9AZlEq7IOXpohg9PIhrCng88JsOxiV4ZWAYfg4sikx/8ky2Z9l862uqwrfscIH8+ugTmVGyiddeVYUgEMn4GZzg14EwIsh9sx2cKKiWXReuOE5gzGOQgdlRKVVdlevqb279Xq0Qnsts2VDaBO0coezsruWtHApu6sKG4IBhN0aGU2kLrMKGRTN3HmbCDwKV14zvkMEDG4QfZVspVlaNU2mhc5TEZ3N1h/zqTheuLpW05ZWTGVjb3dbnNmxKZBnN8JqidaVLKAOyARNLS+MB54Z2+VaqoMLKroVBlngefnTPAcoHNWCSvlfA8CI0HEmBNBnBlXyMrzU7A7WVm94PPqQ2gmqKx+WDGsnvilmcSOBJqOK1nYyAIzuAyesq3UdSK3KfWcYKD95HmfYOU3qser2CtYEUA+FpfqdNvgPBZUBhDrGONRVlQsh8rLcaUCykHG0OOUwTlLBrsh5soEMGezi1E4HRVt1icp5wZEFXdibCkG8Y8vX75sbO4E0iom9z+hjSiOfy3DhpXItpVhE+UGQdvoWjtChmrGHf4YAzKgBNnGtuJxFCeGdhUAfQLLK8kBYAP6gvFJZajMG3Xkycy8KuC0q4Eyymwtwdxdv2M0mIBtK0LKnf640j00Auq4gUkdWGlhs22qJc6dZCsL19oxnlTJG4SYVRIGpD8TPFBuM6OElbS1pldid4mGAyN6ZIupbC5bXJN9fdpbThSxLUaI8IG1XIYBxW3Tjs6KQosKcxfxcQmdnwRGM10GnFcCy2XYunLMyAkdgk4mePiczsLygthcBut6goOqS7YVFXADLjaosB6s6ofcZWAZSIRYqSUkizYwttYab3vUOQ9w2HRxIIg8WwRVeE68xi4UtL3zRphxplzwuZrcqYCq1I3jPI5dnJIygEohMbPqVJSzrwzxBJTs5zN+ReUSgxikPQVF3JVBeNQxbHENrEMNvEdFZVV9lH9+ORGEsNZQpyTNc4C3AG7XF4ngzq+DrO2zbuaaOXgdaFcdkEotoSFBVX2qJ0C8OWZeG4KGlpghA0XfTOPCqV2qqwQ26QWfF2PMLhI2w1lVAa2aPsYd0za25MQRwgcZN6uQDCi+ZxiD4XEM2kZxOT41FnZnaRlcpZouzlRqqdbQVWopQoSB58RV50lBNrHi/AwXS5LrwDVlpY3Fc3ByiYGc52Trist6kOXdwInAQtJpp5QchyaquYOV7Su+fxVMaV3dc0RE2S6mUY0gLt2pMcYqrKIQ9w2l1gpQUMtQYcmmbt5DTNxdhnUCjQqtbK9SUSzvrC0mmhhE1e2FS2+oxypy/ZASutkmtjx3vcBC24PX65nbqkBCRhfjS9kIYPnee8cMagVOhI/3T1fAmdtAWZsCswTJCkQVNa0qWKSKPOpHAUhD9DrbVcyoYkwqhvh17vYAayXLQyKGYdxlUDFp494rBXRjYgO17DDYetNIUj/ezp6S0lnlpEwsWmJMkOwsKXeZKEAjIHn0EQJISaRBcO6UMINz7p/bEjjnw4ft+xmDvksxX4G2rIris7qaeKwAFMP2Oi7n4criuZwtpSUwpfLxSnORSrIqusc5ZFaXysqRWjiZ2DyAWEIL35tVSoQElFACjOeGGSE7AHEQgdo/LSvCOgGBvkxsmDbvlS3Fp5vhaB2TAGqRKrKKMrhLVpaGzEVjZ0OQxDhaCTA+QyRR1d15aQzrJntL3RibsipjG6jlgL4yqbS0sNYg1e84vhbBVrElK64CUcWYXDfKxhpIuxiVJZUxsbMy/uRBKTNRQ4kQ3LdRYLS0rJjRPlTPqY6gdJsEDc+aQXAn+HgsNUCbRuF0Oj0zwnA7bWDkbhO5Ens00qeQhS1laBMl5M/cAaxsLF8rKyql+Tf7ELLEGu/ixiimdCvo0TjfpjKwaggen4eh5v7LokLKbLuyvHhcZG8dhGrEDx7Hg93ZppJF7qBqO3iVveXEDQNInzeoe8Yq6ePaZBZ2JviM3W2UAGotekRCAGq4EkF1X3DOnR11yRsBL1tRa0PVcZiNFXZ2c34FskvomInQQ6lzpJoZbJxk43NwKJFBquJSsrByHydxKOnTxQASBmS3j+JMnsHSla3Ec6K9VWoJVn9zfjwOM7hqYAAqJQwE2a3nA48J2QGegRkpZNivSY+ys3EkKd4oJIwsvIHl3cWgLt5k4NH6OmtLWdpurOkwEMupYc7eMtDRhOcI2ui5JhVIzXzLyto/GAPuZoyo8wkoduVgJglCt7OhGbgID4Mq4si+63zUS1FuFFXFlqyaj2emHlLMcBqYu0FMuR28BbB7lOxRMSiCQXFhCKuwkhZ+pYDiGSgbsKKV8MiSRsuHSIWM9rklRiIlZZuqXjsQK8ooYJMgq3JKWVkhHbhsVxFUzthOWPkYijcbx54IKsSdT+uLr3crGKyoYgFiGR9iBk4kfloUX+JIlQRQqabmpgnhqtpQpb6RVQ1WH5DnrS4hEoGZqaerQ2dhFbz8XePxShmDbo70eISjoorO2vK8SJXI4SUmEU4zWKDzUDtWTYw7xXlbSTEj4FRg7zKnKoGRALv0Gs9Tgc1BpCywGZRQAtqVz2xrBcAMzEpfZwFSa2G5W0QBFjSMapWAEFa3HcGN7CxDzECyIkJ97qwrqWNTWVo876PPsjPkj2wvgroM5lLZKMETKVql/CvnWVFiFa/SzJUQwkoZsr67Y6vlSRV3/2tmNTOY3vnaxYwMuoPKqdzR1w7IqHymlPxaAThfU7Ko2ZXYj4AYJHL+kNdKwRQYESTRa5fsUZ/rVC1TMTyWVyYoqNtuzaHsMyv2tvoarxdfqwYgU1axFo/cnql1FGsqK+uAROV8BX4GU8WcZTATi2q7Qcyi0O0V+GhWBMNRUkn8H1SsWVE5By3Gi0ECqUeJoBfAtDa4amkdXG37AGP5Ggeb84p7UazpoKRzdFzeQ8HkoHGxprKy/Hpm5t12p47J6xTYDEz7uINEXSuxYXvFskYAc+ySxH9sf5ftKzU6IbwVBcUGg5e5FMCEXSErZR0wGayV19woM9guPjTqJdVTqR4uE4nJnLldWVkECCZLd2VLF+xtamex7IpiriSDUpvrpn9lrwGMCHyppMH+ps6LILsuFGUj1XEOXiqbqSHPUKnClpWV68kqtURVNDY4TNaocykoYeTU5ngGEQa/S1DnnE4AeXMcKjHPAmFVjCBENaeyLVNHfr3px8xUstJ94hIpfH4HKE/eDaArK6lSyVVFbdt1gxTIVk3pppVlFXi4pEhVBTObquohU85MLXn1iahvUkHJjSCMc01tLFveVVBx0DodM6jftCu7DOtIzYxrc0qp1JGP2ayYFz2Gb6HvMrO8cnGtV6Gjm3uImSfD2GpWK6uowbZGMxFKQCo1pOMtcMXFpRst+hXGoAomF3sSTBGgTglbBKWwsQ3tZqaYSp0Z1CimRDWFcCJUPYJ00BI5FkKYNoifuQxmN88SWVXWLMaUqqqgC0BmQJR6sk3u9NCf6jYLXxAfqsYEgVLAhRY2AtgtflZNFmFyhxdrLkAdWlk4D88M2ixHyepIdhMHrG/iR1ZGtq0MGpbDbRPYOXeSY1M6Ny4ZstvGSktK+XbFPATj2D371saPEsAMXhXrsZ0km/XStkhhMyBfsa6uXFZe2VCe+YMr1+GKgwrQyNYq1VRrB+EizAow6NsdNKcyVEkYeM73ys6q4kAHp6BiFklTkIrVC5oYV7uzwOGCz4UJ0Stq2lWMJy4wtb+RetL6tZFicnJmBw5UjCvXXMZVJX2MQkbf+XN5EWd78Vz8/JEsMZTBiKNzsm1inLRUQ74H4NidaqI68j5sAFgxcRveC7ieLJXfQYxjZZ2CsiWFewZXJmBIlZ1tdtrX4hSuateKso/RZOtOKW2nmq1oTzeK6dRWAWu2NRVb4hq0SXm1GvtugHrbr5IXqmSktg5CuDE2MSlPwsY5kNE2Wp3AqiZbWVLAxiBF+2iBZbuNj6MB6rsMLC7FyasaYDyo7KkoPyEtw3pEMXfPvxAJi2jAQQgjrz0rLIZSWZlIoNhwd5xK4AR9mYNjWAaLrnuImJeBVN9zBORObVvbr+mTTfFSEJLSRnHo7hEJoIi8MFqjxmvgmF5URZz4zLFgZZ8Ctu2X7ggVccKm9gVxIsOHqxXgNMKnFWZYnf1dBnOhayXq17QwFlWW09eNKyVJFmXqaONGA5aCegMbJ3UUkGY1ic3nKWgjq8qfVYGQG1gRt6rs62a6HiqqUOqdesK5NmX4nGofJoiE1d0dF9lVVkvT1/kEEaaCoYOwFpcVcoLM+7669PxC9rWqktH0sWUYld0VCpuBZ/stVRcGgy9WX2+U1Qthi9SzAqSxzZsy+OiFzBYnySGV6Gku44rD8BCOZBV3BvD5+AKRHNwMEsB6EzHnJpkTAeiUlEGkcECeB6GDZTp5YEJTlvdrknxYjTllMkfNtXwDjM7uVjK5JXUUn43rrqpK2jytaxHW0M5G8DC8rtHMYs7KSgduVQMGTYFqFvVS6rkD3sDJ46afdYFwoq11AOKCBLhvwoUgc8IGANycR6knZrdJPdsuxnyjfd3FovTlRMdEdtOl5CMV5EHsXQBis7TOwvIDZaGj2Vnpbh7cpK63VwYEMLwqbjzyl699sawFFkF1yqjUU31HfC6sW1ZFVFuXVXVgz9keEaw0ys1lWfm+azQAQSWA+hKYVfsZjPncAcUB9oIayy/UZXRNckDGji77GsWbvBo6tPrWPqOyVkBUq+INeqpzNdYs/u0ifh5qmpqIW+33JVSUcwY70KL4U9lYdU6ljtSls7lmfi9g3YzeQfVkaGFaV3ODCnaD2N8wsEDFklE3RzM3ZghdYkWHsszq70FIecnKkVkt8ezMzRq9bkGuKojRLBVSod3Y1yPqKgYW7JRQTPVyy5xIYLjOgxgT52RKJUY1dOrIiRd4futQx/A5AcSmEjz0vFWrkLzvbWAu9HOWbGgxFk1VNTpnBKk6TgwisI/HcxYXP1uAWO72ULFlBTq+aSu2VTUs6hrxM2CF+hEor1VIA9ZmFUaab1lSSgZsVs4sxzHlVLoJHr9H4DhONTkI1XC0/wiY2NoWAG5RlnHFnq6oLccpQddMuJ/O17JVA5OHLi0BqCztq7Y1++ucCd98qLI8MIHBV/cKjxQTme3hFBS3MyCqnDsuym2o80HjvFFTtrURmNaGJsmVahImjTsUXKtQZTAVs7Mvv8/+fzUrZAXcLJ6M4koe6XP0b6SmWWNDzyUpQ8bl+LtWx4tuqZ36cRYV3yuVxPNwvIiqiQCSmu7srgTzR6nkyhpCarXwFy1vGd5iP2cY06lFr5Njhhg1Y6+NB28ftbK83s8rf7kLJbKwDFPbLg25a0AdZJEiqr5phixKMDlRUtcssq1hriLqGoH+zeNgVm9OemjsETV8JdF0NHnkIFxWY1OB4Yrp7rtWJ7NgAAAPXklEQVQ3oNs5nplyVf8u2FoLu1JrHveaZWQjqAkshtFa2gzsSG3Zpkbvg3HafF9slPPlldjFlK80Gysm8Mr4MPhneNWENPGjAIpmilTPATdTRTXlCBYHYAQuPwA36xIpWtGN4q3Y2MhiGsUpuSSnlEJRD8PorC7CFYVw+F51qThgabxsTxWzCGY0ZSsb3lfqAy0OPNjNy8xiQQKsHYFQ2HBZVvVbBuq3m1oWKajqaonsM6uZUr6CjXWNZ0l5E3h3jURma6kP3MJIiy1Lm+kahQq41N2iZja5sjtlLYNZHZrH6qUGm4vMbDp6Rw2CFmvuyFkrBcCyMtFqBaECmsHoK9BZ2LA/lJcRqSaDqnaWbrZdGaz3DLgIvBln4woGztbyJGqslwxkhhHrTjTYFXCtOoKS8uLdofVdAbOylGU6nlYpXWZts4nXBq6WxJitMNokHUJnbnJplQm+aGpY2a5GMV2QD1hRubBPFKdumf5OHkLHz0F9luE5kjBjRa0nFE5CUGqHw32MmjZ6xkgINVnSnZ1VZStK2qKlRaLlQgK7uTq7JFXJwM+3SOEKyhZNI+tJ0I5qMYy9k2qJD7dVWdqKXa0CKNR0Ccjg+B2IYu2fcBZJZkMFgM11r0X92wilghFGgzVnexlqB7xL9mS29SiYUVY2nXOZjNBRsyDsQPRWW5hrZ4XcdC4HVWRbjgJr4sFofK5SzjQ7rhI1UebdPdEbj6sqIvTZQZ5va08rABsAW0UxeWytAk7A2KJ9ZpxzCioB24XFtYAeXYxr6anSqhLgppEqWbGwLunTgrV+IjWlL29ljaAl4EQMGsErp4apeZiquwRXLXAqOCeru32mmydc6oWTSWpFAGdzeTB8RTHVMEtlM90CbbQCYhPjq3egYr1FGdYIQjiuDGZ5zZ/AzobKGOyLxti6c4Rwtv2anyWlLICnlLhxJRXt6A5ebDBWFNONbxWZ2d02mnu4S9YECpeppV1zSWRBWxHYzVIv1CXSouwqqX3jBBBDZdYQbpTQW4ZQlS8r5kH4suSRmg2++3JN10x1PaAmEkmtYlEdeGpJEM6kOuCqCR22oSujj5IV2HdT0zj5prLKTjXFAPjdQlyq7xIBxAQP5yMczG4VxAKw0n6ilZ2QBce2pLulkuxxqnoIzFfgqyqjil9S1VNwBrFmeyeops8yOjZUybZdfS8CuaTIJumzs5tODaNtLpFDQ/PcJGweLhmeL1nB0KqiUDScsiUVD89Di3HtrKtSULw3RLiygZD+7sF8JTObgYsrGvDNUFRGl1iy0Ll1YkUc2aJYMog920I8qW6YDCg1Mqk0JHJFKXkbgbRreI+qpYNOZHrVcDUba7pjsphSJNtK6upgRNAVoOS0mugBeN4bIZgHhuPZ/s1ENaX6KsVr+YNrh1Nb7ipR0PE5zbNRegCbrHRUw6Yf07dLBJl1f8KB9as2V1nNqAsl62LBBhehwalerkHmB1JFIEZKSEusdl5JQj1nJlHXSCF342gJ9CYGrXelknJIXqVP8sD+qtplCR3XH2qfKq0ygMp+KnVkKxNlZ8m2YkIlVMiCnXUwl7qznBKSvQz3m3Pt6oQbXO5b5FixCh/fHxUQW/AEcK6zCNqKQnL9sywqmKuwvqSYzT/aPVNNpVyhvRW21aqciCsjdWvBwILUvh5VyCzbWoC1pJjJ680CWsl+udKB6T5RwG1mlohnlpbg47iz5U9ha0FGtmRLFYBtO99y97Ap0z+ZDTAog6kSLZsMHg/IFkkgp6CpvU2U0cYVSdnmkjwBdOmXbxTWNWzuIbipMioVxEckZEoahSOiy2M3K0jcC1LhVDwaqG0ZvkcWqCnrG4GIxykrqlbWdw6LQyBaZR8HmLRIhQWsHswD42ZXVLNkf9l+FlW0HVQ2lwFsC/Z1FdzlQR0KaPfo+Fdfu+/dwVRICu1CGR7AEIiAhc+AZUF0kOBaPxmUqg4i64vQnU4nFDYJ9Nz+1fVXveH9qmr+kPILx8oKcRV/BFbxbE0JMT0kSD4w6L/lNY8ocsqagVdU3A3MjxhxcGuqzsPH4irpaow1q6OyrVjvp9Npc59E91LldboYVzJWdimWfAW2SNEKcDaX2FmBLLA/uKxlmhh613Is1URQApbKfttwxL02q6Onx5pQxSbPojAg+v5hAnN6LHVRDXIsvKtRjiS0qJUyZTAXVbAK82ElFJWaQdVoqUC1Unt7BVaTQudM6SuqexjQJN4+0icaxv/utbKv83ETbT8H8gjcOKxOJmbUa6OOVXht3dFY6rHv9XoNzFLceEA1o8+pKm0LAHPHZ2rYKjFq0hfZFixsqHJgD3eD5n+U0kb1mFjXkn2lvMSSOsNE/CdIAKF0Sytq6urOHUN5gwg4GZosgbmggM5ucra2qrS2Ig1cbiBBcxYzgzUDNLCvL8GbZXNp6ORy3LmS+Kk83zRIAK6A1ioKa2I9NapIuiUFdfC9766PFZUtqUr6KbWk+zZU1a/ZrIXEztrjTOfz7hwKziCeXIaraHtbZIMz+2pGgazCmw4qWAFvEdhodYp0Xq0pV7G1YWYWbO4qhGq42+Z8BYtrLWvluNPpZAeaFFS1vubPgbgxsqcpnAaszBovKaFoDQ8BGtjfUOl4NAG2nmQV04feJgumvX2fsrQEWZghL0JnVdYkn3DOZIeRN86RqPWCmsvGVqEMRnwxQAxwS8EMYo3IzmY2+BCcLp4MKiuyuhImamlbZFcNoNl7tp+RHd18ZjQIRKyXdFRhN98/hyKqwXWNo7O1wiaXoHN108REZZWEq6grnIfjzeg8jdRf1XEL4kkXa5bBjKxoKaljBjeHlVxQ4GaycpW4lDOAKtnTxHAtOfzOtZwHAM7sqVXkV6yu6kap1nHkXKqWF/4XHqjenNKqBjpR3l1ch3Ejg1+EsgdQhsdG0B4FM9sWAVWpuAyiwTPleZxt9VyZVS2qXfReWqTAilpr9ApoWTjxymit7NwV4JTriZyOA9B0k7HFfULourmKYHVnRQvqGL5HMHdqFcR2qWpmcK6eTwx2dipWrviDilr+fKWq3OWRWdHKwA4eu8wjchbeRzFilqjjZN3ufCpfkJ0/scVpnYk6L0PI77lxdWCZ87WiWm7B/AGquQSnujGKsB8CJmiJq8q1pKIVWyqOiTK66r18BN8r74/AE71fdC3yPS2MxdOpnE1tlVxD9JmVOoggN+r4PjAXVFPa3Eg5jVJGFVUGNolH20GVrUB7BOySWq6WqYQdWR92pcFMYMwckbSgCKCqD67DiiWu1g8MQC9ByfcFqW1L+jL714qNCuznoSxt0da2gtWN1G8F0BK0NN0nuimelUF9dIdAfjO44UT3CjQLoUeLHJFTO3gmpRuIIOvwBQCbqNeo3qtZ9iF6xVK13GRlo4zqimq+CGdTiR1uRY8oqgE02hZBa79kZXPMquxRHKla2saZWN4mRqZUj0vLCKhkjKnqOQHNuSZVJoKvAqS1wpEquvWDC1B2ypwrCPsRMEPVTODMLJMDv6qeKXwi2JYV5Sq4qKyvgGsHCLiuj2jR59V8gMqSJ2FJZRXEHVRHj3sFPrct6OpqlW1GpatQdt0GvwfM6n63InsGVFhJGaBqgqqIV6IsXllZgySPq4R3bnt3wi5cv+cN2yqQLW1T95KYVsWWtKk4cB9W53WQQflQYR6Wl4HaJZjvVE0D5yvq+RKgZCs5qdBEP5sD94cAvQLlSgNaSMAtHx88BuNQ41zdFsX30zKbcs0MLD/ihkpQzl0wiTqKLTfbKmCmyYICnK0IbaieC4CG9iSyLQ7cIMGQwau6TKoq60Apl3WN40LZpca1CKKK9VQyyIEn8w0F8F6CL2h8o3ixGwC7s7EWzCOqmcApYxYD4jsAzVS0sl2t98pA7vrKophCVSonbYpgH6mvSn24pTBV4sdtV3BtMq5k82y+IADvUJ0uAlkCVTxIaPm+UNu/qkV4F1TzHXCGrXIAqItBKypqK99VtAOVs64O4ObX7pHLVCpYHcRmwvLR7TvYAKBBN58LGVzDuFz+hQbWgncQyCZAk+VbsPSouf93261iZgmfCpwRbAvqmSqriU2PwhjaoOyYqtIegVXViTsmyta6bGySpY3gyRrpIyAeaWDDxtpsXwKyalMDKNP7YBXMqEskUsi2uC8FNAPxAKTVfT1o6VzM0E0jF+1rWcUuHvdyg7vgoFplX8HpvHpMCOMRUPHzZkInsqlFKNX/EIO52E0SxSzOwob2VmRLW5D1XIU0rbgM1AzWgyC7fe8G7xUAK/taEBat7luqtyP7EmsaJQOj5F+mrnZfCuYCfBUAWwShyd6pMY/vAHG1UqOYpbI/gy5T0CMKm+UO3gFuC85dgfDVeguPDfITrIBLsLrcgdh3CFgFZjaKJ4Iv3F8ANEqvuxR1tVKOgLoCa1jxboBAkj6v7j/icFbA7f4rfRnQDLRViG13i0vqBQrYVqBbADZT0ZpiHoSzvQpopKIFS3sE1HfBWlHXd0H7LnArqvougMtljHBgZnh3Eoz/BKjLML4Z2Aq0+hEJr9jaVUBbvNzCIUiroC7AWmmFw4o5AK3MtB5VypZMSFgs05JyGVwlwBqsEGAAa2ZU1CjUexXGsE4rKriilBvFzOKKo3AuAroE6QFQU3u8YpNXwS5k+1TZt5UrwouN4KiUEw+k3ZWDp1RXHNRqXb21Ts39945yZSg3VnZFNQ9CF3XeZyr5DgBXKiwCMa2MxeTDYXgP1Fsf9QNKZc0k81RJk3r6EQ3rCmBVyLL75EjZ1pIVDHoFtiOAHoB0BdTVylqBsKKKS+AeBXJVLY+CXASuGvO/Auq7GuEjDfGKg1oKa1z/dmmi9I9SUGNhl0AtfulHAawoYrnSkmNXAVuGEhrEVXvUF+A5Ct2PqNOjDetyna4CmeUolmeXLN4Aq7C5Sj10Q7yjgl+t6CNxSRHmI5X+CpwreYB3Qfdqna4q21KdBuc4GoZsn49ZOOiVinwHqK9WzjvgeweEh2AU5+vtxZ9Cd9Wqkh49V18E5oj6vVyn0RStAyGIO5edXRKd5B0VGVXq2yr3xYp+5Ut+C4QJ4P1N339pQMjRejj4vb/Dcr6rQc3O/0rjmtZpeYCBiCHfCemRbNhbK/pNUPc3wfKy5f2D7OlL3/uPhve/oU4T0F8f+VNM2vyoiv0jK+KHQfdHq+0bncz4oz73/+Y6LbKw1o/5B7eOf1Rl/0du9B9tn/9bvrf/j+v0h6ttn2tp/r/4819y4/zv5391uvzzfwDifz6phT1MPgAAAABJRU5ErkJggg=='); } .x-cursor { cursor: default; width: 16px; height: 16px; border-width: 2px; position: relative; border-style: solid; @include boder-radius(50%); border-color: var(--cursor-color); } .x-info-box { // display: flex; margin-bottom: 8px; // .x-start { margin: { top: auto; bottom: auto; } position: relative; } // .x-margin { width: 2px; height: auto; margin: { left: 4px; right: 4px; } } // .x-end { flex: 1 1 auto; } } .x-selected-color { top: 0; left: 0; width: 40px; height: 40px; position: absolute; @include boder-radius(50%); } .x-selected-color-background { width: 40px; height: 40px; @include boder-radius(50%); background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAh0lEQVRYR+2W0QlAMQgD60zdfwOdqa8TmI/wQMr5K0I5bZLIzLOa2nt37VVVbd+dDx5obgCC3KBLwJ2ff4PnVidkf+ucIhw80HQaCLo3DMH3CRK3iFsmAWVl6hPNDwt8EvNE5q+YuEXcMgkonVM6SdyCoEvAnZ8v1Hjx817MilmxSUB5rdLJDycZgUAZUch/AAAAAElFTkSuQmCC'); } .x-color-hue { width: 100%; height: 16px; border: none; cursor: pointer; margin-bottom: 8px; background-size: 100% 100%; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwkUFWbCCAAAAFxJREFUaN7t0kEKg0AQAME2x83/n2qu5qCgD1iDhCoYdpnbQC9bbY1qVO/jvc6k3ad91s7/7F1/csgPrujuQ17BDYSFsBAWwgJhISyEBcJCWAgLhIWwEBYIi2f7Ar/1TCgFH2X9AAAAAElFTkSuQmCC'); } .x-color-alpha { width: 100%; height: 16px; border: none; cursor: pointer; background-size: 100% 100%; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAQCAYAAAD06IYnAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AIWDwYQlZMa3gAAAWVJREFUaN7tmEGO6jAQRCsOArHgBpyAJYGjcGocxAm4A2IHpmoWE0eBH+ezmFlNvU06shJ3W6VEelWMUQAIIF9f6qZpimsA1LYtS2uF51/u27YVAFZVRUkEoGHdPV/sIcbIEIIkUdI/9Xa7neyv61+SWFUVAVCSct00TWn2fv6u3+Ecfd3tXzy/0+nEUu+SPjo/kqzrmiQpScN6v98XewfA8/lMkiLJ2WxGSUopcT6fM6U0NX9/frfbjev1WtfrlZfLhYfDQQHG/AIOlnGwjINlHCxjHCzjYJm/TJWdCwquJXseFFzGwDNNeiKMOJTO8xQdDQaeB29+K9efeLaBo9J7vdvtJj1RjFFjfiv7qv95tjx/7leSQgh93e1ffMeIp6O+YQjho/N791t1XVOSSI7N//K+4/GoxWLBx+PB5/Op5XLJ+/3OlJJWqxU3m83ovv5iGf8KjYNlHCxjHCzjYBkHy5gf5gusvQU7U37jTAAAAABJRU5ErkJggg=='); } .x-color-value { margin-bottom: 8px; } .x-hex, .x-rgba, .x-hsla { display: flex; margin-bottom: 8px; } .x-color-text { display: block; flex: 1 1 auto; margin: { top: auto; bottom: auto; } } .x-color-input { // width: 100%; background-color: transparent !important; // border: { top: unset; left: unset; right: unset; } &:focus { outline: unset; } } .x-preset-colors-wrapper { * { text-align: start; } } .x-preset-label { display: block; } .x-preset-colors-box { display: flex; flex-wrap: wrap; justify-content: center; } .x-preset-color { width: 18px; height: 18px; cursor: pointer; display: inline-block; margin: 6px 6px 8px 6px; @include boder-radius(25%); border: #a9a9a9 solid 1px; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.component.ts import { Component, ViewChild, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { nameof, rgbString, XHSVAColor, hslaToHsva, hsvaToHsla, rgbaString, rgbaToHsva, hsvaToRgba, rgbaToHex1, hslaString, parseXColor, stringToHsva, toNormalString, denormalizeRGBA, isNullOrEmptyString, XColorWithBrightness, XSliderValueEventModel, getXColorCssVariableName, } from 'x-framework-core'; import { XSliderPosition, XSliderDimension, XColorPickerAction, XColorPickerCssVar, XColorPickerActionModel, XColorPickerOutputFormat, DEFAULT_COLOR_PICKER_COLOR, XColorPickerContainerComponent, } from './x-color-picker.typings'; import { Subscription, Subject } from 'rxjs'; @Component({ selector: 'x-color-picker', templateUrl: './x-color-picker.component.html', styleUrls: ['./x-color-picker.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XColorPickerComponent extends XColorPickerContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private LAST_OUTPUT_COLOR: string; // readonly ColorFormats = Object.assign({}, XColorPickerOutputFormat); // hexValue: string; hslaValue: string; rgbaValue: string; // hsva: XHSVAColor = { h: 0, s: 0, v: 0, a: 1, }; hueSliderColor: string; slider: XSliderPosition; alphaSliderColor: string; sliderDimMax: XSliderDimension; // inputColor: string; // //#region View Childs ... // //#region ColorPicker ViewChild ... private COLOR_PICKER: ElementRef; @ViewChild('colorPicker', { static: false }) set colorPicker(v: ElementRef) { // this.COLOR_PICKER = v; this.initializeComponent(); } get colorPicker() { return this.COLOR_PICKER; } //#endregion // //#region PaletteSlider ViewChild ... private PALETTE_SLIDER: ElementRef; @ViewChild('paletteSlider', { static: false }) set paletteSlider(v: ElementRef) { // this.PALETTE_SLIDER = v; this.initializeComponent(); } get paletteSlider() { return this.PALETTE_SLIDER; } //#endregion // //#region HueSlider ViewChild ... private HUE_SLIDER: ElementRef; @ViewChild('hueSlider', { static: false }) set hueSlider(v: ElementRef) { // this.HUE_SLIDER = v; this.initializeComponent(); } get hueSlider() { return this.HUE_SLIDER; } //#endregion // //#region AlphaSlider ViewChild ... private ALPHA_SLIDER: ElementRef; @ViewChild('alphaSlider', { static: false }) set alphaSlider(v: ElementRef) { // this.ALPHA_SLIDER = v; this.initializeComponent(); } get alphaSlider() { return this.ALPHA_SLIDER; } //#endregion //#endregion //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.applyColors(); await this.initializeComponent(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Colors Changed ... const isCursorColorChanged = changeKeys.includes( nameof('cursorColor') ); if (isCursorColorChanged) { await this.applyColors(); } //#endregion // //#region SelectedColor Changed ... const isSelectedColorChanged = changeKeys.includes( nameof('selectedColor') ); if (isSelectedColorChanged) { // const selectedColor = await this.getValueAsync(this.selectedColor); if (isNullOrEmptyString(selectedColor)) { this.LAST_OUTPUT_COLOR = DEFAULT_COLOR_PICKER_COLOR; } else { this.LAST_OUTPUT_COLOR = selectedColor; } // await this.initializeComponent(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } async afterViewInit() { super.afterViewInit(); } async onResize() { super.onResize(); // await this.initializeComponent(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... //#endregion // //#region UI Handlers ... async handleSaveSelectedColorInClipboard(color: string) { // if (isNullOrEmptyString(color)) { return; } // const isSaved = this.managerService.saveToClipboard(color); if (!isSaved) { return; } // await this.managerService.notificationService.presentDefaultSuccessNotification(); } async handleClearSelectedColor() { // this.selectedColor = DEFAULT_COLOR_PICKER_COLOR; this.LAST_OUTPUT_COLOR = DEFAULT_COLOR_PICKER_COLOR; // this.detectChanges(); this.colorSelected.emit(''); } async handleInputColor(event?: any) { // if (isNullOrEmptyString(this.inputColor)) { return; } // const color = toNormalString(this.inputColor); this.selectedColor = color; await this.initializeComponent(); } //#endregion // //#region Actions ... async setR(model: XSliderValueEventModel) { // const rgba = hsvaToRgba(this.hsva); rgba.r = model.v / model.rg; this.hsva = rgbaToHsva(rgba); // await this.update(); } async setG(model: XSliderValueEventModel) { // const rgba = hsvaToRgba(this.hsva); rgba.g = model.v / model.rg; this.hsva = rgbaToHsva(rgba); // await this.update(); } async setB(model: XSliderValueEventModel) { // const rgba = hsvaToRgba(this.hsva); rgba.b = model.v / model.rg; this.hsva = rgbaToHsva(rgba); // await this.update(); } async setHue(model: XSliderValueEventModel) { // this.hsva.h = model.v / model.rg; // await this.update(); } async setHexColor(model: string) { // let hsva = stringToHsva(model); if (!hsva) { hsva = stringToHsva(model); } // if (hsva) { // this.hsva = hsva; await this.update(); } } async setAlpha(model: XSliderValueEventModel) { // this.hsva.a = model.v / model.rg; // await this.update(); } async setSaturation(model: XSliderValueEventModel) { // const hsla = hsvaToHsla(this.hsva); hsla.s = model.v / model.rg; this.hsva = hslaToHsva(hsla); // await this.update(); } async setLightness(model: XSliderValueEventModel) { // const hsla = hsvaToHsla(this.hsva); hsla.l = model.v / model.rg; this.hsva = hslaToHsva(hsla); // await this.update(); } async setSaturationAndBrightness(model: XSliderValueEventModel) { // this.hsva.s = model.s / model.rgX; this.hsva.v = model.v / model.rgY; // await this.update(); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XColorPickerAction.Refresh: this.detectChanges(); break; // case XColorPickerAction.SetSelectedColor: // if (model.payload) { // this.selectedColor = model.payload as string; await this.initializeComponent(); } break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async applyColors() { // let cursorColor = await this.getValueAsync(this.cursorColor); if (!cursorColor) { cursorColor = XColorWithBrightness.Dark; } // const colorDescriptor = parseXColor(cursorColor); if (!colorDescriptor) { this.detectChanges(); return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XColorPickerCssVar.CursorColor, `var(${bgColor})`); // this.detectChanges(); } private async initializeComponent() { // if (!this.colorPicker) { return; } // const colorPickerElement = this.colorPicker.nativeElement as HTMLElement; if (!colorPickerElement) { return; } // let paletteWidth = 0; let paletteHeight = 0; let hueOffsetWith = 0; let alphaOffsetWith = 0; // //#region Check Palette ... const hasPaletteChannel = await this.getValueAsync(this.showPaletteChannel); if (hasPaletteChannel) { // if (!this.paletteSlider) { return; } // const paletteElement = this.paletteSlider.nativeElement as HTMLElement; if (!paletteElement) { return; } // paletteWidth = paletteElement.offsetWidth; if (paletteWidth === 0) { setTimeout(() => this.initializeComponent(), 100); return; } // paletteHeight = paletteElement.offsetHeight; if (paletteHeight === 0) { setTimeout(() => this.initializeComponent(), 100); return; } } //#endregion // //#region Check Hue ... const hasHueChannel = await this.getValueAsync(this.showHueChannel); if (hasHueChannel) { // if (!this.hueSlider) { return; } // const hueElement = this.hueSlider.nativeElement as HTMLElement; if (!hueElement) { return; } // hueOffsetWith = hueElement.offsetWidth; if (hueOffsetWith === 0) { setTimeout(() => this.initializeComponent(), 100); return; } } //#endregion // //#region Check Alpha ... const hasAlphaChannel = await this.getValueAsync(this.showAlphaChannel); if (hasAlphaChannel) { // if (!this.alphaSlider) { return; } // const alphaElement = this.alphaSlider.nativeElement as HTMLElement; if (!alphaElement) { return; } // alphaOffsetWith = alphaElement.offsetWidth; if (alphaOffsetWith === 0) { setTimeout(() => this.initializeComponent(), 100); return; } } //#endregion // this.sliderDimMax = { h: hueOffsetWith, s: paletteWidth, v: paletteHeight, a: alphaOffsetWith, }; // this.slider = { h: 0, s: 0, v: 0, a: 0, }; // let selectedColor = await this.getValueAsync(this.selectedColor); if (isNullOrEmptyString(selectedColor)) { selectedColor = DEFAULT_COLOR_PICKER_COLOR; } // let hsva = stringToHsva(selectedColor); if (hsva) { // this.hsva = hsva; // await this.update(); } // this.detectChanges(); } private async getSelectedColor() { // const rgba = denormalizeRGBA(hsvaToRgba(this.hsva)); // let outputFormat = await this.getValueAsync(this.outputFormat); if (isNullOrEmptyString(outputFormat)) { outputFormat = XColorPickerOutputFormat.XHEX; } // let result = ''; switch (outputFormat) { // case XColorPickerOutputFormat.XHEX: result = rgbaToHex1(rgba, true); break; // case XColorPickerOutputFormat.XHSLA: // const hsla = hsvaToHsla(this.hsva); result = hslaString(hsla); break; // case XColorPickerOutputFormat.XRGBA: result = rgbaString(rgba); break; } // return result; } private async update() { // const rgba = denormalizeRGBA(hsvaToRgba(this.hsva)); const hsla = hsvaToHsla(this.hsva); // const hHsva: XHSVAColor = { h: this.hsva.h, s: 1, v: 1, a: 1, }; const hueRgba = denormalizeRGBA(hsvaToRgba(hHsva)); // this.hexValue = rgbaToHex1(rgba, true); this.rgbaValue = rgbaString(rgba); this.hslaValue = hslaString(hsla); // this.alphaSliderColor = rgbString(rgba); this.hueSliderColor = rgbString(hueRgba); // this.selectedColor = await this.getSelectedColor(); const selectedColor = await this.getValueAsync(this.selectedColor); // this.slider = { h: this.hsva.h * this.sliderDimMax.h - 8, s: this.hsva.s * this.sliderDimMax.s - 8, v: (1 - this.hsva.v) * this.sliderDimMax.v - 8, a: this.hsva.a * this.sliderDimMax.a - 8, }; // if ( !isNullOrEmptyString(this.LAST_OUTPUT_COLOR) && this.LAST_OUTPUT_COLOR !== selectedColor ) { // this.LAST_OUTPUT_COLOR = selectedColor; this.colorSelected.emit(selectedColor); } // this.detectChanges(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XColorPickerComponent } from './x-color-picker.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XColorTextDirective } from './directives/x-color-text.directive'; import { XColorPickerDialogService } from './x-color-picker-dialog/x-color-picker-dialog.service'; import { XColorPickerDialogComponent } from './x-color-picker-dialog/x-color-picker-dialog.component'; @NgModule({ providers: [XColorPickerDialogService], entryComponents: [XColorPickerDialogComponent], declarations: [ XColorTextDirective, XColorPickerComponent, XColorPickerDialogComponent, ], imports: [ XCardModule, XIconModule, CommonModule, XSlotterModule, XBaseComponentModule, ], exports: [ XCardModule, XIconModule, CommonModule, XSlotterModule, XColorTextDirective, XBaseComponentModule, XColorPickerComponent, XColorPickerDialogComponent, ], }) export class XColorPickerModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XHSVAColor, XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { map, concatMap } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XColorPickerAction { Refresh = 'refresh', SetSelectedColor = 'set_selected_color', } export type XColorPickerActionIdentifier = XColorPickerAction | string; export interface XColorPickerActionModel extends XBaseActionModel {} export interface XSliderPosition extends Required {} export interface XSliderDimension extends Required {} export enum XColorPickerOutputFormat { XHEX = 'hex', XRGBA = 'rgba', XHSLA = 'hsla', } export type XColorPickerOutputFormatIdentifier = | XColorPickerOutputFormat | string; export enum XColorPickerCssVar { CursorColor = 'cursor-color', } export const DEFAULT_COLOR_PICKER_COLOR = '#ffffffff'; // //#region Container ... export interface IXColorPickerContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // colorSelected: EventEmitter; // //#region Colors ... selectedColor: XStandardType; color: XStandardType; foregroundColor: XStandardType; copyToClipboardIconColor: XStandardType; colorInputIconColor: XStandardType; clearColorIconColor: XStandardType; colorTextColor: XStandardType; presetColorsLableColor: XStandardType; cursorColor: XStandardType; //#endregion // //#region Labels ... colorInputIconLabel: XStandardType; copyToClipboardIconLabel: XStandardType; clearColorIconLabel: XStandardType; //#endregion // //#region PresetColors ... presetColorsLable: XStandardType; presetColors: XStandardType>; //#endregion // //#region Represent Color Value ... representColorFormats: XStandardType< XOneOrManyType >; outputFormat: XStandardType; //#endregion // //#region Show Parts Props ... showColorInput: XStandardType; showCopyToClipboard: XStandardType; showSelectedColorPreview: XStandardType; showPaletteChannel: XStandardType; showHueChannel: XStandardType; showAlphaChannel: XStandardType; showColorValue: XStandardType; showPresetColors: XStandardType; //#endregion } @Injectable({ providedIn: 'root', }) export class XColorPickerContainer extends XComponentCardContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly colorSelected: EventEmitter = new EventEmitter(); // //#region Colors ... readonly selectedColor: XStandardType = DEFAULT_COLOR_PICKER_COLOR; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly copyToClipboardIconColor: XStandardType = XColorWithBrightness.TertiaryShade; readonly colorInputIconColor: XStandardType = XColorWithBrightness.SecondaryShade; readonly clearColorIconColor: XStandardType = XColorWithBrightness.Danger; readonly colorTextColor: XStandardType = XColorWithBrightness.Dark; readonly presetColorsLableColor: XStandardType = XColorWithBrightness.Dark; readonly cursorColor: XStandardType = XColorWithBrightness.Dark; //#endregion // //#region Labels ... readonly colorInputIconLabel: XStandardType = XResourceIDs.input; readonly copyToClipboardIconLabel: XStandardType = XResourceIDs.copy_to_clipboard; readonly clearColorIconLabel: XStandardType = XResourceIDs.clear; //#endregion // //#region PresetColors ... readonly presetColorsLable: XStandardType; readonly presetColors: XStandardType>; //#endregion // //#region Represent Color Value ... readonly representColorFormats: XStandardType< XOneOrManyType > = [XColorPickerOutputFormat.XHEX]; readonly outputFormat: XStandardType = XColorPickerOutputFormat.XHEX; //#endregion // //#region Show Parts Props ... readonly showColorInput: XStandardType = true; readonly showCopyToClipboard: XStandardType = false; readonly showSelectedColorPreview: XStandardType = true; readonly showPaletteChannel: XStandardType = true; readonly showHueChannel: XStandardType = true; readonly showAlphaChannel: XStandardType = true; readonly showColorValue: XStandardType = true; readonly showPresetColors: XStandardType = true; //#endregion //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XColorPickerContainerComponent extends XComponentCardContainerComponent implements IXColorPickerContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Output() colorSelected: EventEmitter = new EventEmitter(); // //#region Colors ... @Input() selectedColor: XStandardType = this.propertyProvider.selectedColor; @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; @Input() copyToClipboardIconColor: XStandardType = this.propertyProvider.copyToClipboardIconColor; @Input() colorInputIconColor: XStandardType = this.propertyProvider.colorInputIconColor; @Input() clearColorIconColor: XStandardType = this.propertyProvider.clearColorIconColor; @Input() colorTextColor: XStandardType = this.propertyProvider.colorTextColor; @Input() presetColorsLableColor: XStandardType = this.propertyProvider.presetColorsLableColor; @Input() cursorColor: XStandardType = this.propertyProvider.cursorColor; //#endregion // //#region Labels ... @Input() colorInputIconLabel: XStandardType = this.propertyProvider.colorInputIconLabel; @Input() copyToClipboardIconLabel: XStandardType = this.propertyProvider.copyToClipboardIconLabel; @Input() clearColorIconLabel: XStandardType = this.propertyProvider.clearColorIconLabel; //#endregion // //#region PresetColors ... @Input() presetColorsLable: XStandardType = this.propertyProvider.presetColorsLable; @Input() presetColors: XStandardType> = this.propertyProvider.presetColors; //#endregion // //#region Represent Color Value ... @Input() representColorFormats: XStandardType< XOneOrManyType > = this.propertyProvider.representColorFormats; @Input() outputFormat: XStandardType = this.propertyProvider.outputFormat; //#endregion // //#region Show Parts Props ... @Input() showColorInput: XStandardType = this.propertyProvider.showColorInput; @Input() showCopyToClipboard: XStandardType = this.propertyProvider.showCopyToClipboard; @Input() showSelectedColorPreview: XStandardType = this.propertyProvider.showSelectedColorPreview; @Input() showPaletteChannel: XStandardType = this.propertyProvider.showPaletteChannel; @Input() showHueChannel: XStandardType = this.propertyProvider.showHueChannel; @Input() showAlphaChannel: XStandardType = this.propertyProvider.showAlphaChannel; @Input() showColorValue: XStandardType = this.propertyProvider.showColorValue; @Input() showPresetColors: XStandardType = this.propertyProvider.showPresetColors; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XColorPickerContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXColorPickerContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // //#region Colors ... selectedColor: this.getValue( container ? container.selectedColor : this.selectedColor ), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), copyToClipboardIconColor: this.getValue( container ? container.copyToClipboardIconColor : this.copyToClipboardIconColor ), colorInputIconColor: this.getValue( container ? container.colorInputIconColor : this.colorInputIconColor ), clearColorIconColor: this.getValue( container ? container.clearColorIconColor : this.clearColorIconColor ), colorTextColor: this.getValue( container ? container.colorTextColor : this.colorTextColor ), presetColorsLableColor: this.getValue( container ? container.presetColorsLableColor : this.presetColorsLableColor ), cursorColor: this.getValue( container ? container.cursorColor : this.cursorColor ), //#endregion // //#region Labels ... colorInputIconLabel: this.getValue( container ? container.colorInputIconLabel : this.colorInputIconLabel ), copyToClipboardIconLabel: this.getValue( container ? container.copyToClipboardIconLabel : this.copyToClipboardIconLabel ), clearColorIconLabel: this.getValue( container ? container.clearColorIconLabel : this.clearColorIconLabel ), //#endregion // //#region PresetColors ... presetColorsLable: this.getValue( container ? container.presetColorsLable : this.presetColorsLable ), presetColors: this.getValue( container ? container.presetColors : this.presetColors ), //#endregion // //#region Represent Color Value ... representColorFormats: this.getValue( container ? container.representColorFormats : this.representColorFormats ), outputFormat: this.getValue( container ? container.outputFormat : this.outputFormat ), //#endregion // //#region Show Parts Props ... showColorInput: this.getValue( container ? container.showColorInput : this.showColorInput ), showCopyToClipboard: this.getValue( container ? container.showCopyToClipboard : this.showCopyToClipboard ), showSelectedColorPreview: this.getValue( container ? container.showSelectedColorPreview : this.showSelectedColorPreview ), showPaletteChannel: this.getValue( container ? container.showPaletteChannel : this.showPaletteChannel ), showHueChannel: this.getValue( container ? container.showHueChannel : this.showHueChannel ), showAlphaChannel: this.getValue( container ? container.showAlphaChannel : this.showAlphaChannel ), showColorValue: this.getValue( container ? container.showColorValue : this.showColorValue ), showPresetColors: this.getValue( container ? container.showPresetColors : this.showPresetColors ), //#endregion }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // colorSelected: this.colorSelected, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\directives\x-color-text.directive.ts import { Input, Output, Directive, EventEmitter, HostListener, } from '@angular/core'; @Directive({ selector: '[xColorText]', }) export class XColorTextDirective { // @Input() text: any; @Input() rg: number; // @Output() newValue = new EventEmitter(); // @HostListener('input', ['$event.target.value']) changeInput(value: string) { // if (this.rg === undefined) { this.newValue.emit(value); } else { // const numeric = parseFloat(value); // if (!isNaN(numeric) && numeric >= 0 && numeric <= this.rg) { this.newValue.emit({ v: numeric, rg: this.rg }); } } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.component.html

{{ getTitle() | async }}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.component.scss ::ng-deep.fullscreen-dialog { // width: 80vw !important; max-width: 80vw !important; // height: 80vh !important; max-height: 80vh !important; // &.mobile { // width: 100vw !important; max-width: 100vw !important; // height: 100vh !important; max-height: 100vh !important; } // .mat-dialog-container { padding: 0 !important; } } x-icon { --size: 24px; } .toolbar-area { margin: 8px; } .toolbar-item { width: auto; height: 48px; } .toolbar-button { width: 32px; margin: { left: 4px; right: 4px; } } h1, h2, h3, h4, h5, h6 { margin: 0 !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.component.ts import { Inject, NgZone, Renderer2, Component, ElementRef, ChangeDetectorRef, ChangeDetectionStrategy, } from '@angular/core'; import { XColor, hasChild, isFunction, XResourceIDs, XDialogResult, isNullOrUndefined, isNullOrEmptyString, } from 'x-framework-core'; import { XColorPickerActionModel, XColorPickerOutputFormat, } from '../x-color-picker.typings'; import { Subject, of } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XBasePage } from '../../classes/x-base-page'; import { XManagerService } from 'x-framework-services'; import { XIconNames } from '../../x-icon/x-icon.typings'; import { XSlotName } from '../../x-slotter/x-slotter.typings'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { XColorPickerDialogConfig } from './x-color-picker-dialog.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from './../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from './../../config/x-framework-components.config'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-color-picker-dialog', templateUrl: './x-color-picker-dialog.component.html', styleUrls: ['./x-color-picker-dialog.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XColorPickerDialogComponent extends XBasePage { // //#region Props ... // selectIcon = XIconNames.checked; backIcon = XIconNames.arrow_back; SlotNames = Object.assign({}, XSlotName); // isMobileUi$ = this.managerService.isMobileUi$; isNotMobile$ = this.managerService.isNotMobileUi$; // actionProvider = new Subject(); // selectedColor: string; //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: any, public dialogRef: MatDialogRef ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // this.preventBack = true; } async afterViewInit() { super.afterViewInit(); } //#endregion // //#region UI Providers ... getData() { return this.getValue(this.data as XColorPickerDialogConfig); } hasData() { return !isNullOrUndefined(this.getData()); } canSelect() { return !isNullOrEmptyString(this.selectedColor); } getTitle() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.title)) ); } /** * retrieve selectedColor value ... */ getSelectedColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.selectedColor)) ); } // //#region Colors ... /** * retrieve color value ... */ getColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.color)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light)) ); } /** * determines is Foureground color or not ... */ isForegroundColor() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.foregroundColor)) ); } /** * retrieve cursorColor value ... */ getCursorColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.cursorColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark)) ); } /** * retrieve colorTextColor value ... */ getColorTextColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.colorTextColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark)) ); } /** * retrieve clearColorIconColor value ... */ getClearColorIconColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.clearColorIconColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Danger)) ); } /** * retrieve colorInputIconColor value ... */ getColorInputIconColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.colorInputIconColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Secondary)) ); } /** * retrieve presetColorsLableColor value ... */ getPresetColorsLableColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.presetColorsLableColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark)) ); } /** * retrieve copyToClipboardIconColor value ... */ getCopyToClipboardIconColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.copyToClipboardIconColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Tertiary)) ); } //#endregion // //#region Labels ... /** * retrieve presetColorsLable value ... */ getPresetColorsLable() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.presetColorsLable)), map((value) => !isNullOrEmptyString(value) ? value : XResourceIDs.preset_colors ) ); } /** * retrieve clearColorIconLabel value ... */ getClearColorIconLabel() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.clearColorIconLabel)), map((value) => (!isNullOrEmptyString(value) ? value : XResourceIDs.clear)) ); } /** * retrieve colorInputIconLabel value ... */ getColorInputIconLabel() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.colorInputIconLabel)), map((value) => (!isNullOrEmptyString(value) ? value : XResourceIDs.input)) ); } /** * retrieve copyToClipboardIconLabel value ... */ getCopyToClipboardIconLabel() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.copyToClipboardIconLabel) ), map((value) => !isNullOrEmptyString(value) ? value : XResourceIDs.copy_to_clipboard ) ); } //#endregion // //#region Preset Colors ... getPresetColors() { return this.getData().pipe( concatMap((config) => this.getArrayValue(config.presetColors)) ); } //#endregion // //#region Represent Format ... /** * retrieve representColorFormats value ... */ getRepresentColorFormats() { return this.getData().pipe( concatMap((config) => this.getArrayValue(config.representColorFormats)), map((formats) => hasChild(formats) ? formats : [XColorPickerOutputFormat.XHEX] ) ); } /** * retrieve outputFormat value ... */ getOutputFormat() { return this.getData().pipe( concatMap((config) => this.getValue(config.outputFormat)), map((format) => !isNullOrEmptyString(format) ? format : XColorPickerOutputFormat.XHEX ) ); } //#endregion // //#region Show Parts ... /** * determines showCopyToClipboard or not ... */ showCopyToClipboard() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showCopyToClipboard)) ); } /** * determines showColorInput or not ... */ showColorInput() { return this.getData().pipe( concatMap((config) => !isNullOrUndefined(config.showColorInput) ? this.getOptionalValue(config.showColorInput) : of(true) ) ); } /** * determines showSelectedColorPreview or not ... */ showSelectedColorPreview() { return this.getData().pipe( concatMap((config) => !isNullOrUndefined(config.showSelectedColorPreview) ? this.getOptionalValue(config.showSelectedColorPreview) : of(true) ) ); } /** * determines showPaletteChannel or not ... */ showPaletteChannel() { return this.getData().pipe( concatMap((config) => !isNullOrUndefined(config.showPaletteChannel) ? this.getOptionalValue(config.showPaletteChannel) : of(true) ) ); } /** * determines showHueChannel or not ... */ showHueChannel() { return this.getData().pipe( concatMap((config) => !isNullOrUndefined(config.showHueChannel) ? this.getOptionalValue(config.showHueChannel) : of(true) ) ); } /** * determines showAlphaChannel or not ... */ showAlphaChannel() { return this.getData().pipe( concatMap((config) => !isNullOrUndefined(config.showAlphaChannel) ? this.getOptionalValue(config.showAlphaChannel) : of(true) ) ); } /** * determines showColorValue or not ... */ showColorValue() { return this.getData().pipe( concatMap((config) => !isNullOrUndefined(config.showColorValue) ? this.getOptionalValue(config.showColorValue) : of(true) ) ); } /** * determines showPresetColors or not ... */ showPresetColors() { return this.getData().pipe( concatMap((config) => config.showPresetColors ? this.getOptionalValue(config.showPresetColors) : of(null) ) ); } //#endregion // /** * retrieve css classes ... */ getCssClass() { return this.getData().pipe( concatMap((config) => this.getArrayValue(config.cssClass)) ); } // //#region /** * retireve cardColor value ... */ getCardColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.cardColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light)) ); } /** * determines is cardForegroundColor or not ... */ isCardForegroundColor() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.cardForegroundColor)) ); } /** * retrieve cardTitle value ... */ getCardTitle() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.cardTitle)) ); } /** * retrieve cardSubTitle value ... */ getCardSubTitle() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.cardSubTitle)) ); } //#endregion //#endregion // //#region UI Handlers ... async handleBack() { this.dialogRef.close(); } async handleColorSelected(event: string) { // this.selectedColor = event; // const config = await this.getValueAsync(this.getData()); if (!config || !config.colorSelected || !isFunction(config.colorSelected)) { return; } // config.colorSelected.emit(event); // this.detectChanges(); } async handleSelect() { // if (!this.canSelect()) { return; } // this.dialogRef.close({ result: XDialogResult.Ok, payload: this.selectedColor, }); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.service.ts import { XResourceIDs, XBaseService, XDialogResult, isNullOrUndefined, } from 'x-framework-core'; import { MatDialog, MatDialogRef, MatDialogConfig, } from '@angular/material/dialog'; import { XColorPickerDialogResult, XColorPickerDialogConfig, } from './x-color-picker-dialog.typings'; import { XManagerService } from 'x-framework-services'; import { Injectable, Inject, Output, EventEmitter } from '@angular/core'; import { XColorPickerDialogComponent } from './x-color-picker-dialog.component'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from './../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from './../../config/x-framework-components.config'; @Injectable({ providedIn: 'root', }) export class XColorPickerDialogService extends XBaseService { // //#region Props ... private MOBILE_CLASS_NAME = 'mobile'; private DIALOG_REF: MatDialogRef; // isMobile$ = this.managerService.isMobileUi$; // tslint:disable-next-line:no-output-on-prefix @Output() onResult = new EventEmitter(); //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, private dialog: MatDialog, private managerService: XManagerService ) { super(config); } //#endregion // //#region Actions ... /** * Open Select Map Dialog ... */ async openDialog(config?: XColorPickerDialogConfig) { // // Prevent Double Bubble ... if (this.DIALOG_REF) { return; } // // Prepare Config ... if (!config) { config = {}; } // // Set Default Title ... if (config && !config.title) { config.title = XResourceIDs.color_picker_dialog_title; } // // Prepare Dialog Config ... const data: MatDialogConfig = { data: config, }; // data.panelClass = 'fullscreen-dialog'; // // Show Cropper inside a Dialog ... this.DIALOG_REF = this.dialog.open(XColorPickerDialogComponent, data); this.DIALOG_REF.disableClose = true; // // Attach Mobile Class ... this.isMobile$.subscribe((isMobile) => { // if (isMobile) { if (this.DIALOG_REF) { this.DIALOG_REF.addPanelClass(this.MOBILE_CLASS_NAME); } } else { if (this.DIALOG_REF) { this.DIALOG_REF.removePanelClass(this.MOBILE_CLASS_NAME); } } }); // // Handle Backdrop ... this.DIALOG_REF.backdropClick().subscribe(() => { // // Cancel Dialog ... this.onResult.emit({ result: XDialogResult.Cancel }); // this.closeDialog(); }); // // Handle Dialog Result ... this.DIALOG_REF.afterClosed().subscribe( (model: XColorPickerDialogResult) => { // if (isNullOrUndefined(model) || model.result !== XDialogResult.Ok) { // // Cancel Dialog ... this.onResult.emit({ result: XDialogResult.Cancel }); } else { // // Handle Results ... this.onResult.emit(model); } // this.closeDialog(); } ); } /** * Close Select Map Dialog ... */ closeDialog() { // // Prevent Go Forward ... if (!this.DIALOG_REF) { return; } // // Close Dialog ... this.DIALOG_REF.close(); this.DIALOG_REF = null; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-color-picker\x-color-picker-dialog\x-color-picker-dialog.typings.ts import { XDialogResult } from 'x-framework-core'; import { IXColorPickerContainer } from '../x-color-picker.typings'; import { XBaseDialogConfig } from '../../classes/i-x-base-dialog.container'; export interface XColorPickerDialogResult { payload?: string; result: XDialogResult; } export interface XColorPickerDialogConfig extends XBaseDialogConfig, Partial {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.component.html

{{ displayMessage }}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.component.scss .display-message-container { margin: 2px; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.component.ts import { XCounterTick, XCounterType, XCounterState, XCounterAction, XCounterActionModel, XCounterTypeIdentifier, XCounterContainerComponent, } from './x-counter.typings'; import { nameof } from 'x-framework-core'; import { Subscription, interval, Subject } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ selector: 'x-counter', templateUrl: './x-counter.component.html', styleUrls: ['./x-counter.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XCounterComponent extends XCounterContainerComponent { // //#region Props ... private StepCount: number; private IsCounting: boolean; private TYPE: XCounterTypeIdentifier; private TimerSubscription: Subscription; // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // displayMessage = ''; //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Handle Values ... const isStopValueChanged = changeKeys.includes( nameof('stopValue') ); const isStartValueChanged = changeKeys.includes( nameof('startValue') ); const isCurrentValueChanged = changeKeys.includes( nameof('currentValue') ); if (isStopValueChanged || isStartValueChanged || isCurrentValueChanged) { this.setBoundaries(this.startValue, this.stopValue, this.currentValue); } //#endregion // //#region Handle Type Changed ... const isTypeChanged = changeKeys.includes( nameof('type') ); if (isTypeChanged) { await this.prepareType(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } async onInit() { super.onInit(); // await this.prepareType(); // // Try to Show Start Value ... this.updateDisplayMessage(); // await this.handleAutoStart(); } onDestroy() { super.onDestroy(); // if (this.TimerSubscription) { this.TimerSubscription.unsubscribe(); this.TimerSubscription = null; } // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... //#endregion // //#region UI Handlers ... //#endregion // //#region Actions ... setBoundaries(start: number, stop: number, current: number) { // this.startValue = start; this.stopValue = stop; this.currentValue = current; } async start() { // const isUpdated = await this.updateValues(); // if (isUpdated && !this.TimerSubscription && this.getStepsCount() > 0) { this.startCounter(); } } pause() { // if (this.TimerSubscription) { this.IsCounting = false; this.TimerSubscription.unsubscribe(); this.TimerSubscription = null; } } cancel() { this.currentValue = this.stopValue; } getCounterState(): XCounterState { // if ( this.TYPE === XCounterType.CountDown && this.currentValue === this.startValue ) { return XCounterState.Start; } // if ( this.TYPE === XCounterType.CountUp && this.currentValue === this.stopValue ) { return XCounterState.Start; } // if (this.isLastStep()) { return XCounterState.Stop; } // if ( this.TYPE === XCounterType.CountDown && this.currentValue > this.startValue ) { return XCounterState.Tick; } // if ( this.TYPE === XCounterType.CountUp && this.currentValue < this.startValue ) { return XCounterState.Tick; } // return XCounterState.Stop; } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XCounterAction.START: await this.start(); break; // case XCounterAction.PAUSE: this.pause(); break; // case XCounterAction.CANCEL: this.cancel(); break; // case XCounterAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private startCounter() { // this.StepCount = this.getStepsCount(); // if (!this.IsCounting && this.StepCount && this.StepCount > 0) { // this.IsCounting = true; this.TimerSubscription = interval(this.delay).subscribe(() => { // this.updateDisplayMessage(); // const eventModel = this.getTickModel(); // if (eventModel.state === XCounterState.Start) { this.counterStart.emit(eventModel); } // if (eventModel.state === XCounterState.Stop) { this.counterStop.emit(eventModel); } // this.counterTtick.emit(eventModel); // if (this.isLastStep()) { this.pause(); } else if (this.TYPE === XCounterType.CountDown) { this.currentValue--; } else if (this.TYPE === XCounterType.CountUp) { this.currentValue++; } }); } } private getTickModel(): XCounterTick { return { type: this.TYPE, start: this.startValue, stop: this.stopValue, current: this.currentValue, delay: this.delay, state: this.getCounterState(), } as XCounterTick; } private getStepsCount() { // let count = -1; // switch (this.TYPE) { case XCounterType.CountDown: count = this.startValue - this.stopValue; break; case XCounterType.CountUp: count = this.stopValue - this.startValue; break; } // if (isNaN(count)) { count = -1; } // return count; } private isLastStep() { // switch (this.TYPE) { // case XCounterType.CountDown: return this.currentValue <= this.stopValue; // default: case XCounterType.CountUp: return this.currentValue >= this.startValue; } } private updateValues() { return new Promise((res) => { // switch (this.TYPE) { case XCounterType.CountDown: // if (this.startValue < this.stopValue) { res(false); return; } // if (!this.currentValue) { this.currentValue = this.startValue; } break; case XCounterType.CountUp: if (this.startValue > this.stopValue) { res(false); return; } // if (!this.currentValue) { this.currentValue = this.stopValue; } break; } // res(true); }); } private updateDisplayMessage() { // this.displayMessage = this.displayPattern( this.stopValue, this.startValue, this.currentValue ); } // private async prepareType() { this.TYPE = await this.getValueAsync(this.type); } // private async handleAutoStart() { // const isAutoStart = await this.getValueAsync(this.autoStart); if (!isAutoStart) { return; } // await this.start(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XCounterComponent } from './x-counter.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XCounterComponent], imports: [XCardModule, CommonModule, XBaseComponentModule], exports: [XCardModule, CommonModule, XCounterComponent, XBaseComponentModule], }) export class XCounterModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XOneOrManyType, XStandardType } from 'x-framework-core'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XCounterType { CountUp = 'count_up', CountDown = 'count_down', } export type XCounterTypeIdentifier = XCounterType | string; export enum XCounterState { Start, Tick, Stop, } export interface XCounterTick { type: XCounterType; start: number; stop: number; current: number; delay: number; state: XCounterState; } export const defaultStringPatternMaker = ( max: number, min: number, current: number ) => { return `${current}`; }; export enum XCounterAction { START = 'start', PAUSE = 'pause', CANCEL = 'cancel', // Refresh = 'refresh', } export type XCounterActionIdentifier = XCounterAction | string; export interface XCounterActionModel extends XBaseActionModel {} // //#region Container ... export interface IXCounterContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // type: XStandardType; autoStart: XStandardType; stopValue: number; startValue: number; currentValue: number; delay: number; // displayPattern: (min: number, max: number, current: number) => string; // counterStart: EventEmitter; counterTtick: EventEmitter; counterStop: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XCounterContainer extends XComponentCardContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly type: XStandardType = XCounterType.CountDown; readonly autoStart: XStandardType = false; readonly stopValue: number; readonly startValue: number; readonly currentValue: number; readonly delay: number = 1000; // readonly displayPattern: ( min: number, max: number, current: number ) => string = defaultStringPatternMaker; // readonly counterStart: EventEmitter = new EventEmitter(); readonly counterTtick: EventEmitter = new EventEmitter(); readonly counterStop: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XCounterContainerComponent extends XComponentCardContainerComponent implements IXCounterContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() type: XStandardType = this.propertyProvider.type; @Input() autoStart: XStandardType = false; @Input() stopValue: number = this.propertyProvider.stopValue; @Input() startValue: number = this.propertyProvider.startValue; @Input() currentValue: number = this.propertyProvider.currentValue; @Input() delay = this.propertyProvider.delay; @Input() displayPattern: (min: number, max: number, current: number) => string = this.propertyProvider.displayPattern; // @Output() counterStart: EventEmitter = new EventEmitter(); @Output() counterTtick: EventEmitter = new EventEmitter(); @Output() counterStop: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XCounterContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXCounterContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // type: this.getValue(container ? container.type : this.type), autoStart: this.getValue( container ? container.autoStart : this.autoStart ), stopValue: this.getValue( container ? container.stopValue : this.stopValue ), startValue: this.getValue( container ? container.startValue : this.startValue ), currentValue: this.getValue( container ? container.currentValue : this.currentValue ), delay: this.getValue(container ? container.delay : this.delay), displayPattern: this.getValue( container ? container.displayPattern : this.displayPattern ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // counterStart: this.counterStart, counterTtick: this.counterTtick, counterStop: this.counterStop, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.component.html
{{ preparedPaginatorOptions.pageInfoProvider( managerService.currentLocale, currentPage, pageSize, totalPages, totalItems ) }}
{{ applyLocale(pageSize) }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.component.ts import { nameof, XLocale, toNumber, hasChild, applyLocale, XModalButtonRole, XPickerColumnOption, XBaseDataPagerQuery, } from 'x-framework-core'; import { XDataPagerAction, XDataPagerActionModel, XDataPagerPresentType, XDataPagerPaginatorOptions, XDataPagerPaginatorPosition, XDataPagerContainerComponent, } from './x-data-pager.typings'; import { Subject, Subscription } from 'rxjs'; import { Component, ViewChild } from '@angular/core'; import { XIconNames } from '../x-icon/x-icon.typings'; import { ChangeDetectionStrategy } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; @Component({ selector: 'x-data-pager', templateUrl: './x-data-pager.component.html', styleUrls: ['./x-data-pager.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XDataPagerComponent extends XDataPagerContainerComponent { // //#region Props ... // private MODAL: any; private PAGE_SIZE: number; private TOTAL_PAGES: number; private TOTAL_ITEMS: number; private CURRENT_PAGE: number; private PAGINATOR: MatPaginator; private PAGINATOR_PAGE_SUBSCRIPTION: Subscription; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private PAGINATOR_OPTIONS: XDataPagerPaginatorOptions; // readonly DataPagerPresetTypes = Object.assign({}, XDataPagerPresentType); readonly DataPagerPaginatorPositions = Object.assign( {}, XDataPagerPaginatorPosition ); // showPageNumberInput: boolean; // @ViewChild(MatPaginator, { static: false }) set paginator(v: MatPaginator) { if (!v) { return; } // this.PAGINATOR = v; this.setPaginatorData(); } get paginator() { return this.PAGINATOR; } get pageSize() { return this.PAGE_SIZE; } get currentPage() { return this.CURRENT_PAGE; } get totalPages() { return this.TOTAL_PAGES; } get totalItems() { return this.TOTAL_ITEMS; } get preparedPaginatorOptions() { return this.PAGINATOR_OPTIONS; } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); await this.preparePaginatorOptions(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region PaginatorOptionChanged ... const isPaginatorOptionsChanged = changeKeys.includes( nameof('paginatorOptions') ); if (isPaginatorOptionsChanged) { await this.preparePaginatorOptions(); } //#endregion // //#region Query Changed ... const isTaskChanged = changeKeys.includes( nameof('task') ); const isQueryChanged = changeKeys.includes( nameof('query') ); if (isQueryChanged || isTaskChanged) { await this.handleQueryChanged(); } //#endregion // //#region Result Changed ... const isResultChanged = changeKeys.includes( nameof('result') ); if (isResultChanged) { await this.handleResultChanged(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Handlers ... async handlePageChange(event: CustomEvent | any) { // const selectedPage = (event.detail.value as number) || undefined; if (!selectedPage) { return; } // await this.toPage(selectedPage); } async handlePageSizeChange(event?: any) { // if (!this.preparedPaginatorOptions || !this.pageSize) { return; } // const pageSizes = await this.getValueAsync( this.preparedPaginatorOptions.pageSizes ); if (!hasChild(pageSizes)) { return; } // const options: XPickerColumnOption[] = pageSizes.map((ps) => { // const opt: XPickerColumnOption = { text: this.applyLocale(ps.toString()), value: ps, disabled: ps === this.pageSize, }; // return opt; }); // if (this.MODAL) { await this.managerService.dialogService.pickerController.dismiss(); this.MODAL = null; } // this.MODAL = await this.managerService.dialogService.presentPicker({ buttons: [ { text: this.resourceProvider(this.ResourceIDs.accept), role: XModalButtonRole.Selected, handler: (value) => { if (!value) { return; } // const pageSize = value.pageSize.value; this.changePageSize(pageSize); }, }, { text: this.resourceProvider(this.ResourceIDs.cancel), role: XModalButtonRole.Cancel, }, ], columns: [{ name: 'pageSize', options }], }); // await this.MODAL.onWillDismiss(); this.MODAL = null; } //#endregion // //#region Actions ... // //#region Pager Actions ... async firstPage() { // if (this.uiDisabled || this.loading) { return; } // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // this.paginator.firstPage(); } async lastPage() { // if (this.uiDisabled || this.loading) { return; } // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // this.paginator.lastPage(); } async nextPage() { // if (this.uiDisabled || this.loading) { return; } // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // this.paginator.nextPage(); } async previousPage() { // if (this.uiDisabled || this.loading) { return; } // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // this.paginator.previousPage(); } async toPage(index: number) { // if (this.uiDisabled || this.loading) { return; } // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // index = index === 0 ? 1 : index; // this.paginator.pageIndex = index - 1; this.paginator.page.next({ pageIndex: index - 1, pageSize: this.pageSize, length: this.totalItems, }); } async changePageSize(size: number) { // if (this.uiDisabled || this.loading) { return; } // if (!size || !this.paginator) { return; } // this.paginator.pageSize = size; this.paginator.page.next({ pageIndex: 0, pageSize: size, length: this.totalItems, }); } //#endregion //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XDataPagerAction.Refresh: this.detectChanges(); break; // case XDataPagerAction.GoFirst: await this.firstPage(); break; // case XDataPagerAction.GoLast: await this.lastPage(); break; // case XDataPagerAction.GoNext: await this.nextPage(); break; // case XDataPagerAction.GoPrev: await this.previousPage(); break; // case XDataPagerAction.ToPage: if (model.payload) { await this.toPage(model.payload); } break; // case XDataPagerAction.ChangePageSize: if (model.payload) { await this.changePageSize(model.payload); } break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // private async handleQueryChanged() { // this.result = null; // if (!this.query || !this.task) { return; } // const mTask = this.task(this.query); // this.taskReady.emit(mTask); } private async handleResultChanged() { // if (!this.result) { return; } // //#region Extract Required Options ... this.CURRENT_PAGE = this.query.pageNumber; this.PAGE_SIZE = this.query.rowsInPage; this.TOTAL_PAGES = this.calculatePageCount( this.result.count, this.query.rowsInPage ); this.TOTAL_ITEMS = this.result.count; //#endregion // if (!this.preparedPaginatorOptions) { await this.preparePaginatorOptions(); } // await this.setPaginatorData(); } private async setPaginatorData() { // if (!this.PAGINATOR) { return; } // this.PAGINATOR.pageSize = this.PAGE_SIZE; this.PAGINATOR.pageIndex = this.CURRENT_PAGE - 1; this.PAGINATOR.length = this.TOTAL_ITEMS; // // Prepare Paginator Options ... await this.preparePaginatorOptions(); await this.registerPaginatorHandlers(); } private async preparePaginatorOptions() { // if (!this.result) { return; } // //#region Preparing Options ... // const defaultOptions = this.defaultPaginatorOptions(); const options = await this.getValueAsync(this.paginatorOptions); const preparedOptions: XDataPagerPaginatorOptions = { ...defaultOptions, ...options, pageSize: this.query.rowsInPage, }; // if (options) { // if (!options.first) { preparedOptions.first = undefined; } else { // const first = options.first; // if (first.disabled) { const firstDisabled = await this.getValueAsync(first.disabled); preparedOptions.first.disabled = defaultOptions.first.disabled && firstDisabled; } else { preparedOptions.first.disabled = defaultOptions.first.disabled; } // if (!first.icon) { preparedOptions.first.icon = defaultOptions.first.icon; } // if (!first.title) { preparedOptions.first.title = defaultOptions.first.title; } } // if (!options.last) { preparedOptions.last = undefined; } else { // const last = options.last; // if (last.disabled) { const lastDisabled = await this.getValueAsync(last.disabled); preparedOptions.last.disabled = defaultOptions.last.disabled && lastDisabled; } else { preparedOptions.last.disabled = defaultOptions.last.disabled; } // if (!last.icon) { preparedOptions.last.icon = defaultOptions.last.icon; } // if (!last.title) { preparedOptions.last.title = defaultOptions.last.title; } } // if (!options.next) { preparedOptions.next = undefined; } else { // const next = options.next; // if (next.disabled) { const nextDisabled = await this.getValueAsync(next.disabled); preparedOptions.next.disabled = defaultOptions.next.disabled && nextDisabled; } else { preparedOptions.next.disabled = defaultOptions.next.disabled; } // if (!next.icon) { preparedOptions.next.icon = defaultOptions.next.icon; } // if (!next.title) { preparedOptions.next.title = defaultOptions.next.title; } } // if (!options.prev) { preparedOptions.prev = undefined; } else { // const prev = options.prev; // if (prev.disabled) { const prevDisabled = await this.getValueAsync(prev.disabled); preparedOptions.prev.disabled = defaultOptions.prev.disabled && prevDisabled; } else { preparedOptions.prev.disabled = defaultOptions.prev.disabled; } // if (!prev.icon) { preparedOptions.prev.icon = defaultOptions.prev.icon; } // if (!prev.title) { preparedOptions.prev.title = defaultOptions.prev.title; } } } // this.PAGINATOR_OPTIONS = preparedOptions; // this.detectChanges(); //#endregion } private async registerPaginatorHandlers() { // //#region PageHandler Actions ... // if (!this.PAGINATOR) { return; } // // Unsubscribe last ... if (this.PAGINATOR_PAGE_SUBSCRIPTION) { this.PAGINATOR_PAGE_SUBSCRIPTION.unsubscribe(); this.PAGINATOR_PAGE_SUBSCRIPTION = null; } // // Subscribe New ... this.PAGINATOR_PAGE_SUBSCRIPTION = this.applyTakeUntilWrapper( this.paginator.page.asObservable() ).subscribe(async (res) => { // // Prepare New Query ... const query: XBaseDataPagerQuery = { ...this.query, // pageNumber: res.pageIndex + 1, rowsInPage: res.pageSize, }; // // Notify Query Changed ... this.queryChange.emit(query); }); //#endregion } private defaultPaginatorOptions() { // const options: XDataPagerPaginatorOptions = { pageSizes: this.config.pageSizes, pageSize: this.config.defaultPageSize, first: { title: 'first', icon: XIconNames.first, disabled: !this.paginator || !this.paginator.hasPreviousPage(), }, last: { title: 'last', icon: XIconNames.last, disabled: !this.paginator || !this.paginator.hasNextPage(), }, prev: { title: 'previous', icon: XIconNames.previous, disabled: !this.paginator || !this.paginator.hasPreviousPage(), }, next: { title: 'next', icon: XIconNames.next, disabled: !this.paginator || !this.paginator.hasNextPage(), }, pageInfoProvider: ( locale: XLocale, currentPage: number, pageSize: number, totalPages: number, totalItems: number ) => { // const info = `${currentPage}/${totalPages}`; return applyLocale(info, locale); }, }; // return options; } private calculatePageCount(itemsCount: number, pageSize: number) { // // Data Correction ... pageSize = toNumber(pageSize); itemsCount = toNumber(itemsCount); // // Result ... return Math.floor((itemsCount + (pageSize - 1)) / pageSize); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XEmptyModule } from '../x-empty/x-empty.module'; import { XDataPagerComponent } from './x-data-pager.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XDataPagerComponent], imports: [ XCardModule, XIconModule, XEmptyModule, CommonModule, XBaseComponentModule, ], exports: [ XIconModule, XCardModule, XEmptyModule, CommonModule, XDataPagerComponent, XBaseComponentModule, ], }) export class XDataPagerModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-pager\x-data-pager.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XBaseDataPagerQuery, XColorWithBrightness, XBaseDataPagerQueryResult, } from 'x-framework-core'; import { XCardEmptyContainer, XCardEmptyContainerComponent, } from '../classes/i-x-card-empty.container'; import { map, concatMap } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XTablePaginatorOptions } from '../x-table/x-table.typings'; import { IXCardEmptyContainer } from '../classes/i-x-card-empty.container'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XDataPagerPaginatorPosition { Above = 'above', Below = 'below', } export type XDataPagerPaginatorPositionIdentifier = | XDataPagerPaginatorPosition | string; // tslint:disable-next-line:no-empty-interface export interface XDataPagerPaginatorOptions extends XTablePaginatorOptions {} export enum XDataPagerPresentType { Item = 'item', Page = 'page', } export type XDataPagerPresentTypeIdentifier = XDataPagerPresentType | string; export enum XDataPagerAction { GoFirst = 'go_first', GoLast = 'go_last', GoNext = 'go_next', GoPrev = 'go_prev', ToPage = 'to_page', ChangePageSize = 'change_page_size', Refresh = 'refresh', } export type XDataPagerActionIdentifier = XDataPagerAction | string; export interface XDataPagerActionModel extends XBaseActionModel {} // //#region Inside Card/Empty Container ... export interface IXDataPagerContainer extends IXCardEmptyContainer { // actionProvider: Subject; cssClass: XStandardType>; // pageChanged: EventEmitter; type: XStandardType; itemTemplate: TemplateRef; // result: XBaseDataPagerQueryResult; task: ( query: XBaseDataPagerQuery ) => Observable>; taskReady: EventEmitter>>; query: XBaseDataPagerQuery; queryChange: EventEmitter; // showPaginator: XStandardType; paginatorPosition: XStandardType; paginatorColor: XStandardType; paginatorOptions: XStandardType; // emptyListTemplate: TemplateRef; } @Injectable({ providedIn: 'root', }) export class XDataPagerContainer extends XCardEmptyContainer implements Readonly { // //#region Props ... // readonly actionProvider = new Subject(); readonly cssClass: XStandardType>; // readonly pageChanged: EventEmitter = new EventEmitter(); readonly type: XStandardType = XDataPagerPresentType.Item; readonly itemTemplate: TemplateRef; // readonly result: XBaseDataPagerQueryResult; readonly task: ( query: XBaseDataPagerQuery ) => Observable>; readonly taskReady: EventEmitter>> = new EventEmitter>>(); readonly query: XBaseDataPagerQuery; readonly queryChange: EventEmitter = new EventEmitter(); // readonly showPaginator: XStandardType; readonly paginatorPosition: XStandardType = XDataPagerPaginatorPosition.Below; readonly paginatorColor: XStandardType = XColorWithBrightness.Light; readonly paginatorOptions: XStandardType; // readonly emptyListTemplate: TemplateRef; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XDataPagerContainerComponent extends XCardEmptyContainerComponent implements IXDataPagerContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Output() pageChanged: EventEmitter = new EventEmitter(); @Input() type: XStandardType = this.propertyProvider.type; @Input() itemTemplate: TemplateRef = this.propertyProvider.itemTemplate; // @Input() result: XBaseDataPagerQueryResult = this.propertyProvider.result; @Input() task: ( query: XBaseDataPagerQuery ) => Observable> = this.propertyProvider.task; @Output() taskReady: EventEmitter>> = new EventEmitter(); @Input() query: XBaseDataPagerQuery = this.propertyProvider.query; @Output() queryChange: EventEmitter = new EventEmitter(); // @Input() showPaginator: XStandardType = this.propertyProvider.showPaginator; @Input() paginatorPosition: XStandardType = this.propertyProvider.paginatorPosition; @Input() paginatorColor: XStandardType = this.propertyProvider.paginatorColor; @Input() paginatorOptions: XStandardType = this.propertyProvider.paginatorOptions; // @Input() emptyListTemplate: TemplateRef = this.propertyProvider.emptyListTemplate; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XDataPagerContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXDataPagerContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // type: this.getValue(container ? container.type : this.type), itemTemplate: this.getValue( container ? container.itemTemplate : this.itemTemplate ), result: this.getValue(container ? container.result : this.result), task: this.getValue(container ? container.task : this.task), query: this.getValue(container ? container.query : this.query), showPaginator: this.getValue( container ? container.showPaginator : this.showPaginator ), paginatorPosition: this.getValue( container ? container.paginatorPosition : this.paginatorPosition ), paginatorColor: this.getValue( container ? container.paginatorColor : this.paginatorColor ), paginatorOptions: this.getValue( container ? container.paginatorOptions : this.paginatorOptions ), // emptyListTemplate: this.getValue( container ? container.emptyListTemplate : this.emptyListTemplate ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // pageChanged: this.pageChanged, taskReady: this.taskReady, queryChange: this.queryChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.component.ts import { XDataScrollerAction, XDataScrollerActionModel, XDataScrollerContainerComponent, } from './x-data-scroller.typings'; import { Component } from '@angular/core'; import { of, Subject, Subscription } from 'rxjs'; import { ChangeDetectionStrategy } from '@angular/core'; import { nameof, hasChild, XBaseDataPagerQuery } from 'x-framework-core'; @Component({ selector: 'x-data-scroller', templateUrl: './x-data-scroller.component.html', styleUrls: ['./x-data-scroller.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XDataScrollerComponent extends XDataScrollerContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // canNext: boolean = true; items: any[] = []; //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Query Changed ... const isTaskChanged = changeKeys.includes( nameof('task') ); const isQueryChanged = changeKeys.includes( nameof('query') ); if (isQueryChanged || isTaskChanged) { await this.handleQueryChanged(); } //#endregion // //#region Result Changed ... const isResultChanged = changeKeys.includes( nameof('result') ); if (isResultChanged) { await this.handleResultChanged(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Handlers ... //#endregion // //#region Actions ... async refreshItems() { // if (this.uiDisabled || this.loading) { return; } // this.items = []; this.result = null; this.canNext = true; this.notifyCanNext(); // const query: XBaseDataPagerQuery = { pageNumber: 1, rowsInPage: this.query.rowsInPage, }; // // Notify Query Changed ... this.queryChange.emit(query); } async loadMore() { // if (!this.canNext || this.uiDisabled || this.loading) { this.notifyCanNext(); return; } // // Prepare New Query ... const query: XBaseDataPagerQuery = { ...this.query, // pageNumber: this.query.pageNumber + 1, rowsInPage: this.query.rowsInPage, }; // // Notify Query Changed ... this.queryChange.emit(query); } async clearItems() { // this.items = []; this.result = null; this.canNext = true; this.notifyCanNext(); // this.detectChanges(); } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.notifyCanNext(); // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XDataScrollerAction.Refresh: this.detectChanges(); break; // case XDataScrollerAction.LoadMore: await this.loadMore(); break; // case XDataScrollerAction.RefreshItems: await this.refreshItems(); break; // case XDataScrollerAction.ClearItems: await this.clearItems(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // private async handleQueryChanged() { // this.result = null; // if (!this.query || !this.task) { return; } // const mTask = this.task(this.query); // this.taskReady.emit(mTask); } private async handleResultChanged() { // if (!this.result || !hasChild(this.result.items)) { return; } // of(...this.result.items).subscribe({ next: item => { setTimeout(() => { // this.items.push(item); this.detectChanges(); }, 100); }, error: (err) => {}, complete: () => { this.canNext = this.items.length < this.result.count; this.notifyCanNext(); } }) } private notifyCanNext() { // if (!this.actionProvider) { return; } // this.actionProvider.next({ action: XDataScrollerAction.CanNext, payload: this.canNext, }); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XEmptyModule } from '../x-empty/x-empty.module'; import { XDataScrollerComponent } from './x-data-scroller.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XDataScrollerComponent], imports: [XCardModule, CommonModule, XEmptyModule, XBaseComponentModule], exports: [ XCardModule, CommonModule, XEmptyModule, XBaseComponentModule, XDataScrollerComponent, ], }) export class XDataScrollerModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-data-scroller\x-data-scroller.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XBaseDataPagerQuery, XBaseDataPagerQueryResult, } from 'x-framework-core'; import { IXCardEmptyContainer, XCardEmptyContainer, XCardEmptyContainerComponent, } from '../classes/i-x-card-empty.container'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XDataScrollerAction { Refresh = 'refresh', RefreshItems = 'refresh_items', LoadMore = 'load_more', ClearItems = 'clear_items', CanNext = 'can_next', } export type XDataScrollerActionIdentifier = XDataScrollerAction | string; export interface XDataScrollerActionModel extends XBaseActionModel {} // //#region Inside Card/Empty Container ... export interface IXDataScrollerContainer extends IXCardEmptyContainer { // actionProvider: Subject; cssClass: XStandardType>; // result: XBaseDataPagerQueryResult; task: (query: XBaseDataPagerQuery) => Observable; taskReady: EventEmitter>; query: XBaseDataPagerQuery; queryChange: EventEmitter; // emptyListTemplate: TemplateRef; } @Injectable({ providedIn: 'root', }) export class XDataScrollerContainer extends XCardEmptyContainer implements Readonly { // //#region Props ... // readonly actionProvider = new Subject(); readonly cssClass: XStandardType>; // readonly result: XBaseDataPagerQueryResult; readonly task: (query: XBaseDataPagerQuery) => Observable; readonly taskReady = new EventEmitter>(); readonly query: XBaseDataPagerQuery; readonly queryChange = new EventEmitter(); // readonly emptyListTemplate: TemplateRef; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XDataScrollerContainerComponent extends XCardEmptyContainerComponent implements IXDataScrollerContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() result: XBaseDataPagerQueryResult = this.propertyProvider.result; @Input() task: (query: XBaseDataPagerQuery) => Observable = this.propertyProvider.task; @Output() taskReady: EventEmitter> = new EventEmitter(); @Input() query: XBaseDataPagerQuery = this.propertyProvider.query; @Output() queryChange: EventEmitter = new EventEmitter(); // @Input() emptyListTemplate: TemplateRef; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XDataScrollerContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXDataScrollerContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // result: this.getValue(container ? container.result : this.result), task: this.getValue(container ? container.task : this.task), query: this.getValue(container ? container.query : this.query), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // emptyListTemplate: container ? container.emptyListTemplate : this.emptyListTemplate, // taskReady: this.taskReady, queryChange: this.queryChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.component.html
{{ getTitle(key) | async }}
{{ getContent(key, preparedModel[key]) | async }}
{{ getTitle(key) | async }}
{{ value }} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.component.scss :host ::ng-deep .x-description-list { &.isLegacy { .x-card { .x-description-list-title { padding: { left: 0; right: 0; } } .x-description-list-description:not(.full-width) { padding: { left: 0; right: 0; } } } .x-description-list-title { padding: { left: 4px; right: 4px; } } .x-description-list-description:not(.full-width) { padding: { left: 4px; right: 4px; } } dl { margin: { top: 0; bottom: 0; } } dl.inline dd { display: inline; margin: 0; } dl.inline dd::after { white-space: pre; content: "\a"; } dl.inline dt { display: inline-block; min-width: 100px; } dt { margin-top: 8px; margin-bottom: 8px; } dt::after { content: ": "; } dd { text-align: center; // &.full-width { margin-inline-end: 0 !important; margin-inline-start: 0 !important; } } } &.isNotLegacy { dd { width: 100%; display: inline; margin-inline-start: 8px; } .x-description-list-item-container { width: 100%; } .x-title-span::after { content: ": "; } x-slotter { width: 100%; display: inline-block; } .x-title-span, .x-decription-span { max-width: calc(90%); } .x-slotter { .x-start-top-slot { flex: 1 1 auto !important; } .x-end-bottom-slot { flex: 1 1 0% !important; } } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.component.ts import { Component, QueryList, ContentChildren, ChangeDetectionStrategy, } from '@angular/core'; import { tap, map, filter, mergeMap, concatMap, switchMap, } from 'rxjs/operators'; import { keys, nameof, isDate, isArray, toArray, isObject, isNumber, isString, toXString, isFunction, isSameObject, XModelProperty, XOneOrManyType, toNormalString, getPropertyValue, setPropertyValue, isNullOrUndefined, isNullOrEmptyString, } from 'x-framework-core'; import { XDescriptionListAction, XDescriptionListActionModel, XDescriptionListContainerComponent, } from './x-description-list.typings'; import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings'; import { of, from, Subject, forkJoin, Observable, Subscription } from 'rxjs'; import { XDescriptionListItemComponent } from './x-description-list-item/x-description-list-item.component'; @Component({ selector: 'x-description-list', templateUrl: './x-description-list.component.html', styleUrls: ['./x-description-list.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XDescriptionListComponent< T = any > extends XDescriptionListContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private keyPrefix = ''; private MODEL: T; // readonly SlotNames = Object.assign({}, XSlotName); readonly SlotLayouts = Object.assign({}, XSlotLayout); // get prefix() { return this.keyPrefix; } get preparedModel() { return this.MODEL; } // @ContentChildren(XDescriptionListItemComponent) items: QueryList; //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.prepareModel(); } async afterViewInit() { super.afterViewInit(); // // prepare KeyPrefix ... const keyPrefix = this.element.nativeElement ? (this.element.nativeElement as HTMLElement).getAttribute('keyPrefix') : ''; if (!isNullOrEmptyString(keyPrefix)) { this.keyPrefix += `${keyPrefix}`; } } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Model Changed ... const isModelChanged = changeKeys.includes( nameof('model') ); // if (isModelChanged) { await this.prepareModel(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... keys(model: T) { // let modelKeys = keys(model); // if (!this.hasChild(this.sortOrderModelKeys)) { return modelKeys; } // const sortOrderArray = toArray(this.sortOrderModelKeys) as string[]; const result: string[] = [ ...sortOrderArray.filter((k) => modelKeys.includes(k)), ...modelKeys.filter((k) => !sortOrderArray.includes(k)), ]; // return result; } canShowKey(key: string) { // return forkJoin({ key: this.getValue(key), model: this.getValue(this.model), keyPrefix: this.getValue(this.keyPrefix), hiddenModelKeys: this.getArrayValue(this.hiddenModelKeys), hideOptionalValues: this.getValue(this.hideOptionalValues), availableModelKeys: this.getArrayValue(this.availableModelKeys), }).pipe( map((provider) => { // const value = provider.model[provider.key]; // const modelHasValue = !isNullOrUndefined(provider.model) && !isNullOrUndefined(value) && !isNullOrEmptyString(toXString(provider.model[provider.key])); const hasChildHiddens = this.hasChild(provider.hiddenModelKeys); const hasChildAvailables = this.hasChild(provider.availableModelKeys); // if (!hasChildAvailables && !hasChildHiddens) { // if (!modelHasValue && provider.hideOptionalValues) { return false; } // return true; } // const isInHiddens = provider.hiddenModelKeys.includes( provider.key as any ); const isInAvailables = provider.availableModelKeys.includes( provider.key as any ); // if ( (!hasChildAvailables && !isInHiddens) || (isInAvailables && !hasChildHiddens) || (isInAvailables && !isInHiddens) || (!isInAvailables && !isInHiddens && isNumber(provider.key) && !isNullOrEmptyString(provider.keyPrefix)) ) { // if (!modelHasValue && provider.hideOptionalValues) { return false; } // return true; } // return false; }) ); } canShowLabelKey(key: string) { return this.getArrayValue(this.hiddenLabelModelKeys).pipe( map((hiddenLabelsModelKeys) => { // const hasChildHiddenLabels = this.hasChild(hiddenLabelsModelKeys); // if (!hasChildHiddenLabels) { return true; } // const isInHiddens = hiddenLabelsModelKeys.includes(key as any); return hasChildHiddenLabels && !isInHiddens; }) ); } getTitle(key: string): Observable { return this.getValue(this.modelKeyProvider).pipe( concatMap((provider) => { return isNullOrUndefined(provider) || !isFunction(provider) ? this.getValue(key) : this.getValue(provider(key as any)); }) ); } hasContentItem(key: string) { return of(this.items).pipe( concatMap((items) => { return isNullOrUndefined(items) ? of(false) : this.getArrayValue(items.toArray()).pipe( switchMap((items) => from(items).pipe( mergeMap((item) => this.getValue(item.name).pipe( map((name) => ({ name, item })) ) ), filter( (itemData) => toNormalString(itemData.name) === toNormalString(key) ), map((dataObject) => !isNullOrUndefined(dataObject)) ) ) ); }) ); } getContentItem( key: string, value: any ): Observable { return this.hasContentItem(key).pipe( concatMap((isExists) => { return !isExists ? of(null) : of(this.items).pipe( concatMap((items) => { return isNullOrUndefined(items) ? of(null) : this.getArrayValue(items.toArray()).pipe( switchMap((items) => from(items).pipe( mergeMap((item) => this.getValue(item.name).pipe( map((name) => ({ name, item })) ) ), filter( (itemData) => toNormalString(itemData.name) === toNormalString(key) ), tap((dataObject) => (dataObject.item.value = value)), map((dataObject) => dataObject.item) ) ) ); }) ); }) ); } getContent(key: string, value: any): Observable { return this.getValue(this.modelValueProvider).pipe( concatMap((provider) => { return isNullOrUndefined(provider) || !isFunction(provider) ? this.getValue(value) : this.getValue(provider(key as any, value)); }) ); } canDescribe(key: string, value: any) { return of(value).pipe( map( (eVal) => isDate(eVal) || isFunction(eVal) || (!isArray(eVal) && !isObject(eVal)) ) ); } getDescriptionTitleClasses(key: string) { return [`x-description-${key}-title`]; } getDescriptionContentClasses(key: string) { return [`x-description-${key}-title`]; } // //#region Neste ... getKeyPrefix(key: string) { // const result = isNullOrEmptyString(this.keyPrefix) ? `${key}` : `${this.keyPrefix}.${key}`; // return result; } getHiddenModelKeys(key: string) { return this.prepareNestedCollection(key, this.hiddenModelKeys); } getSortOrderModelKeys(key: string) { return this.prepareNestedCollection(key, this.sortOrderModelKeys); } getAvailableModelKeys(key: string) { return this.prepareNestedCollection(key, this.availableModelKeys); } getHiddenLabelModelKeys(key: string) { return this.prepareNestedCollection(key, this.hiddenLabelModelKeys); } //#endregion //#endregion // //#region UI Handlers ... //#endregion // //#region Actions ... async setModelProperty(property: XModelProperty) { // if (!property || isNullOrEmptyString(property.key)) { return; } // const model = this.MODEL; const nodeValue = getPropertyValue(model, property.prefix); const modelKeys = isNullOrUndefined(nodeValue) ? [] : keys(nodeValue); if (!this.hasChild(modelKeys)) { return; } // const isExists = modelKeys.includes(property.key as string); if (!isExists) { return; } // // normalize value ... const normalValue = isString(property.value) ? !isNullOrEmptyString(property.value) && !isNullOrUndefined(property.value) ? property.value.toString().trim() : undefined : isNullOrUndefined(property.value) ? undefined : property.value; // if (nodeValue[property.key] === normalValue) { return; } // const setterPropertyPath = isNullOrEmptyString(property.prefix) ? `${property.key as string}` : `${property.prefix}.${property.key as string}`; // setPropertyValue(model, setterPropertyPath, normalValue); // this.MODEL = { ...model, }; this.detectChanges(); this.onModelChanged.emit(model); } async getModelProperty(key: keyof T | string) { // if (isNullOrEmptyString(key)) { return null; } // const model = await this.getValueAsync(this.model); const modelKeys = await this.getValueAsync(this.keys(model)); if (!this.hasChild(modelKeys)) { return null; } // const isExists = modelKeys.includes(key); if (!isExists) { return null; } // const result = model[key as any]; return result; } async getModelViewProperty(key: keyof T | string) { // if (isNullOrEmptyString(key)) { return null; } // const model = await this.getValueAsync(this.model); const modelKeys = await this.getValueAsync(this.keys(model)); if (!this.hasChild(modelKeys)) { return null; } // const isExists = modelKeys.includes(key); if (!isExists) { return null; } // const result = await this.getValueAsync( this.getContent(key, model[key as any]) ); return result; } async setModel(model: T) { // if (!model || isSameObject(model as any, this.MODEL as any)) { return; } // this.model = { ...model, }; this.MODEL = { ...model, }; // await this.prepareModel(); this.onModelChanged.emit(model); } async getModel() { // const result = await this.getValueAsync(this.model); return result; } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // let modelProperty: XModelProperty = null; // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XDescriptionListAction.Refresh: this.detectChanges(); break; // case XDescriptionListAction.ClearProperty: // modelProperty = model.payload as XModelProperty; if ( !model.payload || isNullOrUndefined(model) || isNullOrUndefined(model.payload) || isNullOrEmptyString(model.action) ) { return; } // modelProperty.value = null; // await this.setModelProperty(modelProperty); break; // case XDescriptionListAction.SetProperty: // modelProperty = model.payload as XModelProperty; if ( !model.payload || isNullOrUndefined(model) || isNullOrUndefined(model.payload) || isNullOrEmptyString(model.action) ) { return; } // await this.setModelProperty(modelProperty); break; // case XDescriptionListAction.SetModel: // const resetModel = model.payload as T; if (!model || !model.payload || !resetModel) { return; } // await this.setModel(resetModel); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async prepareModel() { // this.MODEL = null; this.detectChanges(); // if (!this.model) { return; } // this.MODEL = await this.getValueAsync(this.model); this.detectChanges(); } private prepareNestedCollection( key: string, collection: XOneOrManyType ) { // return forkJoin({ key: this.getValue(key), keyPrefix: this.getValue(this.getKeyPrefix(key)), model: this.getValue(this.preparedModel[key]), collection: this.getArrayValue(collection), }).pipe( map((provider) => { // const allAvailableCollectionItems = provider.collection; // const keySelector = isNullOrUndefined(provider.keyPrefix) ? `${provider.key}.` : `${provider.keyPrefix}.`; // const canFilter = !isNumber(provider.key) && !provider.keyPrefix.includes(`${provider.key}.`); const result = canFilter ? allAvailableCollectionItems .filter((k) => k.includes(`${provider.key}.`)) .map((k) => k.replace(`${provider.key}.`, '')) : allAvailableCollectionItems; // return result; }) ); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XDescriptionListComponent } from './x-description-list.component'; import { XDescriptionListItemComponent } from './x-description-list-item/x-description-list-item.component'; @NgModule({ declarations: [XDescriptionListComponent, XDescriptionListItemComponent], imports: [XCardModule, CommonModule, XSlotterModule, XBaseComponentModule], exports: [ XCardModule, CommonModule, XSlotterModule, XBaseComponentModule, XDescriptionListComponent, XDescriptionListItemComponent, ], }) export class XDescriptionListModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XModelFieldsType, XModelKeyProvider, XModelValueProvider, XColorWithBrightness, } from 'x-framework-core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XDescriptionListAction { // ExpandAll = 'expand-all', CollapseAll = 'collapse-all', // ClearProperty = 'clear_property', SetProperty = 'set_property', // SetModel = 'set_model', // Refresh = 'refresh', } export type XDescriptionListActionIdentifier = XDescriptionListAction | string; export interface XDescriptionListActionModel extends XBaseActionModel {} // //#region Inside Card Container ... export interface IXDescriptionListContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // isLegacy: XStandardType; showLabels: XStandardType; color: XStandardType; foregroundColor: XStandardType; labelColor: XStandardType; valueColor: XStandardType; propertyActionTemplate: TemplateRef; onModelChanged: EventEmitter; // model: XStandardType; // //#region Model Providers ... hideOptionalValues: XStandardType; availableModelKeys: XModelFieldsType; hiddenModelKeys: XModelFieldsType; hiddenLabelModelKeys: XModelFieldsType; sortOrderModelKeys: XModelFieldsType; modelKeyProvider: XModelKeyProvider; modelValueProvider: XModelValueProvider; //#endregion } @Injectable({ providedIn: 'root', }) export class XDescriptionListContainer extends XComponentCardContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly isLegacy: XStandardType = true; readonly showLabels: XStandardType = false; readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; readonly labelColor: XStandardType = XColorWithBrightness.TertiaryShade; readonly valueColor: XStandardType = XColorWithBrightness.Dark; readonly propertyActionTemplate: TemplateRef; // readonly onModelChanged: EventEmitter; // readonly model: XStandardType; // //#region Model Providers ... readonly hideOptionalValues: XStandardType; readonly availableModelKeys: XModelFieldsType; readonly hiddenModelKeys: XModelFieldsType; readonly hiddenLabelModelKeys: XModelFieldsType; readonly sortOrderModelKeys: XModelFieldsType; readonly modelKeyProvider: XModelKeyProvider; readonly modelValueProvider: XModelValueProvider; //#endregion //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XDescriptionListContainerComponent extends XComponentCardContainerComponent implements IXDescriptionListContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() isLegacy: XStandardType = this.propertyProvider.isLegacy; @Input() showLabels: XStandardType = this.propertyProvider.showLabels; @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; @Input() labelColor: XStandardType = this.propertyProvider.labelColor; @Input() valueColor: XStandardType = this.propertyProvider.valueColor; @Input() propertyActionTemplate: TemplateRef = this.propertyProvider.propertyActionTemplate; @Output() onModelChanged: EventEmitter = new EventEmitter(); // @Input() model: XStandardType = this.propertyProvider.model; // //#region Model Providers ... @Input() hideOptionalValues: XStandardType = this.propertyProvider.hideOptionalValues; @Input() availableModelKeys: XModelFieldsType = this.propertyProvider.availableModelKeys; @Input() hiddenModelKeys: XModelFieldsType = this.propertyProvider.hiddenModelKeys; @Input() hiddenLabelModelKeys: XModelFieldsType = this.propertyProvider.hiddenLabelModelKeys; @Input() sortOrderModelKeys: XModelFieldsType = this.propertyProvider.sortOrderModelKeys; @Input() modelKeyProvider: XModelKeyProvider = this.propertyProvider.modelKeyProvider; @Input() modelValueProvider: XModelValueProvider = this.propertyProvider.modelValueProvider; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XDescriptionListContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXDescriptionListContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // isLegacy: this.getValue( container ? container.isLegacy : this.isLegacy ), showLabels: this.getValue( container ? container.showLabels : this.showLabels ), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), labelColor: this.getValue( container ? container.labelColor : this.labelColor ), valueColor: this.getValue( container ? container.valueColor : this.valueColor ), propertyActionTemplate: this.getValue( container ? container.propertyActionTemplate : this.propertyActionTemplate ), model: this.getValue(container ? container.model : this.model), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // //#region Model Providers ... hideOptionalValues: container ? container.hideOptionalValues : this.hideOptionalValues, availableModelKeys: container ? container.availableModelKeys : this.availableModelKeys, hiddenModelKeys: container ? container.hiddenModelKeys : this.hiddenModelKeys, hiddenLabelModelKeys: container ? container.hiddenLabelModelKeys : this.hiddenLabelModelKeys, sortOrderModelKeys: container ? container.sortOrderModelKeys : this.sortOrderModelKeys, modelKeyProvider: container ? container.modelKeyProvider : this.modelKeyProvider, modelValueProvider: container ? container.modelValueProvider : this.modelValueProvider, //#endregion // onModelChanged: this.onModelChanged, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list-item\x-description-list-item.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list-item\x-description-list-item.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list-item\x-description-list-item.component.ts import { nameof } from 'x-framework-core'; import { XDescriptionListItemAction, XDescriptionListItemActionModel, XDescriptionListItemContainerComponent, } from './x-description-list-item.typings'; import { Subject, Subscription } from 'rxjs'; import { Component, ViewChild, TemplateRef } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-description-list-item', templateUrl: './x-description-list-item.component.html', styleUrls: ['./x-description-list-item.component.scss'], }) export class XDescriptionListItemComponent extends XDescriptionListItemContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // @ViewChild('content', { static: false }) content: TemplateRef; //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XDescriptionListItemAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-description-list\x-description-list-item\x-description-list-item.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../../classes/i-x-base.container'; import { map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XOneOrManyType, XStandardType } from 'x-framework-core'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; export enum XDescriptionListItemAction { Refresh = 'refresh', } export type XDescriptionListItemActionIdentifier = | XDescriptionListItemAction | string; export interface XDescriptionListItemActionModel extends XBaseActionModel {} // //#region Container ... export interface IXDescriptionListItemContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // name: XStandardType; value: XStandardType; } @Injectable({ providedIn: 'root' }) export class XDescriptionListItemContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly name: XStandardType; readonly value: XStandardType; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XDescriptionListItemContainerComponent extends XBaseContainerComponent implements IXDescriptionListItemContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() name: XStandardType = this.propertyProvider.name; @Input() value: XStandardType = this.propertyProvider.value; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XDescriptionListItemContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXDescriptionListItemContainer ): Observable { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // name: this.getValue(container ? container.name : this.name), value: this.getValue(container ? container.value : this.value), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.component.html

{{ getResourceValue(message) | async }}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.component.scss :host { --padding: 6px; } .x-empty { padding: var(--padding); } .x-empty-title { padding-bottom: 6px; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.component.ts import { XEmptyAction, XEmptyActionModel, XEmptyContainerComponent, } from './x-empty.typings'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; import { XButtonType } from '../x-button/x-button.typings'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-empty', templateUrl: './x-empty.component.html', styleUrls: ['./x-empty.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XEmptyComponent extends XEmptyContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly ButtonTypes = Object.assign({}, XButtonType); //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Action Provider Changed ... // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XEmptyAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XEmptyComponent } from './x-empty.component'; import { XIconModule } from '../x-icon/x-icon.module'; import { XButtonModule } from '../x-button/x-button.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XEmptyComponent], imports: [XIconModule, XButtonModule, CommonModule, XBaseComponentModule], exports: [XIconModule, XButtonModule, XEmptyComponent, XBaseComponentModule], }) export class XEmptyModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-empty\x-empty.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XBaseContainer, IXBaseContainer, XBaseComponentContainer, XBaseContainerComponent, IXBaseComponentContainer, XBaseComponentContainerComponent, } from '../classes/i-x-base.container'; import { map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XIconIdentifier, XIconNames } from '../x-icon/x-icon.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XEmptyAction { Refresh = 'refresh', } export type XEmptyActionIdentifier = XEmptyAction | string; export interface XEmptyActionModel extends XBaseActionModel {} // //#region Container ... export interface IXEmptyContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; // message: XStandardType; messageColor: XStandardType; foregroundMessageColor: XStandardType; // hasRefresh: XStandardType; // refreshButtonColor: XStandardType; foregroundRefreshButtonColor: XStandardType; // refreshIcon: XStandardType; // refresh: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XEmptyContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly messageColor: XStandardType = XColorWithBrightness.Dark; readonly foregroundMessageColor: XStandardType = true; // readonly hasRefresh: XStandardType = true; // readonly refreshButtonColor: XStandardType = XColorWithBrightness.Dark; readonly foregroundRefreshButtonColor: XStandardType = true; readonly message: XStandardType = XResourceIDs.no_item; // readonly refreshIcon: XStandardType = XIconNames.refresh; // readonly refresh: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XEmptyContainerComponent extends XBaseContainerComponent implements IXEmptyContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Input() message: XStandardType = this.propertyProvider.message; @Input() messageColor: XStandardType = this.propertyProvider.messageColor; @Input() foregroundMessageColor: XStandardType = this.propertyProvider.foregroundMessageColor; // @Input() hasRefresh: XStandardType = this.propertyProvider.hasRefresh; // @Input() refreshButtonColor: XStandardType = this.propertyProvider.refreshButtonColor; @Input() foregroundRefreshButtonColor: XStandardType = this.propertyProvider.foregroundRefreshButtonColor; // @Input() refreshIcon: XStandardType = this.propertyProvider.refreshIcon; @Output() refresh: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XEmptyContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXEmptyContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), // color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), // messageColor: this.getValue( container ? container.messageColor : this.messageColor ), foregroundMessageColor: this.getValue( container ? container.foregroundMessageColor : this.foregroundMessageColor ), // hasRefresh: this.getValue( container ? container.hasRefresh : this.hasRefresh ), refreshButtonColor: this.getValue( container ? container.refreshButtonColor : this.refreshButtonColor ), foregroundRefreshButtonColor: this.getValue( container ? container.foregroundRefreshButtonColor : this.foregroundRefreshButtonColor ), refreshIcon: this.getValue( container ? container.refreshIcon : this.refreshIcon ), // message: this.getValue(container ? container.message : this.message), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // refresh: this.refresh, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentEmptyContainer = { [TKey in keyof IXEmptyContainer as `empty${Capitalize< string & TKey >}`]: IXEmptyContainer[TKey]; }; export interface IXComponentEmptyContainer extends TXComponentEmptyContainer, IXBaseComponentContainer { showEmpty: XStandardType; } @Injectable({ providedIn: 'root', }) export class XComponentEmptyContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // readonly showEmpty: XStandardType = false; // readonly emptyActionProvider: Subject = this.propertyProvider.actionProvider; readonly emptyCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly emptyColor: XStandardType = this.propertyProvider.color; readonly emptyForegroundColor: XStandardType = this.propertyProvider.foregroundColor; // readonly emptyMessage: XStandardType = this.propertyProvider.message; readonly emptyMessageColor: XStandardType = this.propertyProvider.messageColor; readonly emptyForegroundMessageColor: XStandardType = this.propertyProvider.foregroundMessageColor; // readonly emptyHasRefresh: XStandardType = this.propertyProvider.hasRefresh; // readonly emptyRefreshButtonColor: XStandardType = this.propertyProvider.refreshButtonColor; readonly emptyForegroundRefreshButtonColor: XStandardType = this.propertyProvider.foregroundRefreshButtonColor; // readonly emptyRefreshIcon: XStandardType = this.propertyProvider.refreshIcon; // readonly emptyRefresh: EventEmitter = this.propertyProvider.refresh; //#endregion // //#region Constructor ... constructor(protected propertyProvider: XEmptyContainer) { super(); } //#endregion } @Injectable({ providedIn: 'root', }) @Component({ template: ``, }) export abstract class XComponentEmptyContainerComponent extends XBaseComponentContainerComponent implements IXComponentEmptyContainer { // //#region Props ... // @Input() showEmpty: XStandardType = this.propertyProvider.showEmpty; // @Input() emptyActionProvider: Subject = this.propertyProvider.emptyActionProvider; @Input() emptyCssClass: XStandardType> = this.propertyProvider.emptyCssClass; // @Input() emptyColor: XStandardType = this.propertyProvider.emptyColor; @Input() emptyForegroundColor: XStandardType = this.propertyProvider.emptyForegroundColor; // @Input() emptyMessage: XStandardType = this.propertyProvider.emptyMessage; @Input() emptyMessageColor: XStandardType = this.propertyProvider.emptyMessageColor; @Input() emptyForegroundMessageColor: XStandardType = this.propertyProvider.emptyForegroundMessageColor; // @Input() emptyHasRefresh: XStandardType = this.propertyProvider.emptyHasRefresh; // @Input() emptyRefreshButtonColor: XStandardType = this.propertyProvider.emptyRefreshButtonColor; @Input() emptyForegroundRefreshButtonColor: XStandardType = this.propertyProvider.emptyForegroundRefreshButtonColor; // @Input() emptyRefreshIcon: XStandardType = this.propertyProvider.emptyRefreshIcon; // @Output() emptyRefresh: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XComponentEmptyContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXComponentEmptyContainer ): Observable { return forkJoin({ // showEmpty: this.getValue( container ? container.showEmpty : this.showEmpty ), emptyCssClass: this.getValue( container ? container.emptyCssClass : this.emptyCssClass ), emptyColor: this.getValue( container ? container.emptyColor : this.emptyColor ), emptyForegroundColor: this.getValue( container ? container.emptyForegroundColor : this.emptyForegroundColor ), emptyMessage: this.getValue( container ? container.emptyMessage : this.emptyMessage ), emptyMessageColor: this.getValue( container ? container.emptyMessageColor : this.emptyMessageColor ), emptyForegroundMessageColor: this.getValue( container ? container.emptyForegroundMessageColor : this.emptyForegroundMessageColor ), emptyHasRefresh: this.getValue( container ? container.emptyHasRefresh : this.emptyHasRefresh ), emptyRefreshButtonColor: this.getValue( container ? container.emptyRefreshButtonColor : this.emptyRefreshButtonColor ), emptyForegroundRefreshButtonColor: this.getValue( container ? container.emptyForegroundRefreshButtonColor : this.emptyForegroundRefreshButtonColor ), emptyRefreshIcon: this.getValue( container ? container.emptyRefreshIcon : this.emptyRefreshIcon ), }).pipe( map((data) => { return { // ...data, // emptyActionProvider: container ? container.emptyActionProvider : this.emptyActionProvider, // emptyRefresh: this.emptyRefresh, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.component.html

{{ getResourceValue(item.title) | async }}

{{ getResourceValue(item.title) | async }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.component.scss :host ::ng-deep { // --divider-color: var(--x-color-dark); // --child-color: var(--x-color-primary-shade-contrast); --child-background-color: var(--x-color-primary-shade); // --child-active-color: var(--x-color-dark-tint-contrast); --child-active-background-color: var(--x-color-dark-tint); // --highlight-color: var(--x-color-warning-contrast); --highlight-background-color: var(--x-color-warning); // --parent-color: var(--x-color-tertiary-tint-contrast); --parent-background-color: var(--x-color-tertiary-tint); // --parent-active-color: var(--x-color-dark-contrast); --parent-active-background-color: var(--x-color-dark); } :host ::ng-deep .invisible { display: none; visibility: hidden; } ion-list, ion-item, ion-item-group { width: 100%; --background: transparent; --inner-padding-end: 0px; --inner-padding-start: 0px; --color: var(--child-color); --border-color: var(--divider-color); } ion-item-divider { width: 100%; position: relative; --border-color: var(--divider-color); } h1, h2, h3, h4, h5, h6 { margin: 0; } .item-parent { // width: 100%; padding-top: 0; padding-bottom: 0; position: relative; // color: var(--parent-color); background-color: var(--parent-background-color); // *, ion-icon, x-icon { color: var(--parent-color) !important; } } .item-child { padding-top: 0; padding-bottom: 0; display: block !important; transition: opacity 0.2s ease-in; color: var(--child-color) !important; background-color: var(--child-background-color) !important; // *, ion-icon, x-icon { color: var(--child-color) !important; } } .item-child:hover, .item-parent:hover { color: var(--highlight-color) !important; --color: var(--highlight-color) !important; background-color: var(--highlight-background-color) !important; // *, ion-icon, x-icon { color: var(--highlight-color) !important; } } .item-parent.active-link, .active-parent { // color: var(--parent-active-color) !important; background-color: var(--parent-active-background-color) !important; // *, ion-icon, x-icon { color: var(--parent-active-color) !important; } } .item-child.active-link, .active-child { // color: var(--child-active-color) !important; background-color: var(--child-active-background-color) !important; // *, ion-icon, x-icon { color: var(--child-active-color) !important; } } ion-icon { &.invisible { visibility: hidden; } } .collapsed { opacity: 0; height: 0; } .ion-hide { display: none !important; } x-card { width: inherit; height: inherit; } .item-parent, .expandable-item-parent { // cursor: pointer; // min-height: 48px; // &.active { color: var(--parent-active-color); background-color: var(--parent-active-background-color); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.component.ts import { nameof, toArray, hasChild, parseXColor, XOneOrManyType, toNormalString, isNullOrEmptyString, getXColorCssVariableName, } from 'x-framework-core'; import { findItemById, findItemByRoute, parentItemsById, parentItemsByRoute, containsItemsByRoute, } from './x-expandable-list.tools'; import { XExpandableListItem, XExpandableListAction, XExpandableListCssVarKeys, XExpandableListActionModel, XExpandableListStartupState, XExpandableListContainerComponent, } from './x-expandable-list.typings'; import { concatMap, map } from 'rxjs/operators'; import { XIconNames } from '../x-icon/x-icon.typings'; import { forkJoin, of, Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-expandable-list', templateUrl: './x-expandable-list.component.html', styleUrls: ['./x-expandable-list.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XExpandableListComponent extends XExpandableListContainerComponent { // //#region Props ... // private ACTIVATED_CHILD: XExpandableListItem; private ACTIVATED_PARENTS: XExpandableListItem[]; // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycle ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Item Changed ... const isItemsChanged = changeKeys.includes( nameof('items') ); if (isItemsChanged) { await this.handleStartupState(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Color Change Detectors ... const isChildColorChanged = changeKeys.includes( nameof('childColor') ); if (isChildColorChanged) { await this.applyChildColor(); } const isChildActiveColorChanged = changeKeys.includes( nameof('childActiveColor') ); if (isChildActiveColorChanged) { await this.applyChildActiveColor(); } const isParentColorChanged = changeKeys.includes( nameof('parentColor') ); if (isParentColorChanged) { await this.applyParentColor(); } const isParentActiveColorChanged = changeKeys.includes( nameof('parentActiveColor') ); if (isParentActiveColorChanged) { await this.applyParentActiveColor(); } const isHighlightColorChanged = changeKeys.includes( nameof('highlightColor') ); if (isHighlightColorChanged) { await this.applyHighlightColor(); } const isDividerColorChanged = changeKeys.includes( nameof('dividerColor') ); if (isDividerColorChanged) { await this.applyDividerColor(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Provider Actions ... hasChildItems(item: XExpandableListItem) { // if (!item || !item.childs) { return of(false); } return this.getValue(item.childs).pipe(map((childs) => hasChild(childs))); } getIconName(item: XExpandableListItem) { return this.isExpanded(item).pipe( map((isExpanded) => isExpanded ? XIconNames.arrow_dropup.toString() : XIconNames.arrow_dropdown.toString() ) ); } isParentActivated(item: XExpandableListItem) { // return this.getValue(item).pipe( concatMap((pItem) => this.getValue(this.supportRouting).pipe( map((supportRouting) => { return { item: pItem, supportRouting }; }) ) ), concatMap((dObject) => { // if (!dObject || !dObject.item) { return this.getValue(false); } // return this.getArrayValue(dObject.item.href).pipe( map((hrefArray) => this.managerService.mergeRoutes(hrefArray)), concatMap((route) => { // if (!this.ACTIVATED_PARENTS || !hasChild(this.ACTIVATED_PARENTS)) { return this.getValue(false); } // if (dObject.supportRouting) { // const routes$ = forkJoin( this.ACTIVATED_PARENTS.map((i) => this.getArrayValue(i.href).pipe( map((href) => this.managerService.mergeRoutes(href)) ) ) ); // return routes$.pipe( map( (routes) => routes.findIndex( (r) => toNormalString(r) === toNormalString(route) ) > -1 ) ); } else { // const ids$ = forkJoin(this.ACTIVATED_PARENTS.map((i) => i.id)); // return ids$.pipe( map( (ids) => ids.findIndex( (i) => toNormalString(i) === toNormalString(dObject.item.id) ) > -1 ) ); } }) ); }) ); } isChildActivated(item: XExpandableListItem) { // return this.getValue(item).pipe( concatMap((pItem) => this.getValue(this.supportRouting).pipe( map((supportRouting) => { return { item: pItem, supportRouting }; }) ) ), concatMap((dObject) => { // if (!dObject || !dObject.item || !this.ACTIVATED_CHILD) { return this.getValue(false); } // return this.getArrayValue(this.ACTIVATED_CHILD.href) .pipe(map((hrefArray) => this.managerService.mergeRoutes(hrefArray))) .pipe( concatMap((activatedRoute) => { return this.getArrayValue(dObject.item.href) .pipe( map((hrefArray) => this.managerService.mergeRoutes(hrefArray)) ) .pipe( map((itemRoute) => { return { itemRoute, activatedRoute }; }), map((routeObject) => { // if (dObject.supportRouting) { return ( toNormalString(routeObject.itemRoute) === toNormalString(routeObject.activatedRoute) ); } else { return ( toNormalString(this.ACTIVATED_CHILD.id) === toNormalString(dObject.item.id) ); } }) ); }) ); }) ); } isHidden(item: XExpandableListItem) { return !item || !item.hidden ? of(false) : this.getValue(item.hidden); } isDisabled(item: XExpandableListItem) { return !item || !item.disabled ? of(false) : this.getValue(item.disabled); } isExpanded(item: XExpandableListItem) { return !item || !item.opened ? of(false) : this.getValue(item.opened); } //#endregion // //#region UI Handlers ... async handleItemSelectedAction( item: XExpandableListItem, parent: XExpandableListItem ) { // // Check Component State ... if (this.loading || this.uiDisabled) { return; } // // Emit Event Handler ... this.itemSelected.emit(item); // const isSupportRouting = await this.getValueAsync(this.supportRouting); if (isSupportRouting) { // const currUrl: string = this.managerService.getRoute(); const itemHref = await this.getArrayValueAsync(item.href); const itemUrl = this.managerService.mergeRoutes(itemHref); // if (currUrl === itemUrl) { // await this.setActivatedParent(parent); await this.setActivatedChild(item); } else { await this.handleItemRoutingActions(item); } } else { // await this.setActivatedParent(parent); await this.setActivatedChild(item); } } //#endregion // //#region Actions ... async toggle( item: XExpandableListItem, siblings: XExpandableListItem[] ) { // const isExpanded = await this.toPromise(this.isExpanded(item)); item.opened = !isExpanded; // const isCloseSibling = await this.toPromise( this.getValue(this.closeSiblings) ); // if (isCloseSibling) { this.handleCloseSiblings(item, siblings); } // if (this.loading || this.uiDisabled) { return; } // this.itemSelected.emit(item); // await this.handleItemRoutingActions(item, true); } async expand(item: XExpandableListItem) { item.opened = true; } async expandAll() { // const items = await this.getArrayValueAsync(this.items); await this.handleChangeState(items, true); } async collapse(item: XExpandableListItem) { item.opened = false; } async collapseAll() { // const items = await this.getArrayValueAsync(this.items); await this.handleChangeState(items, false); } //#endregion // //#region Privates ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XExpandableListAction.Refresh: this.detectChanges(); break; // case XExpandableListAction.ExpandAll: await this.expandAll(); break; // case XExpandableListAction.CollapseAll: await this.collapseAll(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // //#region Parent and Child Avtivated ... private async handleApplyCurrentItems() { // if (this.uiDisabled || this.loading) { setTimeout(async () => await this.handleApplyCurrentItems(), 100); } // const supportRouting = await this.getValueAsync(this.supportRouting); if (supportRouting) { await this.handleApplyCurrentItemsByRouting(); } else { await this.handleApplyCurrentItemsById(); } // this.detectChanges(); } private async handleApplyCurrentItemsByRouting() { // const currentRoute = this.managerService.getRoute(); if (isNullOrEmptyString(currentRoute)) { return; } // const foundedItem = await findItemByRoute(this.items, currentRoute); const parentItems = await parentItemsByRoute(this.items, currentRoute); // if (!foundedItem || !hasChild(parentItems)) { // if (foundedItem) { // this.ACTIVATED_CHILD = foundedItem; this.ACTIVATED_PARENTS = [foundedItem]; } // return; } // this.ACTIVATED_PARENTS = parentItems; this.ACTIVATED_CHILD = foundedItem; } private async handleApplyCurrentItemsById() { // const items = await this.getArrayValueAsync(this.items); const currentId = this.ACTIVATED_CHILD ? this.ACTIVATED_CHILD.id : hasChild(items) ? items[0].id : ''; if (isNullOrEmptyString(currentId)) { return; } // const foundedItem = await findItemById(this.items, currentId); const parentItems = await parentItemsById(this.items, currentId); // if (!foundedItem || !hasChild(parentItems)) { return; } // this.ACTIVATED_PARENTS = parentItems; this.ACTIVATED_CHILD = foundedItem; } //#endregion private async handleItemRoutingActions( item: XExpandableListItem, isParent = false ) { // if (!item || this.uiDisabled || this.loading) { return; } // const hidden = await this.getValueAsync(item.hidden); const disabled = await this.getValueAsync(item.disabled); if (hidden || disabled) { return; } // //#region Handle Routing ... // const href = await this.getValueAsync(item.href); const route = this.managerService.mergeRoutes(href); const supportRouting = await this.getValueAsync(this.supportRouting); const replaceUrl = await this.getOptionalValueAsync(item.replaceUrl); const disableParentRouting = await this.getValueAsync( this.disableParentRouting ); // // When just a not Child Parent with Href provided ... const childsArr = !item.childs ? [] : await this.getArrayValueAsync(item.childs); if (isParent && !hasChild(childsArr)) { isParent = false; } // if (isParent && disableParentRouting) { return; } // if (supportRouting && hasChild(href) && !isNullOrEmptyString(route)) { await this.managerService.navigateByUrlReplace(route, {}, replaceUrl); } //#endregion } private handleCloseSiblings( item: XExpandableListItem, siblings: XOneOrManyType> ) { // const pSiblings = toArray(siblings); const others = pSiblings.filter((i) => item.id !== i.id); others.forEach((i) => (i.opened = false)); // this.detectChanges(); } private async handleChangeState( items: XOneOrManyType>, expand: boolean ) { // const pItems = toArray(items); pItems.forEach((i) => { // i.opened = expand; // this.getValueAsync(i.childs).then((childs) => { if (hasChild(childs)) { this.handleChangeState(childs, expand); } }); // this.detectChanges(); }); } private async handleStartupState() { // const items = (await this.getValueAsync( this.items )) as XExpandableListItem[]; // await this.applyStartupState(items); await this.handleApplyCurrentItems(); } private async setActivatedParent(v: XExpandableListItem) { // const isExists = hasChild(this.ACTIVATED_PARENTS) ? this.ACTIVATED_PARENTS.findIndex( (p) => toNormalString(p.id) === toNormalString(v.id) ) > 1 : false; // if (isExists) { return; } // this.ACTIVATED_PARENTS = await containsItemsByRoute(this.items, v.href); // this.detectChanges(); } private async setActivatedChild(v: XExpandableListItem) { // const isSamed = this.ACTIVATED_CHILD ? v.id === this.ACTIVATED_CHILD.id : false; // if (isSamed) { return; } // this.ACTIVATED_CHILD = v; // this.detectChanges(); } private async applyStartupState( items: XOneOrManyType> ) { // if (!hasChild(items)) { return; } // const startupState = await this.getValueAsync(this.startupState); const pItems = await this.getArrayValueAsync(items); // pItems.forEach((i) => { // // Handle StartUp State for Items ... i.opened = startupState === XExpandableListStartupState.CollapseAll ? false : startupState === XExpandableListStartupState.ExpandAll ? true : false; // if (i.childs) { this.getValueAsync(i.childs).then((childs) => { this.applyStartupState(childs); }); } // this.detectChanges(); }); // this.detectChanges(); } // //#region Color Appliers ... private async applyChildColor() { // const color = await this.getValueAsync(this.childColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XExpandableListCssVarKeys.ChildColor, `var(${fgColor})`); this.setCssVar(XExpandableListCssVarKeys.ChildBgColor, `var(${bgColor})`); // this.detectChanges(); } private async applyChildActiveColor() { // const color = await this.getValueAsync(this.childActiveColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XExpandableListCssVarKeys.ChildActiveColor, `var(${fgColor})` ); this.setCssVar( XExpandableListCssVarKeys.ChildActiveBgColor, `var(${bgColor})` ); // this.detectChanges(); } private async applyParentColor() { // const color = await this.getValueAsync(this.parentColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XExpandableListCssVarKeys.ParentColor, `var(${fgColor})`); this.setCssVar(XExpandableListCssVarKeys.ParentBgColor, `var(${bgColor})`); // this.detectChanges(); } private async applyParentActiveColor() { // const color = await this.getValueAsync(this.parentActiveColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XExpandableListCssVarKeys.ParentActiveColor, `var(${fgColor})` ); this.setCssVar( XExpandableListCssVarKeys.ParentActiveBgColor, `var(${bgColor})` ); // this.detectChanges(); } private async applyHighlightColor() { // const color = await this.getValueAsync(this.highlightColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XExpandableListCssVarKeys.HighlightColor, `var(${fgColor})`); this.setCssVar( XExpandableListCssVarKeys.HighlightBgColor, `var(${bgColor})` ); // this.detectChanges(); } private async applyDividerColor() { // const color = await this.getValueAsync(this.dividerColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const colorVar = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(colorVar)) { return; } // this.setCssVar(XExpandableListCssVarKeys.DividerColor, `var(${colorVar})`); // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XExpandableListComponent } from './x-expandable-list.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XExpandableListComponent], imports: [CommonModule, XBaseComponentModule, XCardModule, XIconModule], exports: [ XCardModule, XIconModule, XBaseComponentModule, XExpandableListComponent, ], }) export class XExpandableListModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.tools.ts import { toArray, hasChild, toPromise, mergeRoutes, XStandardType, XOneOrManyType, toNormalString, isNullOrUndefined, isNullOrEmptyString, } from 'x-framework-core'; import { XExpandableListItem } from './x-expandable-list.typings'; export async function toFlatItems( items: XStandardType>> ) { // const result: XExpandableListItem[] = []; // if (!items) { return result; } // const pItemsArray = await toPromise(items); if (!hasChild(pItemsArray)) { return result; } // const pItems = toArray(pItemsArray); for (const item of pItems) { // const childsArray = await toPromise(item.childs); const isParent = hasChild(childsArray); // result.push(item); // if (isParent) { // const childsRes = await toFlatItems(item.childs); result.push(...childsRes); } } // return result; } // //#region By Route ... export async function findItemByRoute( items: XStandardType>>, route: XStandardType> ) { // let result: XExpandableListItem = null; // if (!items || !route) { return result; } // const routeArray = await toPromise(route); if (!hasChild(routeArray)) { return result; } // const pRoute = mergeRoutes(routeArray); if (isNullOrEmptyString(pRoute)) { return result; } // const pItems = await toFlatItems(items); if (!hasChild(pItems)) { return result; } // for (const item of pItems) { // const itemRouteArray = await toPromise(item.href); if (hasChild(itemRouteArray)) { // const itemRoute = mergeRoutes(itemRouteArray); if ( !isNullOrEmptyString(itemRoute) && toNormalString(itemRoute) === toNormalString(pRoute) ) { result = item; } } } // return result; } export async function containsItemsByRoute( items: XStandardType>>, route: XStandardType> ) { // const result: XExpandableListItem[] = []; // if (!items || !route) { return result; } // const routeArray = await toPromise(route); if (!hasChild(routeArray)) { return result; } // const pRoute = mergeRoutes(routeArray); if (isNullOrEmptyString(pRoute)) { return result; } // const pItems = await toFlatItems(items); if (!hasChild(pItems)) { return result; } // for (const item of pItems) { // const itemRouteArray = await toPromise(item.href); if (hasChild(itemRouteArray)) { // const itemRoute = mergeRoutes(itemRouteArray); if ( !isNullOrEmptyString(itemRoute) && toNormalString(pRoute).includes(toNormalString(itemRoute)) ) { result.push(item); } } } // return result; } export async function parentItemsByRoute( items: XStandardType>>, route: XStandardType> ) { // let result: XExpandableListItem[] = []; // if (!items || !route) { return result; } // const parentItems = await containsItemsByRoute(items, route); const foundedItem = await findItemByRoute(items, route); if (!hasChild(parentItems) || isNullOrUndefined(foundedItem)) { return result; } // result = parentItems.filter( (i) => toNormalString(i.id) !== toNormalString(foundedItem.id) ); // return result; } //#endregion // //#region By Id ... export async function findItemById( items: XStandardType>>, id: XStandardType ) { // let result: XExpandableListItem = null; // if (!items || !id) { return result; } // const pId = await toPromise(id); if (isNullOrEmptyString(pId)) { return result; } // const pItems = await toFlatItems(items); if (!hasChild(pItems)) { return result; } // for (const item of pItems) { // const itemRouteArray = await toPromise(item.href); if (hasChild(itemRouteArray)) { // if ( !isNullOrEmptyString(item.id) && toNormalString(item.id) === toNormalString(pId) ) { result = item; } } } // return result; } export async function containsItemsById( items: XStandardType>>, id: XStandardType ) { // const result: XExpandableListItem[] = []; // if (!items || !id) { return result; } // const pId = await toPromise(id); if (isNullOrEmptyString(pId)) { return result; } // const pItems = await toFlatItems(items); if (!hasChild(pItems)) { return result; } // for (const item of pItems) { // const isSameId = toNormalString(item.id) === toNormalString(pId); if (isSameId) { result.push(item); } else { // const childsArr = await toPromise(item.childs); const childs = toArray(childsArr); const isParent = hasChild(childs); // if (isParent) { const pChildsRes = await containsItemsById(childsArr, id); result.push(...pChildsRes); } } } // return result; } export async function parentItemsById( items: XStandardType>>, id: XStandardType ) { // let result: XExpandableListItem[] = []; // if (!items || !id) { return result; } // const parentItems = await containsItemsById(items, id); const foundedItem = await findItemById(items, id); if (!hasChild(parentItems) || isNullOrUndefined(foundedItem)) { return result; } // result = parentItems.filter( (i) => toNormalString(i.id) !== toNormalString(foundedItem.id) ); // return result; } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-list\x-expandable-list.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export interface XExpandableListItem { id: string; data: XStandardType; opened?: XStandardType; hidden?: XStandardType; disabled?: XStandardType; replaceUrl?: XStandardType; title: XStandardType; href?: XStandardType>; description?: XStandardType; childs?: XStandardType>>; } export enum XExpandableListStartupState { ExpandAll = 'expand-all', CollapseAll = 'collapse-all', } export type XExpandableListStartupStateIdentifier = | XExpandableListStartupState | string; export enum XExpandableListAction { // Refresh = 'refresh', // ExpandAll = 'expand-all', CollapseAll = 'collapse-all', } export type XExpandableListActionIdentifier = XExpandableListAction | string; export interface XExpandableListActionModel extends XBaseActionModel {} export enum XExpandableListCssVarKeys { // ChildColor = 'child-color', ChildBgColor = 'child-background-color', // ChildActiveColor = 'child-active-color', ChildActiveBgColor = 'child-active-background-color', // ParentColor = 'parent-color', ParentBgColor = 'parent-background-color', // ParentActiveColor = 'parent-active-color', ParentActiveBgColor = 'parent-active-background-color', // HighlightColor = 'highlight-color', HighlightBgColor = 'highlight-background-color', // DividerColor = 'divider-color', } // //#region Inside Card Container ... export interface IXExpandableListContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // itemCssClass: XStandardType>; // supportRouting: XStandardType; disableParentRouting: XStandardType; showParentDetailIcon: XStandardType; showChildDetailIcon: XStandardType; closeSiblings: XStandardType; startupState: XStandardType; items: XStandardType>>; parentTemplate: TemplateRef; childTemplate: TemplateRef; // childColor: XStandardType; childActiveColor: XStandardType; parentColor: XStandardType; parentActiveColor: XStandardType; highlightColor: XStandardType; dividerColor: XStandardType; // itemSelected: EventEmitter>; } @Injectable({ providedIn: 'root', }) export class XExpandableListContainer extends XComponentCardContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject; readonly cssClass: XStandardType>; // readonly itemCssClass: XStandardType>; // readonly supportRouting: XStandardType = false; readonly disableParentRouting: XStandardType = true; readonly showParentDetailIcon: XStandardType = true; readonly showChildDetailIcon: XStandardType = true; readonly closeSiblings: XStandardType = false; readonly startupState: XStandardType = XExpandableListStartupState.CollapseAll; readonly items: XStandardType>>; readonly parentTemplate: TemplateRef; readonly childTemplate: TemplateRef; // readonly childColor: XStandardType = XColorWithBrightness.PrimaryShade; readonly childActiveColor: XStandardType = XColorWithBrightness.Dark; readonly parentColor: XStandardType = XColorWithBrightness.TertiaryTint; readonly parentActiveColor: XStandardType = XColorWithBrightness.Dark; readonly highlightColor: XStandardType = XColorWithBrightness.Warning; readonly dividerColor: XStandardType = XColorWithBrightness.Dark; // readonly itemSelected: EventEmitter> = new EventEmitter>(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XExpandableListContainerComponent extends XComponentCardContainerComponent implements IXExpandableListContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() itemCssClass: XStandardType> = this.propertyProvider.itemCssClass; // @Input() supportRouting: XStandardType = this.propertyProvider.supportRouting; @Input() disableParentRouting: XStandardType = this.propertyProvider.disableParentRouting; @Input() showParentDetailIcon: XStandardType = this.propertyProvider.showParentDetailIcon; @Input() showChildDetailIcon: XStandardType = this.propertyProvider.showChildDetailIcon; @Input() closeSiblings: XStandardType = this.propertyProvider.closeSiblings; @Input() startupState: XStandardType = this.propertyProvider.startupState; @Input() items: XStandardType>> = this.propertyProvider.items; @Input() parentTemplate: TemplateRef = this.propertyProvider.parentTemplate; @Input() childTemplate: TemplateRef = this.propertyProvider.childTemplate; // @Input() childColor: XStandardType = this.propertyProvider.childColor; @Input() childActiveColor: XStandardType = this.propertyProvider.childActiveColor; @Input() parentColor: XStandardType = this.propertyProvider.parentColor; @Input() parentActiveColor: XStandardType = this.propertyProvider.parentActiveColor; @Input() highlightColor: XStandardType = this.propertyProvider.highlightColor; @Input() dividerColor: XStandardType = this.propertyProvider.dividerColor; // @Output() itemSelected: EventEmitter> = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XExpandableListContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXExpandableListContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // itemCssClass: this.getValue( container ? container.itemCssClass : this.itemCssClass ), // supportRouting: this.getValue( container ? container.supportRouting : this.supportRouting ), disableParentRouting: this.getValue( container ? container.disableParentRouting : this.disableParentRouting ), showParentDetailIcon: this.getValue( container ? container.showParentDetailIcon : this.showParentDetailIcon ), showChildDetailIcon: this.getValue( container ? container.showChildDetailIcon : this.showChildDetailIcon ), closeSiblings: this.getValue( container ? container.closeSiblings : this.closeSiblings ), startupState: this.getValue( container ? container.startupState : this.startupState ), items: this.getValue(container ? container.items : this.items), parentTemplate: this.getValue( container ? container.parentTemplate : this.parentTemplate ), childTemplate: this.getValue( container ? container.childTemplate : this.childTemplate ), // childColor: this.getValue( container ? container.childColor : this.childColor ), childActiveColor: this.getValue( container ? container.childActiveColor : this.childActiveColor ), parentColor: this.getValue( container ? container.parentColor : this.parentColor ), parentActiveColor: this.getValue( container ? container.parentActiveColor : this.parentActiveColor ), highlightColor: this.getValue( container ? container.highlightColor : this.highlightColor ), dividerColor: this.getValue( container ? container.dividerColor : this.dividerColor ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // itemSelected: this.itemSelected, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.component.scss :host { --panel-header-size: 48px; } .x-expandable-panel-header { height: var(--panel-header-size); } .applyColors { .mat-expansion-panel-header { // color: var(--header-foreground-color, var(--x-color-light-contrast)); background-color: var(--header-background-color, var(--x-color-light)); * { color: var(--header-foreground-color, var(--x-color-light-contrast)); } .mat-expansion-indicator { &::after { color: var( --header-foreground-color, var(--x-color-light-contrast) ) !important; } } &:focus, &:hover, &.mat-expanded { background: unset; color: var( --header-highlight-foreground-color, var(--x-color-light-contrast) ); background-color: var( --header-highlight-background-color, var(--x-color-light) ); * { color: var( --header-highlight-foreground-color, var(--x-color-light-contrast) ); } .mat-expansion-indicator { &::after { color: var( --header-highlight-foreground-color, var(--x-color-light-contrast) ); } } } } } :host ::ng-deep .mat-expansion-indicator { &::after { color: var( --header-foreground-color, var(--x-color-light-contrast) ) !important; } } .x-panel-actions, .x-panel-custom-actions-wrapper { width: 100%; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.component.ts import { Component, QueryList, ContentChildren, ChangeDetectionStrategy, } from '@angular/core'; import { nameof, parseXColor, XStandardType, XModalButtonRole, isNullOrEmptyString, XColorWithBrightness, getXColorCssVariableName, } from 'x-framework-core'; import { XExpandablePanelAction, XExpandablePanelCssVars, XExpandablePanelActionModel, XExpandablePanelStartupState, XExpandablePandelContainerComponent, } from './x-expandable-panel.typings'; import { Subject, Subscription } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { XButtonType } from '../x-button/x-button.typings'; import { XPanelComponent } from './x-panel/x-panel.component'; import { XNPRButtonType } from '../classes/i-x-next-prev-reset.container'; @Component({ selector: 'x-expandable-panel', templateUrl: './x-expandable-panel.component.html', styleUrls: ['./x-expandable-panel.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XExpandablePanelComponent extends XExpandablePandelContainerComponent { // //#region Props ... // private IS_ACCORDION: boolean; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly NPRButtonTypes = Object.assign({}, XNPRButtonType); // //#region Panels Props ... // private PANELS: QueryList; // @ContentChildren(XPanelComponent) set panels(p: QueryList) { // if (!p) { return; } // this.PANELS = p; this.detectChanges(); } // get panels() { return this.PANELS; } //#endregion //#endregion // //#region LifeCycles ... async afterViewInit() { super.afterViewInit(); // await this.handleStartupState(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // const isAccordionChanged = changeKeys.includes( nameof('isAccordion') ); if (isAccordionChanged) { this.IS_ACCORDION = await this.getValueAsync(this.isAccordion); } // const isHeaderColorChanged = changeKeys.includes( nameof('headerColor') ); if (isHeaderColorChanged) { await this.applyHeaderColor(); } // const isHeaderHighlighColorChanged = changeKeys.includes( nameof('headerHighlightColor') ); if (isHeaderHighlighColorChanged) { await this.applyHeaderHighlightColor(); } // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Register Handlers ... registerInstanceHandlers() { super.registerInstanceHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Provider ... hasStepAction(panel: XPanelComponent, type: XNPRButtonType) { // switch (type) { // case this.NPRButtonTypes.Next: return this.getOptionalValue(panel.hasNext); // case this.NPRButtonTypes.Prev: return this.getOptionalValue(panel.hasPrev); // case this.NPRButtonTypes.Reset: return this.getOptionalValue(panel.hasReset); } } hasPanels() { return this.panels && this.panels.length > 0; } hasActions(panel: XPanelComponent) { return this.getValue(panel.hasNext).pipe( concatMap((hasNext) => this.getValue(panel.hasPrev).pipe( map((hasPrev) => { return { hasNext, hasPrev, }; }) ) ), concatMap((hasNextPrev) => this.getValue(panel.hasReset).pipe( map((hasReset) => { return { ...hasNextPrev, hasReset, }; }) ) ), map((info) => info.hasNext || info.hasPrev || info.hasReset) ); } getIsAccordion() { return this.IS_ACCORDION; } getExpanded(panel: XPanelComponent) { return this.getValue(panel.id).pipe( concatMap((panelId) => this.getValue(panel.expanded).pipe( map((panelExpanded) => { return { panelId, panelExpanded, }; }) ) ), map((panelInfo) => { return { ...panelInfo, isAccordion: this.IS_ACCORDION, }; }), map((info) => info.isAccordion ? this.selected === info.panelId : info.panelExpanded ) ); } // //#region Button Providers ... getButtonIcon(panel: XPanelComponent, type: XNPRButtonType) { return this.getActionButton(panel, type).pipe( concatMap((actionButton) => this.getValue(actionButton.icon)) ); } getButtonType(panel: XPanelComponent, type: XNPRButtonType) { return this.getActionButton(panel, type).pipe( concatMap((actionButton) => this.getValue(actionButton.type)), map((btnType) => !isNullOrEmptyString(btnType) ? btnType : XButtonType.Raised ) ); } getButtonTitle(panel: XPanelComponent, type: XNPRButtonType) { return this.getActionButton(panel, type).pipe( concatMap((actionButton) => this.getResourceValue(actionButton.title)) ); } getButtonColor(panel: XPanelComponent, type: XNPRButtonType) { return this.getActionButton(panel, type).pipe( concatMap((actionButton) => this.getValue(actionButton.color)), map((btnColor) => !isNullOrEmptyString(btnColor) ? btnColor : XColorWithBrightness.Primary ) ); } getButtonDisabled(panel: XPanelComponent, type: XNPRButtonType) { return this.getActionButtonDisabled(panel, type); } getButtonCssClass(panel: XPanelComponent, type: XNPRButtonType) { return this.getActionButton(panel, type).pipe( concatMap((actionButton) => this.getArrayValue(actionButton.cssClass)) ); } getButtonIconPosition(panel: XPanelComponent, type: XNPRButtonType) { return this.getActionButton(panel, type).pipe( concatMap((actionButton) => this.getValue(actionButton.iconPosition)) ); } getButtonForegroundColor(panel: XPanelComponent, type: XNPRButtonType) { return this.getActionButton(panel, type).pipe( concatMap((actionButton) => this.getOptionalValue(actionButton.foregroundColor) ) ); } //#endregion //#endregion // //#region UI Handlers ... async handleNPRStep(panel: XPanelComponent, type: XNPRButtonType) { // switch (type) { // case this.NPRButtonTypes.Next: await this.handleNextStep(panel); break; // case this.NPRButtonTypes.Prev: await this.handlePrevStep(panel); break; // case this.NPRButtonTypes.Reset: await this.handleReset(panel); break; } } async handleNextStep(panel: XPanelComponent, force?: boolean) { // if ( this.uiDisabled || this.loading || !panel || panel.loading || panel.uiDisabled || !this.hasPanels() ) { return; } // let nextId: string; const panelId = await this.getValueAsync(panel.id); const panelIndex = await this.getPanelIndex(panelId); if (panelIndex === -1) { return; } if (panelIndex < this.panels.length - 1) { nextId = await this.getValueAsync( this.panels.toArray()[panelIndex + 1].id ); } if (isNullOrEmptyString(nextId)) { return; } // if (!force) { // const isUiBusy = this.uiDisabled || this.loading; const canNextStep = await this.getValueAsync(this.canNext); const disableNextStep = await this.getValueAsync(panel.disableNext); // if (isUiBusy || disableNextStep || !canNextStep) { return; } // const isStepNextConfitmedType = panel.nextConfirmer ? panel.nextConfirmer() : this.getValue(true); const isStepNextConfirmed = await this.getValueAsync( isStepNextConfitmedType ); if (!isStepNextConfirmed) { return; } } // this.selected = nextId; this.detectChanges(); this.selectedChange.emit(nextId); this.onNext.emit(panelId); this.detectChanges(); } async handlePrevStep(panel: XPanelComponent, force?: boolean) { // if ( this.uiDisabled || this.loading || !panel || panel.loading || panel.uiDisabled || !this.hasPanels() ) { return; } // let prevId: string; const panelId = await this.getValueAsync(panel.id); const panelIndex = await this.getPanelIndex(panelId); if (panelIndex === -1) { return; } if (panelIndex > 0) { prevId = await this.getValueAsync( this.panels.toArray()[panelIndex - 1].id ); } if (isNullOrEmptyString(prevId)) { return; } // if (!force) { const isUiBusy = this.uiDisabled || this.loading; const canPrevStep = await this.getValueAsync(this.canPrev); const disablePrevStep = await this.getValueAsync(panel.disablePrev); if (isUiBusy || disablePrevStep || !canPrevStep) { return; } // const isStepPrevConfitmedType = panel.prevConfirmer ? panel.prevConfirmer() : this.getValue(true); const isStepPrevConfirmed = await this.getValueAsync( isStepPrevConfitmedType ); if (!isStepPrevConfirmed) { return; } } // this.selected = prevId; this.detectChanges(); this.selectedChange.emit(prevId); this.onPrev.emit(panelId); this.detectChanges(); } async handleReset(panel: XPanelComponent, force?: boolean) { // if ( this.uiDisabled || this.loading || !panel || panel.loading || panel.uiDisabled || !this.hasPanels() ) { return; } // const stepId = await this.getValueAsync(panel.id); const firstId = await this.getValueAsync(this.panels.toArray()[0].id); // if (!force) { const isUiBusy = this.uiDisabled || this.loading; const canResetStep = await this.getValueAsync(this.canReset); const disableResetStep = await this.getValueAsync(panel.disableReset); if (isUiBusy || disableResetStep || !canResetStep) { return; } // const isConfirmedType = await this.resetConfirmer(); const isConfirmed = await this.getValueAsync(isConfirmedType); // if (!isConfirmed) { return; } // const isStepResetConfitmedType = panel.resetConfirmer ? panel.resetConfirmer() : this.getValue(true); const isStepResetConfirmed = await this.getValueAsync( isStepResetConfitmedType ); if (!isStepResetConfirmed) { return; } } // this.selected = firstId; this.detectChanges(); this.selectedChange.emit(firstId); this.onReset.emit(stepId); this.detectChanges(); } async handleToStep(panel: XPanelComponent) { // if ( this.uiDisabled || this.loading || !panel || panel.loading || panel.uiDisabled || !this.hasPanels() || this.selected === (await this.getValueAsync(panel.id)) ) { return; } // const panelId = await this.getValueAsync(panel.id); // this.selected = panelId; this.detectChanges(); this.selectedChange.emit(panelId); this.detectChanges(); } async handlePanelOpened(panel: XPanelComponent) { // const panelId = await this.getValueAsync(panel.id); this.selected = panelId; this.detectChanges(); } //#endregion // //#region Actions ... async next(force?: boolean) { // const panel = await this.getPanel(this.selected); if (!panel) { return; } // await this.handleNextStep(panel, force); } async prev(force?: boolean) { // const panel = await this.getPanel(this.selected); if (!panel) { return; } // await this.handlePrevStep(panel, force); } async reset(force?: boolean) { // const panel = await this.getPanel(this.selected); if (!panel) { return; } // await this.handleReset(panel, force); } async to(id: XStandardType, force?: boolean) { // if (!id || !this.hasPanels()) { return; } // const panelId = await this.getValueAsync(id); if (!panelId) { return; } // const panelIndex = await this.getPanelIndex(panelId); if (panelIndex === -1) { return; } // const panel = await this.getPanel(panelId); if (!panel) { return; } // const selectedIndex = await this.getPanelIndex(this.selected); if (selectedIndex === -1 || selectedIndex === panelIndex) { return; } // if (panelIndex > selectedIndex) { // // next confirm ... // if (!force) { // const isUiBusy = this.uiDisabled || this.loading; const canNextStep = await this.getValueAsync(this.canNext); const disableNextStep = await this.getValueAsync(panel.disableNext); // if (isUiBusy || disableNextStep || !canNextStep) { return; } // const isStepNextConfitmedType = panel.nextConfirmer ? panel.nextConfirmer() : this.getValue(true); const isStepNextConfirmed = await this.getValueAsync( isStepNextConfitmedType ); if (!isStepNextConfirmed) { return; } } // this.selected = panelId; this.selectedChange.emit(panelId); } else if (panelIndex < selectedIndex) { // // prev Confirm ... // if (!force) { const isUiBusy = this.uiDisabled || this.loading; const canPrevStep = await this.getValueAsync(this.canPrev); const disablePrevStep = await this.getValueAsync(panel.disablePrev); if (isUiBusy || disablePrevStep || !canPrevStep) { return; } // const isStepPrevConfitmedType = panel.prevConfirmer ? panel.prevConfirmer() : this.getValue(true); const isStepPrevConfirmed = await this.getValueAsync( isStepPrevConfitmedType ); if (!isStepPrevConfirmed) { return; } } // this.selected = panelId; this.selectedChange.emit(panelId); } } async expandAll() { // if (!this.hasChild(this.PANELS)) { return; } // this.PANELS.toArray().forEach((panel) => { // if (panel) { // panel.expanded = true; panel.detectChanges(); } }); // this.detectChanges(); } async collapseAll() { // if (!this.hasChild(this.PANELS)) { return; } // this.PANELS.toArray().forEach((panel) => { // if (panel) { // panel.expanded = false; panel.detectChanges(); } }); // this.detectChanges(); } //#endregion // //#region Private ... private async handleStartupState() { // const state = await this.getValueAsync(this.startupState); if (isNullOrEmptyString(state)) { return; } // switch (state) { // case XExpandablePanelStartupState.CollapseAll: await this.collapseAll(); break; // case XExpandablePanelAction.ExpandAll: await this.expandAll(); break; } } private defaultStepperResetConfirmer() { // return new Promise((resolver) => { // this.managerService.dialogService.presentAreYouSureYesNoDialog( () => resolver(true), XModalButtonRole.Destructive, () => resolver(false) ); }); } private getActionButton(panel: XPanelComponent, type: XNPRButtonType) { // switch (type) { // case this.NPRButtonTypes.Next: return this.getValue(panel.nextButton); // case this.NPRButtonTypes.Prev: return this.getValue(panel.prevButton); // case this.NPRButtonTypes.Reset: return this.getValue(panel.resetButton); } } private getActionButtonDisabled( panel: XPanelComponent, type: XNPRButtonType ) { // switch (type) { // case this.NPRButtonTypes.Next: return this.getOptionalValue(panel.disableNext).pipe( map((sDisable) => this.uiDisabled || panel.uiDisabled || sDisable) ); // case this.NPRButtonTypes.Prev: return this.getOptionalValue(panel.disablePrev).pipe( map((sDisable) => this.uiDisabled || panel.uiDisabled || sDisable) ); // case this.NPRButtonTypes.Reset: return this.getOptionalValue(panel.disableReset).pipe( map((sDisable) => this.uiDisabled || panel.uiDisabled || sDisable) ); } } private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XExpandablePanelAction.NEXT: await this.next(model.force); break; // case XExpandablePanelAction.PREV: await this.prev(model.force); break; // case XExpandablePanelAction.RESET: await this.reset(model.force); break; // case XExpandablePanelAction.TO: if (model.payload) { await this.to(model.payload, model.force); } break; // case XExpandablePanelAction.ExpandAll: await this.expandAll(); break; // case XExpandablePanelAction.CollapseAll: await this.collapseAll(); break; // case XExpandablePanelAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } private async getPanel(id: string) { // if (!id || !this.hasPanels()) { return null; } // return this.panels.toArray().find(async (p) => { const pId = await this.getValueAsync(p.id); return pId === id; }); } private async getPanelIndex(id: string) { // if (!id || !this.hasPanels()) { return -1; } // let result = -1; const panels = this.panels.toArray(); if (!this.hasChild(panels)) { return result; } // for (let i = 0; i < panels.length; i++) { // const panel = panels[i]; const pId = await this.getValueAsync(panel.id); if (pId === id) { result = i; } } // return result; } // //#region Color Appliers ... private async applyHeaderColor() { // const color = await this.getValueAsync(this.headerColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XExpandablePanelCssVars.HeaderForegroundColor, `var(${fgColor})` ); this.setCssVar( XExpandablePanelCssVars.HeaderBackgroundColor, `var(${bgColor})` ); // this.detectChanges(); } private async applyHeaderHighlightColor() { // const color = await this.getValueAsync(this.headerHighlightColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XExpandablePanelCssVars.HeaderHighlightForegroundColor, `var(${fgColor})` ); this.setCssVar( XExpandablePanelCssVars.HeaderHighlightBackgroundColor, `var(${bgColor})` ); // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XButtonModule } from '../x-button/x-button.module'; import { XPanelComponent } from './x-panel/x-panel.component'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XExpandablePanelComponent } from './x-expandable-panel.component'; @NgModule({ declarations: [XPanelComponent, XExpandablePanelComponent], imports: [ XIconModule, XCardModule, CommonModule, XButtonModule, XSlotterModule, XBaseComponentModule, ], exports: [ XIconModule, XCardModule, CommonModule, XButtonModule, XSlotterModule, XPanelComponent, XBaseComponentModule, XExpandablePanelComponent, ], }) export class XExpandablePanelModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-expandable-panel.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XModalButtonRole, XColorIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { concatMap, map } from 'rxjs/operators'; import { XNextPrevResetHostContainer, XCardNextPrevResetHostContainer, IXCardNextPrevResetHostContainer, XCardNextPrevResetHostContainerComponent, } from '../classes/i-x-next-prev-reset.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XComponentCardContainer } from '../x-card/x-card.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XExpandablePanelStartupState { ExpandAll = 'expand-all', CollapseAll = 'collapse-all', } export type XExpandablePanelStartupStateIdentifier = | XExpandablePanelStartupState | string; export enum XExpandablePanelAction { NEXT = 'next', PREV = 'prev', RESET = 'reset', TO = 'to', // ExpandAll = 'expand-all', CollapseAll = 'collapse-all', // Refresh = 'refresh', } export type XExpandablePanelActionIdentifier = XExpandablePanelAction | string; export interface XExpandablePanelActionModel extends XBaseActionModel { force?: boolean; } export enum XExpandablePanelCssVars { // HeaderForegroundColor = 'header-foreground-color', HeaderBackgroundColor = 'header-background-color', // HeaderHighlightForegroundColor = 'header-highlight-foreground-color', HeaderHighlightBackgroundColor = 'header-highlight-background-color', } export type XExpandablePandelCssVarsIdentifier = | XExpandablePanelCssVars | string; // //#region Inside Host Container ... export interface IXExpandablePandelContainer extends IXCardNextPrevResetHostContainer { // actionProvider: Subject; cssClass: XStandardType>; // startupState: XStandardType; isAccordion: XStandardType; multiExpanded: XStandardType; hideDescriptionOnSmallScreens: XStandardType; // applyColors: XStandardType; headerColor: XStandardType; headerHighlightColor: XStandardType; // resetConfirmer: () => XStandardType; selected: string; // selectedChange: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XExpandablePandelContainer extends XCardNextPrevResetHostContainer implements Readonly { // //#region Props ... // readonly actionProvider = new Subject(); readonly cssClass: XStandardType>; // readonly startupState: XStandardType = XExpandablePanelStartupState.ExpandAll; readonly isAccordion: XStandardType; readonly multiExpanded: XStandardType; readonly hideDescriptionOnSmallScreens: XStandardType; // readonly applyColors: XStandardType = true; readonly headerColor: XStandardType = XColorWithBrightness.Primary; readonly headerHighlightColor: XStandardType = XColorWithBrightness.Warning; // readonly resetConfirmer: () => XStandardType = () => { return new Promise((resolver) => { // this.managerService.dialogService.presentAreYouSureYesNoDialog( () => resolver(true), XModalButtonRole.Destructive, () => resolver(false) ); }); }; readonly selected: string; // readonly selectedChange: EventEmitter; //#endregion // //#region Constructor ... constructor( public managerService: XManagerService, protected cardPropertyProvider: XComponentCardContainer, protected nextPrevResetHostPropertyProvider: XNextPrevResetHostContainer ) { super(cardPropertyProvider, nextPrevResetHostPropertyProvider); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XExpandablePandelContainerComponent extends XCardNextPrevResetHostContainerComponent implements IXExpandablePandelContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() startupState: XStandardType = this.propertyProvider.startupState; @Input() isAccordion: XStandardType = this.propertyProvider.isAccordion; @Input() multiExpanded: XStandardType = this.propertyProvider.multiExpanded; @Input() hideDescriptionOnSmallScreens: XStandardType = this.propertyProvider.hideDescriptionOnSmallScreens; // @Input() applyColors: XStandardType = this.propertyProvider.applyColors; @Input() headerColor: XStandardType = this.propertyProvider.headerColor; @Input() headerHighlightColor: XStandardType = this.propertyProvider.headerHighlightColor; // @Input() resetConfirmer: () => XStandardType = this.propertyProvider.resetConfirmer; @Input() selected: string = this.propertyProvider.selected; // @Output() selectedChange: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XExpandablePandelContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXExpandablePandelContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ cssClass: this.getValue( container ? container.cssClass : this.cssClass ), startupState: this.getValue( container ? container.startupState : this.startupState ), isAccordion: this.getValue( container ? container.isAccordion : this.isAccordion ), multiExpanded: this.getValue( container ? container.multiExpanded : this.multiExpanded ), hideDescriptionOnSmallScreens: this.getValue( container ? container.hideDescriptionOnSmallScreens : this.hideDescriptionOnSmallScreens ), applyColors: this.getValue( container ? container.applyColors : this.applyColors ), headerColor: this.getValue( container ? container.headerColor : this.headerColor ), headerHighlightColor: this.getValue( container ? container.headerHighlightColor : this.headerHighlightColor ), resetConfirmer: this.getValue( container ? container.resetConfirmer : this.resetConfirmer ), selected: this.getValue( container ? container.selected : this.selected ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // selectedChange: this.selectedChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-panel\x-panel.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-panel\x-panel.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-panel\x-panel.component.ts import { Component, ViewChild, TemplateRef, ChangeDetectionStrategy, } from '@angular/core'; import { XPanelAction, XPanelActionModel, XPanelContainerComponent, } from './x-panel.typings'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; @Component({ selector: 'x-panel', templateUrl: './x-panel.component.html', styleUrls: ['./x-panel.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XPanelComponent extends XPanelContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // //#region ViewChilds ... @ViewChild('title', { static: false }) title!: TemplateRef; @ViewChild('description', { static: false }) description!: TemplateRef; @ViewChild('content', { static: false }) content!: TemplateRef; @ViewChild('actions', { static: false }) actions!: TemplateRef; //#endregion //#endregion // //#region LifeCycle ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Privates ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XPanelAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-expandable-panel\x-panel\x-panel.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { IXNextPrevResetContainer, XNextPrevResetContainer, XNextPrevResetContainerComponent, } from '../../classes/i-x-next-prev-reset.container'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { XStandardType, XOneOrManyType, generateUuid } from 'x-framework-core'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; export enum XPanelAction { Refresh = 'refresh', } export type XPanelActionIdentifier = XPanelAction | string; export interface XPanelActionModel extends XBaseActionModel {} // //#region Inside Card Container ... export interface IXPanelContainer extends IXNextPrevResetContainer { // actionProvider: Subject; cssClass: XStandardType>; // id: XStandardType; // hideToggle: XStandardType; expanded: XStandardType; hasCustomActions: XStandardType; } @Injectable({ providedIn: 'root' }) export class XPanelContainer extends XNextPrevResetContainer implements Readonly { // //#region Props ... readonly actionProvider = new Subject(); readonly cssClass: XStandardType>; // readonly id: XStandardType = generateUuid('XPanelComponent'); // readonly hideToggle: XStandardType = false; readonly expanded: XStandardType; readonly hasCustomActions: XStandardType; //#endregion } @Injectable({ providedIn: 'root' }) @Component({ template: ` `, }) export abstract class XPanelContainerComponent extends XNextPrevResetContainerComponent implements IXPanelContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() id: XStandardType = this.propertyProvider.id; @Input() hideToggle: XStandardType = this.propertyProvider.hideToggle; @Input() expanded: XStandardType = this.propertyProvider.expanded; @Input() hasCustomActions: XStandardType = this.propertyProvider.hasCustomActions; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XPanelContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXPanelContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), id: this.getValue(container ? container.id : this.id), hideToggle: this.getValue( container ? container.hideToggle : this.hideToggle ), expanded: this.getValue( container ? container.expanded : this.expanded ), hasCustomActions: this.getValue( container ? container.hasCustomActions : this.hasCustomActions ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.component.scss :host ::ng-deep .x-icon { background-color: transparent !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.component.ts import { XFabItem, XFabButton, XFabAction, XFabButtonSide, XFabActionModel, XFabContainerComponent, } from './x-fab.typings'; import { nameof, hasChild, isFunction, isNullOrUndefined, } from 'x-framework-core'; import { IonFab } from '@ionic/angular'; import { concatMap, map } from 'rxjs/operators'; import { of, Observable, Subject, Subscription } from 'rxjs'; import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-fab', templateUrl: './x-fab.component.html', styleUrls: ['./x-fab.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XFabComponent extends XFabContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // private FAB: IonFab; private PARSED_ITEM: XFabItem; private PARSED_CHILDS: XFabButton[] = []; private HAS_TOP_SIDE_CHILDS: boolean; private HAS_END_SIDE_CHILDS: boolean; private HAS_START_SIDE_CHILDS: boolean; private HAS_BOTTOM_SIDE_CHILDS: boolean; // @ViewChild('fab', { static: false }) set fab(v: IonFab) { // if (!v) { return; } // this.FAB = v; this.detectChanges(); } get fab() { return this.FAB; } get parsedItem() { return this.PARSED_ITEM; } get parsedChilds() { return this.PARSED_CHILDS; } get hasTopSideChilds() { return this.HAS_TOP_SIDE_CHILDS; } get hasEndSideChilds() { return this.HAS_END_SIDE_CHILDS; } get hasStartSideChilds() { return this.HAS_START_SIDE_CHILDS; } get hasBottomSideChilds() { return this.HAS_BOTTOM_SIDE_CHILDS; } //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Items Changes ... // const isItemsChanged = changeKeys.includes(nameof('item')); if (isItemsChanged) { // const item = await this.getValueAsync(this.item); this.detectChanges(); if (!isNullOrUndefined(item)) { // this.PARSED_ITEM = item; this.detectChanges(); // if (item.childs) { // const childs = await this.getValueAsync(item.childs); if (!hasChild(childs)) { return; } // // Sorting Childs ... this.PARSED_CHILDS = childs.sort((a, b) => a.index - b.index); this.detectChanges(); // // Determine Sides ... this.PARSED_CHILDS.forEach(async (ch) => { // const side = await this.getValueAsync(ch.side); switch (side) { case XFabButtonSide.TOP: if (!this.HAS_TOP_SIDE_CHILDS) { this.HAS_TOP_SIDE_CHILDS = true; } break; case XFabButtonSide.END: if (!this.HAS_END_SIDE_CHILDS) { this.HAS_END_SIDE_CHILDS = true; } break; case XFabButtonSide.START: if (!this.HAS_START_SIDE_CHILDS) { this.HAS_START_SIDE_CHILDS = true; } break; case XFabButtonSide.BOTTOM: if (!this.HAS_BOTTOM_SIDE_CHILDS) { this.HAS_BOTTOM_SIDE_CHILDS = true; } break; } // this.detectChanges(); }); } } } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Provider ... getFixedValue(items: XFabItem) { return of(items).pipe( concatMap((rItems) => { // if (!rItems) { return of(''); } // const obs = this.getOptionalValue(rItems.fixed) as Observable; return obs.pipe(map((res) => (res === true ? 'fixed' : ''))); }) ); } // //#region Fab Button Side Providers ... isTopSideFab(child: XFabButton) { return this.getValue(child.side).pipe( map((side) => side === XFabButtonSide.TOP.toString()) ); } isEndSideFab(child: XFabButton) { return this.getValue(child.side).pipe( map((side) => side === XFabButtonSide.END.toString()) ); } isStartSideFab(child: XFabButton) { return this.getValue(child.side).pipe( map((side) => side === XFabButtonSide.START.toString()) ); } isBottomSideFab(child: XFabButton) { return this.getValue(child.side).pipe( map((side) => side === XFabButtonSide.BOTTOM.toString()) ); } //#endregion //#endregion // //#region UI Handlers ... async handleFabButtonClicked(item: XFabButton | XFabButton) { // if (!item) { return; } // if (item.handler && isFunction(item.handler)) { await this.getValueAsync(item.handler(item.id)); } } //#endregion // //#region Actions ... async close() { // if (!this.fab) { return; } // await this.fab.close(); } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper( this.actionProvider.asObservable() ).subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XFabAction.Refresh: this.detectChanges(); break; // case XFabAction.CLOSE: await this.close(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XFabComponent } from './x-fab.component'; import { XIconModule } from '../x-icon/x-icon.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XFabComponent], imports: [CommonModule, XBaseComponentModule, XIconModule], exports: [XBaseComponentModule, XIconModule, XFabComponent], }) export class XFabModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-fab\x-fab.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XRouterDirection, XResourceIdentifier, XRouterTargetIdentifier, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XFabVerticalSlot { TOP = 'top', CENTER = 'center', BOTTOM = 'bottom', } export type XFabVerticalSlotIdentifier = XFabVerticalSlot | string; export enum XFabHorizontalSlot { START = 'start', CENTER = 'center', END = 'end', } export type XFabHorizontalSlotIdentifier = XFabHorizontalSlot | string; export enum XFabButtonSide { TOP = 'top', END = 'end', START = 'start', BOTTOM = 'bottom', } export type XFabButtonSideIdentifier = XFabButtonSide | string; export enum XFabButtonSize { REGULAR = '', MINI = 'small', } export type XFabButtonSizeIdentifier = XFabButtonSize | string; export interface XFabButton { // id: string; index: number; // icon: XStandardType; side: XStandardType; size?: XStandardType; // disabled?: XStandardType; hidden?: XStandardType; // color: XStandardType; // tooltip?: XStandardType; // href?: XStandardType; download?: XStandardType; routerDirection?: XStandardType; routerTarget?: XStandardType; // handler?: (id?: string) => XStandardType; } type FAB_MAIN_BUTTON = Pick< XFabButton, | 'id' | 'icon' | 'size' | 'color' | 'hidden' | 'handler' | 'tooltip' | 'disabled' | 'href' | 'download' | 'routerDirection' | 'routerTarget' >; export interface XFabItem extends FAB_MAIN_BUTTON { // vertical: XStandardType; horizontal: XStandardType; // fixed?: XStandardType; edged?: XStandardType; // activated?: XStandardType; // childs?: XStandardType; } export enum XFabAction { CLOSE = 'close', // Refresh = 'refresh', } export type XFabActionIdentifier = XFabAction | string; export interface XFabActionModel extends XBaseActionModel {} // //#region Container ... export interface IXFabContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // childsCssClass: XStandardType>; item: XStandardType; } @Injectable({ providedIn: 'root' }) export class XFabContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly childsCssClass: XStandardType>; readonly item: XStandardType = null; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XFabContainerComponent extends XBaseContainerComponent implements IXFabContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() childsCssClass: XStandardType> = this.propertyProvider.childsCssClass; @Input() item: XStandardType = this.propertyProvider.item; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XFabContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps(container?: IXFabContainer): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), childsCssClass: this.getValue( container ? container.childsCssClass : this.childsCssClass ), item: this.getValue(container ? container.item : this.item), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.component.html
{{ getResourceValue(message) | async }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.component.scss :host { width: inherit; height: inherit; --label-color: var(--x-color-light-contrast); } .x-wrapper { cursor: grab; } .x-wrapper:active { cursor: grabbing; } .no-drag { cursor: unset; } .x-droppable-container { border-radius: 10px; } .x-drop-area { width: 100%; height: auto; box-sizing: border-box; border-radius: 10px; border: 2px dashed var(--label-color); text-align: center; padding: { top: 16px; bottom: 16px; } } .x-drag-drop-title { color: var(--label-color); } .x-icon { margin: { left: auto; right: auto; } margin-bottom: 16px; font-size: 8px; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.component.ts import { nameof, parseXColor, isNullOrEmptyString, getXColorCssVariableName, } from 'x-framework-core'; import { XFileDropAreaAction, XFileDropAreaCssVars, XFileDropAreaActionModel, XFileDropAreaContainerComponent, } from './x-file-drop-area.typings'; import { Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-file-drop-area', templateUrl: './x-file-drop-area.component.html', styleUrls: ['./x-file-drop-area.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XFileDropAreaComponent extends XFileDropAreaContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Color Changed ... const isColorChanged = changeKeys.includes( nameof('color') ); if (isColorChanged) { await this.applyColor(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Provider ... //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe((model) => { // if (!model) { return; } // switch (model.action) { // case XFileDropAreaAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async applyColor() { // const color = await this.getValueAsync(this.color); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFileDropAreaCssVars.LabelColor, `var(${fgColor})`); // this.detectChanges(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XListModule } from '../x-list/x-list.module'; import { XFileDropAreaComponent } from './x-file-drop-area.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XFileDropAreaComponent], imports: [ XListModule, XCardModule, XIconModule, CommonModule, XBaseComponentModule, ], exports: [ XCardModule, XIconModule, XListModule, XBaseComponentModule, XFileDropAreaComponent, ], }) export class XFileDropAreaModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-drop-area\x-file-drop-area.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XCardActionModel, XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { XBaseComponentContainer, IXBaseComponentContainer, XBaseComponentContainerComponent, } from '../classes/i-x-base.container'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XIconIdentifier, XIconNames } from '../x-icon/x-icon.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XFileDropAreaAction { Refresh = 'refresh', } export type XFileDropAreaActionIdentifier = XFileDropAreaAction | string; export interface XFileDropAreaActionModel extends XBaseActionModel {} export enum XFileDropAreaCssVars { LabelColor = 'label-color', } // //#region Container ... export interface IXFileDropAreaContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; // icon: XStandardType; message: XStandardType; // disableFileCheck: XStandardType; // supportsMultipleFiles: XStandardType; allowedExtensions: XStandardType>; // dragDisabled: XStandardType; contentTemplate: TemplateRef; filesChangeEmiter: EventEmitter>; // successColor: XStandardType; errorColor: XStandardType; accentColor: XStandardType; } @Injectable({ providedIn: 'root', }) export class XFileDropAreaContainer extends XComponentCardContainer implements Readonly { // //#region Props ... // readonly actionProvider = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; readonly icon: XStandardType = XIconNames.arrow_down; readonly message: XStandardType = XResourceIDs.drag_drop_here; // readonly disableFileCheck: XStandardType = false; // readonly allowedExtensions: XStandardType> = []; readonly supportsMultipleFiles: XStandardType = true; // readonly dragDisabled: XStandardType = false; readonly contentTemplate: TemplateRef; readonly filesChangeEmiter = new EventEmitter>(); // readonly successColor: XStandardType = XColorWithBrightness.Success; readonly errorColor: XStandardType = XColorWithBrightness.Danger; readonly accentColor: XStandardType = XColorWithBrightness.Secondary; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XFileDropAreaContainerComponent extends XComponentCardContainerComponent implements IXFileDropAreaContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Input() icon: XStandardType = this.propertyProvider.icon; @Input() message: XStandardType = this.propertyProvider.message; // @Input() disableFileCheck: XStandardType = this.propertyProvider.disableFileCheck; // @Input() supportsMultipleFiles: XStandardType = this.propertyProvider.supportsMultipleFiles; @Input() allowedExtensions: XStandardType> = this.propertyProvider.allowedExtensions; // @Input() dragDisabled: XStandardType = this.propertyProvider.dragDisabled; @Input() contentTemplate: TemplateRef = this.propertyProvider.contentTemplate; @Output() filesChangeEmiter: EventEmitter> = new EventEmitter(); // @Input() successColor: XStandardType = this.propertyProvider.successColor; @Input() errorColor: XStandardType = this.propertyProvider.errorColor; @Input() accentColor: XStandardType = this.propertyProvider.accentColor; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XFileDropAreaContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXFileDropAreaContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), icon: this.getValue(container ? container.icon : this.icon), message: this.getValue( container ? container.message : this.message ), disableFileCheck: this.getValue( container ? container.disableFileCheck : this.disableFileCheck ), supportsMultipleFiles: this.getValue( container ? container.supportsMultipleFiles : this.supportsMultipleFiles ), allowedExtensions: this.getValue( container ? container.allowedExtensions : this.allowedExtensions ), dragDisabled: this.getValue( container ? container.dragDisabled : this.dragDisabled ), successColor: this.getValue( container ? container.successColor : this.successColor ), errorColor: this.getValue( container ? container.errorColor : this.errorColor ), accentColor: this.getValue( container ? container.accentColor : this.accentColor ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // contentTemplate: container ? container.contentTemplate : this.contentTemplate, // filesChangeEmiter: this.filesChangeEmiter, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentFileDropAreaContainer = { [TKey in keyof IXFileDropAreaContainer as `fileDropArea${Capitalize< string & TKey >}`]: IXFileDropAreaContainer[TKey]; }; export interface IXComponentFileDropAreaContainer extends TXComponentFileDropAreaContainer, IXBaseComponentContainer { showFileDropArea: XStandardType; } @Injectable({ providedIn: 'root', }) export class XComponentFileDropAreaContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // readonly showFileDropArea: XStandardType = true; // readonly fileDropAreaActionProvider: Subject = this.propertyProvider.actionProvider; readonly fileDropAreaCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly fileDropAreaColor: XStandardType = this.propertyProvider.color; readonly fileDropAreaForegroundColor: XStandardType = this.propertyProvider.foregroundColor; // readonly fileDropAreaIcon: XStandardType = this.propertyProvider.icon; readonly fileDropAreaMessage: XStandardType = this.propertyProvider.message; // readonly fileDropAreaDisableFileCheck: XStandardType = this.propertyProvider.disableFileCheck; // readonly fileDropAreaSupportsMultipleFiles: XStandardType = this.propertyProvider.supportsMultipleFiles; readonly fileDropAreaAllowedExtensions: XStandardType< XOneOrManyType > = this.propertyProvider.allowedExtensions; // readonly fileDropAreaDragDisabled: XStandardType = this.propertyProvider.dragDisabled; readonly fileDropAreaContentTemplate: TemplateRef = this.propertyProvider.contentTemplate; readonly fileDropAreaFilesChangeEmiter: EventEmitter> = this.propertyProvider.filesChangeEmiter; // readonly fileDropAreaSuccessColor: XStandardType = this.propertyProvider.successColor; readonly fileDropAreaErrorColor: XStandardType = this.propertyProvider.errorColor; readonly fileDropAreaAccentColor: XStandardType = this.propertyProvider.accentColor; // //#region ComponentsCard ... readonly fileDropAreaIsInPage: XStandardType = false; readonly fileDropAreaWrapWithCard: XStandardType = false; readonly fileDropAreaCardShowFooter: XStandardType = false; readonly fileDropAreaCardShowActions: XStandardType = false; readonly fileDropAreaCardColor: XStandardType = XColorWithBrightness.Light; readonly fileDropAreaCardForegroundColor: XStandardType = false; readonly fileDropAreaCardTitle: XStandardType; readonly fileDropAreaCardActionProvider: Subject = new Subject(); readonly fileDropAreaCardSubTitle: XStandardType; readonly fileDropAreaCardCssClass: XStandardType>; //#endregion //#endregion // //#region Constructor ... constructor(protected propertyProvider: XFileDropAreaContainer) { super(); } //#endregion } @Injectable({ providedIn: 'root', }) @Component({ template: ` `, }) export abstract class XComponentFileDropAreaContainerComponent extends XBaseComponentContainerComponent implements IXComponentFileDropAreaContainer { // //#region Props ... // @Input() fileDropAreaActionProvider: Subject = this.propertyProvider.fileDropAreaActionProvider; @Input() fileDropAreaCssClass: XStandardType> = this.propertyProvider.fileDropAreaCssClass; // @Input() fileDropAreaColor: XStandardType = this.propertyProvider.fileDropAreaColor; @Input() fileDropAreaForegroundColor: XStandardType = this.propertyProvider.fileDropAreaForegroundColor; // @Input() fileDropAreaIcon: XStandardType = this.propertyProvider.fileDropAreaIcon; @Input() fileDropAreaMessage: XStandardType = this.propertyProvider.fileDropAreaMessage; // @Input() fileDropAreaDisableFileCheck: XStandardType = this.propertyProvider.fileDropAreaDisableFileCheck; // @Input() fileDropAreaSupportsMultipleFiles: XStandardType = this.propertyProvider.fileDropAreaSupportsMultipleFiles; @Input() fileDropAreaAllowedExtensions: XStandardType> = this.propertyProvider.fileDropAreaAllowedExtensions; // @Input() fileDropAreaDragDisabled: XStandardType = this.propertyProvider.fileDropAreaDragDisabled; @Input() fileDropAreaContentTemplate: TemplateRef = this.propertyProvider.fileDropAreaContentTemplate; @Output() fileDropAreaFilesChangeEmiter: EventEmitter> = new EventEmitter(); // @Input() fileDropAreaSuccessColor: XStandardType = this.propertyProvider.fileDropAreaSuccessColor; @Input() fileDropAreaErrorColor: XStandardType = this.propertyProvider.fileDropAreaErrorColor; @Input() fileDropAreaAccentColor: XStandardType = this.propertyProvider.fileDropAreaAccentColor; // @Input() showFileDropArea: XStandardType = this.propertyProvider.showFileDropArea; // //#region ComponentsCard ... @Input() fileDropAreaIsInPage: XStandardType = this.propertyProvider.fileDropAreaIsInPage; @Input() fileDropAreaWrapWithCard: XStandardType = this.propertyProvider.fileDropAreaWrapWithCard; @Input() fileDropAreaCardShowFooter: XStandardType = this.propertyProvider.fileDropAreaCardShowFooter; @Input() fileDropAreaCardShowActions: XStandardType = this.propertyProvider.fileDropAreaCardShowActions; @Input() fileDropAreaCardColor: XStandardType = this.propertyProvider.fileDropAreaCardColor; @Input() fileDropAreaCardForegroundColor: XStandardType = this.propertyProvider.fileDropAreaCardForegroundColor; @Input() fileDropAreaCardTitle: XStandardType = this.propertyProvider.fileDropAreaCardTitle; @Input() fileDropAreaCardActionProvider: Subject = this.propertyProvider.fileDropAreaCardActionProvider; @Input() fileDropAreaCardSubTitle: XStandardType = this.propertyProvider.fileDropAreaCardSubTitle; @Input() fileDropAreaCardCssClass: XStandardType> = this.propertyProvider.fileDropAreaCardCssClass; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XComponentFileDropAreaContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXComponentFileDropAreaContainer ): Observable { return forkJoin({ // fileDropAreaCssClass: this.getValue( container ? container.fileDropAreaCssClass : this.fileDropAreaCssClass ), fileDropAreaColor: this.getValue( container ? container.fileDropAreaColor : this.fileDropAreaColor ), fileDropAreaForegroundColor: this.getValue( container ? container.fileDropAreaForegroundColor : this.fileDropAreaForegroundColor ), fileDropAreaIcon: this.getValue( container ? container.fileDropAreaIcon : this.fileDropAreaIcon ), fileDropAreaMessage: this.getValue( container ? container.fileDropAreaMessage : this.fileDropAreaMessage ), fileDropAreaDisableFileCheck: this.getValue( container ? container.fileDropAreaDisableFileCheck : this.fileDropAreaDisableFileCheck ), fileDropAreaSupportsMultipleFiles: this.getValue( container ? container.fileDropAreaSupportsMultipleFiles : this.fileDropAreaSupportsMultipleFiles ), fileDropAreaAllowedExtensions: this.getValue( container ? container.fileDropAreaAllowedExtensions : this.fileDropAreaAllowedExtensions ), fileDropAreaDragDisabled: this.getValue( container ? container.fileDropAreaDragDisabled : this.fileDropAreaDragDisabled ), fileDropAreaContentTemplate: this.getValue( container ? container.fileDropAreaContentTemplate : this.fileDropAreaContentTemplate ), fileDropAreaSuccessColor: this.getValue( container ? container.fileDropAreaSuccessColor : this.fileDropAreaSuccessColor ), fileDropAreaErrorColor: this.getValue( container ? container.fileDropAreaErrorColor : this.fileDropAreaErrorColor ), fileDropAreaAccentColor: this.getValue( container ? container.fileDropAreaAccentColor : this.fileDropAreaAccentColor ), showFileDropArea: this.getValue( container ? container.showFileDropArea : this.showFileDropArea ), fileDropAreaIsInPage: this.getValue( container ? container.fileDropAreaIsInPage : this.fileDropAreaIsInPage ), fileDropAreaWrapWithCard: this.getValue( container ? container.fileDropAreaWrapWithCard : this.fileDropAreaWrapWithCard ), fileDropAreaCardShowFooter: this.getValue( container ? container.fileDropAreaCardShowFooter : this.fileDropAreaCardShowFooter ), fileDropAreaCardShowActions: this.getValue( container ? container.fileDropAreaCardShowActions : this.fileDropAreaCardShowActions ), fileDropAreaCardColor: this.getValue( container ? container.fileDropAreaCardColor : this.fileDropAreaCardColor ), fileDropAreaCardForegroundColor: this.getValue( container ? container.fileDropAreaCardForegroundColor : this.fileDropAreaCardForegroundColor ), fileDropAreaCardTitle: this.getValue( container ? container.fileDropAreaCardTitle : this.fileDropAreaCardTitle ), fileDropAreaCardSubTitle: this.getValue( container ? container.fileDropAreaCardSubTitle : this.fileDropAreaCardSubTitle ), fileDropAreaCardCssClass: this.getValue( container ? container.fileDropAreaCardCssClass : this.fileDropAreaCardCssClass ), }).pipe( map((data) => { return { // ...data, // fileDropAreaActionProvider: container ? container.fileDropAreaActionProvider : this.fileDropAreaActionProvider, // fileDropAreaCardActionProvider: container ? container.fileDropAreaCardActionProvider : this.fileDropAreaCardActionProvider, // fileDropAreaFilesChangeEmiter: this.fileDropAreaFilesChangeEmiter, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.component.html
{{ item.data.name }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.component.scss :host { --top-radius: 5px; --padding: 6px; --host-bg-color: var(--x-color-light); } :host ::ng-deep .x-card { box-shadow: unset !important; } :host ::ng-deep .x-thumbnail, :host ::ng-deep .x-item { width: 32px !important; height: 32px !important; object-fit: contain !important; object-position: center !important; } :host ::ng-deep ion-searchbar { padding-left: unset; padding-right: unset; padding-inline-end: 0 !important; padding-inline-start: 0 !important; } .x-file-item { width: 100%; text-align: start; } .x-file-item, .x-file-thumbnail { height: 32px; } .x-file-thumbnail { width: 32px; } .x-file-title, .x-file-thumbnail { margin: { left: 4px; right: 4px; } } .x-file-title { text-align: start; margin: { top: auto; bottom: auto; } } .x-file-upload-file-drag-drop-wrapper { padding: var(--padding); background-color: var(--host-bg-color); border-top-left-radius: var(--top-radius); border-top-right-radius: var(--top-radius); } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.component.ts import { ViewChild, Component, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { XColor, nameof, isFile, isArray, toArray, isString, hasChild, XFileType, XFileBlob, getArrayOf, isXFileBlob, parseXColor, getFileInfo, isExtensionOk, XOneOrManyType, getErrorException, isNullOrUndefined, isNullOrEmptyString, XExceptionIdentifier, XBaseRangeRequestDto, getXColorCssVariableName, } from 'x-framework-core'; import { XFileStatus, XFileUploadAction, XFileUploadCssVars, XFileUploadActionModel, XFileUploadContainerComponent, } from './x-file-upload.typings'; import { map } from 'rxjs/operators'; import { XActionBarItem, defaultActionBarAddItem, DefaultActionBarItemIds, defaultActionBarUploadItem, defaultActionBarRemoveItem, defaultActionBarSelectAllItem, defaultActionBarDeSelectAllItem, defaultActionBarInverseSelectionItem, } from '../x-action-bar/x-action-bar.typings'; import { XIconNames } from '../x-icon/x-icon.typings'; import { BehaviorSubject, Subject, Subscription } from 'rxjs'; import { XListItem, XListAction } from '../x-list/x-list.typings'; import { XThumbnailType } from '../x-thumbnail/x-thumbnail.typings'; import { XFileDropAreaAction } from '../x-file-drop-area/x-file-drop-area.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-file-upload', templateUrl: './x-file-upload.component.html', styleUrls: ['./x-file-upload.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XFileUploadComponent extends XFileUploadContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // private addDisablerSubject = new BehaviorSubject(false); private uploadDisablerSubject = new BehaviorSubject(true); private removeDisablerSubject = new BehaviorSubject(true); private selectAllDisablerSubject = new BehaviorSubject(true); private deSelectAllDisablerSubject = new BehaviorSubject(true); private inverseSelectionDisablerSubject = new BehaviorSubject(true); // @ViewChild('fileInput', { static: false }) private fileInputRef!: ElementRef; // private inputFiles: File[] = []; fileListItems: XListItem[] = []; fileListItemsSubject: BehaviorSubject[]> = new BehaviorSubject([]); // get files() { return this.inputFiles; } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.prepareActionBarActions(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // const isColorChanged = changeKeys.includes( nameof('color') ); if (isColorChanged) { await this.applyColor(); } // //#region ActionBar Actions ... const isActionBarActionsChanged = changeKeys.includes( nameof('actionBarActions') ); const isActionBarHideActionsChanged = changeKeys.includes( nameof('actionBarHideActions') ); if (isActionBarActionsChanged || isActionBarHideActionsChanged) { await this.prepareActionBarActions(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Register Handlers ... registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Ui Providers ... async canAddFile() { // const isMaxFilesOk = await this.isMaxAllowedFilesOk( this.inputFiles.length + 1 ); const isMaxSizeOk = await this.isMaxAllowedSizeOk(); // const result = isMaxFilesOk && isMaxSizeOk; if (result) { this.addDisablerSubject.next(false); } else { this.addDisablerSubject.next(true); } // return result; } getThumbnailType(item: any) { return this.getValue(item).pipe( map((it) => { // let result = XThumbnailType.GENERAL; // let fileInfo; if (isString(it)) { fileInfo = getFileInfo(it); } else if (!isFile(it) && isXFileBlob(fileInfo)) { fileInfo = getFileInfo((it as XFileBlob).name); } else { fileInfo = getFileInfo((it as File).name); } // switch (fileInfo.type) { case XFileType.Image: case XFileType.CoverImage: case XFileType.ProfileImage: result = XThumbnailType.CUSTOM; break; } // return result; }) ); } getThumbnailIdentifier(item: any) { return this.getValue(item).pipe( map((it) => { // let result = ''; if (!isFile(it)) { result = !isNullOrUndefined(it.name) ? it.name : it; } else { result = it; } // return result; }) ); } //#endregion // //#region Ui Handlers ... async handleFileDropped(files: File | File[]) { // if (!files) { return; } // this.loading = true; // if (!isArray(files) && files instanceof File) { await this.handleAddNewFile(files as File); } else { // const filesArr = files as File[]; for (const file of filesArr) { await this.handleAddNewFile(file); } } // this.loading = false; this.fileChange.emit(this.inputFiles); this.handleChangeDetection(); } async handleAddNewFile(file: File) { // if (this.isExists(file)) { return; } // const status = await this.getFileStatusForAdd(file); // await this.prepareActionBarActionsSubjects(this.getSelectedFiles()); if (status !== XFileStatus.OK) { this.loading = false; await this.handleFileStatusForAdd(status); return; } // this.inputFiles.push(file); const fileListItem = await this.getListItem(file); this.fileListItems.push(fileListItem); this.fileListItemsSubject.next(this.fileListItems); this.handleChangeDetection(); } async handleRemoveItems(request: XBaseRangeRequestDto) { // if (!request || !hasChild(request.items)) { return; } // this.loading = true; // const filteredFiles = this.inputFiles.filter( (f) => !request.items.includes(f) ); this.inputFiles = []; this.fileListItems = []; // if (!hasChild(filteredFiles)) { // this.inputFiles = []; this.fileListItems = []; this.fileListItemsSubject.next([]); } else { await this.handleFileDropped(filteredFiles); } // this.loading = false; this.fileChange.emit(this.inputFiles); this.handleChangeDetection(); } async handleFilesSelectionChanged(items: XListItem[]) { await this.prepareActionBarActionsSubjects(items); } async handleListOrderChanged() { // const listItems = await this.getArrayValueAsync(this.fileListItems); this.inputFiles = [...listItems.map((li) => li.data)]; // this.loading = false; this.fileChange.emit(this.inputFiles); this.handleChangeDetection(); } handleFilesSelected() { // if (!this.fileInputRef) { return; } // const fileInput = this.fileInputRef.nativeElement; if (!fileInput || !fileInput.files) { return; } // const files = getArrayOf(fileInput.files); // if (!files || files.length === 0) { return; } // const file = files[0]; if (!file) { return; } // fileInput.value = null; // this.handleFileDropped(files); } //#endregion // //#region Actions ... selectFiles() { // const isBussy = this.uiDisabled || this.loading; if (isBussy) { return; } // if (!this.fileInputRef) { return; } // const fileInput = this.fileInputRef.nativeElement; if (!fileInput) { return; } // fileInput.click(); } isExists(file: File) { // const result = file && hasChild(this.inputFiles) ? this.inputFiles.findIndex( (f) => f.name === file.name && f.size === file.size && f.type === file.type && f.lastModified === file.lastModified ) > -1 : false; // return result; } getSelectedFiles() { return this.fileListItems.filter((i) => i.isSelected === true); } /** * sync files with list ... * @param files */ async handleSyncFiles(files: Array) { // // first Remove List and Files ... await this.handleRemoveItems({ items: this.files, }); // // Drop New Files ... await this.handleFileDropped(files); } //#endregion // //#region Private ... /** * retrieve all exists files in list current size ... */ private currentFilesSize() { // let result = 0; this.inputFiles.forEach((i) => (result += i.size)); // return result; } /** * Check File Extension ... */ private async isExtensionOk(file: File) { // if (!file) { return false; } // const allowedExtensionsType = await this.getValueAsync( this.allowedExtensions ); if (!allowedExtensionsType) { return true; } // const allowedExtensions = toArray(allowedExtensionsType); if (!hasChild(allowedExtensions)) { return true; } // const result = isExtensionOk(file, allowedExtensions); return result; } /** * Check Number of Files is Ok after and before Upload ... */ private async isMaxAllowedFilesOk(num?: number) { // if (!num && !hasChild(this.inputFiles)) { return true; } // if (!num) { num = this.inputFiles.length; } // const maxAllowedFiles = await this.getValueAsync(this.maxAllowedFiles); const result = maxAllowedFiles && maxAllowedFiles > 0 ? num <= maxAllowedFiles : true; // return result; } /** * Check all File Sizes after and before Upload ... */ private async isMaxAllowedSizeOk(file?: File) { // let currentSize = this.currentFilesSize(); // if (file) { currentSize += file.size; } // const maxAllowedSize = await this.getValueAsync(this.maxAllowedSize); // const result = maxAllowedSize && maxAllowedSize > 0 ? currentSize <= maxAllowedSize : true; // return result; } /** * Check File Size satisfied Min Required Size ... */ private async isMinAllowedFileSizeOk(file: File) { // const minAllowedFileSize = await this.getValueAsync( this.minAllowedFileSize ); // const result = minAllowedFileSize && minAllowedFileSize > 0 ? file.size >= minAllowedFileSize : true; // return result; } /** * Check File Size less than or Equals Max Required Size ... */ private async isMaxAllowedFileSizeOk(file: File) { // const maxAllowedFileSize = await this.getValueAsync( this.maxAllowedFileSize ); // const result = maxAllowedFileSize && maxAllowedFileSize > 0 ? file.size <= maxAllowedFileSize : true; // return result; } /** * Check File Status for Add a File to List ... */ private async getFileStatusForAdd(file: File) { // // Check Not Empty File ... if (!file || file.size === 0) { return XFileStatus.EMPTY; } // // Check File Extension Validation ... const isExtensionIsOk = await this.isExtensionOk(file); if (!isExtensionIsOk) { return XFileStatus.NOT_ALLOWED_TYPE; } // // Check File Min Size Ok ... const isMinAllowedFileSizeOk = await this.isMinAllowedFileSizeOk(file); if (!isMinAllowedFileSizeOk) { return XFileStatus.MIN_SIZE_NOT_REACHED; } // // Check File Max Size Ok ... const isMaxAllowedFileSizeOk = await this.isMaxAllowedFileSizeOk(file); if (!isMaxAllowedFileSizeOk) { return XFileStatus.SIZE_EXCEEDED; } // // Check Max Files Size Ok ... const isMaxAllowedSizeOk = await this.isMaxAllowedSizeOk(file); if (!isMaxAllowedSizeOk) { return XFileStatus.MAX_ALLOWED_SIZE_REACHED; } // // Check Max Files Ok ... const isMaxAllowedFilesOk = await this.isMaxAllowedFilesOk( this.inputFiles.length + 1 ); if (!isMaxAllowedFilesOk) { return XFileStatus.MAX_ALLOWED_FILES_REACHED; } // // Everythings Ok ... return XFileStatus.OK; } /** * recieve file status and act based of it (notifiy when exception) ... * * @param status File Status for Add ... */ private async handleFileStatusForAdd(status: XFileStatus) { // let identifier: XExceptionIdentifier = null; switch (status) { // case XFileStatus.EMPTY: identifier = await this.getValueAsync(this.emptyFileException); break; // case XFileStatus.NOT_ALLOWED_TYPE: identifier = await this.getValueAsync(this.notAllowedFileException); break; // case XFileStatus.SIZE_EXCEEDED: identifier = await this.getValueAsync(this.maxAllowedFileSizeException); break; // case XFileStatus.MAX_ALLOWED_SIZE_REACHED: identifier = await this.getValueAsync(this.maxAllowedSizeException); break; // case XFileStatus.MAX_ALLOWED_FILES_REACHED: identifier = await this.getValueAsync(this.maxAllowedFilesException); break; // case XFileStatus.MIN_SIZE_NOT_REACHED: identifier = await this.getValueAsync(this.minAllowedFileSizeException); break; } // const exception = getErrorException(identifier); if (exception) { this.managerService.notificationService.presentErrorNotification({ exception, dissmissable: true, }); } } private handleChangeDetection() { // if (this.listActionProvider) { this.listActionProvider.next({ action: XListAction.Refresh, }); } // if (this.fileDropAreaActionProvider) { this.fileDropAreaActionProvider.next({ action: XFileDropAreaAction.Refresh, }); } // this.detectChanges(); } // //#region ActionBar Preparations ... private async prepareActionBarActions() { // //#region Prepare Default Actions ... const hideActions = await this.getArrayValueAsync( this.actionBarHideActions ); // const defaultActions: XOneOrManyType = []; // // Add ... const addId = DefaultActionBarItemIds.Add.toString(); if (!hideActions.includes(addId)) { defaultActions.push({ // ...defaultActionBarAddItem, // index: 1, disabled: this.addDisablerSubject.asObservable(), // handler: () => { this.selectFiles(); }, }); } // // Upload ... const uploadId = DefaultActionBarItemIds.Upload.toString(); if (!hideActions.includes(uploadId)) { defaultActions.push({ // ...defaultActionBarUploadItem, // index: 2, disabled: this.uploadDisablerSubject.asObservable(), }); } // // Remove ... const removeId = DefaultActionBarItemIds.Remove.toString(); if (!hideActions.includes(removeId)) { defaultActions.push({ // ...defaultActionBarRemoveItem, // index: 3, disabled: this.removeDisablerSubject.asObservable(), }); } // // Select All ... const selectAllId = DefaultActionBarItemIds.SelectAll.toString(); if (!hideActions.includes(selectAllId)) { defaultActions.push({ // ...defaultActionBarSelectAllItem, // index: 4, disabled: this.selectAllDisablerSubject.asObservable(), }); } // // Inverse Selection ... const inverseSelectionId = DefaultActionBarItemIds.InverseSelection.toString(); if (!hideActions.includes(inverseSelectionId)) { defaultActions.push({ // ...defaultActionBarInverseSelectionItem, // index: 5, disabled: this.inverseSelectionDisablerSubject.asObservable(), }); } // // De Select All ... const deselectAllId = DefaultActionBarItemIds.DeSelectAll.toString(); if (!hideActions.includes(deselectAllId)) { defaultActions.push({ // ...defaultActionBarDeSelectAllItem, // index: 6, disabled: this.deSelectAllDisablerSubject.asObservable(), }); } //#endregion // if (!this.actionBarActions) { // this.actionBarActions = defaultActions; this.handleChangeDetection(); return; } // const actions = await this.getArrayValueAsync(this.actionBarActions); if (!hasChild(actions)) { // this.actionBarActions = defaultActions; this.handleChangeDetection(); return; } // this.actionBarActions = actions; this.handleChangeDetection(); } private async prepareActionBarActionsSubjects(items: XListItem[]) { // // Check Can Add ... const canAdd = await this.canAddFile(); if (canAdd) { this.addDisablerSubject.next(false); } else { this.addDisablerSubject.next(true); } // // Check Select All ... if (!hasChild(this.fileListItems)) { // this.addDisablerSubject.next(false); this.uploadDisablerSubject.next(true); this.removeDisablerSubject.next(true); this.selectAllDisablerSubject.next(true); this.deSelectAllDisablerSubject.next(true); this.inverseSelectionDisablerSubject.next(true); } else { // this.uploadDisablerSubject.next(false); // // DeSelectAll ... if (!hasChild(items)) { // this.removeDisablerSubject.next(true); this.deSelectAllDisablerSubject.next(true); this.inverseSelectionDisablerSubject.next(true); } else { // this.removeDisablerSubject.next(false); this.deSelectAllDisablerSubject.next(false); this.inverseSelectionDisablerSubject.next(false); } // if (this.fileListItems.length === items.length) { // this.selectAllDisablerSubject.next(true); this.inverseSelectionDisablerSubject.next(true); } else { this.selectAllDisablerSubject.next(false); } } // this.handleChangeDetection(); } //#endregion // //#region Handler Registerrers ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XFileUploadAction.SELECT_FILES: this.selectFiles(); break; // case XFileUploadAction.CLEAR_LIST: await this.handleRemoveItems({ items: this.files, }); break; // case XFileUploadAction.SYNC_LIST: await this.handleSyncFiles(model.payload); break; // case XFileUploadAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // //#region List Handlers ... private async getListItem(item: any) { // if (!item) { return null; } // const result: XListItem = { data: item, disabled: this.uiDisabled, slideOptions: [ { id: 'delete_file', icon: XIconNames.remove, title: this.ResourceIDs.delete, color: XColor.Danger, onlyIcon: true, disabled: this.uiDisabled, slot: 'end', handler: async () => { await this.confirmAndRemove(item); }, }, ], }; // return result; } private isValidDataSource() { return hasChild(this.inputFiles); } private addToDataSource(item: XListItem) { this.fileListItems.push(item); } private changeDataSourceItem(item: XListItem) { // const index = this.fileListItems.findIndex((i) => i.data === item.data); if (index === -1) { return; } // this.fileListItems[index] = item; } private async clearListItems() { this.fileListItems = null; this.fileListItems = []; } private async refreshListItems(forceClean = false) { // if (forceClean) { await this.clearListItems(); } // if (!this.isValidDataSource()) { return; } // for (const f of this.inputFiles) { // const fListItem = await this.getListItem(f); // if (forceClean) { this.addToDataSource(fListItem); } else { this.changeDataSourceItem(fListItem); } } } private async confirmAndRemove(items: XOneOrManyType) { // if (!items) { return; } // const extractedItems: File[] = !items ? [] : isArray(items) ? (items as File[]) : [items as File]; const removeRequest: XBaseRangeRequestDto = { items: [...extractedItems], }; // const confirmRemove = await this.getValueAsync(this.listConfirmRemove); if (confirmRemove) { await this.managerService.dialogService.presentAreYouSureYesNoDialog( () => { this.handleRemoveItems(removeRequest); } ); } else { this.handleRemoveItems(removeRequest); } } //#endregion // //#region Color Appliers ... private async applyColor() { // const color = await this.getValueAsync(this.color); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFileUploadCssVars.HostBgColor, `var(${bgColor})`); // this.handleChangeDetection(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XListModule } from '../x-list/x-list.module'; import { XFileUploadComponent } from './x-file-upload.component'; import { XThumbnailModule } from '../x-thumbnail/x-thumbnail.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XFileDropAreaModule } from '../x-file-drop-area/x-file-drop-area.module'; @NgModule({ declarations: [XFileUploadComponent], imports: [ XCardModule, XListModule, CommonModule, XThumbnailModule, XFileDropAreaModule, XBaseComponentModule, ], exports: [ XCardModule, XListModule, XThumbnailModule, XFileDropAreaModule, XBaseComponentModule, XFileUploadComponent, ], }) export class XFileUploadModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-file-upload\x-file-upload.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, Injectable, ElementRef, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { hasChild, XFileBlob, XStandardType, XOneOrManyType, toNormalString, XColorIdentifier, fileToJsonString, XResourceIdentifier, XColorWithBrightness, XExceptionIdentifier, } from 'x-framework-core'; import { XListItem, XListFilteringHandler, XComponentListContainer, IXComponentListContainer, } from '../x-list/x-list.typings'; import { XCardActionModel, XComponentCardContainer, IXComponentCardContainer, } from '../x-card/x-card.typings'; import { XEmptyActionModel, XComponentEmptyContainer, IXComponentEmptyContainer, } from '../x-empty/x-empty.typings'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { XActionBarItem, XActionBarActionModel, XActionBarActionIdentifier, XActionBarActionFiredModel, XComponentActionBarContainer, IXComponentActionBarContainer, } from '../x-action-bar/x-action-bar.typings'; import { XSearchBarActionModel, XSearchBarTypeIdentifier, XComponentSearchBarContainer, IXComponentSearchBarContainer, } from '../x-search-bar/x-search-bar.typings'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XFileDropAreaActionModel, XComponentFileDropAreaContainer, IXComponentFileDropAreaContainer, } from '../x-file-drop-area/x-file-drop-area.typings'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { IXFileContainer, XFileContainer } from '../classes/i-x-file.container'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XFileStatus { OK = 'ok', EMPTY = 'empty', SIZE_EXCEEDED = 'size_exceeded', NOT_ALLOWED_TYPE = 'not_allowed_type', MIN_SIZE_NOT_REACHED = 'min_size_not_reached', MAX_ALLOWED_FILES_REACHED = 'max_allowed_files_reached', MAX_ALLOWED_SIZE_REACHED = 'max_allowed_size_reached', } export type XFileStatusIdentifier = XFileStatus | string; export enum XFileUploadAction { SELECT_FILES = 'select_files', CLEAR_LIST = 'clear_list', SYNC_LIST = 'sync_list', // Refresh = 'refresh', } export type XFileUploadActionIdentifier = XFileUploadAction | string; export interface XFileUploadActionModel extends XBaseActionModel {} export const defaultFileUploadListFilteringHandler: XListFilteringHandler = ( query: string, items: XListItem[] ) => { // if (!query || !hasChild(items)) { return []; } // return items.filter((i) => toNormalString(fileToJsonString(i.data)).includes(toNormalString(query)) ); }; export enum XFileUploadCssVars { HostBgColor = 'host-bg-color', } // //#region Container ... // type TXFileUploadContainer = IXComponentCardContainer & Partial & Partial & IXComponentActionBarContainer & IXComponentSearchBarContainer & IXComponentEmptyContainer & IXFileContainer; export interface IXFileUploadContainer extends IXBaseContainer, TXFileUploadContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; // fileChange: EventEmitter>; // actionBarHideActions: XStandardType< XOneOrManyType >; } @Injectable({ providedIn: 'root', }) export class XFileUploadContainer extends XBaseContainer implements Readonly { // //#region Props ... // //#region Self ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly fileChange: EventEmitter> = new EventEmitter< XOneOrManyType >(); readonly actionBarHideActions: XStandardType< XOneOrManyType >; //#endregion // //#region File Drop Props ... // readonly showFileDropArea: XStandardType = this.fileDropAreaPropertyProvider.showFileDropArea; // readonly fileDropAreaActionProvider: Subject = this.fileDropAreaPropertyProvider.fileDropAreaActionProvider; readonly fileDropAreaCssClass: XStandardType> = this.fileDropAreaPropertyProvider.fileDropAreaCssClass; // readonly fileDropAreaColor: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaColor; readonly fileDropAreaForegroundColor: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaForegroundColor; // readonly fileDropAreaIcon: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaIcon; readonly fileDropAreaMessage: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaMessage; // readonly fileDropAreaDisableFileCheck: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaDisableFileCheck; // readonly fileDropAreaSupportsMultipleFiles: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaSupportsMultipleFiles; readonly fileDropAreaAllowedExtensions: XStandardType< XOneOrManyType > = this.fileDropAreaPropertyProvider.fileDropAreaAllowedExtensions; // readonly fileDropAreaDragDisabled: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaDragDisabled; readonly fileDropAreaContentTemplate: TemplateRef = this.fileDropAreaPropertyProvider.fileDropAreaContentTemplate; readonly fileDropAreaFilesChangeEmiter: EventEmitter> = this.fileDropAreaPropertyProvider.fileDropAreaFilesChangeEmiter; // readonly fileDropAreaSuccessColor: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaSuccessColor; readonly fileDropAreaErrorColor: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaErrorColor; readonly fileDropAreaAccentColor: XStandardType = this.fileDropAreaPropertyProvider.fileDropAreaAccentColor; //#endregion // //#region Card Props ... readonly isInPage: XStandardType = this.cardPropertyProvider.isInPage; readonly wrapWithCard: XStandardType = this.cardPropertyProvider.wrapWithCard; readonly cardActionProvider: Subject = this.cardPropertyProvider.cardActionProvider; readonly cardCssClass: XStandardType> = this.cardPropertyProvider.cardCssClass; readonly cardColor: XStandardType = this.cardPropertyProvider.cardColor; readonly cardForegroundColor: XStandardType = this.cardPropertyProvider.cardForegroundColor; readonly cardTitle: XStandardType = this.cardPropertyProvider.cardTitle; readonly cardSubTitle: XStandardType = this.cardPropertyProvider.cardSubTitle; readonly cardShowFooter: XStandardType = this.cardPropertyProvider.cardShowFooter; readonly cardShowActions: XStandardType = this.cardPropertyProvider.cardShowActions; //#endregion // //#region List Props ... readonly showList: XStandardType = this.listPropertyProvider.showList; readonly listConfirmRemove: XStandardType = this.listPropertyProvider.listConfirmRemove; readonly listActionProvider = this.listPropertyProvider.listActionProvider; readonly listCssClass: XStandardType> = this.listPropertyProvider.listCssClass; readonly listShowToolbar: XStandardType = true; readonly listStickyToolbar: XStandardType = this.listPropertyProvider.listStickyToolbar; readonly listEnableReordering: XStandardType = this.listPropertyProvider.listEnableReordering; readonly listShowDivider: XStandardType = this.listPropertyProvider.listShowDivider; readonly listFilteringHandler: XListFilteringHandler = this.listPropertyProvider.listFilteringHandler; //#endregion // //#region ActionBar ... // readonly showActionBar: XStandardType = true; // readonly actionBarActionProvider: Subject = this.actionBarPropertyProvider.actionBarActionProvider; readonly actionBarCssClass: XStandardType> = this.actionBarPropertyProvider.actionBarCssClass; // readonly actionBarColor: XStandardType = this.actionBarPropertyProvider.actionBarColor; readonly actionBarForegroundColor: XStandardType = this.actionBarPropertyProvider.actionBarForegroundColor; // readonly actionBarActions: XStandardType> = this.actionBarPropertyProvider.actionBarActions; // readonly actionBarActionFired: EventEmitter = this.actionBarPropertyProvider.actionBarActionFired; //#endregion // //#region SearchBar ... // readonly showSearchBar: XStandardType = this.searchBarPropertyProvider.showSearchBar; // readonly searchBarActionProvider: Subject = this.searchBarPropertyProvider.searchBarActionProvider; readonly searchBarCssClass: XStandardType> = this.searchBarPropertyProvider.searchBarCssClass; // readonly searchBarColor: XStandardType = this.searchBarPropertyProvider.searchBarColor; readonly searchBarForegroundColor: XStandardType = this.searchBarPropertyProvider.searchBarForegroundColor; // readonly searchBarSearchInputColor: XStandardType = this.searchBarPropertyProvider.searchBarSearchInputColor; readonly searchBarForegroundSearchInputColor: XStandardType = this.searchBarPropertyProvider.searchBarForegroundSearchInputColor; // readonly searchBarType: XStandardType = this.searchBarPropertyProvider.searchBarType; readonly searchBarTitle: XStandardType = this.searchBarPropertyProvider.searchBarTitle; readonly searchBarValue: XStandardType = this.searchBarPropertyProvider.searchBarValue; readonly searchBarEnterKeyHint: XStandardType = this.searchBarPropertyProvider.searchBarEnterKeyHint; readonly searchBarKeyboardType: XStandardType = this.searchBarPropertyProvider.searchBarKeyboardType; readonly searchBarSpellcheck: XStandardType = this.searchBarPropertyProvider.searchBarSpellcheck; readonly searchBarDebounce: XStandardType = this.searchBarPropertyProvider.searchBarDebounce; // readonly searchBarShowCancelButton: XStandardType = this.searchBarPropertyProvider.searchBarShowCancelButton; readonly searchBarCancelButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonIcon; readonly searchBarCancelButtonTitle: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonTitle; readonly searchBarCancelButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonIconColor; // readonly searchBarShowClearButton: XStandardType = this.searchBarPropertyProvider.searchBarShowClearButton; readonly searchBarClearButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarClearButtonIcon; readonly searchBarClearButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarClearButtonIconColor; // readonly searchBarSearchButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarSearchButtonIcon; readonly searchBarSearchButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarSearchButtonIconColor; // readonly searchBarQueryChange: EventEmitter = this.searchBarPropertyProvider.searchBarQueryChange; readonly searchBarOnEvent: EventEmitter = this.searchBarPropertyProvider.searchBarOnEvent; //#endregion // //#region Empty Props ... readonly showEmpty: XStandardType = this.emptyPropertyProvider.showEmpty; readonly emptyActionProvider: Subject = this.emptyPropertyProvider.emptyActionProvider; readonly emptyCssClass: XStandardType> = this.emptyPropertyProvider.emptyCssClass; readonly emptyColor: XStandardType = this.emptyPropertyProvider.emptyColor; readonly emptyForegroundColor: XStandardType = this.emptyPropertyProvider.emptyForegroundColor; readonly emptyMessage: XStandardType = this.emptyPropertyProvider.emptyMessage; readonly emptyMessageColor: XStandardType = this.emptyPropertyProvider.emptyMessageColor; readonly emptyForegroundMessageColor: XStandardType = this.emptyPropertyProvider.emptyForegroundMessageColor; readonly emptyHasRefresh: XStandardType = this.emptyPropertyProvider.emptyHasRefresh; readonly emptyRefreshButtonColor: XStandardType = this.emptyPropertyProvider.emptyRefreshButtonColor; readonly emptyForegroundRefreshButtonColor: XStandardType = this.emptyPropertyProvider.emptyForegroundRefreshButtonColor; readonly emptyRefreshIcon: XStandardType = this.emptyPropertyProvider.emptyRefreshIcon; readonly emptyRefresh: EventEmitter = this.emptyPropertyProvider.emptyRefresh; //#endregion // //#region File Props ... readonly emptyFileException: XStandardType = this.filePropertyProvider.emptyFileException; readonly notAllowedFileException: XStandardType = this.filePropertyProvider.notAllowedFileException; readonly allowedExtensions: XStandardType> = this.filePropertyProvider.allowedExtensions; readonly maxAllowedFiles: XStandardType = this.filePropertyProvider.maxAllowedFiles; readonly maxAllowedFilesException: XStandardType = this.filePropertyProvider.maxAllowedFilesException; readonly maxAllowedSize: XStandardType = this.filePropertyProvider.maxAllowedSize; readonly maxAllowedSizeException: XStandardType = this.filePropertyProvider.maxAllowedSizeException; readonly minAllowedFileSize: XStandardType = this.filePropertyProvider.minAllowedFileSize; readonly minAllowedFileSizeException: XStandardType = this.filePropertyProvider.minAllowedFileSizeException; readonly maxAllowedFileSize: XStandardType = this.filePropertyProvider.maxAllowedFileSize; readonly maxAllowedFileSizeException: XStandardType = this.filePropertyProvider.maxAllowedFileSizeException; //#endregion //#endregion // //#region Constructor ... constructor( protected filePropertyProvider: XFileContainer, protected cardPropertyProvider: XComponentCardContainer, protected listPropertyProvider: XComponentListContainer, protected emptyPropertyProvider: XComponentEmptyContainer, protected actionBarPropertyProvider: XComponentActionBarContainer, protected searchBarPropertyProvider: XComponentSearchBarContainer, protected fileDropAreaPropertyProvider: XComponentFileDropAreaContainer ) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XFileUploadContainerComponent extends XBaseContainerComponent implements IXFileUploadContainer { // //#region Props ... // //#region Self ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Output() fileChange: EventEmitter> = new EventEmitter(); @Input() actionBarHideActions: XStandardType< XOneOrManyType > = this.propertyProvider.actionBarHideActions; //#endregion // //#region File Drop Props ... // @Input() showFileDropArea: XStandardType = this.propertyProvider.showFileDropArea; // @Input() fileDropAreaActionProvider: Subject = this.propertyProvider.fileDropAreaActionProvider; @Input() fileDropAreaCssClass: XStandardType> = this.propertyProvider.fileDropAreaCssClass; // @Input() fileDropAreaColor: XStandardType = this.propertyProvider.fileDropAreaColor; @Input() fileDropAreaForegroundColor: XStandardType = this.propertyProvider.fileDropAreaForegroundColor; // @Input() fileDropAreaIcon: XStandardType = this.propertyProvider.fileDropAreaIcon; @Input() fileDropAreaMessage: XStandardType = this.propertyProvider.fileDropAreaMessage; // @Input() fileDropAreaDisableFileCheck: XStandardType = this.propertyProvider.fileDropAreaDisableFileCheck; // @Input() fileDropAreaSupportsMultipleFiles: XStandardType = this.propertyProvider.fileDropAreaSupportsMultipleFiles; @Input() fileDropAreaAllowedExtensions: XStandardType> = this.propertyProvider.fileDropAreaAllowedExtensions; // @Input() fileDropAreaDragDisabled: XStandardType = this.propertyProvider.fileDropAreaDragDisabled; @Input() fileDropAreaContentTemplate: TemplateRef = this.propertyProvider.fileDropAreaContentTemplate; @Output() fileDropAreaFilesChangeEmiter: EventEmitter> = new EventEmitter(); // @Input() fileDropAreaSuccessColor: XStandardType = this.propertyProvider.fileDropAreaSuccessColor; @Input() fileDropAreaErrorColor: XStandardType = this.propertyProvider.fileDropAreaErrorColor; @Input() fileDropAreaAccentColor: XStandardType = this.propertyProvider.fileDropAreaAccentColor; //#endregion // //#region Card Props ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; //#endregion // //#region List Props ... @Input() showList: XStandardType = this.propertyProvider.showList; @Input() listConfirmRemove: XStandardType = this.propertyProvider.listConfirmRemove; @Input() listActionProvider = this.propertyProvider.listActionProvider; @Input() listCssClass: XStandardType> = this.propertyProvider.listCssClass; @Input() listShowToolbar: XStandardType = this.propertyProvider.listShowToolbar; @Input() listStickyToolbar: XStandardType = this.propertyProvider.listStickyToolbar; @Input() listEnableReordering: XStandardType = this.propertyProvider.listEnableReordering; @Input() listShowDivider: XStandardType = this.propertyProvider.listShowDivider; @Input() listFilteringHandler: XListFilteringHandler = this.propertyProvider.listFilteringHandler; //#endregion // //#region ActionBar ... // @Input() showActionBar: XStandardType = this.propertyProvider.showActionBar; // @Input() actionBarActionProvider: Subject = this.propertyProvider.actionBarActionProvider; @Input() actionBarCssClass: XStandardType> = this.propertyProvider.actionBarCssClass; // @Input() actionBarColor: XStandardType = this.propertyProvider.actionBarColor; @Input() actionBarForegroundColor: XStandardType = this.propertyProvider.actionBarForegroundColor; // @Input() actionBarActions: XStandardType> = this.propertyProvider.actionBarActions; // @Output() actionBarActionFired: EventEmitter = new EventEmitter(); //#endregion // //#region SearchBar ... // @Input() showSearchBar: XStandardType = this.propertyProvider.showSearchBar; // @Input() searchBarActionProvider: Subject = this.propertyProvider.searchBarActionProvider; @Input() searchBarCssClass: XStandardType> = this.propertyProvider.searchBarCssClass; // @Input() searchBarColor: XStandardType = this.propertyProvider.searchBarColor; @Input() searchBarForegroundColor: XStandardType = this.propertyProvider.searchBarForegroundColor; // @Input() searchBarSearchInputColor: XStandardType = this.propertyProvider.searchBarSearchInputColor; @Input() searchBarForegroundSearchInputColor: XStandardType = this.propertyProvider.searchBarForegroundSearchInputColor; // @Input() searchBarType: XStandardType = this.propertyProvider.searchBarType; @Input() searchBarTitle: XStandardType = this.propertyProvider.searchBarTitle; @Input() searchBarValue: XStandardType = this.propertyProvider.searchBarValue; @Input() searchBarEnterKeyHint: XStandardType = this.propertyProvider.searchBarEnterKeyHint; @Input() searchBarKeyboardType: XStandardType = this.propertyProvider.searchBarKeyboardType; @Input() searchBarSpellcheck: XStandardType = this.propertyProvider.searchBarSpellcheck; @Input() searchBarDebounce: XStandardType = this.propertyProvider.searchBarDebounce; // @Input() searchBarShowCancelButton: XStandardType = this.propertyProvider.searchBarShowCancelButton; @Input() searchBarCancelButtonIcon: XStandardType = this.propertyProvider.searchBarCancelButtonIcon; @Input() searchBarCancelButtonTitle: XStandardType = this.propertyProvider.searchBarCancelButtonTitle; @Input() searchBarCancelButtonIconColor: XStandardType = this.propertyProvider.searchBarCancelButtonIconColor; // @Input() searchBarShowClearButton: XStandardType = this.propertyProvider.searchBarShowClearButton; @Input() searchBarClearButtonIcon: XStandardType = this.propertyProvider.searchBarClearButtonIcon; @Input() searchBarClearButtonIconColor: XStandardType = this.propertyProvider.searchBarClearButtonIconColor; // @Input() searchBarSearchButtonIcon: XStandardType = this.propertyProvider.searchBarSearchButtonIcon; @Input() searchBarSearchButtonIconColor: XStandardType = this.propertyProvider.searchBarSearchButtonIconColor; // @Output() searchBarQueryChange: EventEmitter = new EventEmitter(); @Output() searchBarOnEvent: EventEmitter = new EventEmitter(); //#endregion // //#region Empty Props ... @Input() showEmpty: XStandardType = this.propertyProvider.showEmpty; @Input() emptyActionProvider: Subject = this.propertyProvider.emptyActionProvider; @Input() emptyCssClass: XStandardType> = this.propertyProvider.emptyCssClass; @Input() emptyColor: XStandardType = this.propertyProvider.emptyColor; @Input() emptyForegroundColor: XStandardType = this.propertyProvider.emptyForegroundColor; @Input() emptyMessage: XStandardType = this.propertyProvider.emptyMessage; @Input() emptyMessageColor: XStandardType = this.propertyProvider.emptyMessageColor; @Input() emptyForegroundMessageColor: XStandardType = this.propertyProvider.emptyForegroundMessageColor; @Input() emptyHasRefresh: XStandardType = this.propertyProvider.emptyHasRefresh; @Input() emptyRefreshButtonColor: XStandardType = this.propertyProvider.emptyRefreshButtonColor; @Input() emptyForegroundRefreshButtonColor: XStandardType = this.propertyProvider.emptyForegroundRefreshButtonColor; @Input() emptyRefreshIcon: XStandardType = this.propertyProvider.emptyRefreshIcon; @Output() emptyRefresh: EventEmitter = new EventEmitter(); //#endregion // //#region File Props ... @Input() emptyFileException: XStandardType = this.propertyProvider.emptyFileException; @Input() notAllowedFileException: XStandardType = this.propertyProvider.notAllowedFileException; @Input() allowedExtensions: XStandardType> = this.propertyProvider.allowedExtensions; @Input() maxAllowedFiles: XStandardType = this.propertyProvider.maxAllowedFiles; @Input() maxAllowedFilesException: XStandardType = this.propertyProvider.maxAllowedFilesException; @Input() maxAllowedSize: XStandardType = this.propertyProvider.maxAllowedSize; @Input() maxAllowedSizeException: XStandardType = this.propertyProvider.maxAllowedSizeException; @Input() minAllowedFileSize: XStandardType = this.propertyProvider.minAllowedFileSize; @Input() minAllowedFileSizeException: XStandardType = this.propertyProvider.minAllowedFileSizeException; @Input() maxAllowedFileSize: XStandardType = this.propertyProvider.maxAllowedFileSize; @Input() maxAllowedFileSizeException: XStandardType = this.propertyProvider.maxAllowedFileSizeException; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XFileUploadContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXFileUploadContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), actionBarHideActions: this.getValue( container ? container.actionBarHideActions : this.actionBarHideActions ), showFileDropArea: this.getValue( container ? container.showFileDropArea : this.showFileDropArea ), fileDropAreaCssClass: this.getValue( container ? container.fileDropAreaCssClass : this.fileDropAreaCssClass ), fileDropAreaColor: this.getValue( container ? container.fileDropAreaColor : this.fileDropAreaColor ), fileDropAreaForegroundColor: this.getValue( container ? container.fileDropAreaForegroundColor : this.fileDropAreaForegroundColor ), fileDropAreaIcon: this.getValue( container ? container.fileDropAreaIcon : this.fileDropAreaIcon ), fileDropAreaMessage: this.getValue( container ? container.fileDropAreaMessage : this.fileDropAreaMessage ), fileDropAreaDisableFileCheck: this.getValue( container ? container.fileDropAreaDisableFileCheck : this.fileDropAreaDisableFileCheck ), fileDropAreaSupportsMultipleFiles: this.getValue( container ? container.fileDropAreaSupportsMultipleFiles : this.fileDropAreaSupportsMultipleFiles ), fileDropAreaAllowedExtensions: this.getValue( container ? container.fileDropAreaAllowedExtensions : this.fileDropAreaAllowedExtensions ), fileDropAreaDragDisabled: this.getValue( container ? container.fileDropAreaDragDisabled : this.fileDropAreaDragDisabled ), fileDropAreaContentTemplate: this.getValue( container ? container.fileDropAreaContentTemplate : this.fileDropAreaContentTemplate ), fileDropAreaSuccessColor: this.getValue( container ? container.fileDropAreaSuccessColor : this.fileDropAreaSuccessColor ), fileDropAreaErrorColor: this.getValue( container ? container.fileDropAreaErrorColor : this.fileDropAreaErrorColor ), fileDropAreaAccentColor: this.getValue( container ? container.fileDropAreaAccentColor : this.fileDropAreaAccentColor ), isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardCssClass: this.getValue( container ? container.cardCssClass : this.cardCssClass ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), showList: this.getValue(container ? container.showList : this.showList), listConfirmRemove: this.getValue( container ? container.listConfirmRemove : this.listConfirmRemove ), listCssClass: this.getValue( container ? container.listCssClass : this.listCssClass ), listShowToolbar: this.getValue( container ? container.listShowToolbar : this.listShowToolbar ), listStickyToolbar: this.getValue( container ? container.listStickyToolbar : this.listStickyToolbar ), listEnableReordering: this.getValue( container ? container.listEnableReordering : this.listEnableReordering ), listShowDivider: this.getValue( container ? container.listShowDivider : this.listShowDivider ), listFilteringHandler: this.getValue( container ? container.listFilteringHandler : this.listFilteringHandler ), showActionBar: this.getValue( container ? container.showActionBar : this.showActionBar ), actionBarCssClass: this.getValue( container ? container.actionBarCssClass : this.actionBarCssClass ), actionBarColor: this.getValue( container ? container.actionBarColor : this.actionBarColor ), actionBarForegroundColor: this.getValue( container ? container.actionBarForegroundColor : this.actionBarForegroundColor ), actionBarActions: this.getValue( container ? container.actionBarActions : this.actionBarActions ), showSearchBar: this.getValue( container ? container.showSearchBar : this.showSearchBar ), searchBarCssClass: this.getValue( container ? container.searchBarCssClass : this.searchBarCssClass ), searchBarColor: this.getValue( container ? container.searchBarColor : this.searchBarColor ), searchBarForegroundColor: this.getValue( container ? container.searchBarForegroundColor : this.searchBarForegroundColor ), searchBarSearchInputColor: this.getValue( container ? container.searchBarSearchInputColor : this.searchBarSearchInputColor ), searchBarForegroundSearchInputColor: this.getValue( container ? container.searchBarForegroundSearchInputColor : this.searchBarForegroundSearchInputColor ), searchBarType: this.getValue( container ? container.searchBarType : this.searchBarType ), searchBarTitle: this.getValue( container ? container.searchBarTitle : this.searchBarTitle ), searchBarValue: this.getValue( container ? container.searchBarValue : this.searchBarValue ), searchBarEnterKeyHint: this.getValue( container ? container.searchBarEnterKeyHint : this.searchBarEnterKeyHint ), searchBarKeyboardType: this.getValue( container ? container.searchBarKeyboardType : this.searchBarKeyboardType ), searchBarSpellcheck: this.getValue( container ? container.searchBarSpellcheck : this.searchBarSpellcheck ), searchBarDebounce: this.getValue( container ? container.searchBarDebounce : this.searchBarDebounce ), searchBarShowCancelButton: this.getValue( container ? container.searchBarShowCancelButton : this.searchBarShowCancelButton ), searchBarCancelButtonIcon: this.getValue( container ? container.searchBarCancelButtonIcon : this.searchBarCancelButtonIcon ), searchBarCancelButtonTitle: this.getValue( container ? container.searchBarCancelButtonTitle : this.searchBarCancelButtonTitle ), searchBarCancelButtonIconColor: this.getValue( container ? container.searchBarCancelButtonIconColor : this.searchBarCancelButtonIconColor ), searchBarShowClearButton: this.getValue( container ? container.searchBarShowClearButton : this.searchBarShowClearButton ), searchBarClearButtonIcon: this.getValue( container ? container.searchBarClearButtonIcon : this.searchBarClearButtonIcon ), searchBarClearButtonIconColor: this.getValue( container ? container.searchBarClearButtonIconColor : this.searchBarClearButtonIconColor ), searchBarSearchButtonIcon: this.getValue( container ? container.searchBarSearchButtonIcon : this.searchBarSearchButtonIcon ), searchBarSearchButtonIconColor: this.getValue( container ? container.searchBarSearchButtonIconColor : this.searchBarSearchButtonIconColor ), showEmpty: this.getValue( container ? container.showEmpty : this.showEmpty ), emptyCssClass: this.getValue( container ? container.emptyCssClass : this.emptyCssClass ), emptyColor: this.getValue( container ? container.emptyColor : this.emptyColor ), emptyForegroundColor: this.getValue( container ? container.emptyForegroundColor : this.emptyForegroundColor ), emptyMessage: this.getValue( container ? container.emptyMessage : this.emptyMessage ), emptyMessageColor: this.getValue( container ? container.emptyMessageColor : this.emptyMessageColor ), emptyForegroundMessageColor: this.getValue( container ? container.emptyForegroundMessageColor : this.emptyForegroundMessageColor ), emptyHasRefresh: this.getValue( container ? container.emptyHasRefresh : this.emptyHasRefresh ), emptyRefreshButtonColor: this.getValue( container ? container.emptyRefreshButtonColor : this.emptyRefreshButtonColor ), emptyForegroundRefreshButtonColor: this.getValue( container ? container.emptyForegroundRefreshButtonColor : this.emptyForegroundRefreshButtonColor ), emptyRefreshIcon: this.getValue( container ? container.emptyRefreshIcon : this.emptyRefreshIcon ), emptyFileException: this.getValue( container ? container.emptyFileException : this.emptyFileException ), notAllowedFileException: this.getValue( container ? container.notAllowedFileException : this.notAllowedFileException ), allowedExtensions: this.getValue( container ? container.allowedExtensions : this.allowedExtensions ), maxAllowedFiles: this.getValue( container ? container.maxAllowedFiles : this.maxAllowedFiles ), maxAllowedFilesException: this.getValue( container ? container.maxAllowedFilesException : this.maxAllowedFilesException ), maxAllowedSize: this.getValue( container ? container.maxAllowedSize : this.maxAllowedSize ), maxAllowedSizeException: this.getValue( container ? container.maxAllowedSizeException : this.maxAllowedSizeException ), minAllowedFileSize: this.getValue( container ? container.minAllowedFileSize : this.minAllowedFileSize ), minAllowedFileSizeException: this.getValue( container ? container.minAllowedFileSizeException : this.minAllowedFileSizeException ), maxAllowedFileSize: this.getValue( container ? container.maxAllowedFileSize : this.maxAllowedFileSize ), maxAllowedFileSizeException: this.getValue( container ? container.maxAllowedFileSizeException : this.maxAllowedFileSizeException ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // fileChange: this.fileChange, // fileDropAreaActionProvider: container ? container.fileDropAreaActionProvider : this.fileDropAreaActionProvider, // fileDropAreaFilesChangeEmiter: this.fileDropAreaFilesChangeEmiter, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, // listActionProvider: container ? container.listActionProvider : this.listActionProvider, // actionBarActionProvider: container ? container.actionBarActionProvider : this.actionBarActionProvider, // actionBarActionFired: this.actionBarActionFired, // searchBarActionProvider: container ? container.searchBarActionProvider : this.searchBarActionProvider, // searchBarQueryChange: this.searchBarQueryChange, searchBarOnEvent: this.searchBarOnEvent, // emptyActionProvider: container ? container.emptyActionProvider : this.emptyActionProvider, // emptyRefresh: this.emptyRefresh, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.component.html
{{ getControlLabel(control) | async }}
{{ getControlLabel(control) | async }} {{ getResourceValue(option.viewValue) | async }}
{{ getResourceValue(option.viewValue) | async }}
{{ getResourceValue(option.viewValue) | async }}
{{ getControlLabel(control) | async }}
{{ getControlLabel(control) | async }}
{{ getErrorHandlerErrorMessage(handler) | async }}
{{ getControlHint(control) | async }}
{{ getErrorHandlerErrorMessage(handler, control) | async }}
{{ getControlLabel(control) | async }} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.component.scss // :host { // --regular-color: var(--x-color-dark); --valid-color: var(--x-color-success); --hint-color: var(--x-color-tertiary); --invalid-color: var(--x-color-danger); --active-color: var(--x-color-tertiary); --pending-color: var(--x-color-warning); --disabled-color: var(--x-color-medium); --accent-color: var(--x-color-secondary); --fill-color: var(--x-color-secondary-tint); --disabled-fill-color: var(--x-color-light-shade); // --hint-text-size: 7pt; --error-text-size: 7pt; // --form-fields-vertical-margin: 16px; } // //#region Mixins ... // @mixin formFieldRegularProps { // x-icon { --size: 20px; } // .x-field-label { } // .auto-size-flex { flex: 0 0 auto !important; } // .full-heigh { * { height: 100%; } } } @mixin formInputElementProps { // .mat-input-element { @include colorHandler(var(--regular-color), false); } // .x-form-input-element { width: 100%; border: unset; outline: unset; border-color: transparent; // &:focus { // outline: var(--active-color) auto 1px; } // @include colorHandler(var(--regular-color), false); @include backgroundColorHandler(transparent, false); } // .x-form-date-input-element, .x-form-input-element:not(.mat-input-element) { height: 100% !important; } } @mixin formFieldHintProps( $color: var(--hint-color), $size: var(--hint-text-size) ) { .x-form-control-hint { // color: $color; font-size: $size; } } @mixin formFieldErrorProps( $color: var(--invalid-color), $size: var(--error-text-size) ) { // // $duration: 250ms; $transform-show: scaleY(1); $transform-hide: scaleY(0); .x-form-error, .x-form-field-error { // color: $color; font-size: $size; // height: 0; // transform: $transform-hide; -ms-transform: $transform-hide; -webkit-transform: $transform-hide; // transition: transform; -webkit-transition: transform; // transition-duration: $duration; -webkit-transition-duration: $duration; // &.show { // height: auto !important; // transform: $transform-show; -ms-transform: $transform-show; -webkit-transform: $transform-show; // transition-duration: $duration; -webkit-transition-duration: $duration; } } } @mixin formFieldProps { // .x-form-field { // @include dateProps; @include sliderProps; @include radioButtonProps; @include selectOptionProps; @include toogleColorHandler; @include checkBoxColorHandler; @include formFieldRegularProps; @include formInputElementProps; @include formFieldAppearanceHandler; @include colorHandler(var(--regular-color), false); @include backgroundColorHandler(transparent !important); // &.x-mat-form-field { // width: 100%; // &.mat-focused { @include formFieldFocusHandler; } } // &.x-form-radio-field { // outline: unset; // &.x-focused { // @include formFieldFocusHandler; @include iconStatusColorHandler(var(--active-color)); } } // &:not(.x-mat-form-field):not(.x-form-radio-field) { // outline: unset; // &.x-focused { // @include formFieldFocusHandler; border-color: var(--active-color); } } } } @mixin autoCompleteProps { /* Auto Complete Styling */ // $duration: 250ms; $transform-show: scaleY(1); $transform-hide: scaleY(0); .x-auto-complete-wrapper { position: unset; display: unset; } .x-auto-complete { // position: content; // &.x-auto-complete-margin { margin-top: 0; } // height: calc(50%); max-height: 300px; // left: 8px; right: 8px; overflow-y: scroll; // z-index: 113; // transform: $transform-hide; -ms-transform: $transform-hide; -webkit-transform: $transform-hide; // transition: transform; -webkit-transition: transform; // transition-duration: $duration; -webkit-transition-duration: $duration; // &.open { // transform: $transform-show; -ms-transform: $transform-show; -webkit-transform: $transform-show; // transition-duration: $duration; -webkit-transition-duration: $duration; } } /* END Auto Complete Styling */ } @mixin selectOptionProps { // .x-select-option { width: 100%; margin-bottom: 4px; &:last-child { margin-bottom: 8px; } } } @mixin dateProps { // .mat-icon-button { display: table-cell; vertical-align: bottom; } } @mixin radioButtonProps($disabled: false) { // .x-radio-button { // @include radioColorHandler(var(--regular-color), true, false); // &.active { // @include radioColorHandler(var(--active-color) !important, true, true); } } &.x-form-radio-field { // outline: unset; // &.x-focused { // .x-field-label { color: var(--active-color) !important; } border-color: var(--active-color) !important; // @include iconStatusColorHandler(var(--active-color)); } } } @mixin formFieldFocusHandler { // .mat-form-field-ripple { @include backgroundColorHandler(var(--active-color) !important, false); } // @include iconStatusColorHandler(var(--active-color)); @include formFieldLabelColorHandler(var(--active-color)); @include formFieldWrapperColorHandler(var(--active-color)); @include matFormFieldOutlineColorHandler(var(--active-color) !important); } @mixin formFieldAppearanceHandler($disabled: false) { // // Label Colors ... @if $disabled { // @include formFieldLabelColorHandler(var(--disabled-color)); // .x-form-field-appearance-fill:not(.x-mat-form-field) { border-color: var(--disabled-fill-color); } // .mat-select-value-text { color: var(--disabled-color) !important; } } // .mat-select-value-text { color: var(--regular-color); } // // None ... .x-form-field-appearance-none { // @if $disabled { @include formFieldLabelColorHandler(var(--disabled-color)); } @else { } } // // Legacy ... // Standard ... .x-form-field-appearance-legacy, .x-form-field-appearance-standard { // @if $disabled { @include matFormFieldUnderlineColorHandler( var(--disabled-fill-color) !important, true ); } @else { @include matFormFieldUnderlineColorHandler(var(--fill-color) !important); } // &:not(.x-mat-form-field) { @if $disabled { } @else { // padding: 8px; border-radius: 0; border-bottom-width: 1px; border-bottom-style: solid; border-color: var(--fill-color); } } } // // Outline ... .x-form-field-appearance-outline { // @if $disabled { @include matFormFieldOutlineColorHandler(var(--disabled-fill-color)); } @else { @include formFieldLabelColorHandler(var(--regular-color)); @include matFormFieldOutlineColorHandler(var(--fill-color)); } // &:not(.x-mat-form-field) { @if $disabled { @include backgroundColorHandler(transaprent!important, false); } @else { // padding: 8px; border-radius: 3px; border-width: 1px; border-style: solid; } } } // // Fill ... .x-form-field-appearance-fill { // &.x-mat-form-field:not(.x-form-field-disabled) { // @if $disabled { // .mat-form-field-flex { @include colorHandler(var(--disabled-fill-color) !important, false); @include backgroundColorHandler( var(--disabled-fill-color) !important, false ); } // @include matFormFieldUnderlineColorHandler(var(--disabled-color)); } @else { // @include backgroundColorHandler(var(--fill-color) !important, false); // .mat-form-field-flex { @include colorHandler(var(--regular-color), false); @include backgroundColorHandler(var(--fill-color) !important, false); } // @include matFormFieldUnderlineColorHandler(var(--accent-color)); } } // @if $disabled { // &.x-form-field-disabled { background-color: var(--disabled-fill-color) !important; } // .mat-form-field-flex { @include colorHandler(var(--disabled-color) !important, false); @include backgroundColorHandler( var(--disabled-fill-color) !important, false ); } // .x-form-slider-control { // .mat-slider-thumb { background-color: var(--disabled-color) !important; } // .mat-slider-wrapper, .mat-slider-track-wrapper { background-color: var(--disabled-color) !important; } } // @include matFormFieldUnderlineColorHandler(var(--disabled-color)); } @else { // .x-form-slider-control { .mat-slider-wrapper, .mat-slider-track-wrapper { background-color: var(--regular-color) !important; } } } // &:not(.x-mat-form-field) { @if $disabled { @include backgroundColorHandler( var(--disabled-fill-color) !important, false ); } @else { // padding: 8px; border-radius: 3px; border-bottom-width: 1px; border-bottom-style: solid; border-bottom-left-radius: 0; border-bottom-right-radius: 0; border-color: var(--regular-color); // @include backgroundColorHandler(var(--fill-color) !important, false); } } } } @mixin formFieldStatusHandler { // // Global ... @include formFieldAppearanceHandler(false); // // Disabled ... &.x-form-field-wrapper-disabled { // * { cursor: default; pointer-events: none; } // x-icon.x-action-icon > * { color: var(--disabled-color) !important; } // .mat-form-field-disabled { color: var(--disabled-color) !important; } // .x-form-input-element { // opacity: 1 !important; border-color: var(--disabled-fill-color) !important; // @include colorHandler(var(--disabled-color) !important, false); } // .x-form-control { opacity: 1 !important; @include colorHandler(var(--disabled-color) !important, false); } // .mat-slide-toggle-bar { background-color: var(--disabled-fill-color) !important; } // @include sliderProps(true); @include formFieldAppearanceHandler(true); @include formFieldHintProps(var(--disabled-color)); @include formFieldErrorProps(var(--disabled-color)); @include checkBoxColorHandler(--disabled-color, true); @include iconStatusColorHandler(var(--disabled-color), true); @include formFieldWrapperColorHandler(var(--disabled-color) !important); @include radioColorHandler(var(--disabled-color) !important, true, true); } // // Valid ... &.x-form-field-wrapper-valid { // @include iconStatusColorHandler(var(--valid-color), true); // &.apply-status { @include formFieldWrapperColorHandler(var(--valid-color)); } } // // Invalid ... &.x-form-field-wrapper-invalid { // @include iconStatusColorHandler(var(--invalid-color), true); // &.apply-status { @include formFieldWrapperColorHandler(var(--invalid-color)); } } // // Pending ... &.x-form-field-wrapper-pending { // @include iconStatusColorHandler(var(--pending-color), true); // &.apply-status { @include formFieldWrapperColorHandler(var(--pending-color)); } } } @mixin colorHandler($color: var(--regular-color), $applyToChilds: true) { color: $color; // @if $applyToChilds { * { :not(x-icon):not(x-icon > *) { color: $color; } } } // @include matFormFieldOutlineColorHandler($color); } @mixin backgroundColorHandler($color: transaprent, $applyToChilds: true) { // background-color: $color; // @if $applyToChilds { *:not(.x-field-label):not(.x-field-label *):not(.mat-form-field-ripple):not(.mat-slide-toggle-thumb):not(.mat-slide-toggle-bar):not(.mat-checkbox-frame):not(.mat-radio-inner-circle):not(.mat-form-field-underline):not(.mat-slide):not(.mat-slider *):not(.x-markdown *):not(.x-color *):not(.x-map *):not(.x-selected-color):not(.x-color-palette):not(.x-color-alpha) { background-color: $color; } } } @mixin formFieldWrapperColorHandler($color: var(--regular-color)) { // .x-form-input-element { // outline: $color auto 1px; } // .x-form-field:not(.x-mat-form-field) { border-color: $color; } // @include sliderProps; @include toogleColorHandler($color); @include checkBoxColorHandler($color); @include formFieldLabelColorHandler($color); @include matFormFieldOutlineColorHandler($color); @include iconStatusColorHandler($color !important); @include matFormFieldUnderlineColorHandler($color !important); } @mixin radioColorHandler( $color: var(--regular-color), $applyOnOuterCircle: false, $applyOnInnerCircle: false ) { // .mat-radio-label { // color: $color; // @if $applyOnOuterCircle { .mat-radio-outer-circle { border-color: $color; } } // @if $applyOnInnerCircle { .mat-radio-inner-circle { background-color: $color; } } } } @mixin checkBoxColorHandler($color: var(--regular-color), $disabled: false) { // .mat-checkbox-frame { @if $disabled { border-color: var(--disabled-color) !important; } @else { border-color: var(--regular-color); } } // .mat-checkbox-checked { .mat-checkbox-frame, .mat-checkbox-background { background-color: var(--active-color) !important; } } // .mat-checkbox-label { .x-field-label { width: 100%; } } // .x-form-control { &.has-icon { .mat-checkbox-layout { margin: { left: 4px; right: 4px; } } } } } @mixin toogleColorHandler($color: var(--regular-color)) { // :not(.x-form-field-disabled) { .mat-slide-toggle-bar { background-color: var(--active-color) !important; } } // .x-form-field-disabled { .mat-slide-toggle-bar { background-color: var(--disabled-color) !important; } .mat-slide-toggle-thumb { background-color: var(--disabled-fill-color) !important; } } // .mat-slide-toggle-thumb { background-color: $color !important; } // .x-form-control { &.has-icon { .mat-slide-toggle-label { margin: { left: 4px; right: 4px; } } } } } @mixin sliderProps($disabled: false) { // .x-form-slider-control { // @if $disabled { // cursor: default; pointer-events: none; } // &:not(.vertical) { width: 100%; } // &.vertical { display: block; margin: { left: auto; right: auto; } } // .mat-slider-wrapper, .mat-slider-track-wrapper { // @if $disabled { background-color: var(--disabled-fill-color) !important; } @else { background-color: var(--fill-color); } } // .mat-slider-thumb, .mat-slider-thumb-label, .mat-slider-thumb-label-text { // @if $disabled { color: var(--disabled-color) !important; background-color: var(--disabled-fill-color) !important; } @else { color: var(--accent-color); background-color: var(--active-color); } } // .mat-slider-track-fill { // @if $disabled { background-color: var(--disabled-color) !important; } @else { background-color: var(--active-color); } } // .mat-slider-vertical { } } } @mixin formFieldLabelColorHandler($color: var(--regular-color)) { // .mat-form-field-label { color: $color; } // .x-field-label { color: $color; } // .mat-select-placeholder { color: $color; } } @mixin iconStatusColorHandler($color: var(--regular-color), $important: false) { // x-icon.x-status-handler > * { // @if $important { color: $color !important; } @else { color: $color; } } } @mixin matFormFieldUnderlineColorHandler( $color: var(--fill-color), $clearBackground: false ) { // .mat-form-field-underline { // border-color: $color; background-color: $color; // &::before { background-color: $color; } // @if $clearBackground { background-image: none; } } // .mat-select-arrow { color: $color; } } @mixin matFormFieldOutlineColorHandler($color: var(--regular-color)) { // color: $color; // .mat-form-field-outline-start, .mat-form-field-outline-end, .mat-form-field-outline-gap { border-width: 1px !important; } // .mat-form-field-outline, .mat-form-field-outline-thick { color: $color; border-width: 1px !important; } } //#endregion // ::ng-deep.cdk-overlay-pane { // transform: translateY(0px) !important; // .mat-datepicker-content-container { height: auto !important; } } // ::ng-deep.x-form-select-control { // min-width: 100% !important; // &:not(.x-form-select-control-panel) { max-width: 100% !important; } // &.x-form-select-control-panel { } // // // .mat-select-value-text { // color: var(--regular-color) !important; // } // .x-select-option { // color: var(--regular-color) !important; background-color: var(--fill-color) !important; // &.mat-active { color: var(--active-color) !important; } // &.mat-selected { // color: var(--active-color) !important; // .mat-pseudo-checkbox-checked { background: var(--active-color) !important; } // .mat-pseudo-checkbox::after { color: var(--accent-color) !important; } } // &:hover { $level: 0.5; filter: brightness($level); -webkit-filter: brightness($level); color: var(--active-color) !important; } } } // ::ng-deep.x-form-control-date-picker { // &.mat-calendar { // color: var(--regular-color) !important; background-color: var(--fill-color) !important; // .mat-calendar-arrow { border-top-color: unset; } // .mat-calendar-body-today { color: var(--active-color); border-color: var(--acttive-color); } // .mat-calendar-table-header { color: var(--accent-color) !important; } // .mat-calendar-body-selected { // color: var(--accent-color); background-color: var(--active-color); border-color: var(--accent-color); } // .mat-calendar-next-button, .mat-calendar-previous-button, .mat-calendar-period-button { color: var(--active-color) !important; } // .mat-calendar-body-label { color: var(--active-color) !important; } // .mat-calendar-body-cell-content { color: var(--regular-color) !important; } // .mat-calendar-body-disabled { color: var(--disabled-color) !important; filter: contrast(0.5) !important; } } } // :host ::ng-deep .x-form { // display: flex; flex-wrap: wrap; flex-direction: row; // .x-form-field-wrapper { // width: 100%; margin-bottom: var(--form-fields-vertical-margin); // .mat-form-field-wrapper { padding-bottom: 0; } // .mat-form-field-underline { position: initial; } // .ng-invalid, .mat-form-field-invalid { // *:not(.x-field-label):not(ion-icon):not(.mat-form-field-outline):not(.mat-form-field-outline-thick):not(.mat-form-field-outline-end):not(.mat-form-field-outline-gap):not(.mat-form-field-outline-start) { color: var(--regular-color); } // &.apply-status { * { color: var(--invalid-color) !important; } } *:not(.x-field-label) { background-color: transparent; } } // &.readonly { // .x-field-label { color: var(--disabled-color) !important; } // .x-form-control { color: var(--disabled-color) !important; } } // @include formFieldProps; @include autoCompleteProps; @include formFieldStatusHandler; @include formFieldAppearanceHandler(false); @include formFieldHintProps(var(--hint-color), var(--hint-text-size)); @include formFieldErrorProps(var(--invalid-color), var(--error-text-size)); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.component.ts import { FormGroup, FormControl, AbstractControl, ValidationErrors, } from '@angular/forms'; import { defaultFormControlClearIcon, defaultFormControlSelectIcon, } from './x-form.tools'; import { keys, sort, nameof, XColor, isDate, assign, entries, XUiEvent, hasChild, isFunction, parseXColor, momentToDate, XResourceIDs, XBorderStyle, XExceptionIDs, XDialogResult, XOneOrManyType, isNullOrUndefined, isNullOrEmptyString, XColorWithBrightness, getXColorCssVariableName, } from 'x-framework-core'; import { XFormCssVar, XFormStatus, XFormUpdateOn, XFormBaseAction, XFormControlType, XFormActionModel, XControlIconRole, XFormErrorHandler, XFormControlConfig, XFormControlAction, XFormIconDescriptor, XControlIconPosition, XFormStatusIdentifier, XFormMapControlConfig, XControlIconDescriptor, XFormControlAppearance, XFormInputControlConfig, XFormRadioControlConfig, XFormContainerComponent, XFormSelectControlConfig, XFormSliderControlConfig, XFormSelectControlOption, XFormControlLabelPosition, XControlIconRoleIdentifier, XFormMarkdownControlConfig, XFormControlNameIdentifier, XFormMapControlPresentType, XFormCheckBoxControlConfig, XFormSelectorControlConfig, XBaseFormControlActionModel, XFormDatePickerControlConfig, XFormColorPickerControlConfig, XFormControlAutoCompleteConfig, XFormAvatarUploadControlConfig, XFormControlAppearanceDescriptor, XFormControlValueChangeEventModel, XFormControlStatusChangeEventModel, XFormColorPickerControlPresentType, XFormDatePickerControlPickerPosition, } from './x-form.typings'; import { XMapAction, XMapLocation, XMapActionModel, XMapItemPosition, defaultMarkerStyle, defaultMapSearchPlaceProvider, } from '../x-map/x-map.typings'; import { isMoment } from 'moment'; import { XMarkdownMode, XMarkdownActionModel, } from '../x-markdown/x-markdown.typings'; import { XSearchBarType, XSearchBarActionModel, XSearchBarEnterKeyHint, } from '../x-search-bar/x-search-bar.typings'; import { XColorPickerActionModel, XColorPickerOutputFormat, } from '../x-color-picker/x-color-picker.typings'; import { XAvatarUploadActionModel, defaultAvatarUploadActionButtons, } from '../x-avatar-upload/x-avatar-upload.typings'; import { map, concatMap, tap } from 'rxjs/operators'; import { XIconNames } from '../x-icon/x-icon.typings'; import { toLongLat, fromLongLat } from '../x-map/x-map.tools'; import { XStringInputFormatType } from 'x-framework-services'; import { Component, ChangeDetectionStrategy } from '@angular/core'; import { MatFormFieldAppearance } from '@angular/material/form-field'; import { of, Subject, Subscription, Observable, forkJoin } from 'rxjs'; import { MatDatepickerInputEvent } from '@angular/material/datepicker'; import { XSlotName, XSlotLayout } from '../x-slotter/x-slotter.typings'; import { XMapDialogConfig } from '../x-map/x-map-dialog/x-map-dialog.typings'; import { XFileDropAreaActionModel } from '../x-file-drop-area/x-file-drop-area.typings'; import { XColorPickerDialogConfig } from '../x-color-picker/x-color-picker-dialog/x-color-picker-dialog.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-form', templateUrl: './x-form.component.html', styleUrls: ['./x-form.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XFormComponent extends XFormContainerComponent { // //#region Props ... // private VALUE: any; private FORM: FormGroup; private FORM_CONFIG: any; private ERRORS: ValidationErrors; private actionProviders: any = {}; private STATUS: XFormStatusIdentifier; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly SlotNames = Object.assign({}, XSlotName); readonly SlotLayouts = Object.assign({}, XSlotLayout); readonly FormStatuses = Object.assign({}, XFormStatus); readonly ControlTypes = Object.assign({}, XFormControlType); readonly ControlIconRoles = Object.assign({}, XControlIconRole); readonly ControlIconPositions = Object.assign({}, XControlIconPosition); readonly FormControlAppearances = Object.assign({}, XFormControlAppearance); // currentInputFocus: string; // get value() { return this.VALUE; } get status() { return this.STATUS; } get errors() { return this.ERRORS; } get isStatusValid() { return this.status === XFormStatus.Valid; } get form() { return this.FORM; } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.applyColors(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // // Form Config ... const isFormConfigChanged = changeKeys.includes( nameof('formConfig') ); if (isFormConfigChanged) { await this.prepareFormGroup(); } // // Action Provider ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { await this.registerActionProvider(); } // //#region UI Disabled or Loading ... const isUiDisabledChanged = changeKeys.includes( nameof('uiDisabled') ); if (isUiDisabledChanged) { await this.handleUiDisabledChanged(); } //#endregion // //#region Color Change Detecotrs ... // const isRegularColorChanged = changeKeys.includes( nameof('regularColor') ); if (isRegularColorChanged) { await this.applyRegularColor(); } // const isAccentColorChanged = changeKeys.includes( nameof('accentColor') ); if (isAccentColorChanged) { await this.applyAccentColor(); } // const isHintColorChanged = changeKeys.includes( nameof('hintColor') ); if (isHintColorChanged) { await this.applyHintColor(); } // const isPendingColorChanged = changeKeys.includes( nameof('pendingColor') ); if (isPendingColorChanged) { await this.applyPendingColor(); } // const isActiveColorChanged = changeKeys.includes( nameof('activeColor') ); if (isActiveColorChanged) { await this.applyActiveColor(); } // const isValidColorChanged = changeKeys.includes( nameof('validColor') ); if (isValidColorChanged) { await this.applyValidColor(); } // const isInvalidColorChanged = changeKeys.includes( nameof('invalidColor') ); if (isInvalidColorChanged) { await this.applyInvalidColor(); } // const isFillColorChanged = changeKeys.includes( nameof('fillColor') ); if (isFillColorChanged) { await this.applyFillColor(); } // const isDisabledColorChanged = changeKeys.includes( nameof('disabledColor') ); if (isDisabledColorChanged) { await this.applyDisabledColor(); } // const isDisabledFillColorChanged = changeKeys.includes( nameof('disabledFillColor') ); if (isDisabledFillColorChanged) { await this.applyDisabledFillColor(); } //#endregion } async afterViewInit() { super.afterViewInit(); // this.managerService.dispatchResizeEvent(); setTimeout(() => this.managerService.dispatchResizeEvent(), 500); this.detectChanges(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... // //#region Form Providers ... // //#region Form Config ... /** * prepare form config object */ getFormConfig() { return this.getValue(this.formConfig); } //#endregion // //#region Form Model ... /** * get form name ... */ getFormName() { return this.getFormConfig().pipe( concatMap((formConfig) => this.getValue(formConfig.name)) ); } //#endregion // //#region Css Class Lists... /** * retrieve form cssClasses ... */ getFormCssClass() { return this.getArrayValue(this.cssClass).pipe( concatMap((cssClasses) => this.getFormName().pipe( map((formName) => { return { name: formName, cssClasses, }; }) ) ), map((descriptor) => { return descriptor.cssClasses.concat( 'x-form', `x-status-${this.STATUS}`, `x-form-${descriptor.name}` ); }) ); } /** * retrieve form control wrapper classes list ... * * @param control form control config ... */ getFormControlWrapperClasses(control: XFormControlConfig) { return this.getControlInfo(control).pipe( map((cInfo) => { // const fControl = this.getControl(control.propName); const isFocused = this.getControlInputElementId(control) === this.currentInputFocus; // return [ 'x-form-field-wrapper', `x-form-${cInfo.type}-field-wrapper`, `x-form-field-${control.index.toString()}-wrapper`, `x-form-field-${control.propName.toString()}-wrapper`, `x-form-field-appearance-${cInfo.appearance .toString() .toLowerCase()}-wrapper`, // // Focused ... ...(isFocused ? ['x-focused'] : []), // // Disabled ... ...(cInfo.disabled || fControl.disabled ? ['x-form-field-wrapper-disabled'] : []), // // Valid ... ...(fControl.valid ? ['x-form-field-wrapper-valid'] : []), // // Invalid ... ...(fControl.invalid ? ['x-form-field-wrapper-invalid'] : []), // // Pending ... ...(fControl.pending ? ['x-form-field-wrapper-pending'] : []), ]; }) ); } /** * retrieve form errors classes ... */ getFormErrorsClasses() { return this.getFormName().pipe( map((formName) => { return ['x-form-errors', `x-form-${formName}-errors`]; }) ); } /** * retrieve form specific error's class lists ... * * @param handler form error handler ... */ getFormErrorClasses(handler: XFormErrorHandler) { return this.getFormName().pipe( concatMap((formName) => this.getErrorHandlerErrorName(handler).pipe( map((errorName) => { return { formName, errorName, }; }) ) ), map((descriptor) => { return [ 'x-form-error', `x-form-${descriptor.formName}-error`, `x-form-${descriptor.errorName}-error`, `x-form-${descriptor.formName}-${descriptor.errorName}-error`, ]; }) ); } /** * retrieve form card footer css classes ... */ getFormCardFooterCssClass() { return this.getFormName().pipe( map((formName) => { return ['x-form-footer', `x-form-${formName}-footer`]; }) ); } /** * retrieve form card actions css classes ... */ getFormCardActionsCssClass() { return this.getFormName().pipe( map((formName) => { return ['x-form-actions', `x-form-${formName}-actions`]; }) ); } /** * retrieve form field classes list ... * * @param control form control config ... */ getFormFieldClasses(control: XFormControlConfig) { return this.getControlInfo(control).pipe( map((cInfo) => { // const fControl = this.getControl(control.propName); const isFocused = this.getControlInputElementId(control) === this.currentInputFocus; // return [ 'x-form-field', `x-form-${cInfo.type}-field`, `x-form-field-${control.index.toString()}`, `x-form-field-${control.propName.toString()}`, `x-form-field-appearance-${cInfo.appearance .toString() .toLowerCase()}`, // // Focused ... ...(isFocused ? ['x-focused'] : []), // // Disabled ... ...(cInfo.disabled || fControl.disabled ? ['x-form-field-disabled'] : []), // // Valid ... ...(fControl.valid ? ['x-form-field-valid'] : []), // // Invalid ... ...(fControl.invalid ? ['x-form-field-invalid'] : []), // // Pending ... ...(fControl.pending ? ['x-form-field-pending'] : []), ]; }) ); } /** * retrieve form control classes list ... * * @param control form control config ... */ getFormControlClasses(control: XFormControlConfig) { return this.getControlType(control).pipe( map((type) => { return [ 'x-form-control', `x-form-${type}-control`, `x-form-control-${control.index.toString()}`, `x-form-control-${control.propName.toString()}`, ]; }) ); } /** * retrieve focusHandler of a form control ... * * @param control form control config ... */ getControlFocusHandler(control: XFormControlConfig) { return this.getValue(control).pipe(map((config) => config.focusHandler)); } /** * retriev a form control label classes ... */ getFormControlFieldLabelClasses(control: XFormControlConfig) { return this.getControlType(control).pipe( map((type) => { return [ 'x-form-field-label', `x-form-${type}-field-label`, `x-form-field-label-${control.index.toString()}`, `x-form-field-label-${control.propName.toString()}`, ]; }) ); } /** * retrieve form control hint class list */ getFormControlHintClasses(control: XFormControlConfig) { return this.getControlInfo(control).pipe( map((cInfo) => { return [ 'x-form-control-hint', `x-form-${cInfo.type}-control-hint`, `x-form-control-${control.index.toString()}-hint`, `x-form-control-${control.propName.toString()}-hint`, ]; }) ); } //#endregion // //#region Form Model ... /** * retrieve for model which provide's initial input for each field. * if the form model is this type is Partial ... */ getFormModel() { return this.getFormConfig().pipe( concatMap((formConfig) => this.getOptionalValue(formConfig.model)) ); } /** * determines the form has intial value provider or not ... */ formHasModel() { return this.getFormModel().pipe( map((formModel) => !isNullOrUndefined(formModel)) ); } //#endregion // //#region Form Updte On ... /** * retrieve form update strategy identifier ... */ getFormUpdateOn() { return this.getFormConfig().pipe( concatMap((formConfig) => this.getOptionalValue(formConfig.updateOn).pipe( map((updateOn) => (updateOn ? updateOn : XFormUpdateOn.CHANGE)) ) ) ); } //#endregion // //#region Form Validators ... /** * retrieve form Validators object ... */ getFormValidators() { return this.getFormConfig().pipe( concatMap((formConfig) => this.getOptionalValue(formConfig.validators)) ); } /** * determines form has Validators or not ... */ formHasValidators() { return this.getFormValidators().pipe( map((formValidators) => !isNullOrUndefined(formValidators)) ); } //#endregion // //#region Form Controls ... /** * retrieve form Controls Configs ... */ getFormControls() { return this.getFormConfig().pipe( concatMap((formConfig) => this.getArrayValue(formConfig.controls).pipe( map((arrVal) => sort(arrVal, (v1, v2) => v1.index - v2.index)) ) ) ); } //#endregion // //#region Form Error Handlers ... /** * retrieve form Error Handlers Descriptor object ... */ getFormErrorHandlers() { return this.getFormConfig().pipe( concatMap((formConfig) => this.getArrayValue(formConfig.errorHandlers)) ); } /** * determines form has Error Handlers or not ... */ formHasErrorHandlers() { return this.hasChildValue(this.getFormErrorHandlers()); } /** * determines for has specific error or not ... * * @param handler form error handler ... */ formHasError(handler: XFormErrorHandler) { return this.getValue(handler.errorName).pipe( map((errorName) => { return ( !isNullOrUndefined(this.ERRORS) && keys(this.ERRORS).includes(errorName) && !isNullOrUndefined(this.ERRORS[errorName]) ); }) ); } /** * determine form has specific error by name ... * * @param name error name ... */ formHasErrorByName(name: string) { return ( !isNullOrUndefined(this.ERRORS) && keys(this.ERRORS).includes(name) && !isNullOrUndefined(this.ERRORS[name]) ); } /** * retrieve specific error from form ... * * @param handler form error handler ... */ getFormError(handler: XFormErrorHandler) { return this.getErrorHandlerErrorName(handler).pipe( concatMap((errorName) => this.formHasError(handler).pipe( map((hasError) => { return { errorName, hasError, }; }) ) ), map((descriptor) => descriptor.hasError ? this.ERRORS[descriptor.errorName] : null ) ); } /** * retrieve specific form error by name ... * * @param name error name ... */ getFormErrorByName(name: string) { return this.formHasErrorByName(name) ? this.ERRORS[name] : null; } //#endregion //#endregion // //#region Form Control Providers ... /** * retrieve specific control config ... * * @param name control name */ getFormControl(name: XFormControlNameIdentifier) { return this.getFormControls().pipe( map((controls) => controls.find((c) => c.propName === name)) ); } // getControlInputElementId(control: XFormControlConfig) { return `x-form-${control.propName.toString()}-input-element`; } // getControlInputElementIdByName(name: XFormControlNameIdentifier) { return `x-form-${name.toString()}-input-element`; } // getControlInputElementClasses(control: XFormControlConfig) { return this.getControlInputElementCssClasses(control).pipe( concatMap((inpCss) => this.getControlType(control).pipe( map((type) => { // return [ 'x-form-input-element', `x-form-${type}-input-element`, `x-form-${control.index.toString()}-input-element`, `x-form-${control.propName.toString()}-input-element`, // ...inpCss.map((i) => i.toString()), ]; }) ) ) ); } // getControlInputElementCssClasses(control: XFormControlConfig) { return this.getCustomControlConfig(control).pipe( concatMap((config) => { return this.getArrayValue( !isNullOrUndefined(config) && !isNullOrUndefined(config.inputCssClass) ? config.inputCssClass : [] ); }) ); } // getControlDisableInput(control: XFormControlConfig) { return this.getCustomControlConfig(control).pipe( concatMap((config) => { return this.getOptionalValue( !isNullOrUndefined(config) && !isNullOrUndefined(config.disableInput) ? config.disableInput : false ); }) ); } // isInputControlReadOnly(control: XFormControlConfig) { return this.getControlType(control).pipe( concatMap((type) => { // if (type === XFormControlType.Text) { return this.getControlTypeConfig(control).pipe( concatMap((config) => config && (config as XFormInputControlConfig) ? this.getOptionalValue( (config as XFormInputControlConfig).readonly ) : of(false) ) ); } else { return this.getValue(false); } }) ); } // getControlDisableIcon(control: XFormControlConfig) { return this.getCustomControlConfig(control).pipe( concatMap((config) => { return this.getOptionalValue( !isNullOrUndefined(config) && !isNullOrUndefined(config.disableIcon) ? config.disableIcon : false ); }) ); } // //#region Control Type Providers ... // //#region Type Descriptor ... /** * retrieve a control type descriptor object ... * * @param control form control config object ... */ getControlTypeDescriptor(control: XFormControlConfig) { return this.getValue(control.type); } //#endregion // //#region Control Type ... /** * retrieve a control type ... * * @param control form control config object ... */ getControlType(control: XFormControlConfig) { return this.getControlTypeDescriptor(control).pipe( concatMap((typeDesc) => this.getValue( typeDesc && typeDesc.type ? typeDesc.type : XFormControlType.Hidden ) ) ); } //#endregion // //#region Control Type Config ... /** * retrieve a control type specific config object ... * * @param control form control config object ... */ getControlTypeConfig(control: XFormControlConfig) { return this.getControlTypeDescriptor(control).pipe( concatMap((typeDesc) => this.getOptionalValue(typeDesc.config)) ); } //#endregion // //#region Control Action Icon Configs ... /** * determines a custom control has clear icon or not ... */ hasControlClearIcon(control: XFormControlConfig): Observable { return this.getCustomControlConfig(control).pipe( map((config) => { return ( !isNullOrUndefined(config) && !isNullOrUndefined(config.clearIcon) ); }) ); } /** * retrieve custom control clear icon * * @param control form control config object ... */ getControlClearIcon( control: XFormControlConfig ): Observable { return this.getCustomControlConfig(control).pipe( concatMap((config) => { return !isNullOrUndefined(config) ? this.getValue(config.clearIcon) : of(null); }), map((iconSelector) => { return !isNullOrUndefined(iconSelector) ? iconSelector : defaultFormControlClearIcon; }) ); } /** * determines a custom control has select icon or not ... */ hasControlSelectIcon(control: XFormControlConfig): Observable { return this.getCustomControlConfig(control).pipe( map((config) => { return ( !isNullOrUndefined(config) && !isNullOrUndefined(config.selectIcon) ); }) ); } /** * retrieve custom control select icon * * @param control form control config object ... */ getControlSelectIcon( control: XFormControlConfig ): Observable { return this.getCustomControlConfig(control).pipe( concatMap((config) => { return !isNullOrUndefined(config) ? this.getValue(config.selectIcon) : of(null); }), map((iconSelector) => { return !isNullOrUndefined(iconSelector) ? iconSelector : defaultFormControlSelectIcon; }) ); } // //#region XForm Custom Control IconDescriptor Providers ... /** * retrieve Custom Control Action Icon's Name ... * * @param role Icon Action Descriptor... * @param descriptor Selector icon descriptor ... */ getControlIconDescriptorName( role: XControlIconRoleIdentifier, descriptor: XControlIconDescriptor ) { return this.getValue(descriptor.name).pipe( map((name) => { return !isNullOrUndefined(name) && !isNullOrEmptyString(name.toString()) ? name : role === this.ControlIconRoles.Select ? XIconNames.touch : XIconNames.clear; }) ); } /** * retrieve Custom Control Action Icon's color ... * * @param role Icon Action Descriptor... * @param descriptor Selector icon descriptor ... */ getControlIconDescriptorColor( role: XControlIconRoleIdentifier, descriptor: XControlIconDescriptor ) { return this.getValue(descriptor.color).pipe( map((color) => { return !isNullOrEmptyString(color) ? color : role === this.ControlIconRoles.Select ? XColorWithBrightness.Success : XColorWithBrightness.Danger; }) ); } /** * retrieve Custom Control Action Icon's applyStateColor ... * * @param descriptor Selector icon descriptor ... */ getControlIconDescriptorApplyStateColor(descriptor: XControlIconDescriptor) { return this.getOptionalValue(descriptor.applyStateColor); } /** * retrieve Custom Control Action Icon's tooltip ... * * @param role Icon Action Descriptor... * @param descriptor Selector icon descriptor ... */ getControlIconDescriptorTooltip( role: XControlIconRoleIdentifier, descriptor: XControlIconDescriptor ) { return this.getResourceValue(descriptor.tooltip).pipe( map((tooltip) => { return !isNullOrEmptyString(tooltip) ? tooltip : role === this.ControlIconRoles.Select ? this.resourceProvider(this.ResourceIDs.select) : this.resourceProvider(this.ResourceIDs.clear); }) ); } /** * retrieve Custom Control Action Icon's position ... * * @param descriptor Selector icon descriptor ... */ getControlIconDescriptorPosition(descriptor: XControlIconDescriptor) { return this.getValue(descriptor.position).pipe( map((position) => { return !isNullOrEmptyString(position) ? position : XControlIconPosition.Suffix; }) ); } //#endregion //#endregion // //#region Control Type Configs // //#region Markdown Config ... /** * retrieve Markdown Control Config ... * * @param control form control config object ... */ getMarkdownConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormMarkdownControlConfig) ); } /** * determines control has Markdown Config or not ... * * @param control form control config object ... */ hasMarkdownConfig(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * determines markdown Card is In Page or not ... * * @param control form control config object ... */ isMarkdownInPage(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getOptionalValue(config.isInPage); }) ); } /** * retrieve markdown has toolbar ... * * @param control form control config object ... */ getMarkDownHasToolbar(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getOptionalValue(config.hasToolbar); }) ); } /** * retrieve markdown wrap with card ... * * @param control form control config object ... */ isMarkdownWrapWithCard(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getOptionalValue(config.wrapWithCard); }) ); } /** * retrieve markdown card color ... * * @param control form control config object ... */ getMarkdownCardColor(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getValue( config && config.cardColor ? config.cardColor : XColor.Light ); }) ); } /** * retrieve markdown editorBoxColor value ... * * @param control form control config object ... */ getMarkdownEditorBoxColor(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getValue( config && config.editorBoxColor ? config.editorBoxColor : XColor.Light ); }) ); } /** * retrieve markdown previewBoxColor value ... * * @param control form control config object ... */ getMarkdownPreviewBoxColor(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getValue( config && config.previewBoxColor ? config.previewBoxColor : XColorWithBrightness.MediumTint ); }) ); } /** * determines markdown toolbar color is foreground color or not ... * * @param control form control config object ... */ getMarkdownCardForegroundColor(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getOptionalValue(config.cardForegroundColor); }) ); } /** * retrieve markdown mode ... * * @param control form control config object ... */ getMarkdownMode(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => this.getValue(config.mode || null)), map((mode) => (mode ? mode : XMarkdownMode.PREVIEW)) ); } /** * retrieve markdown Toolbar Color ... * * @param control form control config object ... */ getMarkDownToolbarColor(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getValue( config && config.toolbarColor ? config.toolbarColor : XColor.Light ); }) ); } /** * retrieve markdown Card Title ... * * @param control form control config object ... */ getMarkdownCardTitle(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getOptionalValue(config.cardTitle); }) ); } /** * retrieve markdown action provider ... * * @param control form control config object ... */ getMarkdownActionProvider(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( map((config) => { // if (!config.actionProvider) { // if (!this.actionProviders[control.propName]) { this.actionProviders[control.propName] = new Subject(); } // return this.actionProviders[ control.propName ] as Subject; } else { return config.actionProvider; } }) ); } /** * determines markdown toolbar color is foreground color or not ... * * @param control form control config object ... */ getMarkDownToolbarForegroundColor(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getOptionalValue(config.toolbarForegroundColor); }) ); } /** * retrieve markdown cssClass ... * * @param control form control config object ... */ getMarkdownCssClass(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getArrayValue(config.cssClass); }) ); } /** * retrieve markdown content ... * * @param control form control config object ... */ getMarkDownContent(control: XFormControlConfig) { return this.getValue(control).pipe( map((ctrl) => { // if (!this.hasControl(ctrl.propName)) { return ''; } // const xFormControl = this.getControl(ctrl.propName); if (!xFormControl) { return ''; } // return (xFormControl.value || '') as string; }) ); } /** * retrieve markdown Card SubTitle ... * * @param control form control config object ... */ getMarkdownCardSubTitle(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getResourceValue(config.cardSubTitle); }) ); } /** * retrieve markdown toolbar css class ... * * @param control form control config object ... */ getMarkdownToolbarCssClass(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getArrayValue(config.toolbarCssClass); }) ); } /** * retrieve markdown toolbar config ... * * @param control form control config object ... */ getMarkdownToolbarConfig(control: XFormControlConfig) { return this.getMarkdownConfig(control).pipe( concatMap((config) => { return this.getOptionalValue(config.toolbarConfig); }) ); } //#endregion // //#region Select/Radio Config ... /** * retrieve select control config ... * * @param control form control config object ... */ getSelectConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormSelectControlConfig) ); } /** * determines select control has config or not ... * * @param control form control config object ... */ hasSelectConfig(control: XFormControlConfig) { return this.getSelectConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * retrieve select control options ... * * @param control form control config object ... */ getSelectOptions(control: XFormControlConfig) { return this.getSelectConfig(control).pipe( concatMap((config) => this.getArrayValue(config.options)) ); } /** * determines select control can select multiple or not ... * * @param control form control config object ... */ getSelectMultiple(control: XFormControlConfig) { return this.getSelectConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.multiple)) ); } /** * retrieve Select Control Panel Calsses ... */ getSelectPanelClasses(control: XFormControlConfig) { return this.getFormControlClasses(control).pipe( concatMap((classes) => this.getSelectMultiple(control).pipe( map((isMultiple) => ({ classes, isMultiple })) ) ), map((selectInfo) => { return [ ...selectInfo.classes, 'x-form-select-control-panel', ...(selectInfo.isMultiple ? ['multiple'] : []), ]; }) ); } /** * retrieve select control option css classes ... * * @param control form control config object ... */ getOptionClassName(option: XFormSelectControlOption) { return this.getValue(option).pipe( map((opt) => ['x-select-option', `x-select-${opt.value}-option`]) ); } // // Radio ... /** * retrieve radio control config ... * * @param control form control config object ... */ getRadioConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormRadioControlConfig) ); } /** * determines radio control has config or not ... * * @param control form control config object ... */ hasRadioConfig(control: XFormControlConfig) { return this.getRadioConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * retrieve radio control options ... * * @param control form control config object ... */ getRadioOptions(control: XFormControlConfig) { return this.getRadioConfig(control).pipe( concatMap((config) => this.getArrayValue(config.options)) ); } /** * retrieve a radio control options label position ... * * @param control form control config object ... */ getRadioLabelPosition(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.labelPosition : XFormControlLabelPosition.After ).pipe(map((result) => result as 'before' | 'after')) ) ); } //#endregion // //#region CheckBox Config ... /** * retrieve checkbox control config ... * * @param control form control config object ... */ getCheckboxConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormCheckBoxControlConfig) ); } /** * determines checkbox control has config or not ... * * @param control form control config object ... */ hasCheckboxConfig(control: XFormControlConfig) { return this.getCheckboxConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * retrieve a checkbox control label position ... * * @param control form control config object ... */ getCheckboxLabelPosition(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.labelPosition : XFormControlLabelPosition.After ).pipe(map((result) => result as 'before' | 'after')) ) ); } //#endregion // //#region Date Picker Config ... /** * retrieve date control config ... * * @param control form control config object ... */ getDateConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormDatePickerControlConfig) ); } /** * determines date control has config or not ... * * @param control form control config object ... */ hasDateConfig(control: XFormControlConfig) { return this.getDateConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * retrieve date control start at ... * * @param control form control config object ... */ getDateStartAt(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getValue(config.startAt)) ); } /** * retrieve date control picker position ... * * @param control form control config object ... */ getDatePickerPosition(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getValue(config.datePickerPosition)) ); } /** * retrieve date control filter ... * * @param control form control config object ... */ getDateFilter(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getValue(config.dateFilter)) ); } /** * retrieve date control input handler ... * * @param control form control config object ... */ getDateInputHandler(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getValue(config.dateInput)) ); } /** * retrieve date control change handler ... * * @param control form control config object ... */ getDateChangeHandler(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getValue(config.dateChange)) ); } /** * determines date control input field disabled or not ... * * @param control form control config object ... */ isDatePickerInputDisabled(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.disableInput)) ); } /** * determines date control input field disabled or not ... * * @param control form control config object ... */ isDatePickerToggleDisabled(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.disablePicker)) ); } /** * retriece date control classes ... * * @param control form control config object ... */ getDatePickerClasses(control: XFormControlConfig) { return this.getControlType(control).pipe( map((type) => { return [ 'x-date-picker', `x-form-control-${type}-picker`, `x-form-control-${control.propName.toString()}-date-picker`, ]; }) ); } /** * retriece date control toggle icon name ... * * @param control form control config object ... */ getDatePickerIcon(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.toggleIcon)), map((icon) => (icon ? icon : XIconNames.calendar)) ); } /** * retriece date control toggle icon color ... * * @param control form control config object ... */ getDatePickerIconColor(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.iconColor)), map((color) => (color ? color : XColor.Light)) ); } /** * retriece date control toggle icon tooltip ... * * @param control form control config object ... */ getDatePickerIconTooltip(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getResourceValue(config.iconTooltip)) ); } /** * retriece date control toggle apply color state ... * * @param control form control config object ... */ getDatePickerIconApplyStateColor(control: XFormControlConfig) { return this.getDateConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.applyStateColor)) ); } /** * determines date control icon position is suffix or not ... * * @param control form control config object ... */ isDatePickerHasSuffixIcon(control: XFormControlConfig) { return this.getDatePickerPosition(control).pipe( map( (position) => position === XFormDatePickerControlPickerPosition.Suffix ) ); } /** * determines date control icon position is prefix or not ... * * @param control form control config object ... */ isDatePickerHasPrefixIcon(control: XFormControlConfig) { return this.getDatePickerPosition(control).pipe( map( (position) => position === XFormDatePickerControlPickerPosition.Prefix ) ); } //#endregion // //#region Slider Config ... /** * retrieve slider control config ... * * @param control form control config object ... */ getSliderConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormSliderControlConfig) ); } /** * determines slider control has config or not ... * * @param control form control config object ... */ hasSliderConfig(control: XFormControlConfig) { return this.getSliderConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * retrieve slider control min value ... * * @param control form control config object ... */ getSliderMin(control: XFormControlConfig) { return this.getSliderConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.min)), map((min) => (min ? min : 0)) ); } /** * retrieve slider control max value ... * * @param control form control config object ... */ getSliderMax(control: XFormControlConfig) { return this.getSliderConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.max)), map((max) => (max ? max : 99)) ); } /** * retrieve slider control step value ... * * @param control form control config object ... */ getSliderStep(control: XFormControlConfig) { return this.getSliderConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.step)), map((step) => (step ? step : 1)) ); } /** * retrieve slider control invert value ... * * @param control form control config object ... */ getSliderInvert(control: XFormControlConfig) { return this.getSliderConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.invert)) ); } /** * determines slider control is vertical or not ... * * @param control form control config object ... */ isSliderVertical(control: XFormControlConfig) { return this.getSliderConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.vertical)) ); } /** * determines slider control show thumb label or not ... * * @param control form control config object ... */ showSliderThumbLabel(control: XFormControlConfig) { return this.getSliderConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.thumbLabel)) ); } /** * retrieve slider formatter function ... */ getSliderFormatter(control: XFormControlConfig) { return this.getSliderConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.formatter)) ); } //#endregion // //#region Toggle Config ... /** * retrieve a checkbox control label position ... * * @param control form control config object ... */ getToggleLabelPosition(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.labelPosition : XFormControlLabelPosition.After ).pipe(map((result) => result as 'before' | 'after')) ) ); } //#endregion // //#region Map Config ... /** * retrieve map control config ... * * @param control form control config object ... */ getMapConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormMapControlConfig) ); } /** * determines map control has config or not ... * * @param control form control config object ... */ hasMapConfig(control: XFormControlConfig) { return this.getMapConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * retrieve map component's selected point value ... * * @param control form control config object ... */ getMapSelectedPoint(control: XFormControlConfig): Observable { // const fControl = this.getControl(control.propName); if (!fControl || !fControl.value) { return of(null); } // const fValue = fControl.value as string; if (isNullOrEmptyString(fValue)) { return of(null); } // const result = fromLongLat(fValue); this.getMapActionProvider(control).pipe( tap((actionProvider) => { // if (actionProvider) { // actionProvider.next({ action: XMapAction.SetCenter, payload: result, }); } }) ); // return of(result); } /** * retrieve map control zoom value ... * * @param control form control config object ... */ getMapLatitude(control: XFormControlConfig) { return this.getMapSelectedPoint(control).pipe( map((point) => (point && point.latitude ? +point.latitude : 0)) ); } /** * retrieve map control zoom value ... * * @param control form control config object ... */ getMapLongitude(control: XFormControlConfig) { return this.getMapSelectedPoint(control).pipe( map((point) => (point && point.longitude ? +point.longitude : 0)) ); } /** * retrieve map control zoom value ... * * @param control form control config object ... */ getMapZoom(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => (config.zoom ? this.getValue(config.zoom) : of(0))) ); } /** * retrieve map control markerStyle value ... * * @param control form control config object ... */ getMapMarkerStyle(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.markerStyle)), map((markerStyle) => (markerStyle ? markerStyle : defaultMarkerStyle)) ); } /** * retrieve map control cssClass value ... * * @param control form control config object ... */ getMapCssClass(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getArrayValue(config.cssClass)) ); } /** * determines map control canSelect or not ... * * @param control form control config object ... */ mapCanSelect(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.canSelect)) ); } /** * determines map control showProgressBar or not ... * * @param control form control config object ... */ mapShowProgressBar(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showProgressBar)), map((canShow) => (isNullOrUndefined(canShow) ? true : canShow)) ); } /** * retrieve map control progressBarColor value ... * * @param control form control config object ... */ getMapProgressBarColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.progressBarColor)), map((color) => (color ? color : XColor.Light)) ); } /** * retrieve map control progressBarPosition value ... * * @param control form control config object ... */ getMapProgressBarPosition(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.progressBarPosition)), map((position) => isNullOrEmptyString(position) ? XMapItemPosition.TOP : position ) ); } // //#region Map Search Bar ... /** * determines map control showSearchBar or not ... * * @param control form control config object ... */ mapShowSearchBar(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showSearchBar)), map((result) => (isNullOrUndefined(result) ? true : result)) ); } /** * retrieve map control searchBarType value ... * * @param control form control config object ... */ getMapSearchBarType(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarType)), map((result) => isNullOrEmptyString(result) ? XSearchBarType.Search : result ) ); } /** * retrieve map control searchBarValue value ... * * @param control form control config object ... */ getMapSearchBarValue(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getValue(config.searchBarValue)) ); } /** * retrieve map control searchBarDebounce value ... * * @param control form control config object ... */ getMapSearchBarDebounce(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarDebounce)), map((result) => isNullOrUndefined(result) ? this.config.defaultSearchDebounceTime : result ) ); } /** * retrieve map control searchBarSpellcheck value ... * * @param control form control config object ... */ getMapSearchBarSpellcheck(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getValue(config.searchBarSpellcheck)), map((result) => (isNullOrUndefined(result) ? false : result)) ); } /** * retrieve map control searchPlaceProvider value ... * * @param control form control config object ... */ getMapSearchPlaceProvider(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getValue(config.searchPlaceProvider)), map((result) => isNullOrUndefined(result) ? defaultMapSearchPlaceProvider : result ) ); } /** * retrieve map control searchBarColor value ... * * @param control form control config object ... */ getMapSearchBarColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarColor)), map((result) => isNullOrEmptyString(result) ? XColorWithBrightness.Primary : result ) ); } /** * retrieve map control searchBarForegroundColor value ... * * @param control form control config object ... */ getMapSearchBarForegroundColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarForegroundColor) ) ); } /** * retrieve map control searchBarClearIcon value ... * * @param control form control config object ... */ getMapSearchBarClearButtonIcon(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarClearButtonIcon) ), map((result) => (isNullOrUndefined(result) ? XIconNames.clear : result)) ); } /** * retrieve map control searchBarTitle value ... * * @param control form control config object ... */ getMapSearchBarTitle(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getValue(config.searchBarTitle)), map((result) => isNullOrUndefined(result) ? XResourceIDs.search : result ) ); } /** * retrieve map control searchBarSearchIcon value ... * * @param control form control config object ... */ getMapSearchBarSearchButtonIcon(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarSearchButtonIcon) ), map((result) => (isNullOrUndefined(result) ? XIconNames.search : result)) ); } /** * retrieve map control searchBarInputColor value ... * * @param control form control config object ... */ getMapSearchBarSearchInputColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarSearchInputColor) ), map((result) => isNullOrEmptyString(result) ? XColorWithBrightness.Primary : result ) ); } /** * retrieve map control searchBarForegroundInputColor value ... * * @param control form control config object ... */ getMapSearchBarForegroundSearchInputColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarForegroundSearchInputColor) ) ); } /** * retrieve map control searchResultListColor value ... * * @param control form control config object ... */ getMapSearchResultListColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchResultListColor) ), map((result) => isNullOrEmptyString(result) ? XColorWithBrightness.Light : result ) ); } /** * retrieve map control searchBarActionProvider value ... * * @param control form control config object ... */ getMapSearchBarActionProvider(control: XFormControlConfig) { return this.getMapConfig(control).pipe( map((config) => { // const key = `${control.propName.toString()}_SearchBar`; if (!config.searchBarActionProvider) { // if (!this.actionProviders[key]) { this.actionProviders[key] = new Subject(); } // return this.actionProviders[key] as Subject; } else { return config.searchBarActionProvider; } }) ); } /** * retrieve map control searchBarClearIconColor value ... * * @param control form control config object ... */ getMapSearchBarClearButtonIconColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarClearButtonIconColor) ), map((result) => isNullOrEmptyString(result) ? XColorWithBrightness.Light : result ) ); } /** * retrieve map control searchBarCssClass value ... * * @param control form control config object ... */ getMapSearchBarCssClass(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getArrayValue(config.searchBarCssClass)) ); } /** * retrieve map control searchBarSearchIconColor value ... * * @param control form control config object ... */ getMapSearchBarSearchButtonIconColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarSearchButtonIconColor) ), map((result) => isNullOrEmptyString(result) ? XColorWithBrightness.Light : result ) ); } /** * retrieve map control searchBarCancelButtonIcon value ... * * @param control form control config object ... */ getMapSearchBarCancelButtonIcon(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarCancelButtonIcon) ), map((result) => (isNullOrUndefined(result) ? XIconNames.cancel : result)) ); } /** * retrieve map control searchBarPosition value ... * * @param control form control config object ... */ getMapSearchBarPosition(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarPosition)), map((result) => isNullOrEmptyString(result) ? XMapItemPosition.TOP : result ) ); } /** * retrieve map control searchBarKeyboardType value ... * * @param control form control config object ... */ getMapSearchBarKeyboardType(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarKeyboardType) ), map((result) => isNullOrEmptyString(result) ? XSearchBarType.Search : result ) ); } /** * retrieve map control searchBarCancelButtonTitle value ... * * @param control form control config object ... */ getMapSearchBarCancelButtonTitle(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getValue(config.searchBarCancelButtonTitle)) ); } /** * retrieve map control searchBarEnterKeyHint value ... * * @param control form control config object ... */ getMapSearchBarEnterKeyHint(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarEnterKeyHint) ), map((result) => isNullOrEmptyString(result) ? XSearchBarEnterKeyHint.Search : result ) ); } /** * determines map control searchBarShowCancelButton or not ... * * @param control form control config object ... */ mapShowSearchBarCancelButton(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.searchBarShowCancelButton) ) ); } //#endregion /** * determines map control showSelectedLocation or not ... * * @param control form control config object ... */ mapShowSelectedLocation(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showSelectedLocation)), map((result) => (isNullOrUndefined(result) ? false : result)) ); } /** * retrieve map control selectedLocationPosition value ... * * @param control form control config object ... */ getMapSelectedLocationPosition(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.selectedLocationPosition) ), map((position) => isNullOrEmptyString(position) ? XMapItemPosition.TOP : position ) ); } /** * determines map control showGoMarkedPlace or not ... * * @param control form control config object ... */ mapShowGoMarkedPlace(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showGoMarkedPlace)), map((result) => (isNullOrUndefined(result) ? true : result)) ); } /** * retrieve map control goMarkedPlacePosition value ... * * @param control form control config object ... */ getMapGoMarkedPlacePosition(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.goMarkedPlacePosition) ), map((position) => isNullOrEmptyString(position) ? XMapItemPosition.TOP : position ) ); } /** * determines map control showClearMarker or not ... * * @param control form control config object ... */ mapShowClearMarker(control: XFormControlConfig) { // // Clear Marker in Form Components only must shown when user decide to it and the present Type is with dialog // since the clear value handle clear marker actions in without dialog mode ... return this.getMapConfig(control).pipe( concatMap((config) => forkJoin({ showClearMarker: this.getOptionalValue(config.showClearMarker), withDialog: this.isMapPresentWithDialog(control), }) ), map( (info) => (isNullOrUndefined(info.showClearMarker) ? true : info.showClearMarker) && info.withDialog ) ); } /** * retrieve map control clearMarkerPosition value ... * * @param control form control config object ... */ getMapClearMarkerPosition(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.clearMarkerPosition)), map((position) => isNullOrEmptyString(position) ? XMapItemPosition.TOP : position ) ); } /** * determines map control showLocator or not ... * * @param control form control config object ... */ mapShowLocator(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showLocator)), map((result) => (isNullOrUndefined(result) ? true : result)) ); } /** * retrieve map control locatorPosition value ... * * @param control form control config object ... */ getMapLocatorPosition(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.locatorPosition)), map((position) => isNullOrEmptyString(position) ? XMapItemPosition.TOP : position ) ); } /** * determines map control showZoom or not ... * * @param control form control config object ... */ mapShowZoom(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showZoom)), map((result) => (isNullOrUndefined(result) ? true : result)) ); } /** * determines map control showRotate or not ... * * @param control form control config object ... */ mapShowRotate(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showRotate)), map((result) => (isNullOrUndefined(result) ? true : result)) ); } /** * determines map control showZoomSlider or not ... * * @param control form control config object ... */ mapShowZoomSlider(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showZoomSlider)), map((result) => (isNullOrUndefined(result) ? false : result)) ); } /** * determines map control isInPage or not ... * * @param control form control config object ... */ isMapInPage(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.isInPage)) ); } /** * determines map control wrapWithCard or not ... * * @param control form control config object ... */ isMapWrapWithCard(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.wrapWithCard)) ); } /** * retrieve map control cardColor value ... * * @param control form control config object ... */ getMapCardColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.cardColor)), map((color) => (color ? color : XColor.Light)) ); } /** * determines map control cardForegroundColor or not ... * * @param control form control config object ... */ isMapCardForegroundColor(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.cardForegroundColor)) ); } /** * retrieve map control cardTitle value ... * * @param control form control config object ... */ getMapCardTitle(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getResourceValue(config.cardTitle)) ); } /** * retrieve map control cardSubTitle value ... * * @param control form control config object ... */ getMapCardSubTitle(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getResourceValue(config.cardSubTitle)) ); } /** * determines map control showCardFooter or not ... * * @param control form control config object ... */ mapCardShowFooter(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.cardShowFooter)) ); } /** * retrieve map control actionProvider value ... * * @param control form control config object ... */ getMapActionProvider(control: XFormControlConfig) { return this.getMapConfig(control).pipe( map((config) => { // if (!config.actionProvider) { // if (!this.actionProviders[control.propName]) { this.actionProviders[control.propName] = new Subject(); } // return this.actionProviders[ control.propName ] as Subject; } else { return config.actionProvider; } }) ); } // //#region Map Present Types ... /** * retrieve map control presentType value ... * * @param control form control config object ... */ getMapPresentType(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.presentType)), map((presentType) => !isNullOrEmptyString(presentType) ? presentType : XFormMapControlPresentType.WithoutDialog ) ); } /** * determines map control present WithoutDialog or not ... * * @param control form control config object ... */ isMapPresentWithoutDialog(control: XFormControlConfig) { return this.getMapPresentType(control).pipe( map( (presentType) => presentType === XFormMapControlPresentType.WithoutDialog ) ); } /** * determines map control present WithDialog or not ... * * @param control form control config object ... */ isMapPresentWithDialog(control: XFormControlConfig) { return this.getMapPresentType(control).pipe( map( (presentType) => presentType === XFormMapControlPresentType.WithDialog ) ); } //#endregion //#endregion // //#region ColorPicker Config ... /** * retrieve color picker control config ... * * @param control form control config object ... */ getColorPickerConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormColorPickerControlConfig) ); } /** * determines color picker control has config or not ... * * @param control form control config object ... */ hasColorPickerConfig(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * retrieve color picker control color value ... * * @param control form control config object ... */ getColorPickerColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.color)), map((color) => (isNullOrEmptyString(color) ? XColor.Light : color)) ); } /** * retrieve color picker control colorViewBorderColor value ... * * @param control form control config object ... */ getColorPickerColorViewBorderColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.colorViewBorderColor)), map((color) => (isNullOrEmptyString(color) ? XColor.Light : color)) ); } /** * retrieve color picker control colorViewBorderStyle value ... * * @param control form control config object ... */ getColorPickerColorViewBorderStyle(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.colorViewBorderStyle)), map((style) => (isNullOrEmptyString(style) ? XBorderStyle.Solid : style)) ); } /** * retrieve color picker control colorViewBorderWidth value ... * * @param control form control config object ... */ getColorPickerColorViewBorderWidth(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.colorViewBorderWidth)) ); } /** * retrieve color picker control cssClass value ... * * @param control form control config object ... */ getColorPickerCssClass(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getArrayValue(config.cssClass)) ); } /** * retrieve color picker control cardColor value ... * * @param control form control config object ... */ getColorPickerCardColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.cardColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light)) ); } /** * retrieve color picker control cardTitle value ... * * @param control form control config object ... */ getColorPickerCardTitle(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getResourceValue(config.cardTitle)) ); } /** * retrieve color picker control cursorColor value ... * * @param control form control config object ... */ getColorPickerCursorColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.cursorColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark)) ); } /** * retrieve color picker control presetColors value ... * * @param control form control config object ... */ getColorPickerPresetColors(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getArrayValue(config.presetColors)) ); } /** * retrieve color picker control outputFormat value ... * * @param control form control config object ... */ getColorPickerOutputFormat(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.outputFormat)), map((format) => !isNullOrEmptyString(format) ? format : XColorPickerOutputFormat.XHEX ) ); } /** * retrieve color picker control cardSubTitle value ... * * @param control form control config object ... */ getColorPickerCardSubTitle(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getResourceValue(config.cardSubTitle)) ); } /** * retrieve color picker control colorTextColor value ... * * @param control form control config object ... */ getColorPickerColorTextColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.colorTextColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark)) ); } /** * determines color picker control showColorValue or not ... * * @param control form control config object ... */ colorPickerShowColorValue(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => config.showColorValue ? this.getValue(config.showColorValue) : of(true) ) ); } /** * determines color picker control showHueChannel or not ... * * @param control form control config object ... */ colorPickerShowHueChannel(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => config.showHueChannel ? this.getValue(config.showHueChannel) : of(true) ) ); } /** * determines color picker control foregroundColor or not ... * * @param control form control config object ... */ isColorPickerForegroundColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.foregroundColor)) ); } /** * determines color picker control showPresetColors or not ... * * @param control form control config object ... */ colorPickerShowPresetColors(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => config.showPresetColors ? this.getValue(config.showPresetColors) : of(true) ) ); } /** * determines color picker control showAlphaChannel or not ... * * @param control form control config object ... */ colorPickerShowAlphaChannel(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => config.showAlphaChannel ? this.getValue(config.showAlphaChannel) : of(true) ) ); } /** * retrieve color picker control presetColorsLable value ... * * @param control form control config object ... */ getColorPickerPresetColorsLable(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getResourceValue(config.presetColorsLable)), map((value) => isNullOrEmptyString(value) ? XResourceIDs.preset_colors : value ) ); } /** * retrieve color picker control copyToClipboardIconLabel value ... * * @param control form control config object ... */ getColorPickerCopyToClipboardIconLabel(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getResourceValue(config.copyToClipboardIconLabel) ), map((value) => isNullOrEmptyString(value) ? XResourceIDs.copy_to_clipboard : value ) ); } /** * retrieve color picker control colorInputIconLabel value ... * * @param control form control config object ... */ getColorPickerColorInputIconLabel(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getResourceValue(config.colorInputIconLabel)), map((value) => (isNullOrEmptyString(value) ? XResourceIDs.input : value)) ); } /** * retrieve color picker control clearColorIconLabel value ... * * @param control form control config object ... */ getColorPickerClearColorIconLabel(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getResourceValue(config.clearColorIconLabel)), map((value) => (isNullOrEmptyString(value) ? XResourceIDs.clear : value)) ); } /** * determines color picker control showPaletteChannel or not ... * * @param control form control config object ... */ colorPickerShowPaletteChannel(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => config.showPaletteChannel ? this.getValue(config.showPaletteChannel) : of(true) ) ); } /** * determines color picker control cardForegroundColor or not ... * * @param control form control config object ... */ isColorPickerCardForegroundColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.cardForegroundColor)) ); } /** * determines color picker control showCopyToClipboard or not ... * * @param control form control config object ... */ colorPickerShowCopyToClipboard(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => config.showCopyToClipboard ? this.getValue(config.showCopyToClipboard) : of(false) ) ); } /** * determines color picker control showColorInput or not ... * * @param control form control config object ... */ colorPickerShowColorInput(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => config.showCopyToClipboard ? this.getValue(config.showColorInput) : of(true) ) ); } /** * retrieve color picker control representColorFormats value ... * * @param control form control config object ... */ getColorPickerRepresentColorFormats(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getArrayValue(config.representColorFormats)), map((formats) => hasChild(formats) ? formats : [XColorPickerOutputFormat.XHEX] ) ); } /** * retrieve color picker control presetColorsLableColor value ... * * @param control form control config object ... */ getColorPickerPresetColorsLableColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.presetColorsLableColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Dark)) ); } /** * retrieve color picker control copyToClipboardIconColor value ... * * @param control form control config object ... */ getColorPickerCopyToClipboardIconColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.copyToClipboardIconColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Tertiary)) ); } /** * retrieve color picker control copyToClipboardIconColor value ... * * @param control form control config object ... */ getColorPickerColorInputIconColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.colorInputIconColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Secondary)) ); } /** * retrieve color picker control clearColorIconColor value ... * * @param control form control config object ... */ getColorPickerClearColorIconColor(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getValue(config.clearColorIconColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Danger)) ); } /** * determines color picker control showSelectedColorPreview or not ... * * @param control form control config object ... */ colorPickerShowSelectedColorPreview(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => config.showSelectedColorPreview ? this.getValue(config.showSelectedColorPreview) : of(true) ) ); } /** * determines color picker control isInPage or not ... * * @param control form control config object ... */ isColorPickerInPage(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.isInPage)) ); } /** * determines color picker control wrapWithCard or not ... * * @param control form control config object ... */ isColorPickerWrapWithCard(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.wrapWithCard)) ); } /** * determines color picker control showCardFooter or not ... * * @param control form control config object ... */ colorPickercardShowFooter(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showCardFooter)) ); } /** * retrieve color picker component's selected value ... * * @param control form control config object ... */ getColorPickerSelectedColor(control: XFormControlConfig) { // const fControl = this.getControl(control.propName); if (!fControl) { return of(''); } // const fValue = fControl.value as string; if (isNullOrEmptyString(fValue)) { return of(''); } // return of(fValue); } /** * retrieve color picker control actionProvider value ... * * @param control form control config object ... */ getColorPickerActionProvider(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( map((config) => { // if (!config.actionProvider) { // if (!this.actionProviders[control.propName]) { this.actionProviders[control.propName] = new Subject(); } // return this.actionProviders[ control.propName ] as Subject; } else { return config.actionProvider; } }) ); } // //#region ColorPicker Present Types ... /** * retrieve color picker control presentType value ... * * @param control form control config object ... */ getColorPickerPresentType(control: XFormControlConfig) { return this.getColorPickerConfig(control).pipe( concatMap((config) => !isNullOrUndefined(config) && !isNullOrUndefined(config.presentType) ? this.getOptionalValue(config.presentType) : of(null) ), map((presentType) => !isNullOrEmptyString(presentType) ? presentType : XFormColorPickerControlPresentType.WithoutDialog ) ); } /** * determines color picker control present WithoutDialog or not ... * * @param control form control config object ... */ isColorPickerPresentWithoutDialog(control: XFormControlConfig) { return this.getColorPickerPresentType(control).pipe( map( (presentType) => presentType === XFormColorPickerControlPresentType.WithoutDialog ) ); } /** * determines color picker control present WithDialog or not ... * * @param control form control config object ... */ isColorPickerPresentWithDialog(control: XFormControlConfig) { return this.getColorPickerPresentType(control).pipe( map( (presentType) => presentType === XFormColorPickerControlPresentType.WithDialog ) ); } //#endregion //#endregion // //#region Avatar Config ... /** * retrieve avatar upload control config ... * * @param control form control config object ... */ getAvatarConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormAvatarUploadControlConfig) ); } /** * determines avatar upload control has config or not ... * * @param control form control config object ... */ hasAvatarConfig(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } /** * determines avatar upload control canDrop or not ... * * @param control form control config object ... */ avatarCanDrop(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.canDrop)) ); } /** * determines avatar upload control isInPage or not ... * * @param control form control config object ... */ isAvatarInPage(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.isInPage)) ); } /** * determines avatar upload control wrapWithCard or not ... * * @param control form control config object ... */ isAvatarWrapWithCard(control: XFormControlConfig) { return this.getMapConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.wrapWithCard)) ); } /** * retrieve avatar upload control color value ... * * @param control form control config object ... */ getAvatarColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.color)), map((color) => (color ? color : XColor.Light)) ); } /** * determines map control showCardFooter or not ... * * @param control form control config object ... */ avatarCardShowFooter(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.showCardFooter)) ); } /** * determines avatar upload control foregroundColor or not ... * * @param control form control config object ... */ isAvatarForegroundColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.foregroundColor)) ); } /** * retrieve avatar upload control placeHolderAvatar value ... * * @param control form control config object ... */ getAvatarPlaceHolderAvatar(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getValue(config.placeHolderAvatar)) ); } /** * retrieve avatar upload control minAllowedFileSize value ... * * @param control form control config object ... */ getAvatarMinAllowedFileSize(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.minAllowedFileSize)), map((minAllowedFileSize) => minAllowedFileSize ? minAllowedFileSize : this.config.minAllowedFileSize ) ); } /** * retrieve avatar upload control maxAllowedFileSize value ... * * @param control form control config object ... */ getAvatarMaxAllowedFileSize(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.maxAllowedFileSize)), map((maxAllowedFileSize) => maxAllowedFileSize ? maxAllowedFileSize : this.config.maxProfileImageSize ) ); } /** * retrieve avatar upload control cardColor value ... * * @param control form control config object ... */ getAvatarCardColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.cardColor)), map((color) => (color ? color : XColor.Light)) ); } /** * determines avatar upload control cardForegroundColor or not ... * * @param control form control config object ... */ isAvatarCardForegroundColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.cardForegroundColor)) ); } /** * determines avatar upload control fileDropAreaIsInPage or not ... * * @param control form control config object ... */ isAvatarDropAreaInPage(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaIsInPage)) ); } /** * retrieve avatar upload control cardTitle value ... * * @param control form control config object ... */ getAvatarCardTitle(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getResourceValue(config.cardTitle)) ); } /** * retrieve avatar upload control cssClass value ... * * @param control form control config object ... */ getAvatarCssClass(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getArrayValue(config.cssClass)) ); } /** * determines avatar upload control fileDropAreaWrapWithCard or not ... * * @param control form control config object ... */ isAvatarDropAreaWrapWithCard(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaWrapWithCard) ) ); } /** * retrieve avatar upload control fileDropAreaIcon value ... * * @param control form control config object ... */ getAvatarDropAreaIcon(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getValue(config.fileDropAreaIcon)), map((icon) => (icon ? icon : XIconNames.arrow_down)) ); } /** * determines avatar upload control fileDropAreaDragDisabled or not ... * * @param control form control config object ... */ isAvatarDropAreaDragDisabled(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaDragDisabled) ) ); } /** * retrieve avatar upload control cardSubTitle value ... * * @param control form control config object ... */ getAvatarCardSubTitle(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getResourceValue(config.cardSubTitle)) ); } /** * retrieve avatar control actionProvider value ... * * @param control form control config object ... */ getAvatarActionProvider(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( map((config) => { // if (!config.actionProvider) { // if (!this.actionProviders[control.propName]) { this.actionProviders[control.propName] = new Subject(); } // return this.actionProviders[ control.propName ] as Subject; } else { return config.actionProvider; } }) ); } /** * determines map control fileDropAreaShowCardFooter or not ... * * @param control form control config object ... */ avatarDropAreaCardShowFooter(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaShowCardFooter) ) ); } /** * retrieve avatar upload control fileDropAreaColor value ... * * @param control form control config object ... */ getAvatarDropAreaColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaColor)), map((color) => (color ? color : XColor.Light)) ); } /** * determines avatar upload control fileDropAreaForegroundColor or not ... * * @param control form control config object ... */ isAvatarDropAreaForegroundColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaForegroundColor) ) ); } /** * determines avatar upload control fileDropAreaDisableFileCheck or not ... * * @param control form control config object ... */ isAvatarDropAreaDisableFileCheck(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaDisableFileCheck) ) ); } /** * retrieve avatar upload control fileDropAreaCardColor value ... * * @param control form control config object ... */ getAvatarDropAreaCardColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaCardColor) ), map((color) => (color ? color : XColor.Light)) ); } /** * determines avatar upload control fileDropAreaCardForegroundColor or not ... * * @param control form control config object ... */ isAvatarDropAreaCardForegroundColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaCardForegroundColor) ) ); } /** * retrieve avatar upload control emptyFileException value ... * * @param control form control config object ... */ getAvatarEmptyFileException(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.emptyFileException)), map((exception) => (exception ? exception : XExceptionIDs.EmptyFile)) ); } /** * retrieve avatar upload control fileDropAreaErrorColor value ... * * @param control form control config object ... */ getAvatarDropAreaErrorColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaErrorColor) ), map((color) => (color ? color : XColor.Danger)) ); } /** * retrieve avatar upload control fileDropAreaMessage value ... * * @param control form control config object ... */ getAvatarDropAreaMessage(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaMessage)), map((message) => (message ? message : XResourceIDs.drag_drop_here)), concatMap((resource) => this.getResourceValue(resource)) ); } /** * retrieve avatar upload control fileDropAreaAccentColor value ... * * @param control form control config object ... */ getAvatarDropAreaAccesntColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaAccentColor) ), map((color) => (color ? color : XColor.Secondary)) ); } /** * retrieve avatar upload control allowedExtensions value ... * * @param control form control config object ... */ getAvatarAllowedExtensions(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getArrayValue(config.allowedExtensions)), map((allowedExtensions) => hasChild(allowedExtensions) ? allowedExtensions : this.config.allowedImageExtensions ) ); } /** * retrieve avatar upload control fileDropAreaCardTitle value ... * * @param control form control config object ... */ getAvatarDropAreaCardTitle(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getResourceValue(config.fileDropAreaCardTitle)) ); } /** * retrieve avatar upload control fileDropAreaSuccessColor value ... * * @param control form control config object ... */ getAvatarDropAreaSuccessColor(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaSuccessColor) ), map((color) => (color ? color : XColor.Success)) ); } /** * determines avatar upload control fileDropAreaSupportsMultipleFiles or not ... * * @param control form control config object ... */ isAvatarDropAreaSupportsMultipleFiles(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaSupportsMultipleFiles) ) ); } /** * retrieve avatar upload control fileDropAreaCssClass value ... * * @param control form control config object ... */ getAvatarDropAreaCssClass(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getArrayValue(config.fileDropAreaCssClass)) ); } /** * retrieve avatar upload control fileDropAreaCardSubTitle value ... * * @param control form control config object ... */ getAvatarDropAreaCardSubTitle(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getResourceValue(config.fileDropAreaCardSubTitle) ) ); } /** * retrieve avatar upload control emptyFileException value ... * * @param control form control config object ... */ getAvatarNotAllowedFileException(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.notAllowedFileException) ), map((exception) => (exception ? exception : XExceptionIDs.InavlidFile)) ); } /** * retrieve avatar upload control fileDropAreaContentTemplate value ... * * @param control form control config object ... */ getAvatarDropAreaContentTemplate(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.fileDropAreaContentTemplate) ) ); } /** * retrieve avatar upload control minAllowedFileSizeException value ... * * @param control form control config object ... */ getAvatarMinAllowedFileSizeException(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.minAllowedFileSizeException) ), map((exception) => exception ? exception : XExceptionIDs.MinFilesSizeExceeded ) ); } /** * retrieve avatar upload control maxAllowedFileSizeException value ... * * @param control form control config object ... */ getAvatarMaxAllowedFileSizeException(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getOptionalValue(config.maxAllowedFileSizeException) ), map((exception) => exception ? exception : XExceptionIDs.MaxFilesSizeExceeded ) ); } /** * retrieve avatar control actions value ... * * @param control form control config object ... */ getAvatarActions(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getArrayValue(config.actions)), concatMap((actions) => hasChild(actions) ? of(actions) : this.getArrayValue(defaultAvatarUploadActionButtons) ) ); } /** * retrieve avatar control fileDropAreaActionProvider value ... * * @param control form control config object ... */ getAvatarDropAreaActionProvider(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( map((config) => { // const key = `${control.propName.toString()}_drop_area`; // if (!config.fileDropAreaActionProvider) { // if (!this.actionProviders[key]) { this.actionProviders[key] = new Subject(); } // return this.actionProviders[key] as Subject; } else { return config.fileDropAreaActionProvider; } }) ); } /** * retrieve avatar upload control allowedExtensions value ... * * @param control form control config object ... */ getAvatarDropAreaAllowedExtensions(control: XFormControlConfig) { return this.getAvatarConfig(control).pipe( concatMap((config) => this.getArrayValue(config.fileDropAreaAllowedExtensions) ), map((allowedExtensions) => hasChild(allowedExtensions) ? allowedExtensions : this.config.allowedImageExtensions ) ); } //#endregion // //#region Selector Config ... /** * retrieve selector control config ... * * @param control form control config object ... */ getSelectorConfig(control: XFormControlConfig) { return this.getControlTypeConfig(control).pipe( map((config) => config as XFormSelectorControlConfig) ); } /** * determines selector control has config or not ... * * @param control form control config object ... */ hasSelectorConfig(control: XFormControlConfig) { return this.getSelectorConfig(control).pipe( map((config) => !isNullOrUndefined(config)) ); } //#endregion //#endregion //#endregion // //#region Control Update On ... /** * retrieve a control UpdateOn strategy ... * * @param control form control config object ... */ getControlUpdateOn(control: XFormControlConfig) { return this.getOptionalValue(control.updateOn).pipe( map((updateOn) => (updateOn ? updateOn : XFormUpdateOn.CHANGE)) ); } //#endregion // //#region Control Validators ... /** * retrieve a control validators descriptor object ... * * @param control form control config object ... */ getControlValidators(control: XFormControlConfig) { return this.getOptionalValue(control.validators); } /** * determines a control has Validators or not ... * * @param control form control config object ... */ controlHasValidators(control: XFormControlConfig) { return this.getControlValidators(control).pipe( map((controlValidators) => !isNullOrUndefined(controlValidators)) ); } //#endregion // //#region Control Event Handlers ... /** * retrieve a control event handlers descriptor object ... * * @param control form control config object ... */ getControlEventHandlers(control: XFormControlConfig) { return this.getOptionalValue(control.eventHandlers); } /** * determines a control has validators or not ... * * @param control form control config object ... */ controlHasEventHandlers(control: XFormControlConfig) { return this.getControlEventHandlers(control).pipe( map((eventHandlers) => !isNullOrUndefined(eventHandlers)) ); } //#endregion // //#region Control Appearance Descriptor ... /** * retrieve a control appearance descriptor object ... * * @param control form control config object ... */ getControlAppearanceDesc( control: XFormControlConfig ): Observable { return !isNullOrUndefined(control) ? this.getValue(control.appearance) : of(null); } // //#region Appearance Parts ... // //#region Control Hidden ... /** * determines a control hidden or not ... * * @param control form control config object ... */ getControlHidden(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.hidden : true ) ) ); } //#endregion // //#region Control Disabled ... /** * determines a control is disabled or not ... * * @param control form control config object ... */ getControlDisabled(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.disabled : true ) ) ); } //#endregion // //#region Control Hint ... /** * retrieve a control hint ... * * @param control form control config object ... */ getControlHint(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getResourceValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.hint : '' ) ) ); } //#endregion // //#region Control Label ... /** * retrieve a control label ... * * @param control form control config object ... */ getControlLabel(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getResourceValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.label : '' ) ) ); } //#endregion // //#region Control Tooltip ... /** * retrieve a control tooltip ... * * @param control form control config object ... */ getControlTooltip(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getResourceValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.tooltip : '' ) ) ); } //#endregion // //#region Control PlaceHolder ... /** * retrieve a control placeholder ... * * @param control form control config object ... */ getControlPlaceHolder(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getResourceValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.placeholder : '' ) ) ); } //#endregion // //#region Control CssClass ... /** * retrieve a control cssClaases ... * * @param control form control config object ... */ getControlCssClass(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getArrayValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.cssClass : [] ) ), concatMap((cssClasses) => this.getControlType(control).pipe( map((type) => { return { type, cssClasses, }; }) ) ), map((descriptor) => { return descriptor.cssClasses.concat( 'x-form-control', `x-form-control-${control.index}`, `x-form-control-${descriptor.type}` ); }) ); } //#endregion // //#region Control Icons Descriptor ... /** * retrieve a control icons descriptor object ... * * @param control form control config object ... */ getControlIconDesc(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.icons : null ) ) ); } /** * determines a control has icons descriptor object or not ... * * @param control form control config object ... */ controlHasIcons(control: XFormControlConfig) { return this.getControlIconDesc(control).pipe( map((iconDesc) => !isNullOrUndefined(iconDesc)) ); } /** * determines a control has suffix icon or not ... * * @param control form control config object ... */ controlHasSuffixIcon(control: XFormControlConfig) { return this.getControlIconDesc(control).pipe( concatMap((iconDesc) => this.getOptionalValue(iconDesc ? iconDesc.suffix : null).pipe( map((iconSuffix) => !isNullOrUndefined(iconSuffix)) ) ) ); } /** * retrieve a control suffix icon object ... * * @param control form control config object ... */ getControlSuffixIcon(control: XFormControlConfig) { return this.getControlIconDesc(control).pipe( concatMap((iconDesc) => this.getOptionalValue(iconDesc ? iconDesc.suffix : null) ) ); } /** * determines a control has prefix icon or not ... * * @param control form control config object ... */ controlHasPrefixIcon(control: XFormControlConfig) { return this.getControlIconDesc(control).pipe( concatMap((iconDesc) => this.getOptionalValue(iconDesc ? iconDesc.prefix : null).pipe( map((iconPrefix) => !isNullOrUndefined(iconPrefix)) ) ) ); } /** * retrieve a control prefix icon ... * * @param control form control config object ... */ getControlPrefixIcon(control: XFormControlConfig) { return this.getControlIconDesc(control).pipe( concatMap((iconDesc) => this.getOptionalValue(iconDesc ? iconDesc.prefix : null) ) ); } /** * retrieve an icon descriptor's icon name ... * * @param icon form control icon descriptor ... */ getControlIconName(icon: XFormIconDescriptor) { return this.getValue(icon.name); } /** * retrieve an icon descriptor's icon color ... * * @param icon form control icon descriptor ... */ getControlIconColor(icon: XFormIconDescriptor) { return this.getOptionalValue(icon.color).pipe( map((color) => (color ? color : XColor.Light)) ); } /** * retrieve an icon descriptor's icon tooltip ... * * @param icon form control icon descriptor ... */ getControlIconTooltip(icon: XFormIconDescriptor) { return this.getResourceValue(icon.tooltip); } /** * retrieve an icon descriptor's apply state color ... * * @param icon form control icon descriptor ... */ getControlIconApplyStateColor(icon: XFormIconDescriptor) { return this.getOptionalValue(icon.applyStateColor); } //#endregion // //#region Control Formatter Config ... /** * retrieve a control formatter config descriptor object ... * * @param control form control config object ... */ getControlFormatterConfig(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.formatter : null ) ) ); } /** * determines a control has formatter config descriptor or not ... * * @param control form control config object ... */ controlHasFormatter(control: XFormControlConfig) { return this.getControlFormatterConfig(control).pipe( map((formatterConfig) => !isNullOrUndefined(formatterConfig)) ); } /** * retrieve a control formatter locale ... * * @param control form control config object ... */ getFormatterLocale(control: XFormControlConfig) { return this.getControlFormatterConfig(control).pipe( concatMap((formatterConfig) => this.getValue(formatterConfig.locale)) ); } /** * retrieve a control formatter seperator ... * * @param control form control config object ... */ getFormatterSeperator(control: XFormControlConfig) { return this.getControlFormatterConfig(control).pipe( concatMap((formatterConfig) => this.getOptionalValue(formatterConfig.seperator) ) ); } /** * retrieve a control formatter type ... * * @param control form control config object ... */ getFormatterType(control: XFormControlConfig) { return this.getControlFormatterConfig(control).pipe( concatMap((formatterConfig) => this.getValue(formatterConfig.type)) ); } /** * retrieve a control formatter currency label ... * * @param control form control config object ... */ getFormatterCurrencyLabel(control: XFormControlConfig) { return this.getControlFormatterConfig(control).pipe( concatMap((formatterConfig) => isNullOrUndefined(formatterConfig.currencyLable) ? of('') : this.getResourceValue(formatterConfig.currencyLable) ) ); } /** * retrieve a control formatter string formatter ... * * @param control form control config object ... */ getFormatterStringFormatter(control: XFormControlConfig) { return this.getControlFormatterConfig(control).pipe( concatMap((formatterConfig) => this.getArrayValue(formatterConfig.stringFormatter) ) ); } /** * retrieve a control formatter string formatter ... * * @param control form control config object ... */ getFormatterInputType(control: XFormControlConfig) { return this.getControlFormatterConfig(control).pipe( concatMap((formatterConfig) => isNullOrUndefined(formatterConfig.inputType) ? of(XStringInputFormatType.None) : this.getValue(formatterConfig.inputType) ) ); } //#endregion // //#region Control Progressbar ... /** * retrieve a control progress bar config descriptor object ... * * @param control form control config object ... */ getControlProgressBarConfig(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.progressBar : null ) ) ); } /** * retrieve a control has progress bar object descriptor or not ... * * @param control form control config object ... */ controlHasProgressBar(control: XFormControlConfig) { return this.getControlProgressBarConfig(control).pipe( map((progressBarConfig) => !isNullOrUndefined(progressBarConfig)) ); } /** * retrieve a control progressbar color ... * * @param control form control config object ... */ getProgressBarColor(control: XFormControlConfig) { return this.getControlProgressBarConfig(control).pipe( concatMap((progressBarConfig) => this.getValue(progressBarConfig.color)) ); } //#endregion // //#region Control AutoComplete ... /** * retrieve an id number for form control auto complete view ... * * @param control form control config object ... */ getAutoCompleteId(control: XFormControlConfig) { return `x-${control.propName.toString()}-auto-complete`; } /** * retrieve a control autocomplete config object ... * * @param control form control config object ... */ getControlAutoCompleteConfig(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.autoComplete : null ) ) ); } /** * retrieve a control has autocomplete or not ... * * @param control form control config object ... */ controlHasAutoComplete(control: XFormControlConfig) { return this.getControlAutoCompleteConfig(control).pipe( map((autoConpleteConfig) => !isNullOrUndefined(autoConpleteConfig)) ); } /** * retrieve a control autocomplete opened ... * * @param control form control config object ... */ getAutoCompleteOpened(control: XFormControlConfig) { return this.getControlAutoCompleteConfig(control).pipe( concatMap((autoCompleteConfig) => this.getOptionalValue(autoCompleteConfig.opened) ) ); } /** * retrieve a control autocomplete item template ... * * @param control form control config object ... */ getAutoCompleteItemTemplate(control: XFormControlConfig) { return this.getControlAutoCompleteConfig(control).pipe( concatMap((autoCompleteConfig) => this.getValue(autoCompleteConfig.itemTemplate) ) ); } /** * retrieve a control autocomplete color ... * * @param control form control config object ... */ getAutoCompleteColor(control: XFormControlConfig) { return this.getControlAutoCompleteConfig(control).pipe( concatMap((autoCompleteConfig) => this.getOptionalValue(autoCompleteConfig.color).pipe( map((color) => (color ? color : XColor.Light)) ) ) ); } /** * retrieve a control autocomplete onSelect ... * * @param control form control config object ... */ getAutoCompleteOnSelect(control: XFormControlConfig) { return this.getControlAutoCompleteConfig(control).pipe( concatMap((autoCompleteConfig) => this.getValue(autoCompleteConfig.onSelect) ) ); } /** * retrieve a control autocomplete Items ... * * @param control form control config object ... */ getAutoCompleteItems(control: XFormControlConfig) { return this.getControlAutoCompleteConfig(control).pipe( concatMap((autoCompleteConfig) => { return !isNullOrUndefined(autoCompleteConfig.items) && isFunction(autoCompleteConfig.items) ? this.getArrayValue(autoCompleteConfig.items()) : this.getValue([]); }) ); } /** * retrieve autocomplete CssClass ... * * @param control form control config object ... */ getAutoCompleteCssClass(control: XFormControlConfig) { return this.getControlAutoCompleteConfig(control).pipe( concatMap((autoCompleteConfig) => this.getArrayValue(autoCompleteConfig.cssClass).pipe( map((cssClasses) => cssClasses.concat( 'x-auto-complete', `x-${control.propName.toString()}-auto-complete` ) ) ) ) ); } /** * retrieve control errors classes ... * * @param control form control config ... */ getControlErrorsClasses(control: XFormControlConfig) { return this.getControlType(control).pipe( map((type) => { return [ 'x-form-control-errors', `x-form-${type}-control-errors`, `x-form-control-${control.index.toString()}-errors`, `x-form-control-${control.propName.toString()}-errors`, ]; }) ); } /** * retrieve special control's special error's class list ... * * @param control form control config ... * @param handler form error handler instance ... */ getControlErrorClasses( control: XFormControlConfig, handler: XFormErrorHandler ) { return this.getControlType(control).pipe( concatMap((type) => this.getErrorHandlerErrorName(handler).pipe( map((errorName) => { return { type, errorName, }; }) ) ), map((descriptor) => { return [ 'x-form-field-error', `x-form-field-${descriptor.type}-error`, `x-form-field-${descriptor.errorName}-error`, `x-form-field-${control.propName.toString()}-error`, `x-form-field-${descriptor.type}-${descriptor.errorName}-error`, ]; }) ); } //#endregion // //#region Control Appearance ... /** * retrieve a control appearance ... * * @param control form control config object ... */ getControlAppearance(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) && !isNullOrUndefined(appearanceConfig.appearance) ? appearanceConfig.appearance : XFormControlAppearance.Fill ).pipe(map((result) => result as MatFormFieldAppearance)) ) ); } getControlAppearanceObject(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) && !isNullOrUndefined(appearanceConfig.appearance) ? appearanceConfig.appearance : XFormControlAppearance.Fill ) ) ); } //#endregion // //#region Control Label Position ... /** * retrieve a control label position ... * * @param control form control config object ... */ getControlLabelPosition(control: XFormControlConfig) { return this.getControlAppearanceDesc(control).pipe( concatMap((appearanceConfig) => this.getOptionalValue( !isNullOrUndefined(appearanceConfig) ? appearanceConfig.labelPosition : XFormControlLabelPosition.Before ) ) ); } //#endregion //#endregion //#endregion // //#region Control Error Handlers ... /** * retrieve a control error handlers descriptor object ... * * @param control form control config object ... */ getControlErrorHandlers(control: XFormControlConfig) { return this.getArrayValue(control.errorHandlers); } /** * determines a control has error handlers descriptors object or not ... * * @param control form control config object ... */ controlHasErrorHandlers(control: XFormControlConfig) { return this.hasChildValue(this.getControlErrorHandlers(control)); } controlHasErrors(control: XFormControlConfig) { return this.getValue(control).pipe( concatMap((ctrl) => this.getValue(this.getControl(ctrl.propName)).pipe( map((fControl) => ({ ctrl, fControl })) ) ), map((ctrlInfo) => { return isNullOrUndefined(ctrlInfo.ctrl) || isNullOrUndefined(ctrlInfo.fControl) ? false : !isNullOrUndefined(ctrlInfo.fControl.errors); }) ); } /** * determines a control has specific error or not ... * * @param controlName control name ... * @param errorName error name ... */ controlHasErrorByName( controlName: XFormControlNameIdentifier, errorName: string ) { // const control = this.getControl(controlName); if (!control) { return false; } // const result = !isNullOrUndefined(control.errors) && keys(control.errors).includes(errorName) && !isNullOrUndefined(control.errors[errorName]); // return result; } /** * determine a control has specific error or not ... * * @param control form control config ... * @param handler form error handler instance ... */ controlHasError(control: XFormControlConfig, handler: XFormErrorHandler) { return this.getErrorHandlerErrorName(handler).pipe( map((errorName) => { return this.controlHasErrorByName(control.propName, errorName); }) ); } controlGetError(control: XFormControlConfig, handler: XFormErrorHandler) { return this.getErrorHandlerErrorName(handler).pipe( map((errorName) => { return this.controlHasErrorByName(control.propName, errorName); }) ); } /** * retrieve specific error of a control ... * * @param controlName control name ... * @param errorName error name ... */ getControlErrorByName( controlName: XFormControlNameIdentifier, errorName: string ) { // const control = this.getControl(controlName); if (!this.controlHasErrorByName(controlName, errorName)) { return false; } // return control.errors[errorName] || null; } /** * retrieve specific error of a control ... * * @param control form control config ... * @param handler form error handler instance ... */ getControlError(control: XFormControlConfig, handler: XFormErrorHandler) { return this.getErrorHandlerErrorName(handler).pipe( map((errorName) => { if (!isNullOrUndefined(control)) { return this.getControlErrorByName(control.propName, errorName); } else { return this.getFormErrorByName(errorName); } }) ); } //#endregion //#endregion // //#region Error Handler Providers ... /** * retrieve an error handler error name ... * * @param errorHandler an error handler descriptor object ... */ getErrorHandlerErrorName(errorHandler: XFormErrorHandler) { return this.getValue(errorHandler.errorName); } /** * retrieve an error handler error message ... * * @param errorHandler an error handler descriptor object ... */ getErrorHandlerErrorMessage( errorHandler: XFormErrorHandler, control?: XFormControlConfig ) { // if ( errorHandler.errorDataProvider && isFunction(errorHandler.errorDataProvider) ) { // return this.getControlError(control, errorHandler).pipe( concatMap((controlError) => this.getResourceValue(errorHandler.errorDataProvider(controlError)) ) ); } else { return this.getResourceValue(errorHandler.errorMessage); } } //#endregion //#endregion // //#region UI Handlers ... // //#region Common Controls UI Handlers ... async handleControlBlured(name: XFormControlNameIdentifier) { // if (!this.FORM_CONFIG || !this.hasControl(name)) { return; } // const control = await this.getValueAsync(this.getFormControl(name)); if (!control) { return; } // const eventModel: XBaseFormControlActionModel = { name: control.propName, }; // this.controlBlured.emit(eventModel); // const eventHandlers = await this.getValueAsync( this.getControlEventHandlers(control) ); if (!eventHandlers || !eventHandlers.onBlured) { return; } // await this.getValueAsync(eventHandlers.onBlured(eventModel)); } async handleControlFocused(name: XFormControlNameIdentifier) { // if (!this.FORM_CONFIG || !this.hasControl(name)) { return; } // const control = await this.getValueAsync(this.getFormControl(name)); if (!control) { return; } // const inputId = await this.getValueAsync( this.getControlInputElementId(control) ); this.currentInputFocus = inputId; // const eventModel: XBaseFormControlActionModel = { name: control.propName, }; // this.controlFocused.emit(eventModel); // const eventHandlers = await this.getValueAsync( this.getControlEventHandlers(control) ); if (!eventHandlers || !eventHandlers.onFocused) { return; } // await this.getValueAsync(eventHandlers.onFocused(eventModel)); } async handleControlValueChanged(event: XFormControlValueChangeEventModel) { // if ( !this.FORM || this.uiDisabled || !this.FORM_CONFIG || !this.hasControl(event.name) ) { return; } // const control = await this.getValueAsync(this.getFormControl(event.name)); if (control) { // const isDisabled = await this.getValueAsync( this.getControlDisabled(control) ); if (isDisabled) { return; } } // this.controlValueChanged.emit(event); } async handleControlStatusChanged(event: XFormControlStatusChangeEventModel) { // if ( !this.FORM || this.uiDisabled || !this.FORM_CONFIG || !this.hasControl(event.name) ) { return; } // const control = await this.getValueAsync(this.getFormControl(event.name)); if (control) { // const isDisabled = await this.getValueAsync( this.getControlDisabled(control) ); if (isDisabled) { return; } } // this.controlStatusChanged.emit(event); } async handleControlIconClicked(icon: XFormIconDescriptor) { // if (!this.FORM || !this.FORM_CONFIG || !icon.handler) { return; } // await this.getValueAsync(icon.handler()); } async handleControlActionIconClicked( role: XControlIconRoleIdentifier, descriptor: XControlIconDescriptor, control: XFormControlConfig ) { // const type = await this.getValueAsync(this.getControlType(control)); // switch (type) { // case XFormControlType.Map: // await this.handleMapIconClicked(role, descriptor, control); break; // case XFormControlType.Selector: await this.handleItemSelectorIconClicked(role, descriptor, control); break; // case XFormControlType.ColorPicker: // await this.handleColorPickerIconClicked(role, descriptor, control); break; // default: break; } } //#endregion // //#region DatePicker UI Handlers ... async handleDatePickerDateInput( name: XFormControlNameIdentifier, event: MatDatepickerInputEvent ) { // let result: Date = null; const isDateInput = isDate(event.value); const isMomentInput = isMoment(event.value); if (isMomentInput) { result = momentToDate(event.value); } else if (isDateInput) { result = event.value as Date; } // await this.setValue(name, result); // if (!this.FORM_CONFIG || !this.hasControl(name)) { return; } // const control = await this.getValueAsync(this.getFormControl(name)); if (!control) { return; } // const handler = await this.getValueAsync(this.getDateInputHandler(control)); if (!handler) { return; } // // Fire Hanlder ... await this.getValueAsync(handler(result)); } async handleDatePickerDateChange( name: XFormControlNameIdentifier, event: MatDatepickerInputEvent ) { // let result: Date = null; const isDateInput = isDate(event.value); const isMomentInput = isMoment(event.value); if (isMomentInput) { result = momentToDate(event.value); } else if (isDateInput) { result = event.value as Date; } // await this.setValue(name, result); // if (!this.FORM_CONFIG || !this.hasControl(name)) { return; } // const control = await this.getValueAsync(this.getFormControl(name)); if (!control) { return; } // const handler = await this.getValueAsync( this.getDateChangeHandler(control) ); if (!handler) { return; } // // Fire Hanlder ... await this.getValueAsync(handler(result)); } //#endregion // //#region Auto Complete Controls UI Handlers ... async handleAutoCompleteResultSelected( control: XFormControlConfig, autoComplete: XFormControlAutoCompleteConfig, event: any ) { // if (!this.FORM || !this.FORM_CONFIG || !this.hasControl(control.propName)) { return; } // const formCtrl = this.getControl(control.propName); if (!formCtrl) { return; } // formCtrl.setValue(event.data); const formInputControl = this.getElementById( this.getControlInputElementId(control) ); if (formInputControl) { (formInputControl as HTMLInputElement).select(); } // if (autoComplete.onSelect && isFunction(autoComplete.onSelect)) { await this.getValueAsync(autoComplete.onSelect(event)); } // this.focusOnControl(control.propName); // this.detectChanges(); } async handleAutoCompleteEscaped(control: XFormControlConfig) { // if (!this.FORM || !this.FORM_CONFIG || !this.hasControl(control.propName)) { return; } // const autoComplete = await this.getValueAsync( this.getControlAutoCompleteConfig(control) ); if ( autoComplete && autoComplete.onEscape && isFunction(autoComplete.onEscape) ) { await this.getValueAsync(autoComplete.onEscape()); } // this.detectChanges(); } async handleAutoCompleteOutsideClicked(control: XFormControlConfig) { // if (!this.FORM || !this.FORM_CONFIG || !this.hasControl(control.propName)) { return; } // const autoComplete = await this.getValueAsync( this.getControlAutoCompleteConfig(control) ); if ( autoComplete && autoComplete.onOutsideClicked && isFunction(autoComplete.onOutsideClicked) ) { await this.getValueAsync(autoComplete.onOutsideClicked()); } // this.detectChanges(); } //#endregion // //#region Markdown Control UI Handlers ... async handleMarkDownContentChanged( name: XFormControlNameIdentifier, event: string ) { // if (!this.hasControl(name)) { return; } // await this.setValue(name, event); // const controlConfig = await this.getValueAsync(this.getFormControl(name)); if (!controlConfig) { return; } // const markDownConfig = await this.getValueAsync( this.getMarkdownConfig(controlConfig) ); if (!markDownConfig || !markDownConfig.contentChanged) { return; } // await this.getValueAsync(markDownConfig.contentChanged(event)); } //#endregion // //#region Checkbox Control UI Handlers ... async handleCheckboxCheckedChange( control: XFormControlConfig, checked: boolean ) { // if (!this.hasControl(control.propName)) { return; } // const config = await this.getValueAsync(this.getCheckboxConfig(control)); if (!config || !config.checkedChanged) { return; } // await this.getValueAsync(config.checkedChanged(checked)); } //#endregion // //#region Map UI Handlers ... async handleMapIsReady(control: XFormControlConfig) { // if (!this.hasControl(control.propName)) { return; } // const config = await this.getValueAsync(this.getMapConfig(control)); if (!config || !config.isReady) { return; } // config.isReady.emit(); } async handleMapZoomChanged(control: XFormControlConfig, zoom: number) { } async handleMapLocationSelected( control: XFormControlConfig, event: XMapLocation ) { // if (!this.hasControl(control.propName)) { return; } // const longLat = event ? toLongLat(event) : null; await this.setValue(control.propName, longLat); // const config = await this.getValueAsync(this.getMapConfig(control)); if (!config || !config.locationSelected) { return; } // config.locationSelected.emit(event); } async handleMapIconClicked( role: XControlIconRoleIdentifier, descriptor: XControlIconDescriptor, control: XFormControlConfig ) { // const presentType = await this.getValueAsync( this.getMapPresentType(control) ); // switch (role) { // case this.ControlIconRoles.Clear: await this.managerService.dialogService.presentAreYouSureYesNoDialog( async () => { // await this.setValue(control.propName, undefined); // const mapControlActionPtovider = await this.getValueAsync( this.getMapActionProvider(control) ); if ( mapControlActionPtovider && presentType === XFormMapControlPresentType.WithoutDialog ) { // // Clear Marker ... mapControlActionPtovider.next({ action: XMapAction.ClearMarker, }); } // // Notify Handler ... if ( !isNullOrUndefined(descriptor) && !isNullOrUndefined(descriptor.handler) && isFunction(descriptor.handler) ) { await this.getValueAsync(descriptor.handler()); } } ); break; // case this.ControlIconRoles.Select: // // Notify Handler ... if ( !isNullOrUndefined(descriptor) && !isNullOrUndefined(descriptor.handler) && isFunction(descriptor.handler) ) { await this.getValueAsync(descriptor.handler()); } // let center: XMapLocation = null; const longLatControl = this.getControl(control.propName); if (longLatControl) { // const longLat = longLatControl.value as string; if (!isNullOrEmptyString(longLat)) { center = fromLongLat(longLat); } } // // Prevent go forward if map control present type does't support map dialog ... if (presentType === XFormMapControlPresentType.WithoutDialog) { return; } // // Prepare Selector Dialog Config ... const controlConfig = await this.getValueAsync( this.getMapConfig(control) ); const dialogConfig: XMapDialogConfig = { ...controlConfig, // latitude: center && center.latitude ? +center.latitude : 0, longitude: center && center.longitude ? +center.longitude : 0, // showSelectedLocation: true, }; // // Open Dialog ... await this.mapDialogService.openDialog(dialogConfig); // // Wait for Handle Dialog Result ... const s = this.mapDialogService.onResult .asObservable() .subscribe(async (result) => { // let value: any; // if ( !isNullOrUndefined(result) && !isNullOrUndefined(result.payload) && result.result === XDialogResult.Ok ) { value = toLongLat(result.payload); } // if (!isNullOrUndefined(value)) { await this.setValue(control.propName, value); } // s.unsubscribe(); }); break; } } async handleMapControlInputValueChanged( control: XFormControlConfig, event: string ) { // if (!this.hasControl(control.propName)) { return; } // const config = await this.getValueAsync(this.getMapConfig(control)); if ( !config || !config.inputValueChanged || !isFunction(config.inputValueChanged) ) { return; } // await this.getValueAsync(config.inputValueChanged(event)); } async handleMapSearchBarQueryChange( control: XFormControlConfig, event: string ) { // if (!this.hasControl(control.propName)) { return; } // const config = await this.getValueAsync(this.getMapConfig(control)); if (!config || !config.searchBarQueryChange) { return; } // config.searchBarQueryChange.emit(event); } //#endregion // //#region ColorPicker UI Handlers ... async handleColorPickerIconClicked( role: XControlIconRoleIdentifier, descriptor: XControlIconDescriptor, control: XFormControlConfig ) { // switch (role) { // case this.ControlIconRoles.Clear: await this.managerService.dialogService.presentAreYouSureYesNoDialog( async () => { // await this.setValue(control.propName, undefined); // // Notify Handler ... if ( !isNullOrUndefined(descriptor) && !isNullOrUndefined(descriptor.handler) && isFunction(descriptor.handler) ) { await this.getValueAsync(descriptor.handler()); } } ); break; // case this.ControlIconRoles.Select: // // Notify Handler ... if ( !isNullOrUndefined(descriptor) && !isNullOrUndefined(descriptor.handler) && isFunction(descriptor.handler) ) { await this.getValueAsync(descriptor.handler()); } // const presentType = await this.getValueAsync( this.getColorPickerPresentType(control) ); // // Prevent go forward if color picker control present type does't support map dialog ... if (presentType === XFormColorPickerControlPresentType.WithoutDialog) { return; } // let selectedColor: string = null; const colorPickerControl = this.getControl(control.propName); if (colorPickerControl) { // const colorVal = colorPickerControl.value as string; if (!isNullOrEmptyString(colorVal)) { selectedColor = colorVal; } } // // Prepare Selector Dialog Config ... const controlConfig = await this.getValueAsync( this.getColorPickerConfig(control) ); const dialogConfig: XColorPickerDialogConfig = { ...controlConfig, // selectedColor, }; // // Open Dialog ... await this.colorPickerDialogService.openDialog(dialogConfig); // // Wait for Handle Dialog Result ... const s = this.colorPickerDialogService.onResult .asObservable() .subscribe(async (result) => { // let value: any; // if ( !isNullOrUndefined(result) && !isNullOrUndefined(result.payload) && result.result === XDialogResult.Ok ) { value = result.payload; } // if (!isNullOrUndefined(value)) { await this.setValue(control.propName, value); } // s.unsubscribe(); }); break; } } async handleColorPickerControlInputValueChanged( control: XFormControlConfig, event: string ) { // if (!this.hasControl(control.propName)) { return; } // const config = await this.getValueAsync(this.getColorPickerConfig(control)); if ( !config || !config.inputValueChanged || !isFunction(config.inputValueChanged) ) { return; } // await this.getValueAsync(config.inputValueChanged(event)); } async handleColorPickerColorSelected( control: XFormControlConfig, event: string ) { // if (!this.hasControl(control.propName)) { return; } // await this.setValue(control.propName, event); // const config = await this.getValueAsync(this.getColorPickerConfig(control)); if (!config || !config.colorSelected) { return; } // config.colorSelected.emit(event); } //#endregion // //#region Avatar UI Handlers ... async handleAvatarFileDropAreaFilesChangeEmitter( control: XFormControlConfig, event?: XOneOrManyType ) { // if (!event || !this.hasControl(control.propName)) { return; } // const config = await this.getValueAsync(this.getAvatarConfig(control)); if ( !config || !config.fileDropAreaFilesChangeEmiter || !isFunction(config.fileDropAreaFilesChangeEmiter) ) { return; } // await this.getValueAsync(config.fileDropAreaFilesChangeEmiter(event)); } async handleAvatarAvatarChange(control: XFormControlConfig, event?: File) { // if (!this.hasControl(control.propName)) { return; } // await this.setValue(control.propName, event); // const config = await this.getValueAsync(this.getAvatarConfig(control)); if (!config || !config.avatarChange || !isFunction(config.avatarChange)) { return; } // await this.getValueAsync(config.avatarChange(event)); } //#endregion // //#region Selector UI Handlers ... async handleItemSelectorIconClicked( role: XControlIconRoleIdentifier, descriptor: XControlIconDescriptor, control: XFormControlConfig ) { // switch (role) { // case this.ControlIconRoles.Clear: await this.managerService.dialogService.presentAreYouSureYesNoDialog( async () => { // await this.setValue(control.propName, undefined); // // Notify Handler ... if ( !isNullOrUndefined(descriptor) && !isNullOrUndefined(descriptor.handler) && isFunction(descriptor.handler) ) { await this.getValueAsync(descriptor.handler()); } } ); break; // case this.ControlIconRoles.Select: // // Notify Handler ... if ( !isNullOrUndefined(descriptor) && !isNullOrUndefined(descriptor.handler) && isFunction(descriptor.handler) ) { await this.getValueAsync(descriptor.handler()); } // // Prepare Selector Dialog Config ... const controlConfig = await this.getValueAsync( this.getSelectorConfig(control) ); const dialogConfig: XFormSelectorControlConfig = { ...controlConfig, }; // // Open Dialog ... await this.selectorDialogService.openDialog(dialogConfig); // // Wait for Handle Dialog Result ... const s = this.selectorDialogService.onResult .asObservable() .subscribe(async (result) => { // let content: any; // if ( !isNullOrUndefined(result) && !isNullOrUndefined(result.payload) && result.result === XDialogResult.Ok ) { content = result.payload; } // if (!isNullOrUndefined(content)) { // const value = !controlConfig || !controlConfig.formatSelectedItem || !isFunction(controlConfig.formatSelectedItem) ? content : await this.getValueAsync( controlConfig.formatSelectedItem(content) ); // await this.setValue(control.propName, value); } // s.unsubscribe(); }); break; } } async handleSelectorControlInputValueChanged( control: XFormControlConfig, event: string ) { // if (!this.hasControl(control.propName)) { return; } // const config = await this.getValueAsync(this.getSelectorConfig(control)); if ( !config || !config.inputValueChanged || !isFunction(config.inputValueChanged) ) { return; } // await this.getValueAsync(config.inputValueChanged(event)); } //#endregion //#endregion // //#region Actions ... /** * determine a control exists or not ... * * @param name a control name ... */ hasControl(name: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return false; } // const controlName = this.getControlName(name); if (!controlName) { return false; } // return ( this.FORM.contains(controlName) || !isNullOrUndefined(this.FORM.controls[controlName]) ); } /** * retrieve a control based on it's name ... * * @param name a control name ... */ getControl(name: XFormControlNameIdentifier) { // if (!this.hasControl(name)) { return null; } // const controlName = this.getControlName(name); if (!controlName) { return null; } // return this.FORM.get(controlName) || null; } /** * retrieve a form control status if exists in form ... * * @param control a form control config ... */ getControlStatus(control: XFormControlConfig) { // const mControl = this.getControl(control.propName); if (!mControl) { return XFormStatus.UnKnown; } // return mControl.status as XFormStatus; } /** * focus on a control ... * * @param name a control name ... */ focusOnControl(name: XFormControlNameIdentifier) { // if (!this.hasControl(name)) { return; } // const inputElement = this.getElementById( this.getControlInputElementIdByName(name) ); if (!inputElement) { return; } // setTimeout(() => inputElement.focus(), 100); } /** * blur from a control ... * * @param name a control name ... */ blurOfControl(name: XFormControlNameIdentifier) { // if (!this.hasControl(name)) { return; } // const inputElement = this.getElementById( this.getControlInputElementIdByName(name) ); if (!inputElement) { return; } // setTimeout(() => inputElement.blur(), 100); } /** * determines specific control has value or not ... * * @param name a control name ... */ controlHasValue(name: XFormControlNameIdentifier) { return !this.hasControl(name) ? false : this.getControl(name).value && !isNullOrEmptyString(this.getControl(name).value.toString()); } /** * retrieve an specific control value ... * * @param name a control name ... */ getControlValue(name: XFormControlNameIdentifier) { return !this.hasControl(name) ? undefined : this.getControl(name).value; } /** * determines a control has error by it's name ... * * @param name a control name ... */ controlHasErrorByControlName(name: XFormControlNameIdentifier) { return !this.hasControl(name) ? false : !isNullOrUndefined(this.getControl(name).errors); } /** * set a value to an specific control or form ... * * @param name a control name ... * @param value a value of any type ... */ async setValue(name?: XFormControlNameIdentifier, value?: any) { // if (!name) { return; } // if (name) { // const control = this.getControl(name); if (!control) { return; } // control.setValue(value); } else { this.FORM.setValue(value, { emitEvent: true }); } // this.detectChanges(); } /** * trigger markAsDirty on form or specific control ... * if provide a control name and it's exists ... * * @param name a control name ... */ async markAsDirty(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG || this.uiDisabled) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.markAsDirty(); this.detectChanges(); return; } // control.markAsDirty(); this.detectChanges(); } /** * trigger markAsTouched on form or specific control ... * if provide a control name and it's exists ... * * @param name a control name ... */ async markAsTouched(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.markAsTouched(); this.detectChanges(); return; } // control.markAsTouched(); this.detectChanges(); } /** * trigger markAsPending on form or specific control ... * if provide a control name and it's exists ... * * @param name a control name ... */ async markAsPending(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.markAsPending(); this.detectChanges(); return; } // control.markAsPending(); this.detectChanges(); } /** * trigger markAsPristine on form or specific control ... * if provide a control name and it's exists ... * * @param name a control name ... */ async markAsPristine(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.markAsPristine(); this.detectChanges(); return; } // control.markAsPristine(); this.detectChanges(); } /** * trigger markAsUntouched on form or specific control ... * if provide a control name and it's exists ... * * @param name a control name ... */ async markAsUnTouched(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.markAsUntouched(); this.detectChanges(); return; } // control.markAsUntouched(); this.detectChanges(); } /** * trigger updateValueAndValidity on form or specific control ... * if provide a control name and it's exists ... * * @param name a control name ... */ async updateValueAndValidity(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.updateValueAndValidity({ emitEvent: true }); this.detectChanges(); return; } // control.updateValueAndValidity({ emitEvent: true }); this.detectChanges(); } /** * trigger setError on form or specific control ... * if provide a control name and it's exists ... * * @param errors: an instance of ValidationErrors object ... * @param name a control name ... */ async setError(errors: ValidationErrors, name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.setErrors(errors, { emitEvent: true }); this.detectChanges(); return; } // control.setErrors(errors, { emitEvent: true }); this.detectChanges(); } /** * clearErrors on form or specific control ... * if provide a control name and it's exists ... * * @param name a control name ... */ async clearError(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.setErrors(null, { emitEvent: true }); this.detectChanges(); return; } // control.setErrors(null, { emitEvent: true }); this.detectChanges(); } /** * enable form or form control ... * * @param name a control name ... */ async enable(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.enable({ emitEvent: true }); this.detectChanges(); return; } // control.enable({ emitEvent: true }); this.detectChanges(); } /** * disable form or form control ... * * @param name a control name ... */ async disable(name?: XFormControlNameIdentifier) { // if (!this.FORM || !this.FORM_CONFIG) { return; } // const control = this.getControl(name); if (!control) { // this.FORM.disable({ emitEvent: true }); this.detectChanges(); return; } // control.disable({ emitEvent: true }); this.detectChanges(); } /** * remove all data and form elements ... */ async clearData() { // // this.formConfig = null; this.FORM_CONFIG = null; this.FORM = null; // this.detectChanges(); // await this.prepareFormGroup(); } /** * refresh component ... */ async refresh() { this.detectChanges(); } //#endregion // //#region Private ... // //#region Prepare Form Group ... private async prepareFormGroup() { // //#region Form Config ... // this.currentInputFocus = undefined; const modelFormConfig = await this.getValueAsync(this.formConfig); if (!modelFormConfig) { return; } // const formConfig = { name: await this.getValueAsync(this.getFormName()), model: (await this.getValueAsync(this.formHasModel())) ? await this.getValueAsync(this.getFormModel()) : undefined, updateOn: await this.getValueAsync(this.getFormUpdateOn()), controls: await Promise.all( ( await this.getValueAsync(this.getFormControls()) ).map(async (c) => { // //#region Action Provider ... let actionProvider = c.actionProvider ? c.actionProvider : undefined; // if (!actionProvider) { // if (!this.actionProviders[c.propName]) { this.actionProviders[c.propName] = new Subject(); } // actionProvider = this.actionProviders[c.propName]; } //#endregion // //#region Control ... return { index: c.index, propName: c.propName, type: { type: await this.getValueAsync(this.getControlType(c)), config: await this.getValueAsync(this.getControlTypeConfig(c)), }, updateOn: await this.getValueAsync(this.getControlUpdateOn(c)), validators: (await this.getValueAsync(this.controlHasValidators(c))) ? await this.getValueAsync(this.getControlValidators(c)) : undefined, actionProvider, eventHandlers: (await this.getValueAsync( this.controlHasEventHandlers(c) )) ? await this.getValueAsync(this.getControlEventHandlers(c)) : undefined, appearance: { hidden: await this.getValueAsync(this.getControlHidden(c)), disabled: await this.getValueAsync(this.getControlDisabled(c)), hint: await this.getValueAsync(this.getControlHint(c)), label: await this.getValueAsync(this.getControlLabel(c)), tooltip: await this.getValueAsync(this.getControlTooltip(c)), placeholder: await this.getValueAsync( this.getControlPlaceHolder(c) ), cssClass: await this.getValueAsync(this.getControlCssClass(c)), icons: (await this.getValueAsync(this.controlHasIcons(c))) ? { suffix: (await this.getValueAsync( this.controlHasSuffixIcon(c) )) ? { name: await this.getValueAsync( this.getControlIconName( await this.getValueAsync( this.getControlSuffixIcon(c) ) ) ), color: await this.getValueAsync( this.getControlIconColor( await this.getValueAsync( this.getControlSuffixIcon(c) ) ) ), applyStateColor: await this.getValueAsync( this.getControlIconApplyStateColor( await this.getValueAsync( this.getControlSuffixIcon(c) ) ) ), handler: ( await this.getValueAsync( this.getControlSuffixIcon(c) ) ).handler, } : undefined, prefix: (await this.getValueAsync( this.controlHasPrefixIcon(c) )) ? { name: await this.getValueAsync( this.getControlIconName( await this.getValueAsync( this.getControlPrefixIcon(c) ) ) ), color: await this.getValueAsync( this.getControlIconColor( await this.getValueAsync( this.getControlPrefixIcon(c) ) ) ), applyStateColor: await this.getValueAsync( this.getControlIconApplyStateColor( await this.getValueAsync( this.getControlPrefixIcon(c) ) ) ), handler: ( await this.getValueAsync( this.getControlPrefixIcon(c) ) ).handler, } : undefined, } : undefined, formatter: (await this.getValueAsync(this.controlHasFormatter(c))) ? { locale: await this.getValueAsync( this.getFormatterLocale(c) ), seperator: await this.getValueAsync( this.getFormatterSeperator(c) ), type: await this.getValueAsync(this.getFormatterType(c)), currencyLable: await this.getValueAsync( this.getFormatterCurrencyLabel(c) ), inputType: await this.getValueAsync( this.getFormatterInputType(c) ), stringFormatter: await this.getValueAsync( this.getFormatterStringFormatter(c) ), } : undefined, progressBar: (await this.getValueAsync( this.controlHasProgressBar(c) )) ? { color: await this.getValueAsync( this.getProgressBarColor(c) ), } : undefined, autoComplete: (await this.getValueAsync( this.controlHasAutoComplete(c) )) ? { itemTemplate: await this.getValueAsync( this.getAutoCompleteItemTemplate(c) ), opened: await this.getValueAsync( this.getAutoCompleteOpened(c) ), color: await this.getValueAsync( this.getAutoCompleteColor(c) ), onSelect: await this.getValueAsync( this.getAutoCompleteOnSelect(c) ), items: await this.getValueAsync( this.getAutoCompleteItems(c) ), cssClass: await this.getValueAsync( this.getAutoCompleteCssClass(c) ), } : undefined, appearance: await this.getValueAsync( this.getControlAppearance(c) ), labelPosition: await this.getValueAsync( this.getControlLabelPosition(c) ), }, errorHandlers: (await this.getValueAsync( this.controlHasErrorHandlers(c) )) ? await Promise.all( ( await this.getValueAsync(this.getControlErrorHandlers(c)) ).map(async (e) => { return { errorName: await this.getValueAsync(e.errorName), errorMessage: await this.getResourceValueAsync( e.errorMessage ), }; }) ) : undefined, }; //#endregion }) ), validators: (await this.getValueAsync(this.formHasValidators())) ? await this.getValueAsync(this.getFormValidators()) : undefined, errorHandlers: (await this.getValueAsync(this.formHasErrorHandlers())) ? await Promise.all( ( await this.getValueAsync(this.getFormErrorHandlers()) ).map(async (e) => { return { errorName: await this.getValueAsync(e.errorName), errorMessage: await this.getResourceValueAsync(e.errorMessage), }; }) ) : undefined, }; // if (!this.FORM_CONFIG) { this.FORM_CONFIG = formConfig; } //#endregion // //#region Preparing Form Controls ... const controls = assign( {}, ...formConfig.controls .map((c) => { // const initialValue = { value: !isNullOrUndefined(formConfig.model) && !isNullOrUndefined(formConfig.model[c.propName.toString()]) ? formConfig.model[c.propName.toString()] : null, disabled: this.uiDisabled || (c.appearance && c.appearance.disabled ? c.appearance.disabled : false), }; // const formControl = new FormControl(initialValue, { updateOn: c.updateOn.toString() as 'change' | 'blur' | 'submit', validators: c.validators ? c.validators.validators : null, asyncValidators: c.validators ? c.validators.asyncValidators : null, }); // //#region Apply Event Handlers ... // //#region Value Change ... formControl.valueChanges.subscribe(async (res) => { // const eventModel: XFormControlValueChangeEventModel = { name: c.propName, value: res, }; // if ( c.eventHandlers && c.eventHandlers.valueChanged && isFunction(c.eventHandlers.valueChanged) ) { c.eventHandlers.valueChanged(eventModel); } // await this.handleControlValueChanged(eventModel); // //#region Handle Map Control Input Value Change Action ... const controlConfig = await this.getValueAsync( this.getFormControl(c.propName) ); if (controlConfig) { // const type = await this.getValueAsync( this.getControlType(controlConfig) ); // if (type === XFormControlType.Map) { await this.handleMapControlInputValueChanged( controlConfig, res ); } else if (type === XFormControlType.ColorPicker) { await this.handleColorPickerControlInputValueChanged( controlConfig, res ); } else if (type === XFormControlType.Selector) { await this.handleSelectorControlInputValueChanged( controlConfig, res ); } } //#endregion // this.detectChanges(); }); // // Notify Initial Value ... if ( !isNullOrUndefined(initialValue) && !isNullOrUndefined(initialValue.value) ) { // const eventModel: XFormControlValueChangeEventModel = { name: c.propName, value: initialValue.value, }; // if ( c.eventHandlers && c.eventHandlers.valueChanged && isFunction(c.eventHandlers.valueChanged) ) { c.eventHandlers.valueChanged(eventModel); } // this.controlValueChanged.emit(eventModel); } //#endregion // //#region Status Change ... formControl.statusChanges.subscribe(async (res) => { // const eventModel: XFormControlStatusChangeEventModel = { name: c.propName, status: res, }; // if ( c.eventHandlers && c.eventHandlers.statusChanged && isFunction(c.eventHandlers.statusChanged) ) { c.eventHandlers.statusChanged(eventModel); } // await this.handleControlStatusChanged(eventModel); // this.detectChanges(); }); //#endregion //#endregion // //#region Apply Action Provider ... if (c.actionProvider) { // c.actionProvider.asObservable().subscribe(async (model) => { // if ( !model || !model.name || isNullOrEmptyString(model.name.toString()) || !this.hasControl(model.name) ) { return; } // switch (model.action) { // case XFormBaseAction.Enable: await this.enable(model.name); break; // case XFormBaseAction.Disable: await this.disable(model.name); break; // case XFormBaseAction.SetError: // const errors = model.payload as ValidationErrors; if (model.payload && errors) { await this.setError(errors, model.name); } break; // case XFormBaseAction.ClearError: await this.clearError(model.name); break; // case XFormBaseAction.MarkAsDirty: await this.markAsDirty(model.name); break; // case XFormBaseAction.MarkAsTouched: await this.markAsTouched(model.name); break; // case XFormBaseAction.MarkAsPending: await this.markAsPending(model.name); break; // case XFormBaseAction.MarkAsPristine: await this.markAsPending(model.name); break; // case XFormBaseAction.MarkAsUnTouched: await this.markAsTouched(model.name); break; // case XFormBaseAction.UpdateValueAndValidity: await this.updateValueAndValidity(model.name); break; } }); } //#endregion // return { name: c.propName, control: formControl }; }) .map((fc) => { return { key: fc.name.toString(), value: fc.control }; }) ) as { [key: string]: AbstractControl }; //#endregion // //#region Prepare Form Group ... if (!this.FORM) { // this.FORM = new FormGroup( controls, formConfig.validators ? { updateOn: formConfig.updateOn.toString() as | 'change' | 'blur' | 'submit', validators: formConfig.validators.validators || null, asyncValidators: formConfig.validators.asyncValidators || null, } : null ); // // Form Value Changed ... this.FORM.valueChanges.subscribe((res) => { // if (this.uiDisabled) { return; } // this.valueChanged.emit({ name: formConfig.name, value: res, }); // this.VALUE = res; // this.detectChanges(); }); // // Form Status Changed ... this.FORM.statusChanges.subscribe((res) => { // if (this.uiDisabled) { return; } // this.STATUS = res; // if (this.FORM.errors) { this.ERRORS = this.FORM.errors; } else { this.ERRORS = null; } // this.statusChanged.emit({ name: formConfig.name, status: res, }); // this.detectChanges(); }); } else { // entries(controls).forEach((ctrlEtry) => { // const name = ctrlEtry[0]; const control = ctrlEtry[1] as AbstractControl; // if (this.FORM.contains(name)) { this.FORM.setControl(name, control); } }); } //#endregion // this.FORM.markAllAsTouched(); this.FORM.updateValueAndValidity(); // this.detectChanges(); } //#endregion // //#region Control Config Object ... // private getControlName(name?: XFormControlNameIdentifier) { return name ? name.toString() : null; } // private getCustomControlConfig(control: XFormControlConfig) { return this.getControlType(control).pipe( concatMap((type) => { switch (type) { // case XFormControlType.Map: return this.getMapConfig(control); // case XFormControlType.Selector: return this.getSelectorConfig(control); // case XFormControlType.ColorPicker: return this.getColorPickerConfig(control); // default: return of(null); } }) ); } // private getControlInfo(control: XFormControlConfig) { return this.getControlType(control).pipe( concatMap((type) => this.getControlDisabled(control).pipe( map((disabled) => ({ type, disabled })) ) ), concatMap((typeInfo) => this.getControlAppearance(control).pipe( map((appearance) => ({ ...typeInfo, appearance })) ) ) ); } //#endregion // private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XFormBaseAction.Enable: await this.enable(model.name); break; // case XFormBaseAction.Disable: await this.disable(model.name); break; // case XFormBaseAction.Refresh: await this.refresh(); break; // case XFormBaseAction.SetError: // if (model.payload) { await this.setError(model.payload, model.name); } break; // case XFormBaseAction.ClearError: await this.clearError(model.name); break; // case XFormBaseAction.MarkAsDirty: await this.markAsDirty(model.name); break; // case XFormBaseAction.MarkAsTouched: await this.markAsTouched(model.name); break; // case XFormBaseAction.MarkAsPending: await this.markAsPending(model.name); break; // case XFormBaseAction.MarkAsPristine: await this.markAsPending(model.name); break; // case XFormBaseAction.MarkAsUnTouched: await this.markAsUnTouched(model.name); break; // case XFormBaseAction.UpdateValueAndValidity: await this.updateValueAndValidity(model.name); break; // case XFormBaseAction.SetValue: await this.setValue(model.name, model.payload); break; // case XFormBaseAction.ClearData: await this.clearData(); break; // case XFormControlAction.Focuse: if (model.name) { this.focusOnControl(model.name); } break; // case XFormControlAction.Blur: if (model.name) { this.blurOfControl(model.name); } break; } }); } // private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } // private async handleUiDisabledChanged() { // if (this.uiDisabled) { await this.disable(); } else { await this.enable(); } } // //#region Color Appliers ... private async applyColors() { // await this.applyRegularColor(); await this.applyAccentColor(); await this.applyHintColor(); await this.applyPendingColor(); await this.applyActiveColor(); await this.applyValidColor(); await this.applyInvalidColor(); await this.applyFillColor(); await this.applyDisabledColor(); await this.applyDisabledFillColor(); } private async applyRegularColor() { // const color = await this.getValueAsync(this.regularColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.RegularColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.RegularColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyAccentColor() { // let color = await this.getValueAsync(this.accentColor); if (!color) { color = XColor.Secondary; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.AccentColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.AccentColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyHintColor() { // let color = await this.getValueAsync(this.hintColor); if (!color) { color = XColor.Tertiary; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.HintColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.HintColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyPendingColor() { // let color = await this.getValueAsync(this.pendingColor); if (!color) { color = XColor.Warning; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.PendingColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.PendingColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyActiveColor() { // let color = await this.getValueAsync(this.activeColor); if (!color) { color = XColor.Tertiary; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.ActiveColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.ActiveColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyValidColor() { // let color = await this.getValueAsync(this.validColor); if (!color) { color = XColor.Success; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.ValidColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.ValidColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyInvalidColor() { // let color = await this.getValueAsync(this.invalidColor); if (!color) { color = XColor.Danger; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.InvalidColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.InvalidColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyFillColor() { // let color = await this.getValueAsync(this.fillColor); if (!color) { color = XColorWithBrightness.SecondaryTint; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.FillColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.FillColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyDisabledColor() { // let color = await this.getValueAsync(this.disabledColor); if (!color) { color = XColorWithBrightness.LightTint; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.DisableColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.DisableColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } private async applyDisabledFillColor() { // let color = await this.getValueAsync(this.disabledFillColor); if (!color) { color = XColorWithBrightness.LightShade; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XFormCssVar.DisabledFillColor, `var(${bgColor})`); this.setCssVar( XFormCssVar.DisabledFillColor, `var(${bgColor})`, document.documentElement ); // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.module.ts import { LocaleFactory, XPersianDateAdapter, MatDateFormatFactory, } from 'x-framework-core'; import { DateAdapter, MAT_DATE_LOCALE, MAT_DATE_FORMATS, } from '@angular/material/core'; import { CommonModule } from '@angular/common'; import { XMapModule } from '../x-map/x-map.module'; import { LOCALE_ID, NgModule } from '@angular/core'; import { XFormComponent } from './x-form.component'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XListModule } from '../x-list/x-list.module'; import { XColorModule } from '../x-color/x-color.module'; import { XDialogsModule } from '../dialogs/x-dialog.module'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { XMarkdownModule } from '../x-markdown/x-markdown.module'; import { XDataPagerModule } from '../x-data-pager/x-data-pager.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XFileUploadModule } from '../x-file-upload/x-file-upload.module'; import { XColorPickerModule } from '../x-color-picker/x-color-picker.module'; import { XAvatarUploadModule } from '../x-avatar-upload/x-avatar-upload.module'; import { MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter'; @NgModule({ entryComponents: [], declarations: [XFormComponent], imports: [ XMapModule, XCardModule, XListModule, XIconModule, FormsModule, CommonModule, XColorModule, XDialogsModule, XSlotterModule, XMarkdownModule, XDataPagerModule, XFileUploadModule, XColorPickerModule, ReactiveFormsModule, XAvatarUploadModule, XBaseComponentModule, ], exports: [ XMapModule, XCardModule, XListModule, XIconModule, FormsModule, CommonModule, XColorModule, XDialogsModule, XFormComponent, XSlotterModule, XMarkdownModule, XDataPagerModule, XFileUploadModule, XColorPickerModule, ReactiveFormsModule, XAvatarUploadModule, XBaseComponentModule, ], providers: [ { provide: LOCALE_ID, useFactory: LocaleFactory, }, { provide: MAT_DATE_LOCALE, useFactory: LocaleFactory, }, { deps: [MAT_DATE_LOCALE], provide: MAT_DATE_FORMATS, useFactory: MatDateFormatFactory, }, { provide: DateAdapter, useClass: XPersianDateAdapter, deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS], }, ], }) export class XFormModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.tools.ts import { XIconNames } from '../x-icon/x-icon.typings'; import { XColorWithBrightness } from 'x-framework-core'; import { XControlIconPosition, XControlIconDescriptor } from './x-form.typings'; export const defaultFormControlClearIcon: XControlIconDescriptor = { name: XIconNames.clear, applyStateColor: false, color: XColorWithBrightness.Danger, position: XControlIconPosition.Suffix, } export const defaultFormControlSelectIcon: XControlIconDescriptor = { name: XIconNames.touch, applyStateColor: false, color: XColorWithBrightness.Success, position: XControlIconPosition.Suffix, } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\x-form.typings.ts import { Input, Inject, NgZone, Output, Renderer2, Component, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XLocale, XBaseDto, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XExceptionIdentifier, XColorWithBrightness, XBorderStyleIdentifier, } from 'x-framework-core'; import { XManagerService, XFormInputFormatterIdentifier, XStringInputFormatTypeIdentifier, } from 'x-framework-services'; import { XMarkdownActionModel, XMarkdownModeIdentifier, XMarkdownToolbarConfigProps, } from '../x-markdown/x-markdown.typings'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { XAvatarUploadActionModel, XAvatarUploadActionButton, } from '../x-avatar-upload/x-avatar-upload.typings'; import { ViewportRuler } from '@angular/cdk/overlay'; import { forkJoin, Observable, Subject } from 'rxjs'; import { AbstractControlOptions } from '@angular/forms'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { IXMapContainer, XMapActionModel } from '../x-map/x-map.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XMapDialogService } from '../x-map/x-map-dialog/x-map-dialog.service'; import { XColorPickerActionModel } from '../x-color-picker/x-color-picker.typings'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; import { XFileDropAreaActionModel } from '../x-file-drop-area/x-file-drop-area.typings'; import { XSelectorDialogConfig } from '../dialogs/x-selector-dialog/x-selector-dialog.typings'; import { XSelectorDialogService } from '../dialogs/x-selector-dialog/x-selector-dialog.service'; import { XColorPickerDialogConfig } from '../x-color-picker/x-color-picker-dialog/x-color-picker-dialog.typings'; import { XColorPickerDialogService } from '../x-color-picker/x-color-picker-dialog/x-color-picker-dialog.service'; // //#region Css Vars ... export enum XFormCssVar { FillColor = 'fill-color', HintColor = 'hint-color', ValidColor = 'valid-color', ActiveColor = 'active-color', AccentColor = 'accent-color', RegularColor = 'regular-color', PendingColor = 'pending-color', InvalidColor = 'invalid-color', DisableColor = 'disabled-color', DisabledFillColor = 'disabled-fill-color', } //#endregion // //#region Base Form Control Action Model ... export type XFormControlNameIdentifier = string | number | symbol; export interface XBaseFormControlActionModel { name?: XFormControlNameIdentifier; } //#endregion // //#region Control Auto Complete Config ... export interface XFormControlAutoCompleteConfig { opened?: XStandardType; color?: XStandardType; onSelect?: (item: T) => XStandardType; items: () => XStandardType>; itemTemplate: XStandardType>; cssClass?: XStandardType>; onEscape?: () => XStandardType; onOutsideClicked?: () => XStandardType; } //#endregion // //#region XForm Validator Model ... export type XFormValidatorDescriptor = Partial< Pick >; //#endregion // //#region Error Handler Configs ... export interface XFormErrorHandler { errorName: XStandardType; errorMessage: XStandardType; errorDataProvider?: (errorObject: any) => XStandardType; } //#endregion // //#region Formatter Config ... export interface XFormControlFormatterConfig { locale?: XStandardType; seperator?: XStandardType; type: XStandardType; inputType?: XStandardType; currencyLable?: XStandardType; stringFormatter?: XStandardType>; } //#endregion // //#region Control Progressbar Config ... export interface XFormControlProgressbarConfig { color: XStandardType; } //#endregion // //#region XForm Control Appearance ... export enum XFormControlAppearance { None = 'none', Legacy = 'legacy', Standard = 'standard', Fill = 'fill', Outline = 'outline', } export type XFormControlAppearanceIdentifier = XFormControlAppearance | string; export interface XFormControlAppearanceDescriptor { hidden?: XStandardType; disabled?: XStandardType; hint?: XStandardType; label: XStandardType; tooltip?: XStandardType; placeholder?: XStandardType; cssClass?: XStandardType>; icons?: XStandardType; formatter?: XStandardType; progressBar?: XStandardType; autoComplete?: XStandardType; appearance?: XStandardType; labelPosition?: XStandardType; } //#endregion // //#region Icon Configs ... export enum XControlIconPosition { Prefix = 'prefix', Suffix = 'suffix', } export type XControlIconPositionIdentifier = XControlIconPosition | string; export enum XControlIconRole { Clear = 'clear', Select = 'select', } export type XControlIconRoleIdentifier = XControlIconRole | string; export interface XControlIconDescriptor { handler?: () => XStandardType; name?: XStandardType; color?: XStandardType; applyStateColor?: XStandardType; tooltip?: XStandardType; position?: XStandardType; } export interface XFormIconDescriptor extends Pick< Partial, 'handler' | 'name' | 'color' | 'applyStateColor' | 'tooltip' > {} export interface XFormControlIconDescriptor { suffix?: XStandardType; prefix?: XStandardType; } //#endregion // //#region Form Control Status and Values Changed ... export interface XFormControlValueChangeEventModel extends XBaseFormControlActionModel { value: any; } export interface XFormControlStatusChangeEventModel extends XBaseFormControlActionModel { status: XFormStatusIdentifier; } // tslint:disable-next-line:no-empty-interface export interface XFormValueChangeEventModel extends XFormControlValueChangeEventModel {} // tslint:disable-next-line:no-empty-interface export interface XFormStatusChangeEventModel extends XFormControlStatusChangeEventModel {} // // Form and Form Control Status ... export enum XFormStatus { UnKnown = 'UNKNOWN', Valid = 'VALID', Invalid = 'INVALID', Pending = 'PENDING', Disabled = 'DISABLED', } export type XFormStatusIdentifier = XFormStatus | string; export interface XFormControlEventsDescriptor { statusChanged?: ( model: XFormControlStatusChangeEventModel ) => XStandardType; valueChanged?: ( model: XFormControlValueChangeEventModel ) => XStandardType; onBlured?: (model: XBaseFormControlActionModel) => XStandardType; onFocused?: (model: XBaseFormControlActionModel) => XStandardType; } //#endregion // //#region Form Control Label Position ... export enum XFormControlLabelPosition { After = 'after', Before = 'before', } export type XFormControlLabelPositionIdentifier = | XFormControlLabelPosition | string; //#endregion // //#region Form and Form Control Action Provider ... export enum XFormBaseAction { // MarkAsDirty = 'mark_as_dirty', MarkAsTouched = 'mark_as_touched', MarkAsPending = 'mark_as_pending', MarkAsPristine = 'mark_as_pristine', MarkAsUnTouched = 'mark_as_untouched', UpdateValueAndValidity = 'update_value_and_validity', // SetError = 'set_error', ClearError = 'clear_error', // SetValue = 'set_value', // Enable = 'enable', Disable = 'disable', // Refresh = 'refresh', // ClearData = 'clear_data', } export enum XFormControlAction { Focuse = 'focuse', Blur = 'blur', } export type XFormControlActionIdentifier = | XFormBaseAction | XFormControlAction | string; export interface XFormControlActionProviderModel extends XBaseActionModel, XBaseFormControlActionModel {} export interface XFormActionModel extends XFormControlActionProviderModel {} //#endregion // //#region XForm and XForm Control Update On ... export enum XFormUpdateOn { BLUR = 'blur', CHANGE = 'change', SUBMIT = 'submit', } export type XFormUpdateOnIdentifier = XFormUpdateOn | string; //#endregion // //#region Form Control Types ... export enum XFormControlType { Text = 'text', Number = 'number', Password = 'password', Color = 'color', Email = 'email', Tel = 'tel', Url = 'url', Select = 'select', Radio = 'radio', CheckBox = 'checkbox', Hidden = 'hidden', Date = 'date', Slider = 'slider', Toggle = 'toggle', MarkDown = 'markdown', Map = 'map', ColorPicker = 'color_picker', AvatarUpload = 'avatar_upload', Selector = 'selector', } export type XFormControlTypeIdentifier = XFormControlType | string; export type XFormControlTypeConfig = | XFormMapControlConfig | XFormRadioControlConfig | XFormInputControlConfig | XFormSelectControlConfig | XFormSliderControlConfig | XFormSelectorControlConfig | XFormMarkdownControlConfig | XFormCheckBoxControlConfig | XFormDatePickerControlConfig | XFormColorPickerControlConfig | XFormAvatarUploadControlConfig | undefined; export interface XFormControlTypeDescriptor { type: XStandardType; config?: XStandardType; } // //#region Type Configs ... // //#region Input Type ... export interface XFormInputControlConfig { readonly?: XStandardType; } //#endregion // //#region Select Type ... export interface XFormSelectControlOption { value: XStandardType; viewValue: XStandardType; } export interface XFormSelectControlConfig { options?: XStandardType>>; multiple?: XStandardType; } //#endregion // //#region Radio Type ... export interface XFormRadioControlOption { value: XStandardType; viewValue: XStandardType; } export interface XFormRadioControlConfig { options?: XStandardType>>; } //#endregion // //#region Date Control Config ... export enum XFormDatePickerControlPickerPosition { Suffix = 'suffix', Prefix = 'prefix', } export type XFormDatePickerControlPickerPositionIdentifier = | XFormDatePickerControlPickerPosition | string; export interface XFormDatePickerControlConfig { startAt?: XStandardType; dateFilter?: (d: any) => boolean; applyStateColor?: XStandardType; toggleIcon?: XStandardType; iconColor?: XStandardType; datePickerPosition: XStandardType; disableInput?: XStandardType; disablePicker?: XStandardType; iconTooltip?: XStandardType; dateInput?: (event: Date) => XStandardType; dateChange?: (event: Date) => XStandardType; } //#endregion // //#region Slider Control ... export interface XFormSliderControlConfig { min?: XStandardType; max?: XStandardType; step?: XStandardType; invert?: XStandardType; vertical?: XStandardType; thumbLabel?: XStandardType; formatter?: (value: number) => string; } //#endregion // //#region Markdown Control Config ... export interface XFormMarkdownControlConfig { // isInPage?: XStandardType; hasToolbar?: XStandardType; wrapWithCard?: XStandardType; cardColor?: XStandardType; cardForegroundColor?: XStandardType; mode?: XStandardType; toolbarColor?: XStandardType; cardTitle?: XStandardType; actionProvider?: Subject; toolbarForegroundColor?: XStandardType; cssClass?: XStandardType>; editorBoxColor?: XStandardType; previewBoxColor?: XStandardType; cardSubTitle?: XStandardType; toolbarCssClass?: XStandardType>; contentChanged?: (content: string) => XStandardType; toolbarConfig?: XStandardType; } //#endregion // //#region Check Box Config ... export interface XFormCheckBoxControlConfig { checkedChanged?: (checked: boolean) => XStandardType; } //#endregion // //#region Map Config ... export enum XFormMapControlPresentType { WithDialog = 'width_dialog', WithoutDialog = 'without_dialog', } export type XFormMapControlPresentTypeIdentifier = | XFormMapControlPresentType | string; // export interface XFormMapControlConfig extends Pick< Partial, | 'zoom' | 'markerStyle' | 'cssClass' | 'canSelect' // | 'showProgressBar' | 'progressBarColor' | 'progressBarPosition' // | 'showSearchBar' | 'searchBarType' | 'searchBarValue' | 'searchBarDebounce' | 'searchBarQueryChange' | 'searchBarSpellcheck' | 'searchPlaceProvider' | 'searchBarColor' | 'searchBarForegroundColor' | 'searchBarClearButtonIcon' | 'searchBarTitle' | 'searchBarSearchButtonIcon' | 'searchBarSearchInputColor' | 'searchBarForegroundSearchInputColor' | 'searchResultListColor' | 'searchBarActionProvider' | 'searchBarClearButtonIconColor' | 'searchBarCssClass' | 'searchBarSearchButtonIconColor' | 'searchBarCancelButtonIcon' | 'searchBarPosition' | 'searchBarKeyboardType' | 'searchBarCancelButtonTitle' | 'searchBarEnterKeyHint' | 'searchBarShowCancelButton' // | 'showSelectedLocation' | 'selectedLocationPosition' // | 'showGoMarkedPlace' | 'goMarkedPlacePosition' // | 'showClearMarker' | 'clearMarkerPosition' // | 'showLocator' | 'locatorPosition' // | 'showZoom' | 'showRotate' | 'showZoomSlider' // | 'isReady' | 'locationSelected' // | 'isInPage' | 'wrapWithCard' | 'cardShowFooter' | 'cardColor' | 'cardForegroundColor' | 'cardTitle' | 'cardSubTitle' > { // disableIcon?: XStandardType; disableInput?: XStandardType; actionProvider?: Subject; clearIcon?: XStandardType; selectIcon?: XStandardType; inputCssClass?: XStandardType>; inputValueChanged?: (value?: string) => XStandardType; presentType?: XStandardType; } //#endregion // //#region ColorPicker Config ... export enum XFormColorPickerControlPresentType { WithDialog = 'width_dialog', WithoutDialog = 'without_dialog', // Both = 'both', } export type XFormColorPickerControlPresentTypeIdentifier = | XFormColorPickerControlPresentType | string; // export interface XFormColorPickerControlConfig extends Pick< Partial, | 'color' | 'cssClass' | 'cardColor' | 'cardTitle' | 'cursorColor' | 'presetColors' | 'outputFormat' | 'cardSubTitle' | 'colorSelected' | 'colorTextColor' | 'showColorValue' | 'showHueChannel' | 'showColorInput' | 'foregroundColor' | 'showPresetColors' | 'showAlphaChannel' | 'presetColorsLable' | 'showPaletteChannel' | 'cardForegroundColor' | 'showCopyToClipboard' | 'colorInputIconLabel' | 'colorInputIconColor' | 'clearColorIconColor' | 'clearColorIconLabel' | 'representColorFormats' | 'presetColorsLableColor' | 'copyToClipboardIconLabel' | 'copyToClipboardIconColor' | 'showSelectedColorPreview' > { // isInPage?: XStandardType; disableIcon?: XStandardType; disableInput?: XStandardType; wrapWithCard?: XStandardType; showCardFooter?: XStandardType; colorViewBorderWidth?: XStandardType; actionProvider?: Subject; clearIcon?: XStandardType; selectIcon?: XStandardType; inputCssClass?: XStandardType>; colorViewBorderColor?: XStandardType; colorViewBorderStyle?: XStandardType; inputValueChanged?: (value?: string) => XStandardType; presentType?: XStandardType; } //#endregion // //#region Avatar Upload Config ... export interface XFormAvatarUploadControlConfig { fileDropAreaFilesChangeEmiter?: ( files?: XOneOrManyType ) => XStandardType; canDrop?: XStandardType; isInPage?: XStandardType; wrapWithCard?: XStandardType; color?: XStandardType; showCardFooter?: XStandardType; foregroundColor?: XStandardType; placeHolderAvatar?: XStandardType; minAllowedFileSize?: XStandardType; maxAllowedFileSize?: XStandardType; cardColor?: XStandardType; cardForegroundColor?: XStandardType; fileDropAreaIsInPage?: XStandardType; cardTitle?: XStandardType; cssClass?: XStandardType>; fileDropAreaWrapWithCard?: XStandardType; fileDropAreaIcon?: XStandardType; fileDropAreaDragDisabled?: XStandardType; cardSubTitle?: XStandardType; actionProvider?: Subject; fileDropAreaShowCardFooter?: XStandardType; fileDropAreaColor?: XStandardType; fileDropAreaForegroundColor?: XStandardType; avatarChange?: (avatar?: File) => XStandardType; fileDropAreaDisableFileCheck?: XStandardType; fileDropAreaCardColor?: XStandardType; fileDropAreaCardForegroundColor?: XStandardType; emptyFileException?: XStandardType; fileDropAreaErrorColor?: XStandardType; fileDropAreaMessage?: XStandardType; fileDropAreaAccentColor?: XStandardType; allowedExtensions?: XStandardType>; fileDropAreaCardTitle?: XStandardType; fileDropAreaSuccessColor?: XStandardType; fileDropAreaSupportsMultipleFiles?: XStandardType; fileDropAreaCssClass?: XStandardType>; fileDropAreaCardSubTitle?: XStandardType; notAllowedFileException?: XStandardType; fileDropAreaContentTemplate?: XStandardType>; fileDropAreaActionProvider?: Subject; minAllowedFileSizeException?: XStandardType; maxAllowedFileSizeException?: XStandardType; actions?: XStandardType>; fileDropAreaAllowedExtensions?: XStandardType>; } //#endregion // //#region Selector Config ... export interface XFormSelectorControlConfig extends Partial { // clearIcon?: XStandardType; selectIcon?: XStandardType; inputCssClass?: XStandardType>; inputValueChanged?: (value?: string) => XStandardType; formatSelectedItem?: (item: XOneOrManyType) => XStandardType; } //#endregion //#endregion //#endregion // //#region Form Control Config ... export interface XFormControlConfig { index: number; propName: keyof Partial; focusHandler?: Subject; type: XStandardType; updateOn?: XStandardType; validators?: XStandardType; actionProvider?: Subject; eventHandlers?: XStandardType; appearance: XStandardType; errorHandlers?: XStandardType>; } //#endregion // // Form Config ... export interface XFormConfig { name: XStandardType; model?: XStandardType>; updateOn?: XStandardType; validators?: XStandardType; controls: XStandardType>>; errorHandlers?: XStandardType>; } // //#region Inside Card Container ... export interface IXFormContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; formConfig: XStandardType; applyStatusOnControls: XStandardType; // regularColor: XStandardType; accentColor: XStandardType; hintColor: XStandardType; activeColor: XStandardType; validColor: XStandardType; invalidColor: XStandardType; pendingColor: XStandardType; fillColor: XStandardType; disabledColor: XStandardType; disabledFillColor: XStandardType; // valueChanged: EventEmitter; statusChanged: EventEmitter; controlFocused: EventEmitter; controlBlured: EventEmitter; controlValueChanged: EventEmitter; controlStatusChanged: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XFormContainer extends XComponentCardContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; readonly formConfig: XStandardType = null; readonly applyStatusOnControls: XStandardType = false; // readonly regularColor: XStandardType = XColorWithBrightness.Dark; readonly accentColor: XStandardType = XColorWithBrightness.Secondary; readonly hintColor: XStandardType = XColorWithBrightness.Tertiary; readonly activeColor: XStandardType = XColorWithBrightness.Tertiary; readonly validColor: XStandardType = XColorWithBrightness.Success; readonly invalidColor: XStandardType = XColorWithBrightness.Danger; readonly pendingColor: XStandardType = XColorWithBrightness.Warning; readonly fillColor: XStandardType = XColorWithBrightness.SecondaryTint; readonly disabledColor: XStandardType = XColorWithBrightness.LightTint; readonly disabledFillColor: XStandardType = XColorWithBrightness.LightShade; // readonly valueChanged: EventEmitter = new EventEmitter(); readonly statusChanged: EventEmitter = new EventEmitter(); readonly controlFocused: EventEmitter = new EventEmitter(); readonly controlBlured: EventEmitter = new EventEmitter(); readonly controlValueChanged: EventEmitter = new EventEmitter(); readonly controlStatusChanged: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XFormContainerComponent extends XComponentCardContainerComponent implements IXFormContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() formConfig: XStandardType = this.propertyProvider.formConfig; @Input() applyStatusOnControls: XStandardType = this.propertyProvider.applyStatusOnControls; // @Input() regularColor: XStandardType = this.propertyProvider.regularColor; @Input() accentColor: XStandardType = this.propertyProvider.accentColor; @Input() hintColor: XStandardType = this.propertyProvider.hintColor; @Input() activeColor: XStandardType = this.propertyProvider.activeColor; @Input() validColor: XStandardType = this.propertyProvider.validColor; @Input() invalidColor: XStandardType = this.propertyProvider.invalidColor; @Input() pendingColor: XStandardType = this.propertyProvider.pendingColor; @Input() fillColor: XStandardType = this.propertyProvider.fillColor; @Input() disabledColor: XStandardType = this.propertyProvider.disabledColor; @Input() disabledFillColor: XStandardType = this.propertyProvider.disabledFillColor; // @Output() valueChanged: EventEmitter = new EventEmitter(); @Output() statusChanged: EventEmitter = new EventEmitter(); @Output() controlFocused: EventEmitter = new EventEmitter(); @Output() controlBlured: EventEmitter = new EventEmitter(); @Output() controlValueChanged: EventEmitter = new EventEmitter(); @Output() controlStatusChanged: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XFormContainer, protected mapDialogService: XMapDialogService, protected selectorDialogService: XSelectorDialogService, protected colorPickerDialogService: XColorPickerDialogService ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXFormContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), formConfig: this.getValue( container ? container.formConfig : this.formConfig ), applyStatusOnControls: this.getValue( container ? container.applyStatusOnControls : this.applyStatusOnControls ), regularColor: this.getValue( container ? container.regularColor : this.regularColor ), accentColor: this.getValue( container ? container.accentColor : this.accentColor ), hintColor: this.getValue( container ? container.hintColor : this.hintColor ), activeColor: this.getValue( container ? container.activeColor : this.activeColor ), validColor: this.getValue( container ? container.validColor : this.validColor ), invalidColor: this.getValue( container ? container.invalidColor : this.invalidColor ), pendingColor: this.getValue( container ? container.pendingColor : this.pendingColor ), fillColor: this.getValue( container ? container.fillColor : this.fillColor ), disabledColor: this.getValue( container ? container.disabledColor : this.disabledColor ), disabledFillColor: this.getValue( container ? container.disabledFillColor : this.disabledFillColor ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // valueChanged: this.valueChanged, statusChanged: this.statusChanged, controlFocused: this.controlFocused, controlBlured: this.controlBlured, controlValueChanged: this.controlValueChanged, controlStatusChanged: this.controlStatusChanged, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-form\validators\x-form-validators.ts import { isValidURL, XCountryCode, isNullOrUndefined, isValidPhoneNumber, isNullOrEmptyString, toNumber, toXString, } from 'x-framework-core'; import { ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms'; export class XFormValidators { /** * check given date in between start and end date ... * * @param startDate start date for validating * @param endDate end date for validating */ static validateDate( startDate: Date | string, endDate: Date | string ): ValidatorFn { // const errorObject = { startDate, endDate, currentDate: new Date(), xValidateDate: true, }; // const validatorFn = (control: AbstractControl): ValidationErrors | null => { // if ( isNullOrEmptyString(control.value) || isNullOrUndefined(startDate) || isNullOrUndefined(endDate) ) { return null; } // const mStartDate = new Date(startDate); const mEndDate = new Date(endDate); const mDate = new Date(control.value); // const isValid = mDate >= mStartDate && mDate <= mEndDate; if (!isValid) { // errorObject.currentDate = mDate; return errorObject; } // return null; }; // return validatorFn; } /** * check given value be a valid phone number ... * * @param defaultCountryCode an optional value which used for country code if not exists in value */ static validatePhoneNumber(defaultCountry?: XCountryCode): ValidatorFn { // const errorObject = { xPhoneNumberValidator: true, }; // const validatorFn = (control: AbstractControl): ValidationErrors | null => { // if (isNullOrEmptyString(control.value)) { return null; } // const value = control.value as string; const isValid = isValidPhoneNumber(value, defaultCountry); // if (!isValid) { return errorObject; } // return null; }; // return validatorFn; } /** * check given value is Valid URL or not ... */ static validateUrl(): ValidatorFn { // const errorObject = { xUrlValidator: true, }; // const validatorFn = (control: AbstractControl): ValidationErrors | null => { // if (isNullOrEmptyString(control.value)) { return null; } // const value = control.value as string; const isValid = isValidURL(value); // if (!isValid) { return errorObject; } // return null; }; // return validatorFn; } /** * check give value notEquals to Zero ... * usually works for id's in Selector Component ... */ static validateNotZero(): ValidatorFn { // const errorObject = { xNotZeroValidator: true, }; // const validatorFn = (control: AbstractControl): ValidationErrors | null => { // if (isNullOrEmptyString(control.value)) { return null; } // const value = control.value as string; const isValid = !isNullOrEmptyString(value) && (toXString(value) !== '0' || toNumber(value) !== 0); // if (!isValid) { return errorObject; } // return null; }; // return validatorFn; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.component.scss :host { --x-frame-height: auto; } .v-frame-frame, .v-frame-container { width: 100%; height: var(--x-frame-height); } .v-frame-frame { border: unset; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.component.ts import { Component, ViewChild, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { nameof, generateUuid, isNullOrUndefined, isNullOrEmptyString, } from 'x-framework-core'; import { XFrameAction, XFrameActionModel, XFrameContainerComponent, } from './x-frame.typings'; import { Subject, Subscription } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { SafeHtml, SafeResourceUrl } from '@angular/platform-browser'; @Component({ selector: 'x-frame', templateUrl: './x-frame.component.html', styleUrls: ['./x-frame.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XFrameComponent extends XFrameContainerComponent { // //#region Props ... // readonly id = generateUuid('VFrame'); // private ORIGIN: string = ''; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private FRAME_VIEW: ElementRef = null; // @ViewChild('frameView', { static: false }) set frameView(v: ElementRef) { // if (isNullOrUndefined(v)) { return; } // this.FRAME_VIEW = v; this.applyFrameProps(); } // //#region Getters ... get iFrame() { return this.FRAME_VIEW!.nativeElement; } get contentWindow() { return this.iFrame!.contentWindow; } get contentDocuent() { return this.iFrame!.contentDocument; } get innerHTML() { return this.iFrame!.innerHTML; } get innerText() { return this.iFrame!.innerText; } get frameView() { return this.FRAME_VIEW; } get origin() { return this.ORIGIN; } //#endregion // contentHTML: SafeHtml; contentUrl: SafeResourceUrl; //#endregion // //#region Constructor ... //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Action Providers ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Url Changed ... const isUrlChanged = changeKeys.includes(nameof('url')); if (isUrlChanged) { this.prepareContentUrl(); } //#endregion // //#region Content ... const isContentChanged = changeKeys.includes( nameof('content') ); if (isContentChanged) { this.prepareContent(); } //#endregion // //#region VFrame Props ... // //#region Allow ... const isAllowChanged = changeKeys.includes( nameof('allow') ); if (isAllowChanged) { this.handleAllowChanged(); } //#endregion // //#region FrameLoading ... const isFrameLoadingChanged = changeKeys.includes( nameof('frameLoading') ); if (isFrameLoadingChanged) { this.handleFrameLoadingChanged(); } //#endregion // //#region FrameReferrerPolicy ... const isReferrerPolicyChanged = changeKeys.includes( nameof('referrerPolicy') ); if (isReferrerPolicyChanged) { this.handleReferrerPolicyChanged(); } //#endregion // //#region FrameSandbox ... const isSandboxChanged = changeKeys.includes( nameof('sandbox') ); if (isSandboxChanged) { this.handleSandboxChanged(); } //#endregion // //#region AllowFullScreen ... const isAllowFullScreenChanged = changeKeys.includes( nameof('allowFullscreen') ); if (isAllowFullScreenChanged) { this.handleAllowFullScreenChanged(); } //#endregion // //#region AllowPaymentRequest ... const isAllowPaymentRequestChanged = changeKeys.includes( nameof('allowPaymentRequest') ); if (isAllowPaymentRequestChanged) { this.handleAllowPaymentRequestChanged(); } //#endregion // //#region AddAllowTransparency ... if ( isAllowChanged || isSandboxChanged || isFrameLoadingChanged || isReferrerPolicyChanged || isAllowFullScreenChanged || isAllowPaymentRequestChanged ) { this.addTransparency(); } //#endregion //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Register Handlers ... registerInstanceHandlers() { super.registerInstanceHandlers(); // this.registerActionProvider(); } //#endregion // //#region Task Handlers ... //#endregion // //#region UI Providers ... getCssClasses(infix: string) { return this.getValue(false).pipe( concatMap(() => this.getArrayValue(this.cssClass)), map((classes) => { // const result: string[] = []; // result.push(`v-frame-${infix}`); result.push(`v-frame-${this.id}-${infix}`); // if (this.hasChild(classes)) { result.push(...classes); } // return result; }) ); } //#endregion // //#region UI Handlers ... //#endregion // //#region Actions ... appendElement(element: HTMLElement) { // if ( isNullOrUndefined(element) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.appendChild(this.frameView.nativeElement, element); } loadHtml(html: string) { // if ( isNullOrEmptyString(html) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.frameView.nativeElement.contentWindow.frames.document.body.insertAdjacentHTML( 'beforebegin', html ); } loadText(text: string) { // if ( isNullOrEmptyString(text) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.frameView.nativeElement.contentWindow.frames.document.body.insertAdjacentText( 'beforebegin', text ); } loadElement(element: HTMLElement) { // if ( isNullOrUndefined(element) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.frameView.nativeElement.contentWindow.frames.document.body.insertAdjacentElement( 'beforebegin', element ); } applyUrl(url: string) { // this.contentUrl = url; this.detectChanges(); } applyContent(content: string) { // this.content = content; this.detectChanges(); } fullScreen(options?: FullscreenOptions) { this.frameView.nativeElement.requestFullscreen(options); } //#endregion // //#region Abstracts ... //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() // tslint:disable-next-line: deprecation .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XFrameAction.Refresh: this.detectChanges(); break; // case XFrameAction.AppendElement: this.appendElement(model.payload); break; // case XFrameAction.ApplyContent: this.applyContent(model.payload); break; // case XFrameAction.ApplyUrl: this.applyUrl(model.payload); break; // case XFrameAction.LoadElement: this.loadElement(model.payload); break; // case XFrameAction.LoadText: this.loadText(model.payload); break; // case XFrameAction.LoadHtml: this.loadHtml(model.payload); break; // case XFrameAction.FullScreen: this.fullScreen(model.payload); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // //#region Preparation ... private prepareContent(content?: string) { this.getValue(this.content).subscribe((tContent) => { // this.ORIGIN = ''; this.contentUrl = ''; this.contentHTML = ''; // content = !isNullOrEmptyString(content) ? content : tContent; if (isNullOrEmptyString(content)) { this.detectChanges(); return; } // this.contentHTML = this.managerService.securityService.toSafeHTML(content); }); } private prepareContentUrl(url?: string) { this.getValue(this.url).subscribe((tUrl) => { // this.ORIGIN = ''; this.contentUrl = ''; this.contentHTML = ''; // url = !isNullOrEmptyString(url) ? url : tUrl; if (isNullOrEmptyString(tUrl)) { this.detectChanges(); return; } // // Retrieve Origin ... const mUrl = new URL(url); this.ORIGIN = mUrl.origin; // this.contentUrl = this.managerService.securityService.toSafeResourceURL(url); }); } private applyFrameAttribute( attr: string, value: string, element: ElementRef ) { // if (isNullOrUndefined(element) || isNullOrEmptyString(attr)) { return; } // if (!isNullOrEmptyString(value)) { // // Set Attribute ... this.setAttribute(attr, value, element); } else { // // Remove Attribute ... this.removeAttribute(attr, element); } } // //#region Frame Props ... private applyFrameProps() { this.addTransparency(); this.handleAllowChanged(); this.handleSandboxChanged(); this.handleFrameLoadingChanged(); this.handleReferrerPolicyChanged(); this.handleAllowFullScreenChanged(); this.handleAllowPaymentRequestChanged(); } private addTransparency() { // const value = true.toString(); if ( isNullOrEmptyString(value) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.applyFrameAttribute('allowtransparency', value, this.frameView); this.detectChanges(); } private handleAllowChanged() { this.getArrayValue(this.allow).subscribe((allows) => { // if ( isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // const value = this.hasChild(allows) ? allows.join('; ') : null; // this.applyFrameAttribute('allow', value, this.frameView); this.detectChanges(); }); } private handleSandboxChanged() { this.getValue(this.sandbox).subscribe((value) => { // if ( isNullOrEmptyString(value) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.applyFrameAttribute('sandbox', value, this.frameView); this.detectChanges(); }); } private handleFrameLoadingChanged() { this.getValue(this.frameLoading).subscribe((value) => { // if ( isNullOrEmptyString(value) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.applyFrameAttribute('loading', value, this.frameView); this.detectChanges(); }); } private handleReferrerPolicyChanged() { this.getArrayValue(this.referrerPolicy).subscribe((referrerPolicies) => { // if ( isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // const value = this.hasChild(referrerPolicies) ? referrerPolicies.join('|') : null; // this.applyFrameAttribute('referrerpolicy', value, this.frameView); this.detectChanges(); }); } private handleAllowFullScreenChanged() { this.getValue(this.allowFullscreen).subscribe((allowFullscreen) => { // const value = allowFullscreen.toString(); if ( isNullOrEmptyString(value) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.applyFrameAttribute('allowfullscreen', value, this.frameView); this.detectChanges(); }); } private handleAllowPaymentRequestChanged() { this.getValue(this.allowPaymentRequest).subscribe((allowPaymentRequest) => { // const value = allowPaymentRequest.toString(); if ( isNullOrEmptyString(value) || isNullOrUndefined(this.frameView) || isNullOrUndefined(this.frameView.nativeElement) ) { return; } // this.applyFrameAttribute('allowpaymentrequest', value, this.frameView); this.detectChanges(); }); } //#endregion //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XFrameComponent } from './x-frame.component'; import { XCardModule } from '../x-card/x-card.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XFrameComponent], imports: [CommonModule, XBaseComponentModule, XCardModule], exports: [CommonModule, XBaseComponentModule, XCardModule, XFrameComponent], }) export class XFrameModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-frame\x-frame.typings.ts import { Input, Inject, NgZone, Output, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { forkJoin, Observable, Subject } from 'rxjs'; import { XManagerService } from 'x-framework-services'; import { ViewportRuler } from '@angular/cdk/scrolling'; import { XOneOrManyType, XStandardType } from 'x-framework-core'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XFrameAction { Refresh = 'refresh', AppendElement = 'appendElement', LoadHtml = 'loadHtml', LoadText = 'loadText', LoadElement = 'loadElement', ApplyUrl = 'applyUrl', ApplyContent = 'applyContent', FullScreen = 'fullScreen', } export type XFrameActionIdentifier = XFrameAction | string; export interface XFrameActionModel extends XBaseActionModel {} // //#region XFrame Loading ... export enum XFrameLoading { Eager = 'eager', Lazy = 'lazy', } export type XFrameLoadingIdentifier = XFrameLoading | string; //#endregion // //#region XFrame ReferrerPolicy ... export enum XFrameReferrerPolicy { NoReferrer = 'no-referrer', NoReferrerWhenDowngrade = 'no-referrer-when-downgrade', Origin = 'origin', OriginWhenCrossOrigin = 'origin-when-cross-origin', SameOrigin = 'same-origin', StrictOriginWhenCrossOrigin = 'strict-origin-when-cross-origin', UnsafeUrl = 'unsafe-url', } export type XFrameReferrerPolicyIdentifier = XFrameReferrerPolicy | string; //#endregion // //#region Sandbox ... export enum XFrameSandbox { AllowForms = 'allow-forms', AllowModals = 'allow-modals', AllowOrientationLock = 'allow-orientation-lock', AllowPointerLock = 'allow-pointer-lock', AllowPopups = 'allow-popups', AllowPopupsToEscapeSandbox = 'allow-popups-to-escape-sandbox', AllowPresentation = 'allow-presentation', AllowSameOrigin = 'allow-same-origin', AllowScripts = 'allow-scripts', AllowTopNavigation = 'allow-top-navigation', AllowTopNavigationByUserActivation = 'allow-top-navigation-by-user-activation', } export type XFrameSandboxIdentifier = XFrameSandbox | string; //#endregion // //#region Containers ... export interface IXFrameContainer extends IXComponentCardContainer { url: XStandardType; content: XStandardType; onContentLoaded: EventEmitter; allowFullscreen: XStandardType; actionProvider: Subject; allowPaymentRequest: XStandardType; allow: XStandardType>; cssClass: XStandardType>; sandbox: XStandardType; frameLoading: XStandardType; referrerPolicy: XStandardType>; } @Injectable({ providedIn: 'root', }) export class XFrameContainer extends XComponentCardContainer implements Readonly { // //#region Props ... readonly url: XStandardType; readonly content: XStandardType; readonly referrerPolicy: XStandardType< XOneOrManyType > = null; readonly actionProvider: Subject = new Subject(); readonly allow: XStandardType>; readonly allowFullscreen: XStandardType = false; readonly cssClass: XStandardType>; readonly allowPaymentRequest: XStandardType = false; readonly sandbox: XStandardType = null; readonly frameLoading: XStandardType = null; readonly onContentLoaded: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XFrameContainerComponent extends XComponentCardContainerComponent implements IXFrameContainer { // //#region Props ... @Input() allowFullscreen: XStandardType = this.propertyProvider.allowFullscreen; @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() allowPaymentRequest: XStandardType = this.propertyProvider.allowPaymentRequest; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() sandbox: XStandardType = this.propertyProvider.sandbox; @Input() frameLoading: XStandardType = this.propertyProvider.frameLoading; @Input() url: XStandardType = this.propertyProvider.url; @Input() content: XStandardType = this.propertyProvider.content; @Input() referrerPolicy: XStandardType< XOneOrManyType > = this.propertyProvider.referrerPolicy; @Output() onContentLoaded: EventEmitter = this.propertyProvider.onContentLoaded; @Input() allow: XStandardType> = this.propertyProvider.allow; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XFrameContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXFrameContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ url: this.getValue(container ? container.url : this.url), content: this.getValue( container ? container.content : this.content ), allowFullscreen: this.getValue( container ? container.allowFullscreen : this.allowFullscreen ), allowPaymentRequest: this.getValue( container ? container.allowPaymentRequest : this.allowPaymentRequest ), allow: this.getArrayValue(container ? container.allow : this.allow), cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), sandbox: this.getValue( container ? container.sandbox : this.sandbox ), frameLoading: this.getValue( container ? container.frameLoading : this.frameLoading ), referrerPolicy: this.getValue( container ? container.referrerPolicy : this.referrerPolicy ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // onContentLoaded: container ? container.onContentLoaded : this.onContentLoaded, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.component.html
{{ item | json }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.component.scss ion-item-option > ion-item { --background: transparent !important; } ion-button.transparent-button { --box-shadow: transparent !important; --background: transparent !important; --background-hover: transparent !important; --background-focused: transparent !important; --background-activated: transparent !important; } ion-list, ion-item.item, ion-item-divider { --background: transparent !important; } ion-item-divider { --color: var(--ion-color-dark-shade); } ion-item.item.mobile { --ion-safe-area-end: 0px; --padding-start: 0px; --inner-padding-start: 0px; --padding-end: 0px; --inner-padding-end: 0px; } h1, h2, h3, h4, h5, h6 { margin: 0; } .x-menu { z-index: 10; } .x-check { z-index: 1; } .grid-box { margin-top: 8px; } .grid-box.mobile { margin-top: 0px; } gridster { width: 100%; display: flex; direction: ltr; position: inherit; flex-direction: column; background-color: transparent; height: calc(var(--grid-height, inherit)); &.inCard { position: relative; } } gridster-item { padding: 0; background-color: transparent; } .x-grid-item-wrapper { position: relative; background: inherit; } a[href=''], [disabled], .disable { color: inherit; cursor: default; pointer-events: none; text-decoration: none; } .transparent { --background: transparent !important; background-color: transparent !important; } x-card { width: inherit; height: inherit; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.component.ts import { XGridItem, XGridAction, XGridActionModel, XGridPresentType, defaultGridOptions, XStaggedGridOptions, XGridContainerComponent, } from './x-grid.typings'; import { Subject, Subscription } from 'rxjs'; import { nameof, cloneJson, toObservable } from 'x-framework-core'; import { GridsterItem, GridsterComponent } from 'angular-gridster2'; import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-grid', templateUrl: './x-grid.component.html', styleUrls: ['./x-grid.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XGridComponent extends XGridContainerComponent { // //#region Props ... // private COLS: number; private TYPE: XGridPresentType; private GRIDSTER: GridsterComponent; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // colItems: number[] = []; get preparedCols() { return this.COLS; } get preparedType() { return this.TYPE; } // @ViewChild('gridster', { static: false }) set gridster(v: GridsterComponent) { // if (!v) { return; } // this.GRIDSTER = v; this.prepareData(); } get gridster() { return this.GRIDSTER; } //#endregion // //#region LifeCycles ... afterViewInit() { super.afterContentInit(); // this.prepareData(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // const isColsChanged = changeKeys.includes(nameof('cols')); const isTypeChanged = changeKeys.includes(nameof('type')); const isOptionsChanged = changeKeys.includes( nameof('options') ); // if (isColsChanged) { this.COLS = await this.getValueAsync(this.cols); this.detectChanges(); } // if (isTypeChanged) { this.TYPE = await this.getValueAsync(this.type); this.detectChanges(); } // if (isColsChanged || isTypeChanged || isOptionsChanged) { this.prepareData(); } } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Ui Provider Actions ... // //#region Type Detectors ... isTypeLinear() { return this.preparedType === XGridPresentType.AsLinear; } isTypeGrid() { return this.preparedType === XGridPresentType.AsGrid; } isTypeFlex() { return this.preparedType === XGridPresentType.AsFlex; } isTypeStaggedGrid() { return this.preparedType === XGridPresentType.AsStaggedGrid; } //#endregion // isNewRow(i: number, cols: number) { return (i + 1) % cols === 1; } // toStaggedGrid(index: number) { return { id: index, data: this.items[index], cols: 1, rows: 1, x: 0, y: 0, } as GridsterItem; } // getItemHref(item?: XGridItem) { // if (!item || !item.href) { return toObservable(''); } // return this.getValue(item.href); } // getItemHide(item?: XGridItem) { // if (!item || !item.hide) { return toObservable(false); } // return this.getValue(item.hide); } // getItemDisabled(item?: XGridItem) { // if (!item || !item.disabled) { return toObservable(false); } // return this.getValue(item.disabled); } //#endregion // //#region Type Detectors ... //#endregion // //#region Actions ... async handleItemSelected(item: XGridItem) { // if (!this.selectableItems) { return; } // const hided = await this.toPromise(this.getItemHide(item)); const disabled = await this.toPromise(this.getItemDisabled(item)); // if (!hided && !disabled) { this.itemSelected.emit(item); } } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper( this.actionProvider.asObservable() ).subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XGridAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // private prepareData() { // if (!this.preparedCols) { return; } // const mCols = this.preparedCols < 0 ? 0 : this.preparedCols; this.colItems = Array.from(Array(mCols).keys()); // setTimeout(() => { // this.options = { ...cloneJson(defaultGridOptions), minCols: mCols, maxCols: mCols, } as XStaggedGridOptions; // this.detectChanges(); }, 300); // this.detectChanges(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { GridsterModule } from 'angular-gridster2'; import { XGridComponent } from './x-grid.component'; import { XCardModule } from '../x-card/x-card.module'; import { XEmptyModule } from '../x-empty/x-empty.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XGridComponent], imports: [ CommonModule, XCardModule, XEmptyModule, GridsterModule, XBaseComponentModule, ], exports: [XCardModule, XGridComponent, XEmptyModule, XBaseComponentModule], }) export class XGridModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-grid\x-grid.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { IXCardEmptyContainer, XCardEmptyContainer, XCardEmptyContainerComponent, } from '../classes/i-x-card-empty.container'; import { concatMap, map } from 'rxjs/operators'; import { GridsterConfig } from 'angular-gridster2'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XStandardType, XOneOrManyType } from 'x-framework-core'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export interface XGridItem { data: T; hide?: XStandardType; disabled?: XStandardType; href?: XStandardType>; } export interface XStaggedGridOptions extends Partial {} export const defaultGridOptions: XStaggedGridOptions = { gridType: 'scrollVertical', compactType: 'compactLeft&Up', disableWarnings: true, draggable: { enabled: true, }, pushItems: true, resizable: { enabled: true, }, minCols: 2, maxCols: 2, minRows: 1, }; export enum XGridPresentType { AsLinear, AsGrid, AsFlex, AsStaggedGrid, } export enum XGridAction { Refresh = 'refresh', } export type XGridActionIdentifier = XGridAction | string; export interface XGridActionModel extends XBaseActionModel {} // //#region Inside Card/Empty Container ... export interface IXGridContainer extends IXCardEmptyContainer { // actionProvider: Subject; cssClass: XStandardType>; // options: XStandardType; cols: XStandardType; type: XStandardType; gap: string; layout: string; align: string; selectableItems: XStandardType; items: XGridItem[]; itemTemplate: TemplateRef; // itemSelected: EventEmitter>; } @Injectable({ providedIn: 'root', }) export class XGridContainer extends XCardEmptyContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly options: XStandardType; readonly cols: XStandardType; readonly type: XStandardType; readonly gap: string = '1px'; readonly layout: string = 'row wrap'; readonly align: string = 'center start'; readonly selectableItems: XStandardType = false; readonly items: XGridItem[]; readonly itemTemplate: TemplateRef; // readonly itemSelected: EventEmitter>; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XGridContainerComponent extends XCardEmptyContainerComponent implements IXGridContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() options: XStandardType = this.propertyProvider.options; @Input() cols: XStandardType = this.propertyProvider.cols; @Input() type: XStandardType = this.propertyProvider.type; @Input() gap: string = this.propertyProvider.gap; @Input() layout: string = this.propertyProvider.layout; @Input() align: string = this.propertyProvider.align; @Input() selectableItems: XStandardType = this.propertyProvider.selectableItems; @Input() items: XGridItem[] = this.propertyProvider.items; @Input() itemTemplate: TemplateRef = this.propertyProvider.itemTemplate; // @Output() itemSelected: EventEmitter> = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XGridContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXGridContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), options: this.getValue( container ? container.options : this.options ), cols: this.getValue(container ? container.cols : this.cols), type: this.getValue(container ? container.type : this.type), gap: this.getValue(container ? container.gap : this.gap), layout: this.getValue(container ? container.layout : this.layout), align: this.getValue(container ? container.align : this.align), selectableItems: this.getValue( container ? container.selectableItems : this.selectableItems ), items: this.getValue(container ? container.items : this.items), itemTemplate: this.getValue( container ? container.itemTemplate : this.itemTemplate ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // itemSelected: this.itemSelected, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.component.scss :host { // --size: 24px; // display: inline-block; position: relative; // font-size: var(--size); line-height: var(--size); width: var(--size); height: var(--size); // min-width: var(--size); min-height: var(--size); // margin: 0 !important; padding: 0 !important; } // $delay: 0; $duration: 1; $transform: scaleX(-1); .x-icon { // display: inline-block; position: relative; // margin: 0 !important; padding: 0 !important; // box-sizing: border-box !important; // min-width: var(--size); min-height: var(--size); &.rtl { // transform: $transform; -ms-transform: $transform; -webkit-transform: $transform; // transition: transform; -webkit-transition: transform; // transition-delay: $delay; -webkit-transition-delay: $delay; // transition-duration: $duration; -webkit-transition-duration: $duration; } } ion-icon, ion-ripple-effect { font-size: var(--size); min-width: var(--size); min-height: var(--size); } .ion-activatable { cursor: pointer; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.component.ts import { XIconAction, XCustomIcons, XProvidedIcons, XIconActionModel, XIconContainerComponent, } from './x-icon.typings'; import { map } from 'rxjs/operators'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-icon', templateUrl: './x-icon.component.html', styleUrls: ['./x-icon.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XIconComponent extends XIconContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Icon Provider Properties ... get providedIcons() { return XProvidedIcons; } get icon() { return this.getValue(this.name).pipe( map((name) => { return (this.providedIcons as any)[name.toString()] as string; }) ); } //#endregion // //#region UI Providers ... isCustomIcon() { return this.getValue(this.name).pipe( map((name) => { return name && XCustomIcons.includes(name.toString()); }) ); } customIconUrl() { return this.getValue(this.name).pipe( map((name) => { // const svgName = (this.providedIcons as any)[name.toString()] return this.name ? `./assets/icon/svg/${svgName}.svg` : null; }) ); } //#endregion // //#region Action Handlers ... async handleClicked(event?: Event) { // const clickable = await this.toPromise(this.getValue(this.clickable)); const disabled = this.uiDisabled; if (!clickable || disabled) { return; } // if (event && event.stopPropagation) { event.stopPropagation(); } // this.clicked.emit(event); } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XIconAction.Click: this.clicked.emit(); break; // case XIconAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconComponent } from './x-icon.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XIconComponent], imports: [CommonModule, XBaseComponentModule], exports: [XBaseComponentModule, XIconComponent], }) export class XIconModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-icon\x-icon.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XIconAction { Click = 'click', Refresh = 'refresh', } export type XIconActionIdentifier = XIconAction | string; export interface XIconActionModel extends XBaseActionModel {} export enum XIconNames { tv = 'tv', ol = 'ol', ul = 'ul', job = 'job', add = 'add', sad = 'sad', web = 'web', map = 'map', dns = 'dns', dvr = 'dvr', fax = 'fax', mic = 'mic', mop = 'mop', info = 'info', lock = 'lock', mail = 'mail', shop = 'shop', edit = 'edit', done = 'done', list = 'list', user = 'user', star = 'star', sync = 'sync', undo = 'undo', redo = 'redo', home = 'home', flag = 'flag', save = 'save', last = 'last', next = 'next', copy = 'copy', link = 'link', bold = 'bold', code = 'code', crop = 'crop', call = 'call', tabs = 'tabs', cast = 'cast', wifi = 'wifi', stop = 'stop', play = 'play', phone = 'phone', reply = 'reply', label = 'label', liked = 'liked', terms = 'terms', event = 'event', clear = 'clear', input = 'input', close = 'close', users = 'users', files = 'files', login = 'login', posts = 'posts', enter = 'enter', power = 'power', cloud = 'cloud', first = 'first', touch = 'touch', error = 'error', print = 'print', share = 'share', image = 'image', audio = 'audio', video = 'video', guide = 'guide', quote = 'quote', toast = 'toast', cards = 'cards', mouse = 'mouse', album = 'album', badge = 'badge', radio = 'radio', watch = 'watch', movie = 'movie', pause = 'pause', unlock = 'unlock', cancel = 'cancel', expand = 'expand', mobile = 'mobile', search = 'search', survey = 'survey', remove = 'remove', invite = 'invite', logout = 'logout', school = 'school', server = 'server', upload = 'upload', locate = 'locate', italic = 'italic', repeat = 'repeat', report = 'report', policy = 'policy', router = 'router', shield = 'shield', stylus = 'stylus', tv_off = 'tv_off', swords = 'swords', nearby = 'nearby', flight = 'flight', memory = 'memory', replay = 'replay', visible = 'visible', checked = 'checked', unliked = 'unliked', profile = 'profile', account = 'account', avatars = 'avatars', archive = 'archive', refresh = 'refresh', unknown = 'unknown', preview = 'preview', heading = 'heading', toolbar = 'toolbar', dialogs = 'dialogs', dialpad = 'dialpad', vpn_key = 'vpn_key', widgets = 'widgets', passkey = 'passkey', mic_off = 'mic_off', monitor = 'monitor', gpp_bad = 'gpp_bad', charger = 'charger', devices = 'devices', capture = 'capture', live_tv = 'live_tv', sd_card = 'sd_card', verified = 'verified', collapse = 'collapse', arrow_up = 'arrow_up', contacts = 'contacts', contrast = 'contrast', calendar = 'calendar', register = 'register', explorer = 'explorer', settings = 'settings', business = 'business', bookmark = 'bookmark', chat_box = 'chat_box', location = 'location', previous = 'previous', download = 'download', language = 'language', document = 'document', logo_npm = 'logo_npm', logo_pwa = 'logo_pwa', logo_rss = 'logo_rss', logo_usd = 'logo_usd', logo_vue = 'logo_vue', dropdown = 'dropdown', add_call = 'add_call', sim_card = 'sim_card', security = 'security', password = 'password', podcasts = 'podcasts', wifi_off = 'wifi_off', no_sound = 'no_sound', keyboard = 'keyboard', exercise = 'exercise', computer = 'computer', autoplay = 'autoplay', autostop = 'autostop', videocam = 'videocam', label_off = 'label_off', swap_vert = 'swap_vert', dashboard = 'dashboard', checkmark = 'checkmark', star_half = 'star_half', thumbs_up = 'thumbs_up', bookmarks = 'bookmarks', bluetooth = 'bluetooth', analytics = 'analytics', clipboard = 'clipboard', logo_css3 = 'logo_css3', logo_edge = 'logo_edge', logo_sass = 'logo_sass', touch_app = 'touch_app', voicemail = 'voicemail', call_made = 'call_made', subtitles = 'subtitles', music_off = 'music_off', encrypted = 'encrypted', apartment = 'apartment', dark_mode = 'dark_mode', deskphone = 'deskphone', autopause = 'autopause', video_cam = 'video_cam', swap_horiz = 'swap_horiz', first_name = 'first_name', un_checked = 'un_checked', arrow_down = 'arrow_down', arrow_back = 'arrow_back', select_all = 'select_all', management = 'management', logo_apple = 'logo_apple', logo_ionic = 'logo_ionic', logo_html5 = 'logo_html5', blockchain = 'blockchain', logo_react = 'logo_react', logo_skype = 'logo_skype', logo_slack = 'logo_slack', logo_yahoo = 'logo_yahoo', data_table = 'data_table', device_hub = 'device_hub', call_split = 'call_split', router_off = 'router_off', light_mode = 'light_mode', mouse_lock = 'mouse_lock', nightlight = 'nightlight', volume_off = 'volume_off', volume_low = 'volume_low', play_arrow = 'play_arrow', video_call = 'video_call', video_chat = 'video_chat', video_file = 'video_file', voice_chat = 'voice_chat', fit_screen = 'fit_screen', fullscreen = 'fullscreen', rotate_left = 'rotate_left', visible_off = 'visible_off', friendships = 'friendships', thumbs_down = 'thumbs_down', chat_bubble = 'chat_bubble', stats_chart = 'stats_chart', logo_amazon = 'logo_amazon', logo_chrome = 'logo_chrome', logo_docker = 'logo_docker', logo_github = 'logo_github', logo_gitlab = 'logo_gitlab', logo_google = 'logo_google', blockchain1 = 'blockchain1', logo_nodejs = 'logo_nodejs', logo_paypal = 'logo_paypal', voicemail_2 = 'voicemail_2', devices_off = 'devices_off', exit_to_app = 'exit_to_app', ring_volume = 'ring_volume', call_missed = 'call_missed', privacy_tip = 'privacy_tip', dual_screen = 'dual_screen', engineering = 'engineering', volume_high = 'volume_high', volume_mute = 'volume_mute', play_circle = 'play_circle', fast_rewind = 'fast_rewind', rotate_right = 'rotate_right', chat_bubbles = 'chat_bubbles', deselect_all = 'deselect_all', arrow_dropup = 'arrow_dropup', logo_android = 'logo_android', logo_angular = 'logo_angular', logo_bitcoin = 'logo_bitcoin', logo_dropbox = 'logo_dropbox', logo_firefox = 'logo_firefox', logo_windows = 'logo_windows', logo_twitter = 'logo_twitter', logo_youtube = 'logo_youtube', wifi_calling = 'wifi_calling', phone_locked = 'phone_locked', phone_missed = 'phone_missed', call_quality = 'call_quality', screen_share = 'screen_share', room_service = 'room_service', other_houses = 'other_houses', dock_to_left = 'dock_to_left', keyboard_off = 'keyboard_off', cameraswitch = 'cameraswitch', architecture = 'architecture', fast_forward = 'fast_forward', arrow_forward = 'arrow_forward', accessibility = 'accessibility', cloud_offline = 'cloud_offline', menu_vertical = 'menu_vertical', logo_electron = 'logo_electron', logo_facebook = 'logo_facebook', logo_firebase = 'logo_firebase', logo_linkedin = 'logo_linkedin', logo_markdown = 'logo_markdown', logo_whatsapp = 'logo_whatsapp', color_palette = 'color_palette', phone_enabled = 'phone_enabled', phone_in_talk = 'phone_in_talk', call_received = 'call_received', print_connect = 'print_connect', screen_record = 'screen_record', shield_person = 'shield_person', verified_user = 'verified_user', network_check = 'network_check', encrypted_off = 'encrypted_off', dock_to_right = 'dock_to_right', electric_bolt = 'electric_bolt', reset_password = 'reset_password', customers_club = 'customers_club', checkmark_done = 'checkmark_done', arrow_dropdown = 'arrow_dropdown', logo_instagram = 'logo_instagram', logo_wordpress = 'logo_wordpress', devices_fold_2 = 'devices_fold_2', perm_phone_msg = 'perm_phone_msg', phone_callback = 'phone_callback', phone_disabled = 'phone_disabled', settings_phone = 'settings_phone', print_disabled = 'print_disabled', wifi_tethering = 'wifi_tethering', speech_to_text = 'speech_to_text', mouse_lock_off = 'mouse_lock_off', directions_car = 'directions_car', local_shipping = 'local_shipping', cast_connected = 'cast_connected', voice_chat_off = 'voice_chat_off', password_change = 'password_change', menu_horizontal = 'menu_horizontal', logo_javascript = 'logo_javascript', phone_forwarded = 'phone_forwarded', string_resources = 'string_resources', chatbox_ellipses = 'chatbox_ellipses', checkmark_circle = 'checkmark_circle', select_all_group = 'select_all_group', blockchain_block = 'blockchain_block', friendship_block = 'friendship_block', blockchain_token = 'blockchain_token', document_scanner = 'document_scanner', splitscreen_left = 'splitscreen_left', close_fullscreen = 'close_fullscreen', inverse_selection = 'inverse_selection', friendship_reuest = 'friendship_reuest', friendship_friend = 'friendship_friend', friendship_reject = 'friendship_reject', friendship_cancel = 'friendship_cancel', friendship_accept = 'friendship_accept', stop_screen_share = 'stop_screen_share', missed_video_call = 'missed_video_call', keyboard_lock_off = 'keyboard_lock_off', video_camera_back = 'video_camera_back', deselect_all_group = 'deselect_all_group', logo_stackoverflow = 'logo_stackoverflow', logo_web_component = 'logo_web_component', blockchain_address = 'blockchain_address', friendship_unblock = 'friendship_unblock', friendship_unknown = 'friendship_unknown', wifi_calling_bar_1 = 'wifi_calling_bar_1', wifi_calling_bar_2 = 'wifi_calling_bar_2', video_camera_front = 'video_camera_front', picture_in_picture = 'picture_in_picture', logo_apple_appstore = 'logo_apple_appstore', friendship_follower = 'friendship_follower', friendship_unfollow = 'friendship_unfollow', signal_cellular_alt = 'signal_cellular_alt', signal_disconnected = 'signal_disconnected', chat_bubble_ellipses = 'chat_bubble_ellipses', friendship_following = 'friendship_following', call_missed_outgoing = 'call_missed_outgoing', audio_video_receiver = 'audio_video_receiver', admin_panel_settings = 'admin_panel_settings', checkmark_done_circle = 'checkmark_done_circle', logo_google_playstore = 'logo_google_playstore', video_camera_back_add = 'video_camera_back_add', blockchain_transaction = 'blockchain_transaction', display_external_input = 'display_external_input', picture_in_picture_off = 'picture_in_picture_off', video_camera_front_off = 'video_camera_front_off', phone_bluetooth_speaker = 'phone_bluetooth_speaker', desktop_access_disabled = 'desktop_access_disabled', blockchain_smart_contract = 'blockchain_smart_contract', blockchain_contract_address = 'blockchain_contract_address', } export const defaultIcon = ''; export type XIconName = [keyof typeof XIconNames]; export type XIconIdentifier = XIconName | XIconNames | string; export type XIconsIndex = { [key in keyof typeof XIconNames]?: string; }; // // Contains Path of Custom icons File Names ... export const XProvidedIcons = { tv: 'tv', ol: 'ol', ul: 'ul', add: 'add', dns: 'dns', dvr: 'dvr', fax: 'fax', mic: 'mic', mop: 'mop', sad: 'sad', map: 'map', mail: 'mail', undo: 'undo', redo: 'redo', home: 'home', flag: 'flag', save: 'save', sync: 'sync', play: 'play', star: 'star', cast: 'cast', wifi: 'wifi', call: 'call', tabs: 'tabs', stop: 'stop', code: 'code', bold: 'bold', crop: 'crop', web: 'globe', link: 'link', last: 'last', next: 'next', copy: 'copy', phone: 'call', guide: 'help', reply: 'reply', label: 'label', visible: 'eye', liked: 'heart', mobile: 'call', shop: 'basket', event: 'pulse', clear: 'close', edit: 'create', close: 'close', enter: 'enter', power: 'power', pause: 'pause', cloud: 'cloud', toast: 'toast', cards: 'cards', mouse: 'mouse', album: 'album', badge: 'badge', radio: 'radio', watch: 'watch', movie: 'movie', image: 'image', quote: 'quote', touch: 'touch', error: 'error', first: 'first', print: 'print', cancel: 'close', remove: 'trash', terms: 'hammer', input: 'pencil', login: 'log-in', posts: 'albums', files: 'folder', italic: 'italic', locate: 'locate', search: 'search', job: 'megaphone', list: 'list-box', rewind: 'rewind', school: 'school', server: 'server', repeat: 'repeat', report: 'report', policy: 'policy', router: 'router', shield: 'shield', stylus: 'stylus', tv_off: 'tv_off', swords: 'swords', nearby: 'nearby', flight: 'flight', memory: 'memory', replay: 'replay', unknown: 'attach', video: 'videocam', done: 'checkmark', logout: 'log-out', avatars: 'images', account: 'person', invite: 'contract', archive: 'archive', toolbar: 'toolbar', dialogs: 'dialogs', dialpad: 'dialpad', vpn_key: 'vpn_key', widgets: 'widgets', passkey: 'passkey', mic_off: 'mic_off', monitor: 'monitor', gpp_bad: 'gpp_bad', charger: 'charger', devices: 'devices', sd_card: 'sd_card', capture: 'capture', live_tv: 'live_tv', preview: 'preview', heading: 'heading', refresh: 'refresh', lock: 'lock-closed', unlock: 'lock-open', un_checked: 'close', survey: 'newspaper', chat_box: 'chatbox', verified: 'verified', arrow_up: 'arrow-up', business: 'business', contrast: 'contrast', first_name: 'person', calendar: 'calendar', checked: 'checkmark', dashboard: 'journal', explorer: 'browsers', settings: 'settings', bookmark: 'bookmark', dropdown: 'dropdown', add_call: 'add_call', sim_card: 'sim_card', security: 'security', password: 'password', podcasts: 'podcasts', wifi_off: 'wifi_off', no_sound: 'no_sound', keyboard: 'keyboard', exercise: 'exercise', computer: 'computer', videocam: 'videocam', autoplay: 'autoplay', autostop: 'autostop', logo_npm: 'logo-npm', logo_pwa: 'logo-pwa', logo_rss: 'logo-rss', logo_usd: 'logo-usd', logo_vue: 'logo-vue', previous: 'previous', location: 'location', language: 'language', document: 'document', expand: 'expand_more', friendships: 'people', user: 'person-circle', video_cam: 'videocam', share: 'share-social', deselect_all: 'close', label_off: 'label_off', visible_off: 'eye-off', users: 'people-circle', checkmark: 'checkmark', star_half: 'star-half', bookmarks: 'bookmarks', thumbs_up: 'thumbs-up', bluetooth: 'bluetooth', logo_css3: 'logo-css3', logo_edge: 'logo-edge', logo_sass: 'logo-sass', voicemail: 'voicemail', call_made: 'call_made', touch_app: 'touch_app', subtitles: 'subtitles', music_off: 'music_off', encrypted: 'encrypted', apartment: 'apartment', dark_mode: 'dark_mode', deskphone: 'deskphone', autopause: 'autopause', upload: 'cloud-upload', audio: 'musical-notes', clipboard: 'clipboard', analytics: 'analytics', select_all: 'checkbox', management: 'construct', unliked: 'heart-outline', arrow_down: 'arrow-down', arrow_back: 'arrow-back', profile: 'person-circle', register: 'finger-print', customers_club: 'trophy', volume_off: 'volume-off', volume_low: 'volume-low', logo_html5: 'logo-html5', logo_ionic: 'logo-ionic', logo_apple: 'logo-apple', logo_react: 'logo-react', logo_skype: 'logo-skype', logo_slack: 'logo-slack', logo_yahoo: 'logo-yahoo', blockchain: 'blockchain', data_table: 'data_table', device_hub: 'device_hub', call_split: 'call_split', router_off: 'router_off', light_mode: 'light_mode', mouse_lock: 'mouse_lock', nightlight: 'nightlight', play_arrow: 'play_arrow', video_call: 'video_call', video_chat: 'video_chat', video_file: 'video_file', voice_chat: 'voice_chat', fit_screen: 'fit_screen', fullscreen: 'fullscreen', friendship_reuest: 'add', arrow_dropup: 'caret-up', collapse: 'chevron_right', contacts: 'people-circle', friendship_block: 'block', chat_bubble: 'chatbubble', info: 'information-circle', rotate_left: 'rotate_left', swap_vert: 'swap-vertical', friendship_friend: 'forum', download: 'cloud-download', thumbs_down: 'thumbs-down', stats_chart: 'stats-chart', volume_high: 'volume-high', volume_mute: 'volume-mute', play_circle: 'play-circle', logo_amazon: 'logo-amazon', logo_chrome: 'logo-chrome', logo_docker: 'logo-docker', logo_github: 'logo-github', logo_gitlab: 'logo-gitlab', logo_google: 'logo-google', logo_paypal: 'logo-paypal', blockchain1: 'blockchain1', logo_nodejs: 'logo-nodejs', voicemail_2: 'voicemail_2', devices_off: 'devices_off', exit_to_app: 'exit_to_app', ring_volume: 'ring_volume', call_missed: 'call_missed', privacy_tip: 'privacy_tip', dual_screen: 'dual_screen', engineering: 'engineering', fast_rewind: 'fast_rewind', reset_password: 'construct', chat_bubbles: 'chatbubbles', friendship_reject: 'remove', friendship_follower: 'chat', rotate_right: 'rotate_right', logo_android: 'logo-android', logo_angular: 'logo-angular', logo_bitcoin: 'logo-bitcoin', logo_dropbox: 'logo-dropbox', logo_firefox: 'logo-firefox', logo_twitter: 'logo-twitter', logo_youtube: 'logo-youtube', logo_windows: 'logo-windows', wifi_calling: 'wifi_calling', phone_locked: 'phone_locked', phone_missed: 'phone_missed', call_quality: 'call_quality', screen_share: 'screen_share', room_service: 'room_service', other_houses: 'other_houses', dock_to_left: 'dock_to_left', keyboard_off: 'keyboard_off', cameraswitch: 'cameraswitch', architecture: 'architecture', fast_forward: 'fast_forward', arrow_dropdown: 'caret-down', string_resources: 'pricetags', swap_horiz: 'swap-horizontal', arrow_forward: 'arrow-forward', password_change: 'lock-closed', cloud_offline: 'cloud-offline', accessibility: 'accessibility', logo_electron: 'logo-electron', logo_facebook: 'logo-facebook', logo_firebase: 'logo-firebase', logo_linkedin: 'logo-linkedin', logo_markdown: 'logo-markdown', logo_whatsapp: 'logo-whatsapp', phone_enabled: 'phone_enabled', phone_in_talk: 'phone_in_talk', call_received: 'call_received', print_connect: 'print_connect', screen_record: 'screen_record', shield_person: 'shield_person', verified_user: 'verified_user', network_check: 'network_check', encrypted_off: 'encrypted_off', dock_to_right: 'dock_to_right', electric_bolt: 'electric_bolt', color_palette: 'color-palette', friendship_accept: 'checkmark', friendship_following: 'comment', checkmark_done: 'checkmark-done', logo_instagram: 'logo-instagram', logo_wordpress: 'logo-wordpress', devices_fold_2: 'devices_fold_2', perm_phone_msg: 'perm_phone_msg', phone_callback: 'phone_callback', phone_disabled: 'phone_disabled', settings_phone: 'settings_phone', print_disabled: 'print_disabled', wifi_tethering: 'wifi_tethering', speech_to_text: 'speech_to_text', mouse_lock_off: 'mouse_lock_off', directions_car: 'directions_car', local_shipping: 'local_shipping', cast_connected: 'cast_connected', voice_chat_off: 'voice_chat_off', logo_javascript: 'logo-javascript', phone_forwarded: 'phone_forwarded', menu_vertical: 'ellipsis-vertical', chatbox_ellipses: 'chatbox-ellipses', checkmark_circle: 'checkmark-circle', blockchain_block: 'blockchain-block', blockchain_token: 'blockchain-token', document_scanner: 'document_scanner', splitscreen_left: 'splitscreen_left', close_fullscreen: 'close_fullscreen', friendship_unblock: 'thumbs_up_down', friendship_unfollow: 'highlight_off', select_all_group: 'select_all_group', stop_screen_share: 'stop_screen_share', missed_video_call: 'missed_video_call', keyboard_lock_off: 'keyboard_lock_off', video_camera_back: 'video_camera_back', menu_horizontal: 'ellipsis-horizontal', logo_stackoverflow: 'logo-stackoverflow', blockchain_address: 'blockchain-address', logo_web_component: 'logo-web-component', wifi_calling_bar_1: 'wifi_calling_bar_1', wifi_calling_bar_2: 'wifi_calling_bar_2', video_camera_front: 'video_camera_front', picture_in_picture: 'picture_in_picture', deselect_all_group: 'deselect_all_group', logo_apple_appstore: 'logo-apple-appstore', signal_cellular_alt: 'signal_cellular_alt', signal_disconnected: 'signal_disconnected', friendship_cancel: 'remove_circle_outline', inverse_selection: 'remove-circle-outline', chat_bubble_ellipses: 'chatbubble-ellipses', call_missed_outgoing: 'call_missed_outgoing', audio_video_receiver: 'audio_video_receiver', admin_panel_settings: 'admin_panel_settings', friendship_unknown: 'radio_button_unchecked', checkmark_done_circle: 'checkmark-done-circle', video_camera_back_add: 'video_camera_back_add', logo_google_playstore: 'logo-google-playstore', blockchain_transaction: 'blockchain-transaction', video_camera_front_off: 'video_camera_front_off', display_external_input: 'display_external_input', picture_in_picture_off: 'picture_in_picture_off', phone_bluetooth_speaker: 'phone_bluetooth_speaker', desktop_access_disabled: 'desktop_access_disabled', blockchain_smart_contract: 'blockchain-smart-contract', blockchain_contract_address: 'blockchain-contract-address', }; export const XCustomIcons: string[] = [ XIconNames.ol, XIconNames.ul, XIconNames.tv, XIconNames.dns, XIconNames.dvr, XIconNames.fax, XIconNames.mic, XIconNames.mop, XIconNames.call, XIconNames.tabs, XIconNames.cast, XIconNames.wifi, XIconNames.stop, XIconNames.cast, XIconNames.link, XIconNames.bold, XIconNames.code, XIconNames.undo, XIconNames.redo, XIconNames.next, XIconNames.last, XIconNames.list, XIconNames.toast, XIconNames.cards, XIconNames.mouse, XIconNames.album, XIconNames.badge, XIconNames.radio, XIconNames.watch, XIconNames.guide, XIconNames.image, XIconNames.quote, XIconNames.touch, XIconNames.error, XIconNames.first, XIconNames.reply, XIconNames.label, XIconNames.movie, XIconNames.repeat, XIconNames.report, XIconNames.policy, XIconNames.router, XIconNames.shield, XIconNames.stylus, XIconNames.tv_off, XIconNames.swords, XIconNames.nearby, XIconNames.flight, XIconNames.memory, XIconNames.replay, XIconNames.expand, XIconNames.italic, XIconNames.toolbar, XIconNames.devices, XIconNames.dialogs, XIconNames.dialpad, XIconNames.vpn_key, XIconNames.widgets, XIconNames.passkey, XIconNames.mic_off, XIconNames.monitor, XIconNames.gpp_bad, XIconNames.charger, XIconNames.devices, XIconNames.sd_card, XIconNames.capture, XIconNames.live_tv, XIconNames.monitor, XIconNames.preview, XIconNames.heading, XIconNames.dropdown, XIconNames.add_call, XIconNames.sim_card, XIconNames.security, XIconNames.password, XIconNames.podcasts, XIconNames.wifi_off, XIconNames.no_sound, XIconNames.keyboard, XIconNames.exercise, XIconNames.computer, XIconNames.videocam, XIconNames.autoplay, XIconNames.autostop, XIconNames.previous, XIconNames.collapse, XIconNames.verified, XIconNames.touch_app, XIconNames.voicemail, XIconNames.call_made, XIconNames.subtitles, XIconNames.music_off, XIconNames.encrypted, XIconNames.apartment, XIconNames.dark_mode, XIconNames.deskphone, XIconNames.autopause, XIconNames.label_off, XIconNames.data_table, XIconNames.device_hub, XIconNames.call_split, XIconNames.router_off, XIconNames.light_mode, XIconNames.mouse_lock, XIconNames.nightlight, XIconNames.play_arrow, XIconNames.video_call, XIconNames.video_chat, XIconNames.video_file, XIconNames.voice_chat, XIconNames.fit_screen, XIconNames.fullscreen, XIconNames.blockchain, XIconNames.voicemail_2, XIconNames.devices_off, XIconNames.exit_to_app, XIconNames.ring_volume, XIconNames.call_missed, XIconNames.privacy_tip, XIconNames.dual_screen, XIconNames.engineering, XIconNames.fast_rewind, XIconNames.blockchain1, XIconNames.logo_docker, XIconNames.logo_gitlab, XIconNames.logo_paypal, XIconNames.rotate_left, XIconNames.wifi_calling, XIconNames.phone_locked, XIconNames.phone_missed, XIconNames.call_quality, XIconNames.screen_share, XIconNames.room_service, XIconNames.other_houses, XIconNames.dock_to_left, XIconNames.keyboard_off, XIconNames.cameraswitch, XIconNames.architecture, XIconNames.rotate_right, XIconNames.fast_forward, XIconNames.phone_enabled, XIconNames.phone_in_talk, XIconNames.call_received, XIconNames.print_connect, XIconNames.screen_record, XIconNames.shield_person, XIconNames.verified_user, XIconNames.network_check, XIconNames.encrypted_off, XIconNames.dock_to_right, XIconNames.electric_bolt, XIconNames.devices_fold_2, XIconNames.perm_phone_msg, XIconNames.phone_callback, XIconNames.phone_disabled, XIconNames.settings_phone, XIconNames.print_disabled, XIconNames.wifi_tethering, XIconNames.speech_to_text, XIconNames.mouse_lock_off, XIconNames.directions_car, XIconNames.local_shipping, XIconNames.cast_connected, XIconNames.voice_chat_off, XIconNames.phone_forwarded, XIconNames.document_scanner, XIconNames.splitscreen_left, XIconNames.close_fullscreen, XIconNames.blockchain_block, XIconNames.blockchain_token, XIconNames.select_all_group, XIconNames.friendship_block, XIconNames.stop_screen_share, XIconNames.missed_video_call, XIconNames.keyboard_lock_off, XIconNames.video_camera_back, XIconNames.friendship_friend, XIconNames.friendship_reject, XIconNames.friendship_cancel, XIconNames.wifi_calling_bar_1, XIconNames.wifi_calling_bar_2, XIconNames.video_camera_front, XIconNames.picture_in_picture, XIconNames.blockchain_address, XIconNames.deselect_all_group, XIconNames.friendship_unblock, XIconNames.friendship_unknown, XIconNames.signal_cellular_alt, XIconNames.signal_disconnected, XIconNames.friendship_follower, XIconNames.friendship_unfollow, XIconNames.call_missed_outgoing, XIconNames.audio_video_receiver, XIconNames.admin_panel_settings, XIconNames.friendship_following, XIconNames.video_camera_back_add, XIconNames.video_camera_front_off, XIconNames.display_external_input, XIconNames.picture_in_picture_off, XIconNames.blockchain_transaction, XIconNames.phone_bluetooth_speaker, XIconNames.desktop_access_disabled, XIconNames.blockchain_smart_contract, XIconNames.blockchain_contract_address, ]; export type XIconSlot = 'start' | 'end'; // //#region Container ... export interface IXIconContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // slot: XStandardType; name: XStandardType; // color: XStandardType; foregroundColor: XStandardType; // applyDirection: XStandardType; // selectable: XStandardType; clickable: XStandardType; clicked: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XIconContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly slot: XStandardType = 'start'; readonly name: XStandardType; // readonly color: XStandardType; readonly foregroundColor: XStandardType = true; readonly selectable: XStandardType = false; readonly clickable: XStandardType = false; readonly applyDirection: XStandardType = false; // readonly clicked = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XIconContainerComponent extends XBaseContainerComponent implements IXIconContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() slot: XStandardType = this.propertyProvider.slot; @Input() name: XStandardType = this.propertyProvider.name; @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; @Input() selectable: XStandardType = this.propertyProvider.selectable; @Input() clickable: XStandardType = this.propertyProvider.clickable; @Input() applyDirection: XStandardType = this.propertyProvider.applyDirection; @Output() clicked: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XIconContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXIconContainer ): Observable { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // slot: this.getValue(container ? container.slot : this.slot), name: this.getValue(container ? container.name : this.name), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), selectable: this.getValue( container ? container.selectable : this.selectable ), clickable: this.getValue( container ? container.clickable : this.clickable ), applyDirection: this.getValue( container ? container.applyDirection : this.applyDirection ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // clicked: this.clicked, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.component.html
{{ tab.name }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.component.ts import { Component, ViewChild, ElementRef, HostListener, ChangeDetectionStrategy, } from '@angular/core'; import { XIDEMode, XIDETheme, XIDEAction, XIDEActionModel, XIDEMinFontSize, XIDEMaxFontSize, XIDEActionBarItem, XIDETabDescriptor, XIDEModeIdentifier, XIDEDefaultTabName, XIDEThemeIdentifier, XIDEContainerComponent, } from './x-ide.typings'; import { nameof, toArray, isNumber, toBoolean, isBoolean, countChild, XStandardType, toNormalString, XOneOrManyType, isNullOrUndefined, isNullOrEmptyString, XColorWithBrightness, } from 'x-framework-core'; import { XTabAlign, XTabsAction, XTabChangeEvent, XTabsActionModel, XTabsHeaderPosition, } from '../x-tabs/x-tabs.typings'; import * as ace from 'ace-builds'; import { XActionBarItem, XActionBarItemSlot, XActionBarActionFiredModel, } from '../x-action-bar/x-action-bar.typings'; import { concatMap, map } from 'rxjs/operators'; import 'ace-builds/src-noconflict/ext-beautify'; import { XIconNames } from '../x-icon/x-icon.typings'; import 'ace-builds/src-noconflict/ext-language_tools'; import { forkJoin, Subject, Subscription } from 'rxjs'; import { XPopoverOption } from '../dialogs/x-popover/x-popover.typings'; // //#region Themes ... import 'ace-builds/src-noconflict/theme-ambiance'; import 'ace-builds/src-noconflict/theme-chaos'; import 'ace-builds/src-noconflict/theme-chrome'; import 'ace-builds/src-noconflict/theme-cloud9_day'; import 'ace-builds/src-noconflict/theme-cloud9_night'; import 'ace-builds/src-noconflict/theme-cloud9_night_low_color'; import 'ace-builds/src-noconflict/theme-clouds'; import 'ace-builds/src-noconflict/theme-clouds_midnight'; import 'ace-builds/src-noconflict/theme-cobalt'; import 'ace-builds/src-noconflict/theme-crimson_editor'; import 'ace-builds/src-noconflict/theme-dawn'; import 'ace-builds/src-noconflict/theme-dracula'; import 'ace-builds/src-noconflict/theme-dreamweaver'; import 'ace-builds/src-noconflict/theme-eclipse'; import 'ace-builds/src-noconflict/theme-github'; import 'ace-builds/src-noconflict/theme-gob'; import 'ace-builds/src-noconflict/theme-gruvbox'; import 'ace-builds/src-noconflict/theme-gruvbox_dark_hard'; import 'ace-builds/src-noconflict/theme-gruvbox_light_hard'; import 'ace-builds/src-noconflict/theme-idle_fingers'; import 'ace-builds/src-noconflict/theme-iplastic'; import 'ace-builds/src-noconflict/theme-katzenmilch'; import 'ace-builds/src-noconflict/theme-kr_theme'; import 'ace-builds/src-noconflict/theme-kuroir'; import 'ace-builds/src-noconflict/theme-merbivore'; import 'ace-builds/src-noconflict/theme-merbivore_soft'; import 'ace-builds/src-noconflict/theme-mono_industrial'; import 'ace-builds/src-noconflict/theme-monokai'; import 'ace-builds/src-noconflict/theme-nord_dark'; import 'ace-builds/src-noconflict/theme-one_dark'; import 'ace-builds/src-noconflict/theme-pastel_on_dark'; import 'ace-builds/src-noconflict/theme-solarized_dark'; import 'ace-builds/src-noconflict/theme-solarized_light'; import 'ace-builds/src-noconflict/theme-sqlserver'; import 'ace-builds/src-noconflict/theme-terminal'; import 'ace-builds/src-noconflict/theme-textmate'; import 'ace-builds/src-noconflict/theme-tomorrow'; import 'ace-builds/src-noconflict/theme-tomorrow_night'; import 'ace-builds/src-noconflict/theme-tomorrow_night_blue'; import 'ace-builds/src-noconflict/theme-tomorrow_night_bright'; import 'ace-builds/src-noconflict/theme-tomorrow_night_eighties'; import 'ace-builds/src-noconflict/theme-twilight'; import 'ace-builds/src-noconflict/theme-vibrant_ink'; import 'ace-builds/src-noconflict/theme-xcode'; //#endregion // //#region Modes ... import 'ace-builds/src-noconflict/mode-abap'; import 'ace-builds/src-noconflict/mode-abc'; import 'ace-builds/src-noconflict/mode-actionscript'; import 'ace-builds/src-noconflict/mode-ada'; import 'ace-builds/src-noconflict/mode-alda'; import 'ace-builds/src-noconflict/mode-apache_conf'; import 'ace-builds/src-noconflict/mode-apex'; import 'ace-builds/src-noconflict/mode-applescript'; import 'ace-builds/src-noconflict/mode-aql'; import 'ace-builds/src-noconflict/mode-asciidoc'; import 'ace-builds/src-noconflict/mode-asl'; import 'ace-builds/src-noconflict/mode-assembly_x86'; import 'ace-builds/src-noconflict/mode-autohotkey'; import 'ace-builds/src-noconflict/mode-batchfile'; import 'ace-builds/src-noconflict/mode-c9search'; import 'ace-builds/src-noconflict/mode-c_cpp'; import 'ace-builds/src-noconflict/mode-cirru'; import 'ace-builds/src-noconflict/mode-clojure'; import 'ace-builds/src-noconflict/mode-cobol'; import 'ace-builds/src-noconflict/mode-coffee'; import 'ace-builds/src-noconflict/mode-coldfusion'; import 'ace-builds/src-noconflict/mode-crystal'; import 'ace-builds/src-noconflict/mode-csharp'; import 'ace-builds/src-noconflict/mode-csound_document'; import 'ace-builds/src-noconflict/mode-csound_orchestra'; import 'ace-builds/src-noconflict/mode-csound_score'; import 'ace-builds/src-noconflict/mode-csp'; import 'ace-builds/src-noconflict/mode-css'; import 'ace-builds/src-noconflict/mode-curly'; import 'ace-builds/src-noconflict/mode-d'; import 'ace-builds/src-noconflict/mode-dart'; import 'ace-builds/src-noconflict/mode-diff'; import 'ace-builds/src-noconflict/mode-django'; import 'ace-builds/src-noconflict/mode-dockerfile'; import 'ace-builds/src-noconflict/mode-dot'; import 'ace-builds/src-noconflict/mode-drools'; import 'ace-builds/src-noconflict/mode-edifact'; import 'ace-builds/src-noconflict/mode-eiffel'; import 'ace-builds/src-noconflict/mode-ejs'; import 'ace-builds/src-noconflict/mode-elixir'; import 'ace-builds/src-noconflict/mode-elm'; import 'ace-builds/src-noconflict/mode-erlang'; import 'ace-builds/src-noconflict/mode-forth'; import 'ace-builds/src-noconflict/mode-fortran'; import 'ace-builds/src-noconflict/mode-fsharp'; import 'ace-builds/src-noconflict/mode-fsl'; import 'ace-builds/src-noconflict/mode-ftl'; import 'ace-builds/src-noconflict/mode-gcode'; import 'ace-builds/src-noconflict/mode-gherkin'; import 'ace-builds/src-noconflict/mode-gitignore'; import 'ace-builds/src-noconflict/mode-glsl'; import 'ace-builds/src-noconflict/mode-gobstones'; import 'ace-builds/src-noconflict/mode-golang'; import 'ace-builds/src-noconflict/mode-graphqlschema'; import 'ace-builds/src-noconflict/mode-groovy'; import 'ace-builds/src-noconflict/mode-haml'; import 'ace-builds/src-noconflict/mode-handlebars'; import 'ace-builds/src-noconflict/mode-haskell'; import 'ace-builds/src-noconflict/mode-haskell_cabal'; import 'ace-builds/src-noconflict/mode-haxe'; import 'ace-builds/src-noconflict/mode-hjson'; import 'ace-builds/src-noconflict/mode-html'; import 'ace-builds/src-noconflict/mode-html_elixir'; import 'ace-builds/src-noconflict/mode-html_ruby'; import 'ace-builds/src-noconflict/mode-ini'; import 'ace-builds/src-noconflict/mode-io'; import 'ace-builds/src-noconflict/mode-ion'; import 'ace-builds/src-noconflict/mode-jack'; import 'ace-builds/src-noconflict/mode-jade'; import 'ace-builds/src-noconflict/mode-java'; import 'ace-builds/src-noconflict/mode-javascript'; import 'ace-builds/src-noconflict/mode-json'; import 'ace-builds/src-noconflict/mode-json5'; import 'ace-builds/src-noconflict/mode-jsoniq'; import 'ace-builds/src-noconflict/mode-jsp'; import 'ace-builds/src-noconflict/mode-jssm'; import 'ace-builds/src-noconflict/mode-jsx'; import 'ace-builds/src-noconflict/mode-julia'; import 'ace-builds/src-noconflict/mode-kotlin'; import 'ace-builds/src-noconflict/mode-latex'; import 'ace-builds/src-noconflict/mode-latte'; import 'ace-builds/src-noconflict/mode-less'; import 'ace-builds/src-noconflict/mode-liquid'; import 'ace-builds/src-noconflict/mode-lisp'; import 'ace-builds/src-noconflict/mode-livescript'; import 'ace-builds/src-noconflict/mode-logiql'; import 'ace-builds/src-noconflict/mode-logtalk'; import 'ace-builds/src-noconflict/mode-lsl'; import 'ace-builds/src-noconflict/mode-lua'; import 'ace-builds/src-noconflict/mode-luapage'; import 'ace-builds/src-noconflict/mode-lucene'; import 'ace-builds/src-noconflict/mode-makefile'; import 'ace-builds/src-noconflict/mode-markdown'; import 'ace-builds/src-noconflict/mode-mask'; import 'ace-builds/src-noconflict/mode-matlab'; import 'ace-builds/src-noconflict/mode-maze'; import 'ace-builds/src-noconflict/mode-mediawiki'; import 'ace-builds/src-noconflict/mode-mel'; import 'ace-builds/src-noconflict/mode-mips'; import 'ace-builds/src-noconflict/mode-mixal'; import 'ace-builds/src-noconflict/mode-mushcode'; import 'ace-builds/src-noconflict/mode-mysql'; import 'ace-builds/src-noconflict/mode-nginx'; import 'ace-builds/src-noconflict/mode-nim'; import 'ace-builds/src-noconflict/mode-nix'; import 'ace-builds/src-noconflict/mode-nsis'; import 'ace-builds/src-noconflict/mode-nunjucks'; import 'ace-builds/src-noconflict/mode-objectivec'; import 'ace-builds/src-noconflict/mode-ocaml'; import 'ace-builds/src-noconflict/mode-partiql'; import 'ace-builds/src-noconflict/mode-pascal'; import 'ace-builds/src-noconflict/mode-perl'; import 'ace-builds/src-noconflict/mode-pgsql'; import 'ace-builds/src-noconflict/mode-php'; import 'ace-builds/src-noconflict/mode-php_laravel_blade'; import 'ace-builds/src-noconflict/mode-pig'; import 'ace-builds/src-noconflict/mode-plain_text'; import 'ace-builds/src-noconflict/mode-powershell'; import 'ace-builds/src-noconflict/mode-praat'; import 'ace-builds/src-noconflict/mode-prisma'; import 'ace-builds/src-noconflict/mode-prolog'; import 'ace-builds/src-noconflict/mode-properties'; import 'ace-builds/src-noconflict/mode-protobuf'; import 'ace-builds/src-noconflict/mode-puppet'; import 'ace-builds/src-noconflict/mode-python'; import 'ace-builds/src-noconflict/mode-qml'; import 'ace-builds/src-noconflict/mode-r'; import 'ace-builds/src-noconflict/mode-raku'; import 'ace-builds/src-noconflict/mode-razor'; import 'ace-builds/src-noconflict/mode-rdoc'; import 'ace-builds/src-noconflict/mode-red'; import 'ace-builds/src-noconflict/mode-redshift'; import 'ace-builds/src-noconflict/mode-rhtml'; import 'ace-builds/src-noconflict/mode-robot'; import 'ace-builds/src-noconflict/mode-rst'; import 'ace-builds/src-noconflict/mode-ruby'; import 'ace-builds/src-noconflict/mode-rust'; import 'ace-builds/src-noconflict/mode-sac'; import 'ace-builds/src-noconflict/mode-sass'; import 'ace-builds/src-noconflict/mode-scad'; import 'ace-builds/src-noconflict/mode-scala'; import 'ace-builds/src-noconflict/mode-scheme'; import 'ace-builds/src-noconflict/mode-scrypt'; import 'ace-builds/src-noconflict/mode-scss'; import 'ace-builds/src-noconflict/mode-sh'; import 'ace-builds/src-noconflict/mode-sjs'; import 'ace-builds/src-noconflict/mode-slim'; import 'ace-builds/src-noconflict/mode-smarty'; import 'ace-builds/src-noconflict/mode-smithy'; import 'ace-builds/src-noconflict/mode-snippets'; import 'ace-builds/src-noconflict/mode-soy_template'; import 'ace-builds/src-noconflict/mode-space'; import 'ace-builds/src-noconflict/mode-sparql'; import 'ace-builds/src-noconflict/mode-sql'; import 'ace-builds/src-noconflict/mode-sqlserver'; import 'ace-builds/src-noconflict/mode-stylus'; import 'ace-builds/src-noconflict/mode-svg'; import 'ace-builds/src-noconflict/mode-swift'; import 'ace-builds/src-noconflict/mode-tcl'; import 'ace-builds/src-noconflict/mode-terraform'; import 'ace-builds/src-noconflict/mode-tex'; import 'ace-builds/src-noconflict/mode-text'; import 'ace-builds/src-noconflict/mode-textile'; import 'ace-builds/src-noconflict/mode-toml'; import 'ace-builds/src-noconflict/mode-tsx'; import 'ace-builds/src-noconflict/mode-turtle'; import 'ace-builds/src-noconflict/mode-twig'; import 'ace-builds/src-noconflict/mode-typescript'; import 'ace-builds/src-noconflict/mode-vala'; import 'ace-builds/src-noconflict/mode-vbscript'; import 'ace-builds/src-noconflict/mode-velocity'; import 'ace-builds/src-noconflict/mode-verilog'; import 'ace-builds/src-noconflict/mode-vhdl'; import 'ace-builds/src-noconflict/mode-visualforce'; import 'ace-builds/src-noconflict/mode-wollok'; import 'ace-builds/src-noconflict/mode-xml'; import 'ace-builds/src-noconflict/mode-xquery'; import 'ace-builds/src-noconflict/mode-yaml'; import 'ace-builds/src-noconflict/mode-zeek'; //#endregion @Component({ selector: 'x-ide', templateUrl: './x-ide.component.html', styleUrls: ['./x-ide.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XIDEComponent extends XIDEContainerComponent { // //#region Props ... // //#region Private Props ... private CODE_EDITOR_BEAUTIFY: any = null; private CODE_EDITOR: ace.Ace.Editor = null; private CODE_EDITOR_UNDO_MANAGER: any; // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private CONTENT_CHANGE_SUBJECT = new Subject(); // readonly Modes = Object.assign({}, XIDEMode); readonly Themes = Object.assign({}, XIDETheme); readonly TabAligns = Object.assign({}, XTabAlign); readonly IconNames = Object.assign({}, XIconNames); readonly ColorNames = Object.assign({}, XColorWithBrightness); readonly ActionBarItems = Object.assign({}, XIDEActionBarItem); readonly ActionBarItemSlots = Object.assign({}, XActionBarItemSlot); readonly TabHeaderPositions = Object.assign({}, XTabsHeaderPosition); // readonly tabsActionProvider = new Subject(); //#endregion // @ViewChild('codeEditor') codeEditorElmRef: ElementRef; @HostListener('resize', ['$event']) onResize (event: any) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.CODE_EDITOR.resize(); } // lastContent: string; currentTab = XIDEDefaultTabName; // readonly Sessions: Pick< XIDETabDescriptor, 'name' | 'session' | 'canSave' | 'canBeautify' >[] = []; //#endregion // //#region Constructor ... //#endregion // //#region LifeCycles ... afterViewInit () { super.afterViewInit(); // this.prepareCodeEditor(); } async onChange (changeKeys: string[]): Promise { // //#region Action Provider Changed ... // const isActionProviderChaged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChaged) { this.registerActionProvider(); } //#endregion // //#region Theme Changed ... const isThemeChanged = changeKeys.includes(nameof('theme')); if (isThemeChanged) { this.setTheme(this.theme); } //#endregion // //#region Mode Changed ... const isModeChanged = changeKeys.includes(nameof('mode')); if (isModeChanged) { this.setMode(this.mode); } //#endregion // //#region MinLines Changed ... const isMinLinesChanged = changeKeys.includes( nameof('minLines') ); if (isMinLinesChanged) { this.setMinLines(this.minLines); } //#endregion // //#region MaxLines Changed ... const isMaxLinesChanged = changeKeys.includes( nameof('maxLines') ); if (isMaxLinesChanged) { this.setMaxLines(this.maxLines); } //#endregion // //#region FontSize Changed ... const isFontSizeChanged = changeKeys.includes( nameof('fontSize') ); if (isFontSizeChanged) { this.setFontSize(this.fontSize); } //#endregion // //#region Readonly Changed ... const isReadonlyChanged = changeKeys.includes( nameof('readonly') ); if (isReadonlyChanged) { this.setReadOnly(this.readonly); } //#endregion // //#region Content Changed ... const isContentChanged = changeKeys.includes( nameof('content') ); if (isContentChanged) { this.setContent(this.content); } //#endregion // //#region WordWrapping Changed ... const isWordWrappingChanged = changeKeys.includes( nameof('wordWrapping') ); if (isWordWrappingChanged) { this.setWordWrapping(this.wordWrapping); } //#endregion // //#region ShowPrintMargin Changed ... const isShowPrintMarginChanged = changeKeys.includes( nameof('showPrintMargin') ); if (isShowPrintMarginChanged) { this.setShowPrintMargin(this.showPrintMargin); } //#endregion // //#region HighlightActiveLine Changed ... const isHighlightActiveLineChanged = changeKeys.includes( nameof('highlightActiveLine') ); if (isHighlightActiveLineChanged) { this.setHighlightActiveLine(this.highlightActiveLine); } //#endregion // //#region BasicAutocompletion Changed ... const isBasicAutocompletionChanged = changeKeys.includes( nameof('basicAutocompletion') ); if (isBasicAutocompletionChanged) { this.setBasicAutocompletion(this.basicAutocompletion); } //#endregion // //#region DefaultTabName Changed ... const isDefaultTabNameChanged = changeKeys.includes( nameof('defaultTabName') ); if (isDefaultTabNameChanged) { await this.handleDefaultTabNameChanged(this.defaultTabName); } //#endregion // //#region ActionBar ... const isDefaultActionBarItemColorChanged = changeKeys.includes( nameof('defaultActionBarItemColor') ); const isAvailableActionBarItemsChanged = changeKeys.includes( nameof('availableActionBarItems') ); if ( isAvailableActionBarItemsChanged || isDefaultActionBarItemColorChanged ) { // if (isNullOrUndefined(this.availableActionBarItems)) { this.availableActionBarItems = this.propertyProvider.availableActionBarItems; } await this.prepareActionBar(); } //#endregion } onDestroy () { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Register Handlers ... registerViewHandlers (): void { super.registerViewHandlers(); // this.registerActionProvider(); // this.applyTakeUntilWrapper( this.CONTENT_CHANGE_SUBJECT.asObservable() ).subscribe(async (content) => { // if (content === this.lastContent) { return; } // this.lastContent = content; this.updateCurrentTabDescriptor({ canSave: true, canBeautify: true, }); // this.contentChange.emit(content); // await this.prepareActionBar(); }); } //#endregion // //#region Task Handlers ... //#endregion // //#region UI Providers ... //#endregion // //#region UI Handlers ... async handleActionBarActionFired (model: XActionBarActionFiredModel) { // if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) { return; } // switch (model.action) { // case this.ActionBarItems.ChangeMode: this.handleActionModeFired(model.event); break; // case this.ActionBarItems.ChangeTheme: this.handleActionThemFired(model.event); break; // case this.ActionBarItems.Close: this.closeTab(this.currentTab); break; // case this.ActionBarItems.Undo: this.undo(); break; // case this.ActionBarItems.Redo: this.redo(); break; // case this.ActionBarItems.Beautify: await this.beautifyCode(); break; // case this.ActionBarItems.Save: // this.updateCurrentTabDescriptor({ canSave: false, }); this.prepareActionBar(); break; } // this.actionBarActionFired.emit(model); } async handleTabsSelectedTabChanged (event: XTabChangeEvent) { // if ( event.index < 0 || isNullOrUndefined(event) || event.index > this.Sessions.length || isNullOrUndefined(this.CODE_EDITOR) ) { return; } // const descriptor = this.Sessions[event.index]; this.showTab(descriptor.name); } //#endregion // //#region Actions ... setTheme (theme: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(theme).subscribe((value) => { // if (isNullOrEmptyString(value)) { return; } // this.CODE_EDITOR.setTheme(value); }); } setMode (mode: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(mode).subscribe((value) => { // if (isNullOrEmptyString(value)) { return; } // this.CODE_EDITOR.getSession().setMode(value); this.detectChanges(); }); } setMinLines (minLines: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(minLines).subscribe((value) => { // if (value <= 0) { return; } // this.CODE_EDITOR.setOption('minLines', value); this.detectChanges(); }); } setMaxLines (maxLines: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(maxLines).subscribe((value) => { // if (value <= 0) { return; } // this.CODE_EDITOR.setOption('maxLines', value); this.detectChanges(); }); } setFontSize (fontSize: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(fontSize).subscribe((value) => { // if (value <= XIDEMinFontSize || value >= XIDEMaxFontSize) { return; } // this.CODE_EDITOR.setFontSize(value); this.detectChanges(); }); } setReadOnly (readonly: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(readonly).subscribe((value) => { // this.CODE_EDITOR.setReadOnly(value); this.detectChanges(); }); } getFontSize () { // if (isNullOrUndefined(this.CODE_EDITOR)) { return ''; } // return this.CODE_EDITOR.getFontSize(); } setHighlightActiveLine (highlightActiveLine: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(highlightActiveLine).subscribe((value) => { // this.CODE_EDITOR.setOption('highlightActiveLine', value); this.detectChanges(); }); } setBasicAutocompletion (basicAutocompletion: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(basicAutocompletion).subscribe((value) => { // this.CODE_EDITOR.setOption('enableBasicAutocompletion' as any, value); this.detectChanges(); }); } setWordWrapping (wordWrapping: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(wordWrapping).subscribe((value) => { // this.CODE_EDITOR.getSession().setUseWrapMode(value); this.detectChanges(); }); } setShowLineNumbers (showLineNumbers: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(showLineNumbers).subscribe((value) => { // this.CODE_EDITOR.setOption('showLineNumbers', value); this.detectChanges(); }); } setShowPrintMargin (showPrintMargin: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(showPrintMargin).subscribe((value) => { // this.CODE_EDITOR.setShowPrintMargin(value); this.detectChanges(); }); } setShowFoldWidgets (showFoldWidgets: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(showFoldWidgets).subscribe((value) => { // this.CODE_EDITOR.setShowFoldWidgets(value); this.detectChanges(); }); } // //#region IDEEdit ... async beautifyCode () { // if ( isNullOrUndefined(this.CODE_EDITOR) || isNullOrUndefined(this.CODE_EDITOR_BEAUTIFY) ) { return; } // const session = this.CODE_EDITOR.getSession(); this.CODE_EDITOR_BEAUTIFY.beautify(session); // this.updateCurrentTabDescriptor({ canBeautify: false, }); await this.prepareActionBar(); } getContent () { // if (isNullOrUndefined(this.CODE_EDITOR)) { return ''; } // const result = this.CODE_EDITOR.getValue(); return result; } setContent (value: XStandardType) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // this.getValue(value).subscribe((content) => { // if (isNullOrEmptyString(content)) { return; } // if (value === this.getContent()) { return; } // this.CODE_EDITOR.setValue(content); }); } clearcontent (force = false) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // if (!!force) { // this.CODE_EDITOR.setValue(''); this.detectChanges(); } else { // this.managerService.dialogService.presentAreYouSureYesNoDialog(() => { this.CODE_EDITOR.setValue(''); this.detectChanges(); }); } } goToLine (lineNumber: number) { // const totalLines = this.getTotalLines(); if ( lineNumber <= 0 || totalLines <= 0 || lineNumber > totalLines || isNullOrUndefined(this.CODE_EDITOR) ) { return; } // this.CODE_EDITOR.gotoLine(lineNumber, 0, true); } getTotalLines () { // if (isNullOrUndefined(this.CODE_EDITOR)) { return -1; } // return this.CODE_EDITOR.getSession().getLength(); } canUndo () { // if (isNullOrUndefined(this.CODE_EDITOR)) { return false; } // const session = this.CODE_EDITOR.getSession(); if (isNullOrUndefined(session)) { return false; } // const undoManager = session.getUndoManager(); if (isNullOrUndefined(undoManager)) { return false; } // return undoManager.canUndo(); } undo (dontSelect = true) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // const session = this.CODE_EDITOR.getSession(); if (isNullOrUndefined(session)) { return; } // const undoManager = session.getUndoManager(); if (isNullOrUndefined(undoManager) || !this.canUndo()) { return; } // undoManager.undo(session, dontSelect); this.prepareActionBar(); } canRedo () { // if (isNullOrUndefined(this.CODE_EDITOR)) { return false; } // const session = this.CODE_EDITOR.getSession(); if (isNullOrUndefined(session)) { return false; } // const undoManager = session.getUndoManager(); if (isNullOrUndefined(undoManager)) { return false; } // return undoManager.canRedo(); } redo (dontSelect = true) { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // const session = this.CODE_EDITOR.getSession(); if (isNullOrUndefined(session)) { return; } // const undoManager = session.getUndoManager(); if (isNullOrUndefined(undoManager) || !this.canRedo()) { return; } // undoManager.redo(session, dontSelect); this.prepareActionBar(); } cleaEditorHistory () { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // const session = this.CODE_EDITOR.getSession(); if (isNullOrUndefined(session)) { return; } // const undoManager = session.getUndoManager(); if (isNullOrUndefined(undoManager)) { return; } // undoManager.reset(); this.prepareActionBar(); } //#endregion // //#region IDETabs ... getTabDescritor (name: string) { // if ( isNullOrEmptyString(name) || !this.hasChild(this.Sessions) || isNullOrUndefined(this.CODE_EDITOR) ) { return null; } // return this.Sessions.find( (sd) => toNormalString(sd.name) === toNormalString(name) ); } getTabDescritorIndex (name: string) { // if ( isNullOrEmptyString(name) || !this.hasChild(this.Sessions) || isNullOrUndefined(this.CODE_EDITOR) ) { return null; } // return this.Sessions.findIndex( (sd) => toNormalString(sd.name) === toNormalString(name) ); } getCurrentTabDescritor () { return this.getTabDescritor(this.currentTab); } updateCurrentTabDescriptor ( options: Pick ) { // const currentTabDescriptor = this.getCurrentTabDescritor(); const currentTabdescriptorIndex = this.Sessions.findIndex( (sd) => toNormalString(sd.name) === toNormalString(this.currentTab) ); if ( currentTabdescriptorIndex < 0 || isNullOrUndefined(currentTabDescriptor) ) { return; } // const optionsKeys = Object.keys(options); const hasCanSave = optionsKeys.includes( nameof('canSave') ); const hasCanBeautify = optionsKeys.includes( nameof('canBeautify') ); // const canSave = hasCanSave ? options.canSave : currentTabDescriptor.canSave; const canBeautify = hasCanBeautify ? options.canBeautify : currentTabDescriptor.canBeautify; // this.Sessions[currentTabdescriptorIndex] = { ...currentTabDescriptor, canSave, canBeautify, }; // this.detectChanges(); } addTab ( tab: Pick ) { // if (isNullOrUndefined(tab) || isNullOrUndefined(this.CODE_EDITOR)) { return; } // // Set Default Content if not Provided ... if (isNullOrEmptyString(tab.content)) { tab.content = ''; } // // Set Default Mode if Not Provided ... if ( isNullOrEmptyString(tab.mode) || isNullOrUndefined(tab.mode as XIDEMode) || !isNullOrUndefined(this.getTabDescritor(tab.name)) ) { tab.mode = XIDEMode.Text; } // // Create Editor Session ... const session = ace.createEditSession(tab.content, tab.mode as any); const undoManager = new this.CODE_EDITOR_UNDO_MANAGER(); // session.setUndoManager(undoManager); undoManager.reset(); // this.Sessions.push({ session, name: tab.name, }); // if (!!tab.forceShow) { // this.runTimedOut(() => { // this.tabsActionProvider.next({ action: XTabsAction.TO, payload: this.Sessions.length - 1, }); }, 500); } // this.detectChanges(); } addTabs ( tabs: XOneOrManyType> ) { // if (!this.hasChild(tabs) || isNullOrUndefined(this.CODE_EDITOR)) { return; } // toArray(tabs).forEach((tab) => this.addTab({ ...tab, forceShow: false, }) ); } showTab (name: string) { // if ( isNullOrEmptyString(name) || !this.hasChild(this.Sessions) || isNullOrUndefined(this.CODE_EDITOR) ) { return; } // const tabDescriptor = this.getTabDescritor(name); if (isNullOrUndefined(tabDescriptor)) { return; } // this.currentTab = tabDescriptor.name; this.lastContent = tabDescriptor.session.getValue(); this.CODE_EDITOR.setSession(tabDescriptor.session); // this.prepareActionBar(); } closeTab (name: string, force = false) { // this.getValue(this.defaultTabName).subscribe((defaultTabName) => { // if ( isNullOrEmptyString(name) || !this.hasChild(this.Sessions) || isNullOrUndefined(this.CODE_EDITOR) || toNormalString(name) === toNormalString(defaultTabName) ) { return; } // const destinationTab = this.getTabDescritor(name); const destinationTabIndex = this.getTabDescritorIndex(name); if (isNullOrUndefined(destinationTab) || destinationTabIndex < 0) { return; } // if (!!force || !destinationTab.canSave) { // this.handleRemoveTab(destinationTab.name, destinationTabIndex); this.detectChanges(); } else { // this.managerService.dialogService.presentAreYouSureYesNoDialog(() => { // this.handleRemoveTab(destinationTab.name, destinationTabIndex); this.detectChanges(); }); } }); } //#endregion //#endregion // //#region Abstracts ... //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider () { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe((action) => { // if (isNullOrUndefined(action) || isNullOrEmptyString(action.action)) { return; } // switch (action.action) { // // Undo ... case XIDEAction.Undo: // const undoDontSelect = toBoolean(action.payload) || false; this.undo(undoDontSelect); break; // // Redo ... case XIDEAction.Redo: // const redoDontSelect = toBoolean(action.payload) || false; this.redo(redoDontSelect); break; // // CleaEditorHistory ... case XIDEAction.CleaEditorHistory: this.cleaEditorHistory(); break; // // AddTab ... case XIDEAction.AddTab: // const tabDescriptor = action.payload as XIDETabDescriptor; if ( !isNullOrUndefined(tabDescriptor) && !isNullOrUndefined(action.payload) ) { this.addTab({ ...tabDescriptor, }); } break; // // AddTabs ... case XIDEAction.AddTabs: // const tabDescriptors = action.payload as XIDETabDescriptor[]; if ( this.hasChild(tabDescriptors) && !isNullOrUndefined(action.payload) ) { this.addTabs([...tabDescriptors]); } break; // // ShowTab ... case XIDEAction.ShowTab: // const showTabDescriptor = action.payload as string; if ( !isNullOrEmptyString(showTabDescriptor) && !isNullOrEmptyString(action.payload) ) { // const index = this.getTabDescritorIndex(showTabDescriptor); // this.runTimedOut(() => { // this.tabsActionProvider.next({ action: XTabsAction.TO, payload: index, }); }, 500).then(() => { this.showTab(showTabDescriptor); }); } break; // // CloseTab ... case XIDEAction.CloseTab: // const forceCloseTab = action.payload.force || false; const closeTabDescriptor = action.payload.name as string; if ( !isNullOrEmptyString(closeTabDescriptor) && !isNullOrEmptyString(action.payload) ) { this.closeTab(closeTabDescriptor, forceCloseTab); } break; // // Refresh ... case XIDEAction.Refresh: this.detectChanges(); break; // // SetMode ... case XIDEAction.SetMode: // const mode = action.payload as XIDEMode; if ( !isNullOrUndefined(mode) && !isNullOrUndefined(action.payload) ) { this.setMode(mode); } break; // // Beautify ... case XIDEAction.Beautify: this.beautifyCode(); break; // // SetTheme ... case XIDEAction.SetTheme: // const theme = action.payload as XIDETheme; if ( !isNullOrUndefined(theme) && !isNullOrUndefined(action.payload) ) { this.setTheme(theme); } break; // // GoToLine ... case XIDEAction.GoToLine: // const lineNumber = action.payload as number; if ( isNumber(action.payload) && !isNullOrUndefined(action.payload) ) { this.goToLine(lineNumber); } break; // // SetContent ... case XIDEAction.SetContent: // const content = action.payload as string; if ( !isNullOrEmptyString(content) && !isNullOrUndefined(action.payload) ) { this.setContent(content); } break; // // SetMinLines ... case XIDEAction.SetMinLines: // const minLines = action.payload as number; if ( isNumber(action.payload) && !isNullOrUndefined(action.payload) ) { this.setMinLines(minLines); } break; // // SetMaxLines ... case XIDEAction.SetMaxLines: // const maxLines = action.payload as number; if ( isNumber(action.payload) && !isNullOrUndefined(action.payload) ) { this.setMaxLines(maxLines); } break; // // SetReadOnly ... case XIDEAction.SetReadOnly: // const isReadonly = toBoolean(action.payload); if ( isBoolean(action.payload) && !isNullOrUndefined(action.payload) ) { this.setReadOnly(isReadonly); } break; // // SetFontSize ... case XIDEAction.SetFontSize: // const fontSize = action.payload as number; if ( isNumber(action.payload) && !isNullOrUndefined(action.payload) ) { this.setFontSize(fontSize); } break; // // ClearContent ... case XIDEAction.ClearContent: // const isForceClearContent = toBoolean(action.payload); if ( isBoolean(action.payload) && !isNullOrUndefined(action.payload) ) { this.clearcontent(isForceClearContent); } else { this.clearcontent(); } break; // // SetWordWrapping ... case XIDEAction.SetWordWrapping: // const isWrapping = toBoolean(action.payload); if ( isBoolean(action.payload) && !isNullOrUndefined(action.payload) ) { this.setWordWrapping(isWrapping); } break; // // SetShowFoldWidgets ... case XIDEAction.SetShowFoldWidgets: // const showFoldingWidgets = toBoolean(action.payload); if ( isBoolean(action.payload) && !isNullOrUndefined(action.payload) ) { this.setReadOnly(showFoldingWidgets); } break; // // SetShowLineNumbers ... case XIDEAction.SetShowLineNumbers: // const showLineNumbers = toBoolean(action.payload); if ( isBoolean(action.payload) && !isNullOrUndefined(action.payload) ) { this.setShowLineNumbers(showLineNumbers); } break; // // SetShowPrintMargin ... case XIDEAction.SetShowPrintMargin: // const showPrintMargin = toBoolean(action.payload); if ( isBoolean(action.payload) && !isNullOrUndefined(action.payload) ) { this.setShowPrintMargin(showPrintMargin); } break; // // SetHighlightActiveLine ... case XIDEAction.SetHighlightActiveLine: // const highlightActiveLine = toBoolean(action.payload); if ( isBoolean(action.payload) && !isNullOrUndefined(action.payload) ) { this.setHighlightActiveLine(highlightActiveLine); } break; // // SetBasicAutocompletion ... case XIDEAction.SetBasicAutocompletion: // const basicAutoCompletion = toBoolean(action.payload); if ( isBoolean(action.payload) && !isNullOrUndefined(action.payload) ) { this.setBasicAutocompletion(basicAutoCompletion); } break; } }); } private unregisterActionProvider () { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private prepareCodeEditor () { // const element = this.codeEditorElmRef.nativeElement; if (isNullOrUndefined(element)) { return; } // this.CODE_EDITOR_BEAUTIFY = ace.require('ace/ext/beautify'); this.CODE_EDITOR_UNDO_MANAGER = ace.require('ace/undomanager').UndoManager; // this.CODE_EDITOR = ace.edit(element, { minLines: 1, maxLines: 1, }); // //#region Attach Undo Manager ... this.CODE_EDITOR.getSession().setUndoManager( new this.CODE_EDITOR_UNDO_MANAGER() ); //#endregion // //#region Apply Code Editor Options ... this.setMode(this.mode); this.setTheme(this.theme); this.setMinLines(this.minLines); this.setMaxLines(this.maxLines); this.setFontSize(this.fontSize); this.setReadOnly(this.readonly); this.setWordWrapping(this.wordWrapping); this.setShowLineNumbers(this.showLineNumbers); this.setShowPrintMargin(this.showPrintMargin); this.setShowFoldWidgets(this.showFoldWidgets); this.setHighlightActiveLine(this.highlightActiveLine); this.setBasicAutocompletion(this.basicAutocompletion); //#endregion // //#region Setting Default Content ... this.setContent(this.content); // // Reset Undo Manager after first code attached ... this.CODE_EDITOR.getSession().getUndoManager().reset(); //#endregion // //#region Default Session Handler ... forkJoin({ mode: this.getValue(this.mode), content: this.getValue(this.content), name: this.getValue(this.defaultTabName).pipe( map((defTabName) => defTabName || XIDEDefaultTabName) ), }).subscribe((info) => { // const name = info.name; const session = this.CODE_EDITOR.getSession(); this.Sessions.push({ session, name, }); }); //#endregion // //#region Code Editor Event Handlers ... // // Change Event handler ... this.CODE_EDITOR.on('change', (e) => { // const currentContent = this.getContent(); this.CONTENT_CHANGE_SUBJECT.next(currentContent); }); //#endregion // this.prepareActionBar(); // // Detectin Changes ... this.detectChanges(); } private async prepareActionBar () { // if (isNullOrUndefined(this.CODE_EDITOR)) { return; } // const showActionBar = await this.getValueAsync(this.showActionBar); if (!showActionBar) { return; } // //#region DefaultActionBarActions ... // const defaultThemeItem: XActionBarItem = { onlyIcon: true, disabled: this.uiDisabled, title: this.ResourceIDs.theme, icon: this.IconNames.color_palette, slot: this.ActionBarItemSlots.START, id: this.ActionBarItems.ChangeTheme, iconColor: this.defaultActionBarItemColor, }; // const defaultModeItem: XActionBarItem = { onlyIcon: true, disabled: this.uiDisabled, icon: this.IconNames.list, title: this.ResourceIDs.ide_mode, id: this.ActionBarItems.ChangeMode, slot: this.ActionBarItemSlots.START, iconColor: this.defaultActionBarItemColor, }; // const defaultSaveItem: XActionBarItem = { onlyIcon: true, disabled: this.uiDisabled, icon: this.IconNames.save, title: this.ResourceIDs.save, id: this.ActionBarItems.Save, slot: this.ActionBarItemSlots.END, iconColor: this.defaultActionBarItemColor, }; // const defaultCloseItem: XActionBarItem = { onlyIcon: true, disabled: this.uiDisabled, icon: this.IconNames.close, title: this.ResourceIDs.close, id: this.ActionBarItems.Close, slot: this.ActionBarItemSlots.END, iconColor: this.ColorNames.Danger, }; // const defaultUndoItem: XActionBarItem = { onlyIcon: true, disabled: this.uiDisabled, icon: this.IconNames.undo, title: this.ResourceIDs.undo, id: this.ActionBarItems.Undo, slot: this.ActionBarItemSlots.END, iconColor: this.defaultActionBarItemColor, }; // const defaultRedoItem: XActionBarItem = { onlyIcon: true, disabled: this.uiDisabled, icon: this.IconNames.redo, title: this.ResourceIDs.redo, id: this.ActionBarItems.Redo, slot: this.ActionBarItemSlots.END, iconColor: this.defaultActionBarItemColor, }; // const defaultBeautifyItem: XActionBarItem = { onlyIcon: true, disabled: this.uiDisabled, icon: this.IconNames.ul, id: this.ActionBarItems.Beautify, slot: this.ActionBarItemSlots.END, title: this.ResourceIDs.ide_format, iconColor: this.defaultActionBarItemColor, }; //#endregion // this.actionBarActions = []; this.detectChanges(); // const availableItems = await this.getArrayValueAsync( this.availableActionBarItems ); if (!this.hasChild(availableItems)) { return; } // const actionBarItems: XActionBarItem[] = []; const currentTabDescriptor = this.getCurrentTabDescritor(); // //#region Save ... const hasSaveItem = availableItems .map((ai) => ai.actionId) .includes(this.ActionBarItems.Save); // if (hasSaveItem) { // const selectedItem = availableItems.find( (ai) => ai.actionId === this.ActionBarItems.Save ); const providedSaveItem = selectedItem.descriptor; let saveItem = { ...defaultSaveItem, }; if (!isNullOrUndefined(providedSaveItem)) { saveItem = { ...saveItem, ...providedSaveItem, }; } // saveItem = { ...saveItem, disabled: this.uiDisabled || !isNullOrUndefined(currentTabDescriptor) ? !currentTabDescriptor.canSave : true, }; // actionBarItems.push(saveItem); } //#endregion // //#region Close ... const hasCloseItem = availableItems .map((ai) => ai.actionId) .includes(this.ActionBarItems.Close); const hasCloseOnDefaultTab = await this.getValueAsync( this.hasCloseOnDefaultTab ); // const currentTabIndex = this.getTabDescritorIndex(this.currentTab); if ( hasCloseItem && (!!hasCloseOnDefaultTab ? true : currentTabIndex !== 0 ) && currentTabIndex > -1) { // const selectedItem = availableItems.find( (ai) => ai.actionId === this.ActionBarItems.Close ); const providedCloseItem = selectedItem.descriptor; let closeItem = { ...defaultCloseItem, }; if (!isNullOrUndefined(providedCloseItem)) { closeItem = { ...closeItem, ...providedCloseItem, }; } // closeItem = { ...closeItem, disabled: this.uiDisabled, }; // actionBarItems.push(closeItem); } //#endregion // //#region Unde ... const hasUndoItem = availableItems .map((ai) => ai.actionId) .includes(this.ActionBarItems.Undo); // if (hasUndoItem) { // const selectedItem = availableItems.find( (ai) => ai.actionId === this.ActionBarItems.Undo ); const providedUndoItem = selectedItem.descriptor; let undoItem = { ...defaultUndoItem, }; if (!isNullOrUndefined(providedUndoItem)) { undoItem = { ...undoItem, ...providedUndoItem, }; } // // Prepare Disable/Enable Toggling of Item ... undoItem = { ...undoItem, disabled: this.uiDisabled || !this.CODE_EDITOR.getSession().getUndoManager().canUndo() || isNullOrUndefined(this.CODE_EDITOR.getSession().getUndoManager()), }; // actionBarItems.push(undoItem); } //#endregion // //#region Redo ... const hasRedoItem = availableItems .map((ai) => ai.actionId) .includes(this.ActionBarItems.Redo); // if (hasRedoItem) { // const selectedItem = availableItems.find( (ai) => ai.actionId === this.ActionBarItems.Redo ); const providedRedoItem = selectedItem.descriptor; let redoItem = { ...defaultRedoItem, }; if (!isNullOrUndefined(providedRedoItem)) { redoItem = { ...redoItem, ...providedRedoItem, }; } // // Prepare Disable/Enable Toggling of Item ... redoItem = { ...redoItem, disabled: this.uiDisabled || !this.CODE_EDITOR.getSession().getUndoManager().canRedo() || isNullOrUndefined(this.CODE_EDITOR.getSession().getUndoManager()), }; // actionBarItems.push(redoItem); } //#endregion // //#region Beautify ... const hasBeautifyItem = availableItems .map((ai) => ai.actionId) .includes(this.ActionBarItems.Beautify); // if (hasBeautifyItem) { // const selectedItem = availableItems.find( (ai) => ai.actionId === this.ActionBarItems.Beautify ); const providedBeautifyItem = selectedItem.descriptor; let beautifyItem = { ...defaultBeautifyItem, }; if (!isNullOrUndefined(providedBeautifyItem)) { beautifyItem = { ...beautifyItem, ...providedBeautifyItem, }; } // // Prepare Disable/Enable Toggling of Item ... beautifyItem = { ...beautifyItem, disabled: this.uiDisabled || isNullOrUndefined(this.CODE_EDITOR) || !isNullOrUndefined(currentTabDescriptor) ? !currentTabDescriptor.canBeautify : true || isNullOrUndefined(this.CODE_EDITOR_BEAUTIFY), }; // actionBarItems.push(beautifyItem); } //#endregion // //#region Mode ... const hasModeChangeItem = availableItems .map((ai) => ai.actionId) .includes(this.ActionBarItems.ChangeMode); // if (hasModeChangeItem) { // const selectedItem = availableItems.find( (ai) => ai.actionId === this.ActionBarItems.ChangeMode ); const providedModeItem = selectedItem.descriptor; let modeItem = { ...defaultModeItem, }; if (!isNullOrUndefined(providedModeItem)) { modeItem = { ...modeItem, ...providedModeItem, }; } // modeItem = { ...modeItem, disabled: this.uiDisabled, }; // actionBarItems.push(modeItem); } //#endregion // //#region Theme ... const hasThemeChangeItem = availableItems .map((ai) => ai.actionId) .includes(this.ActionBarItems.ChangeTheme); // if (hasThemeChangeItem) { // const selectedItem = availableItems.find( (ai) => ai.actionId === this.ActionBarItems.ChangeTheme ); const providedThemeItem = selectedItem.descriptor; let themeItem = { ...defaultThemeItem, }; if (!isNullOrUndefined(providedThemeItem)) { themeItem = { ...themeItem, ...providedThemeItem, }; } // themeItem = { ...themeItem, disabled: this.uiDisabled, }; // actionBarItems.push(themeItem); } //#endregion // this.actionBarActions = [...actionBarItems]; this.detectChanges(); } // //#region Tabs Handlers ... private async handleDefaultTabNameChanged ( defaultTabName: XStandardType ) { // let value = await this.getValueAsync(defaultTabName); if (isNullOrEmptyString(value)) { value = XIDEDefaultTabName; } // if (!this.hasChild(this.Sessions)) { return; } // if ( this.currentTab === XIDEDefaultTabName || this.currentTab === this.Sessions[0].name ) { this.currentTab = value; } // this.Sessions[0].name = value; // this.prepareActionBar(); this.detectChanges(); } private handleRemoveTab (name: string, destinationTabIndex: number) { // if ( destinationTabIndex <= 0 || isNullOrEmptyString(name) || destinationTabIndex > this.Sessions.length - 1 ) { return; } // this.Sessions.splice(destinationTabIndex, 1); this.detectChanges(); this.tabsActionProvider.next({ action: XTabsAction.Refresh, }); // const canShowNewTab = name === this.currentTab; if (canShowNewTab) { // const newTabIndex = this.Sessions.length - 1; // if (countChild(this.Sessions) > 1) { // this.tabsActionProvider.next({ action: XTabsAction.TO, payload: newTabIndex, }); // this.tabsActionProvider.next({ action: XTabsAction.Refresh, }); } // const newTab = this.Sessions[newTabIndex]; this.showTab(newTab.name); } // this.detectChanges(); } //#endregion // //#region ActionBar Handlers ... private handleActionModeFired (event: Event) { this.getValue(this.mode) .pipe( concatMap((mode) => this.getArrayValue(this.availableActionBarItems).pipe( map((availableItems) => { return { mode, availableItems, }; }) ) ) ) .subscribe((info) => { // // Selected Item Model ... const selectedItemModel = info.availableItems.find( (ai) => ai.actionId === this.ActionBarItems.ChangeMode ); // // get Item Colors ... const itemsColor = selectedItemModel.itemsColor; // // Retrieve Popover Present Options ... const popoverPresentOptions = selectedItemModel.popoverPresentOptions; // // Generate Available Modes ... const availableModes = Object.keys(this.Modes) // // By Filtering Curent Mode ... .filter((key) => this.Modes[key] !== info.mode); // // Convert Available Modes to XPopoverOptions ... const options = availableModes.map((key) => { return { id: key, color: !isNullOrEmptyString(itemsColor) ? itemsColor : this.ColorNames.Dark, title: key, handler: () => { // this.mode = this.Modes[key]; this.setMode(this.Modes[key]); }, } as XPopoverOption; }); // // Present Popover Options ... this.popoverService.presentContextMenu( options, event, popoverPresentOptions ); }); } private handleActionThemFired (event: Event) { this.getValue(this.theme) .pipe( concatMap((theme) => this.getArrayValue(this.availableActionBarItems).pipe( map((availableItems) => { return { theme, availableItems, }; }) ) ) ) .subscribe((info) => { // // Selected Item Model ... const selectedItemModel = info.availableItems.find( (ai) => ai.actionId === this.ActionBarItems.ChangeTheme ); // // get Item Colors ... const itemsColor = selectedItemModel.itemsColor; // // Retrieve Popover Present Options ... const popoverPresentOptions = selectedItemModel.popoverPresentOptions; // // Generate Available Themes ... const availableThemes = Object.keys(this.Themes) // // By Filtering Curent Theme ... .filter((key) => this.Themes[key] !== info.theme); // // Convert Available Themes to XPopoverOptions ... const options = availableThemes.map((key) => { return { id: key, color: !isNullOrEmptyString(itemsColor) ? itemsColor : this.ColorNames.Dark, title: key, handler: () => { // this.theme = this.Themes[key]; this.setTheme(this.Themes[key]); }, } as XPopoverOption; }); // // Present Popover Options ... this.popoverService.presentContextMenu( options, event, popoverPresentOptions ); }); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIDEComponent } from './x-ide.component'; import { XTabsModule } from '../x-tabs/x-tabs.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XActionBarModule } from '../x-action-bar/x-action-bar.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XIDEComponent], imports: [ XTabsModule, XIconModule, XCardModule, CommonModule, XActionBarModule, XBaseComponentModule, ], exports: [ XTabsModule, XIconModule, XCardModule, CommonModule, XIDEComponent, XActionBarModule, XBaseComponentModule, ], }) export class XIDEModule { } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-ide\x-ide.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XCardActionModel, XComponentCardContainer, IXComponentCardContainer, } from '../x-card/x-card.typings'; import * as ace from 'ace-builds'; import { map } from 'rxjs/operators'; import { XBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { XActionBarItem, XActionBarActionModel, XActionBarActionFiredModel, XComponentActionBarContainer, IXComponentActionBarContainer, } from '../x-action-bar/x-action-bar.typings'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/scrolling'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XPopoverService } from '../dialogs/x-popover/x-popover.service'; import { XTabAlign, XTabAlignIdentifier } from '../x-tabs/x-tabs.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XPopoverPresentOptions } from '../dialogs/x-popover/x-popover.typings'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Action Provider ... export enum XIDEAction { // Refresh = 'refresh', SetReadOnly = 'set_read_only', // AddTab = 'add_tab', ShowTab = 'show_tab', AddTabs = 'add_tabs', CloseTab = 'close_tab', // Undo = 'undo', Redo = 'redo', CleaEditorHistory = 'clear_editor_history', Beautify = 'beautify', GoToLine = 'go_to_line', SetContent = 'set_content', ClearContent = 'clear_content', // SetMode = 'set_mode', SetTheme = 'set_theme', SetMinLines = 'set_min_lines', SetMaxLines = 'set_max_lines', SetFontSize = 'set_font_size', SetWordWrapping = 'set_word_wrapping', SetShowFoldWidgets = 'set_show_fold_widgets', SetShowLineNumbers = 'set_show_line_numbers', SetShowPrintMargin = 'set_show_print_margin', SetHighlightActiveLine = 'set_highlight_active_line', SetBasicAutocompletion = 'set_basic_autoc_ompletion', } export type XIDEActionIdentifier = XIDEAction | string; export interface XIDEActionModel extends XBaseActionModel {} //#endregion // // Font Size Constants ... export const XIDEMinFontSize = 12; export const XIDEMaxFontSize = 25; export const XIDEDefaultTabName = 'DEFAULT'; // type AnyTypeIndex = { [key: string]: any; }; // export type XIDEOptionsType = Partial & AnyTypeIndex; // //#region Theme ... export enum XIDETheme { Ambiance = 'ace/theme/ambiance', Chaos = 'ace/theme/chaos', Chrome = 'ace/theme/chrome', Cloud9Day = 'ace/theme/cloud9_day', Cloud9Night = 'ace/theme/cloud9_night', Cloud9NightLowColor = 'ace/theme/cloud9_night_low_color', Clouds = 'ace/theme/clouds', CloudsMidnight = 'ace/theme/clouds_midnight', Cobalt = 'ace/theme/cobalt', CrimsonEditor = 'ace/theme/crimson_editor', Dawn = 'ace/theme/dawn', Dracula = 'ace/theme/dracula', Dreamweaver = 'ace/theme/dreamweaver', Eclipse = 'ace/theme/eclipse', Github = 'ace/theme/github', Gob = 'ace/theme/gob', Gruvbox = 'ace/theme/gruvbox', GruvboxDarkHard = 'ace/theme/gruvbox_dark_hard', GruvboxLightHard = 'ace/theme/gruvbox_light_hard', IdleFingers = 'ace/theme/idle_fingers', Iplastic = 'ace/theme/iplastic', Katzenmilch = 'ace/theme/katzenmilch', KrTheme = 'ace/theme/kr_theme', Kuroir = 'ace/theme/kuroir', Merbivore = 'ace/theme/merbivore', MerbivoreSoft = 'ace/theme/merbivore_soft', MonoIndustrial = 'ace/theme/mono_industrial', Monokai = 'ace/theme/monokai', NordDark = 'ace/theme/nord_dark', OneDark = 'ace/theme/one_dark', PastelOnDark = 'ace/theme/pastel_on_dark', SolarizedDark = 'ace/theme/solarized_dark', SolarizedLight = 'ace/theme/solarized_light', Sqlserver = 'ace/theme/sqlserver', Terminal = 'ace/theme/terminal', Textmate = 'ace/theme/textmate', Tomorrow = 'ace/theme/tomorrow', TomorrowNight = 'ace/theme/tomorrow_night', TomorrowNightBlue = 'ace/theme/tomorrow_night_blue', TomorrowNightBright = 'ace/theme/tomorrow_night_bright', TomorrowNightEighties = 'ace/theme/tomorrow_night_eighties', Twilight = 'ace/theme/twilight', VibrantInk = 'ace/theme/vibrant_ink', Xcode = 'ace/theme/xcode', } export type XIDEThemeIdentifier = XIDETheme | string; //#endregion // //#region Mode ... export enum XIDEMode { Abap = 'ace/mode/abap', Abc = 'ace/mode/abc', Actionscript = 'ace/mode/actionscript', Ada = 'ace/mode/ada', Alda = 'ace/mode/alda', ApacheConf = 'ace/mode/apache_conf', Apex = 'ace/mode/apex', Applescript = 'ace/mode/applescript', Aql = 'ace/mode/aql', Asciidoc = 'ace/mode/asciidoc', Asl = 'ace/mode/asl', AssemblyX86 = 'ace/mode/assembly_x86', Autohotkey = 'ace/mode/autohotkey', Batchfile = 'ace/mode/batchfile', C9search = 'ace/mode/c9search', CCpp = 'ace/mode/c_cpp', Cirru = 'ace/mode/cirru', Clojure = 'ace/mode/clojure', Cobol = 'ace/mode/cobol', Coffee = 'ace/mode/coffee', Coldfusion = 'ace/mode/coldfusion', Crystal = 'ace/mode/crystal', Csharp = 'ace/mode/csharp', CsoundDocument = 'ace/mode/csound_document', CsoundOrchestra = 'ace/mode/csound_orchestra', CsoundScore = 'ace/mode/csound_score', Csp = 'ace/mode/csp', Css = 'ace/mode/css', Curly = 'ace/mode/curly', D = 'ace/mode/d', Dart = 'ace/mode/dart', Diff = 'ace/mode/diff', Django = 'ace/mode/django', Dockerfile = 'ace/mode/dockerfile', Dot = 'ace/mode/dot', Drools = 'ace/mode/drools', Edifact = 'ace/mode/edifact', Eiffel = 'ace/mode/eiffel', Ejs = 'ace/mode/ejs', Elixir = 'ace/mode/elixir', Elm = 'ace/mode/elm', Erlang = 'ace/mode/erlang', Forth = 'ace/mode/forth', Fortran = 'ace/mode/fortran', Fsharp = 'ace/mode/fsharp', Fsl = 'ace/mode/fsl', Ftl = 'ace/mode/ftl', Gcode = 'ace/mode/gcode', Gherkin = 'ace/mode/gherkin', Gitignore = 'ace/mode/gitignore', Glsl = 'ace/mode/glsl', Gobstones = 'ace/mode/gobstones', Golang = 'ace/mode/golang', Graphqlschema = 'ace/mode/graphqlschema', Groovy = 'ace/mode/groovy', Haml = 'ace/mode/haml', Handlebars = 'ace/mode/handlebars', Haskell = 'ace/mode/haskell', HaskellCabal = 'ace/mode/haskell_cabal', Haxe = 'ace/mode/haxe', Hjson = 'ace/mode/hjson', Html = 'ace/mode/html', HtmlElixir = 'ace/mode/html_elixir', HtmlRuby = 'ace/mode/html_ruby', Ini = 'ace/mode/ini', Io = 'ace/mode/io', Ion = 'ace/mode/ion', Jack = 'ace/mode/jack', Jade = 'ace/mode/jade', Java = 'ace/mode/java', Javascript = 'ace/mode/javascript', Json = 'ace/mode/json', Json5 = 'ace/mode/json5', Jsoniq = 'ace/mode/jsoniq', Jsp = 'ace/mode/jsp', Jssm = 'ace/mode/jssm', Jsx = 'ace/mode/jsx', Julia = 'ace/mode/julia', Kotlin = 'ace/mode/kotlin', Latex = 'ace/mode/latex', Latte = 'ace/mode/latte', Less = 'ace/mode/less', Liquid = 'ace/mode/liquid', Lisp = 'ace/mode/lisp', Livescript = 'ace/mode/livescript', Logiql = 'ace/mode/logiql', Logtalk = 'ace/mode/logtalk', Lsl = 'ace/mode/lsl', Lua = 'ace/mode/lua', Luapage = 'ace/mode/luapage', Lucene = 'ace/mode/lucene', Makefile = 'ace/mode/makefile', Markdown = 'ace/mode/markdown', Mask = 'ace/mode/mask', Matlab = 'ace/mode/matlab', Maze = 'ace/mode/maze', Mediawiki = 'ace/mode/mediawiki', Mel = 'ace/mode/mel', Mips = 'ace/mode/mips', Mixal = 'ace/mode/mixal', Mushcode = 'ace/mode/mushcode', Mysql = 'ace/mode/mysql', Nginx = 'ace/mode/nginx', Nim = 'ace/mode/nim', Nix = 'ace/mode/nix', Nsis = 'ace/mode/nsis', Nunjucks = 'ace/mode/nunjucks', ObjectiveC = 'ace/mode/objectivec', Ocaml = 'ace/mode/ocaml', Partiql = 'ace/mode/partiql', Pascal = 'ace/mode/pascal', Perl = 'ace/mode/perl', Pgsql = 'ace/mode/pgsql', Php = 'ace/mode/php', PhpLaravelBlade = 'ace/mode/php_laravel_blade', Pig = 'ace/mode/pig', PlainText = 'ace/mode/plain_text', Powershell = 'ace/mode/powershell', Praat = 'ace/mode/praat', Prisma = 'ace/mode/prisma', Prolog = 'ace/mode/prolog', Properties = 'ace/mode/properties', Protobuf = 'ace/mode/protobuf', Puppet = 'ace/mode/puppet', Python = 'ace/mode/python', Qml = 'ace/mode/qml', R = 'ace/mode/r', Raku = 'ace/mode/raku', Razor = 'ace/mode/razor', Rdoc = 'ace/mode/rdoc', Red = 'ace/mode/red', Redshift = 'ace/mode/redshift', Rhtml = 'ace/mode/rhtml', Robot = 'ace/mode/robot', Rst = 'ace/mode/rst', Ruby = 'ace/mode/ruby', Rust = 'ace/mode/rust', Sac = 'ace/mode/sac', Sass = 'ace/mode/sass', Scad = 'ace/mode/scad', Scala = 'ace/mode/scala', Scheme = 'ace/mode/scheme', Scrypt = 'ace/mode/scrypt', Scss = 'ace/mode/scss', Sh = 'ace/mode/sh', Sjs = 'ace/mode/sjs', Slim = 'ace/mode/slim', Smarty = 'ace/mode/smarty', Smithy = 'ace/mode/smithy', Snippets = 'ace/mode/snippets', SoyTemplate = 'ace/mode/soy_template', Space = 'ace/mode/space', Sparql = 'ace/mode/sparql', Sql = 'ace/mode/sql', Sqlserver = 'ace/mode/sqlserver', Stylus = 'ace/mode/stylus', Svg = 'ace/mode/svg', Swift = 'ace/mode/swift', Tcl = 'ace/mode/tcl', Terraform = 'ace/mode/terraform', Tex = 'ace/mode/tex', Text = 'ace/mode/text', Textile = 'ace/mode/textile', Toml = 'ace/mode/toml', Tsx = 'ace/mode/tsx', Turtle = 'ace/mode/turtle', Twig = 'ace/mode/twig', Typescript = 'ace/mode/typescript', Vala = 'ace/mode/vala', Vbscript = 'ace/mode/vbscript', Velocity = 'ace/mode/velocity', Verilog = 'ace/mode/verilog', Vhdl = 'ace/mode/vhdl', Visualforce = 'ace/mode/visualforce', Wollok = 'ace/mode/wollok', Xml = 'ace/mode/xml', Xquery = 'ace/mode/xquery', Yaml = 'ace/mode/yaml', Zeek = 'ace/mode/zeek', } export type XIDEModeIdentifier = XIDEMode | string; //#endregion // //#region ActionBar ... export enum XIDEActionBarItem { ChangeMode = 'change_mode', ChangeTheme = 'change_theme', Save = 'save', Close = 'close', Undo = 'undo', Redo = 'redo', Beautify = 'beautify', } export type XIDEActionBarItemIdentifier = XIDEActionBarItem | string; export type XIDEActionBarItemDescriptor = Partial< Pick< XActionBarItem, | 'slot' | 'icon' | 'title' | 'color' | 'onlyIcon' | 'iconColor' | 'titleColor' > >; export interface XIDEAvailableActionBarItem { itemsColor?: XColorIdentifier; actionId: XIDEActionBarItemIdentifier; descriptor?: XIDEActionBarItemDescriptor; popoverPresentOptions?: XPopoverPresentOptions; } //#endregion // //#region IDETabs ... export interface XIDETabDescriptor { name: string; content?: string; canSave?: boolean; forceShow?: boolean; canBeautify?: boolean; mode?: XIDEModeIdentifier; session?: ace.Ace.EditSession; } //#endregion // //#region Container ... type TXIDEContainer = IXComponentCardContainer & IXComponentActionBarContainer; export interface IXIDEContainer extends TXIDEContainer { // //#region Props ... content: XStandardType; minLines: XStandardType; maxLines: XStandardType; fontSize: XStandardType; readonly: XStandardType; contentChange: EventEmitter; wordWrapping: XStandardType; defaultTabName: XStandardType; showLineNumbers: XStandardType; showPrintMargin: XStandardType; showFoldWidgets: XStandardType; mode: XStandardType; actionProvider: Subject; theme: XStandardType; highlightActiveLine: XStandardType; basicAutocompletion: XStandardType; hasCloseOnDefaultTab: XStandardType; cssClass: XStandardType>; // //#region Tabs ... alignTabs: XStandardType; tabHeaderColor: XStandardType; activeTabColor: XStandardType; //#endregion // //#region ActionBar ... defaultActionBarItemColor: XStandardType; availableActionBarItems: XStandardType< XOneOrManyType >; //#endregion //#endregion } @Injectable({ providedIn: 'root', }) export class XIDEContainer extends XBaseContainer implements IXIDEContainer { // //#region Props ... // //#region Self Props ... readonly content: XStandardType = ''; readonly minLines: XStandardType = 10; readonly fontSize: XStandardType = XIDEMinFontSize; readonly readonly: XStandardType = false; readonly actionProvider: Subject = new Subject(); readonly maxLines: XStandardType = Infinity; readonly wordWrapping: XStandardType = true; readonly cssClass: XStandardType>; readonly showLineNumbers: XStandardType = true; readonly showFoldWidgets: XStandardType = true; readonly showPrintMargin: XStandardType = false; readonly highlightActiveLine: XStandardType = true; readonly basicAutocompletion: XStandardType = true; readonly hasCloseOnDefaultTab: XStandardType = false; readonly defaultTabName: XStandardType = XIDEDefaultTabName; readonly mode: XStandardType = XIDEMode.Typescript; readonly theme: XStandardType = XIDETheme.Dracula; readonly contentChange: EventEmitter = new EventEmitter(); // //#region Tabs ... readonly alignTabs: XStandardType = XTabAlign.START; readonly tabHeaderColor: XStandardType = XColorWithBrightness.Dark; readonly activeTabColor: XStandardType = XColorWithBrightness.Warning; //#endregion // readonly availableActionBarItems: XStandardType< XOneOrManyType > = [ { actionId: XIDEActionBarItem.Save, }, { actionId: XIDEActionBarItem.Close, }, { actionId: XIDEActionBarItem.Undo, }, { actionId: XIDEActionBarItem.Redo, }, { actionId: XIDEActionBarItem.Beautify, }, { actionId: XIDEActionBarItem.ChangeTheme, }, { actionId: XIDEActionBarItem.ChangeMode, }, ]; readonly defaultActionBarItemColor: XStandardType = XColorWithBrightness.Dark; //#endregion // //#region ComponentCard Props ... readonly isInPage: XStandardType = this.cardPropertyProvider.isInPage; readonly wrapWithCard: XStandardType = this.cardPropertyProvider.wrapWithCard; readonly cardActionProvider: Subject = this.cardPropertyProvider.cardActionProvider; readonly cardCssClass: XStandardType> = this.cardPropertyProvider.cardCssClass; readonly cardColor: XStandardType = this.cardPropertyProvider.cardColor; readonly cardForegroundColor: XStandardType = this.cardPropertyProvider.cardForegroundColor; readonly cardTitle: XStandardType = this.cardPropertyProvider.cardTitle; readonly cardSubTitle: XStandardType = this.cardPropertyProvider.cardSubTitle; readonly cardShowFooter: XStandardType = this.cardPropertyProvider.cardShowFooter; readonly cardShowActions: XStandardType = this.cardPropertyProvider.cardShowActions; //#endregion // //#region ComponentActionBar Props ... readonly showActionBar: XStandardType = this.actionBarPropertyProvider.showActionBar; readonly actionBarActionProvider: Subject = this.actionBarPropertyProvider.actionBarActionProvider; readonly actionBarCssClass: XStandardType> = this.actionBarPropertyProvider.actionBarCssClass; readonly actionBarColor: XStandardType = this.actionBarPropertyProvider.actionBarColor; readonly actionBarForegroundColor: XStandardType = this.actionBarPropertyProvider.actionBarForegroundColor; readonly actionBarActions: XStandardType> = this.actionBarPropertyProvider.actionBarActions; readonly actionBarActionFired: EventEmitter = this.actionBarPropertyProvider.actionBarActionFired; //#endregion //#endregion // //#region Constructor ... constructor( protected cardPropertyProvider: XComponentCardContainer, protected actionBarPropertyProvider: XComponentActionBarContainer ) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export class XIDEContainerComponent extends XBaseContainerComponent implements IXIDEContainer { // //#region Props ... // //#region Self Props ... @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() defaultTabName: XStandardType = this.propertyProvider.defaultTabName; @Input() hasCloseOnDefaultTab: XStandardType = this.propertyProvider.hasCloseOnDefaultTab; @Input() theme: XStandardType = this.propertyProvider.theme; @Input() mode: XStandardType = this.propertyProvider.mode; @Input() minLines: XStandardType = this.propertyProvider.minLines; @Input() maxLines: XStandardType = this.propertyProvider.maxLines; @Input() fontSize: XStandardType = this.propertyProvider.fontSize; @Input() readonly: XStandardType = this.propertyProvider.readonly; @Input() highlightActiveLine: XStandardType = this.propertyProvider.highlightActiveLine; @Input() wordWrapping: XStandardType = this.propertyProvider.wordWrapping; @Input() showLineNumbers: XStandardType = this.propertyProvider.showLineNumbers; @Input() showPrintMargin: XStandardType = this.propertyProvider.showPrintMargin; @Input() showFoldWidgets: XStandardType = this.propertyProvider.showFoldWidgets; @Input() basicAutocompletion: XStandardType = this.propertyProvider.basicAutocompletion; @Input() content: XStandardType = this.propertyProvider.content; // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Output() contentChange: EventEmitter = this.propertyProvider.contentChange; // //#region Tabs ... @Input() alignTabs: XStandardType = this.propertyProvider.alignTabs; @Input() tabHeaderColor: XStandardType = this.propertyProvider.tabHeaderColor; @Input() activeTabColor: XStandardType = this.propertyProvider.activeTabColor; //#endregion // //#region ActionBar ... @Input() defaultActionBarItemColor: XStandardType = this.propertyProvider.defaultActionBarItemColor; @Input() availableActionBarItems: XStandardType< XOneOrManyType > = this.propertyProvider.availableActionBarItems; //#endregion //#endregion // //#region ComponentCard Props ... @Input() isInPage: XStandardType = this.propertyProvider.isInPage; @Input() wrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; @Input() cardCssClass: XStandardType> = this.propertyProvider.cardCssClass; @Input() cardColor: XStandardType = this.propertyProvider.cardColor; @Input() cardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; @Input() cardTitle: XStandardType = this.propertyProvider.cardTitle; @Input() cardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; @Input() cardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; @Input() cardShowActions: XStandardType = this.propertyProvider.cardShowActions; @Input() cardActionProvider: Subject = this.propertyProvider.cardActionProvider; //#endregion // //#region ComponentActionBar Props ... @Input() showActionBar: XStandardType = this.propertyProvider.showActionBar; @Input() actionBarCssClass: XStandardType> = this.propertyProvider.actionBarCssClass; @Input() actionBarColor: XStandardType = this.propertyProvider.actionBarColor; @Input() actionBarForegroundColor: XStandardType = this.propertyProvider.actionBarForegroundColor; @Input() actionBarActionProvider: Subject = this.propertyProvider.actionBarActionProvider; @Output() actionBarActionFired: EventEmitter = this.propertyProvider.actionBarActionFired; actionBarActions: XStandardType> = this.propertyProvider.actionBarActions; //#endregion //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XIDEContainer, protected popoverService: XPopoverService ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstracts ... public extractProps(container?: IXIDEContainer): Observable { return forkJoin({ // //#region Self Props ... minLines: this.getValue(container ? container.minLines : this.minLines), maxLines: this.getValue(container ? container.maxLines : this.maxLines), fontSize: this.getValue(container ? container.fontSize : this.fontSize), readonly: this.getValue(container ? container.readonly : this.readonly), content: this.getValue(container ? container.content : this.content), mode: this.getValue(container ? container.mode : this.mode), theme: this.getValue(container ? container.theme : this.theme), highlightActiveLine: this.getValue( container ? container.highlightActiveLine : this.highlightActiveLine ), cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), basicAutocompletion: this.getValue( container ? container.basicAutocompletion : this.basicAutocompletion ), wordWrapping: this.getValue( container ? container.wordWrapping : this.wordWrapping ), showPrintMargin: this.getValue( container ? container.showPrintMargin : this.showPrintMargin ), showLineNumbers: this.getValue( container ? container.showLineNumbers : this.showLineNumbers ), showFoldWidgets: this.getValue( container ? container.showFoldWidgets : this.showFoldWidgets ), defaultTabName: this.getValue( container ? container.defaultTabName : this.defaultTabName ), hasCloseOnDefaultTab: this.getValue( container ? container.hasCloseOnDefaultTab : this.hasCloseOnDefaultTab ), // //#region Tabs ... alignTabs: this.getValue( container ? container.alignTabs : this.alignTabs ), tabHeaderColor: this.getValue( container ? container.tabHeaderColor : this.tabHeaderColor ), activeTabColor: this.getValue( container ? container.activeTabColor : this.activeTabColor ), //#endregion // // ActionBar ... defaultActionBarItemColor: this.getValue( container ? container.defaultActionBarItemColor : this.defaultActionBarItemColor ), availableActionBarItems: this.getArrayValue( container ? container.availableActionBarItems : this.availableActionBarItems ), //#endregion // //#region XComponentCard ... cardCssClass: this.getArrayValue( container ? container.cardCssClass : this.cardCssClass ), isInPage: this.getValue(container ? container.isInPage : this.isInPage), wrapWithCard: this.getValue( container ? container.wrapWithCard : this.wrapWithCard ), cardShowFooter: this.getValue( container ? container.cardShowFooter : this.cardShowFooter ), cardShowActions: this.getValue( container ? container.cardShowActions : this.cardShowActions ), cardColor: this.getValue( container ? container.cardColor : this.cardColor ), cardForegroundColor: this.getValue( container ? container.cardForegroundColor : this.cardForegroundColor ), cardTitle: this.getValue( container ? container.cardTitle : this.cardTitle ), cardSubTitle: this.getValue( container ? container.cardSubTitle : this.cardSubTitle ), //#endregion // //#region XComponentActionBar ... showActionBar: this.getValue( container ? container.showActionBar : this.showActionBar ), actionBarCssClass: this.getValue( container ? container.actionBarCssClass : this.actionBarCssClass ), actionBarColor: this.getValue( container ? container.actionBarColor : this.actionBarColor ), actionBarForegroundColor: this.getValue( container ? container.actionBarForegroundColor : this.actionBarForegroundColor ), actionBarActions: this.getValue( container ? container.actionBarActions : this.actionBarActions ), //#endregion }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // cardActionProvider: container ? container.cardActionProvider : this.cardActionProvider, // actionBarActionProvider: container ? container.actionBarActionProvider : this.actionBarActionProvider, // contentChange: this.contentChange, actionBarActionFired: this.actionBarActionFired, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.component.html
 
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.component.scss :host::ng-deep .mat-dialog-container { padding: 0 !important; margin: 0 !important; } x-icon, mat-icon { color: white; } :host { display: flex; position: relative; width: 100%; max-width: 100%; max-height: 100%; padding-top: 6px; overflow: hidden; text-align: center; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } :host > div { position: relative; width: 100%; } :host div > img.source-image { max-width: 98%; max-height: 98%; } .actions { margin: 2px; margin-top: 6px; } .actions > button { width: 36px; min-width: 36px; height: 36px36px; min-height: 36px; padding: 0; } .cropper { position: absolute; display: flex; color: #53535c; background: transparent; outline-color: rgba(255, 255, 255, 0.3); outline-width: 100vw; outline-style: solid; touch-action: none; } @media (orientation: portrait) { .cropper { outline-width: 100vh; } } .cropper:after { position: absolute; content: ''; top: 0; bottom: 0; left: 0; right: 0; pointer-events: none; border: dashed 1px; opacity: 0.75; color: inherit; z-index: 1; } .cropper .move { width: 100%; cursor: move; border: 1px solid rgba(255, 255, 255, 0.5); } .cropper .resize { position: absolute; display: inline-block; line-height: 6px; padding: 8px; opacity: 0.85; z-index: 1; } .cropper .resize .square { display: inline-block; background: #53535c; width: 6px; height: 6px; border: 1px solid rgba(255, 255, 255, 0.5); box-sizing: content-box; } .cropper .resize.topleft { top: -12px; left: -12px; cursor: nwse-resize; } .cropper .resize.top { top: -12px; left: calc(50% - 12px); cursor: ns-resize; } .cropper .resize.topright { top: -12px; right: -12px; cursor: nesw-resize; } .cropper .resize.right { top: calc(50% - 12px); right: -12px; cursor: ew-resize; } .cropper .resize.bottomright { bottom: -12px; right: -12px; cursor: nwse-resize; } .cropper .resize.bottom { bottom: -12px; left: calc(50% - 12px); cursor: ns-resize; } .cropper .resize.bottomleft { bottom: -12px; left: -12px; cursor: nesw-resize; } .cropper .resize.left { top: calc(50% - 12px); left: -12px; cursor: ew-resize; } .cropper .resize-bar { position: absolute; z-index: 1; } .cropper .resize-bar.top { top: -11px; left: 11px; width: calc(100% - 22px); height: 22px; cursor: ns-resize; } .cropper .resize-bar.right { top: 11px; right: -11px; height: calc(100% - 22px); width: 22px; cursor: ew-resize; } .cropper .resize-bar.bottom { bottom: -11px; left: 11px; width: calc(100% - 22px); height: 22px; cursor: ns-resize; } .cropper .resize-bar.left { top: 11px; left: -11px; height: calc(100% - 22px); width: 22px; cursor: ew-resize; } .cropper.rounded { outline-color: transparent; } .cropper.rounded:after { border-radius: 100%; box-shadow: 0 0 0 100vw rgba(255, 255, 255, 0.3); } @media (orientation: portrait) { .cropper.rounded:after { box-shadow: 0 0 0 100vh rgba(255, 255, 255, 0.3); } } .cropper.rounded .move { border-radius: 100%; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.component.ts import { NgZone, Inject, Component, ViewChild, Renderer2, ElementRef, HostListener, ChangeDetectorRef, ChangeDetectionStrategy, } from '@angular/core'; import { nameof, isPromise, resizeCanvas, XDialogResult, isNullOrUndefined, isNullOrEmptyString, resetExifOrientation, transformBase64BasedOnExifRotation, } from 'x-framework-core'; import { XMoveStart, XDimensions, XOutputType, XCropperPosition, XImageCroppedEvent, XImageCropperAction, XImageCropperContainer, XImageCropperProperties, XImageCropperActionModel, XImageCropperContainerComponent, } from './x-image-cropper.typings'; import { Subject, Subscription } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { SafeUrl, SafeStyle, DomSanitizer } from '@angular/platform-browser'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from './../config/x-framework-components.config'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-image-cropper', templateUrl: './x-image-cropper.component.html', styleUrls: ['./x-image-cropper.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XImageCropperComponent extends XImageCropperContainerComponent { // //#region Props ... private originalImage: any; private originalBase64: string; private moveStart: XMoveStart; private maxSize: XDimensions; private originalSize: XDimensions; private setImageMaxSizeRetries = 0; private cropperScaledMinWidth = 20; private cropperScaledMinHeight = 20; // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // safeImgDataUrl: SafeUrl | string; marginLeft: SafeStyle | string = '0px'; marginRight: SafeStyle | string = '0px'; imageVisible = false; // @ViewChild('sourceImage', { static: false }) sourceImage: ElementRef; // //#region Host Listeners ... @HostListener('window:resize') onResize(): void { this.resizeCropperPosition(); this.setMaxSize(); this.setCropperScaledMinSize(); } @HostListener('document:mousemove', ['$event']) @HostListener('document:touchmove', ['$event']) moveImg(event: any): void { if (this.moveStart.active) { event.stopPropagation(); event.preventDefault(); if (this.moveStart.type === 'move') { this.move(event); this.checkCropperPosition(true); } else if (this.moveStart.type === 'resize') { this.resize(event); this.checkCropperPosition(false); } this.changeDetector.detectChanges(); } } @HostListener('document:mouseup') @HostListener('document:touchend') moveStop(): void { if (this.moveStart.active) { this.moveStart.active = false; this.doAutoCrop(); } } //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XImageCropperContainer, private sanitizer: DomSanitizer, @Inject(MAT_DIALOG_DATA) private data: any, private dialogRef: MatDialogRef ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region LifeCycles ... onInit() { this.startUp(); } onChanges(changeKeys: string[]): void { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region ImageFileChanged ... const isImageFileChangedChanged = changeKeys.includes( nameof('imageFileChanged') ); if (isImageFileChangedChanged) { // this.initCropper(); if (this.imageFileChanged) { this.loadImageFile(this.imageFileChanged); } } //#endregion // //#region Image Changed Event Changed ... const isImageChangedEventChanged = changeKeys.includes( nameof('imageChangedEvent') ); if (isImageChangedEventChanged) { // this.initCropper(); if ( this.imageChangedEvent && this.imageChangedEvent.target && this.imageChangedEvent.target.files && this.imageChangedEvent.target.files.length > 0 ) { this.loadImageFile(this.imageChangedEvent.target.files[0]); } } //#endregion // //#region CropperChanged ... const isCropperChanged = changeKeys.includes( nameof('cropper') ); if (isCropperChanged) { // this.setMaxSize(); this.setCropperScaledMinSize(); this.checkCropperPosition(false); this.doAutoCrop(); this.changeDetector.markForCheck(); } //#endregion // //#region Aspect Ratio Changed ... const isAspectRatioChanged = changeKeys.includes( nameof('aspectRatio') ); if (isAspectRatioChanged && this.imageVisible) { this.resetCropperPosition(); } //#endregion // //#region ImageBase64 Changed ... const isImageBase64Changed = changeKeys.includes( nameof('imageBase64') ); if (isImageBase64Changed) { // this.initCropper(); if (!isNullOrEmptyString(this.imageBase64)) { this.loadBase64Image(this.imageBase64); } } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Handlers ... handleImageLoadedInView(): void { if (this.originalImage != null) { this.imageLoaded.emit(); this.setImageMaxSizeRetries = 0; setTimeout(() => this.checkImageMaxSizeRecursively()); } } handleCancel(): void { this.dialogRef.close({ result: XDialogResult.Cancel, }); } handleOk(): void { // // Get Crop Result and make Dialog close // Strategy based on it ... const res = this.crop(); // // if result is null ... if (isNullOrUndefined(res)) { // this.dialogRef.close({ event: null, result: XDialogResult.Ok, }); // // if result is Promise Object ... } else if (isPromise(res)) { // (res as Promise).then((event) => { this.dialogRef.close({ event, result: XDialogResult.Ok, }); }); // // if result ir ImagedCroppedEvent instance ... } else { this.dialogRef.close({ event: res, result: XDialogResult.Ok, }); } } handleRotateLeft() { this.rotateLeft(); } handleFlipHorizontal() { this.flipHorizontal(); } handleFlipVertical() { this.flipVertical(); } handleRotateRight() { this.rotateRight(); } handleStartMove( event: any, moveType: string, position: string | null = null ): void { event.preventDefault(); this.moveStart = { active: true, type: moveType, position, clientX: this.getClientX(event), clientY: this.getClientY(event), ...this.cropper, }; } //#endregion // //#region Actions ... rotateLeft() { this.transformBase64(8); } rotateRight() { this.transformBase64(6); } flipHorizontal() { this.transformBase64(2); } flipVertical() { this.transformBase64(4); } crop( outputType: XOutputType = this.outputType ): XImageCroppedEvent | Promise | null { if (this.sourceImage.nativeElement && this.originalImage != null) { this.startCropImage.emit(); const imagePosition = this.getImagePosition(); const width = imagePosition.x2 - imagePosition.x1; const height = imagePosition.y2 - imagePosition.y1; const cropCanvas = document.createElement('canvas') as HTMLCanvasElement; cropCanvas.width = width; cropCanvas.height = height; const ctx = cropCanvas.getContext('2d'); if (ctx) { ctx.drawImage( this.originalImage, imagePosition.x1, imagePosition.y1, width, height, 0, 0, width, height ); const output = { width, height, imagePosition, cropperPosition: { ...this.cropper }, }; const resizeRatio = this.getResizeRatio(width); if (resizeRatio !== 1) { output.width = Math.floor(width * resizeRatio); output.height = Math.floor(height * resizeRatio); resizeCanvas(cropCanvas, output.width, output.height); } // const result = this.cropToOutputType(outputType, cropCanvas, output); return result; } } return null; } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XImageCropperAction.Refresh: this.detectChanges(); break; // case XImageCropperAction.RotateLeft: this.rotateLeft(); break; // case XImageCropperAction.RotateRight: this.rotateRight(); break; // case XImageCropperAction.FlipVertical: this.flipVertical(); break; // case XImageCropperAction.FlipHorizontal: this.flipHorizontal(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private startUp() { // // Handle Dialog Data ... if (this.data) { // //#region Handle Properties ... if (this.data.props) { // const props = this.data.props as XImageCropperProperties; // if (props.imagefile) { this.imageFileChanged = props.imagefile; } // if (props.imageChangedEvent) { this.imageChangedEvent = props.imageChangedEvent; } // if (props.imageBase64) { this.imageBase64 = props.imageBase64; } // if (props.format) { this.format = props.format; } // if (props.outputType) { this.outputType = props.outputType; } // if (props.alignImage) { this.alignImage = props.alignImage; } // if (props.cropper) { this.cropper = props.cropper; } // if (props.autoCrop) { this.autoCrop = props.autoCrop; } // if (props.aspectRatio) { this.aspectRatio = props.aspectRatio; } // if (props.imageQuality) { this.imageQuality = props.imageQuality; } // if (props.resizeToWidth) { this.resizeToWidth = props.resizeToWidth; } // if (props.roundCropper) { this.roundCropper = props.roundCropper; } // if (props.onlyScaleDown) { this.onlyScaleDown = props.onlyScaleDown; } // if (props.cropperMinWidth) { this.cropperMinWidth = props.cropperMinWidth; } // if (props.cropperMinHeight) { this.cropperMinHeight = props.cropperMinHeight; } // if (props.maintainAspectRatio) { this.maintainAspectRatio = props.maintainAspectRatio; } } //#endregion } // this.initCropper(); if (this.imageFileChanged) { this.loadImageFile(this.imageFileChanged); } } private initCropper(): void { this.imageVisible = false; this.originalImage = null; this.safeImgDataUrl = 'data:image/png;base64,iVBORw0KGg' + 'oAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAU' + 'AAarVyFEAAAAASUVORK5CYII='; this.moveStart = { active: false, type: null, position: null, x1: 0, y1: 0, x2: 0, y2: 0, clientX: 0, clientY: 0, }; this.maxSize = { width: 0, height: 0, }; this.originalSize = { width: 0, height: 0, }; this.cropper.x1 = -100; this.cropper.y1 = -100; this.cropper.x2 = 10000; this.cropper.y2 = 10000; } private loadImageFile(file: File): void { const fileReader = new FileReader(); fileReader.onload = (event: any) => { const imageType = file.type; if (this.isValidImageType(imageType)) { resetExifOrientation(event.target.result) .then((resultBase64: string) => this.loadBase64Image(resultBase64)) .catch(() => this.loadImageFailed.emit()); } else { this.loadImageFailed.emit(); } }; fileReader.readAsDataURL(file); } private isValidImageType(type: string): boolean { return /image\/(png|jpg|jpeg|bmp|gif|tiff)/.test(type); } private loadBase64Image(imageBase64: string): void { this.originalBase64 = imageBase64; this.safeImgDataUrl = this.sanitizer.bypassSecurityTrustResourceUrl(imageBase64); this.originalImage = new Image(); this.originalImage.onload = () => { this.originalSize.width = this.originalImage.width; this.originalSize.height = this.originalImage.height; this.changeDetector.markForCheck(); }; this.originalImage.src = imageBase64; } private checkImageMaxSizeRecursively(): void { if (this.setImageMaxSizeRetries > 40) { this.loadImageFailed.emit(); } else if ( this.sourceImage && this.sourceImage.nativeElement && this.sourceImage.nativeElement.offsetWidth > 0 ) { this.setMaxSize(); this.setCropperScaledMinSize(); this.resetCropperPosition(); this.cropperReady.emit(); this.changeDetector.markForCheck(); } else { this.setImageMaxSizeRetries++; setTimeout(() => { this.checkImageMaxSizeRecursively(); }, 50); } } private transformBase64(exifOrientation: number): void { if (this.originalBase64) { transformBase64BasedOnExifRotation( this.originalBase64, exifOrientation ).then((rotatedBase64: string) => this.loadBase64Image(rotatedBase64)); } } private resizeCropperPosition(): void { const sourceImageElement = this.sourceImage.nativeElement; if ( this.maxSize.width !== sourceImageElement.offsetWidth || this.maxSize.height !== sourceImageElement.offsetHeight ) { this.cropper.x1 = (this.cropper.x1 * sourceImageElement.offsetWidth) / this.maxSize.width; this.cropper.x2 = (this.cropper.x2 * sourceImageElement.offsetWidth) / this.maxSize.width; this.cropper.y1 = (this.cropper.y1 * sourceImageElement.offsetHeight) / this.maxSize.height; this.cropper.y2 = (this.cropper.y2 * sourceImageElement.offsetHeight) / this.maxSize.height; } } private resetCropperPosition(): void { const sourceImageElement = this.sourceImage.nativeElement; if (!this.maintainAspectRatio) { this.cropper.x1 = 0; this.cropper.x2 = sourceImageElement.offsetWidth; this.cropper.y1 = 0; this.cropper.y2 = sourceImageElement.offsetHeight; } else if ( sourceImageElement.offsetWidth / this.aspectRatio < sourceImageElement.offsetHeight ) { this.cropper.x1 = 0; this.cropper.x2 = sourceImageElement.offsetWidth; const cropperHeight = sourceImageElement.offsetWidth / this.aspectRatio; this.cropper.y1 = (sourceImageElement.offsetHeight - cropperHeight) / 2; this.cropper.y2 = this.cropper.y1 + cropperHeight; } else { this.cropper.y1 = 0; this.cropper.y2 = sourceImageElement.offsetHeight; const cropperWidth = sourceImageElement.offsetHeight * this.aspectRatio; this.cropper.x1 = (sourceImageElement.offsetWidth - cropperWidth) / 2; this.cropper.x2 = this.cropper.x1 + cropperWidth; } this.doAutoCrop(); this.imageVisible = true; } private setMaxSize(): void { const sourceImageElement = this.sourceImage.nativeElement; this.maxSize.width = sourceImageElement.offsetWidth; this.maxSize.height = sourceImageElement.offsetHeight; this.marginLeft = this.sanitizer.bypassSecurityTrustStyle( 'calc(50% - ' + this.maxSize.width / 2 + 'px)' ); this.marginRight = this.sanitizer.bypassSecurityTrustStyle( 'calc(50% - ' + this.maxSize.width / 2 + 'px)' ); } private setCropperScaledMinSize(): void { if (this.originalImage) { this.setCropperScaledMinWidth(); this.setCropperScaledMinHeight(); } else { this.cropperScaledMinWidth = 20; this.cropperScaledMinHeight = 20; } } private setCropperScaledMinWidth(): void { this.cropperScaledMinWidth = this.cropperMinWidth > 0 ? Math.max( 20, (this.cropperMinWidth / this.originalImage.width) * this.maxSize.width ) : 20; } private setCropperScaledMinHeight(): void { if (this.maintainAspectRatio) { this.cropperScaledMinHeight = Math.max( 20, this.cropperScaledMinWidth / this.aspectRatio ); } else if (this.cropperMinHeight > 0) { this.cropperScaledMinHeight = Math.max( 20, (this.cropperMinHeight / this.originalImage.height) * this.maxSize.height ); } else { this.cropperScaledMinHeight = 20; } } private checkCropperPosition(maintainSize = false): void { if (this.cropper.x1 < 0) { this.cropper.x2 -= maintainSize ? this.cropper.x1 : 0; this.cropper.x1 = 0; } if (this.cropper.y1 < 0) { this.cropper.y2 -= maintainSize ? this.cropper.y1 : 0; this.cropper.y1 = 0; } if (this.cropper.x2 > this.maxSize.width) { this.cropper.x1 -= maintainSize ? this.cropper.x2 - this.maxSize.width : 0; this.cropper.x2 = this.maxSize.width; } if (this.cropper.y2 > this.maxSize.height) { this.cropper.y1 -= maintainSize ? this.cropper.y2 - this.maxSize.height : 0; this.cropper.y2 = this.maxSize.height; } } private move(event: any) { const diffX = this.getClientX(event) - this.moveStart.clientX; const diffY = this.getClientY(event) - this.moveStart.clientY; this.cropper.x1 = this.moveStart.x1 + diffX; this.cropper.y1 = this.moveStart.y1 + diffY; this.cropper.x2 = this.moveStart.x2 + diffX; this.cropper.y2 = this.moveStart.y2 + diffY; } private resize(event: any): void { const diffX = this.getClientX(event) - this.moveStart.clientX; const diffY = this.getClientY(event) - this.moveStart.clientY; switch (this.moveStart.position) { case 'left': this.cropper.x1 = Math.min( this.moveStart.x1 + diffX, this.cropper.x2 - this.cropperScaledMinWidth ); break; case 'topleft': this.cropper.x1 = Math.min( this.moveStart.x1 + diffX, this.cropper.x2 - this.cropperScaledMinWidth ); this.cropper.y1 = Math.min( this.moveStart.y1 + diffY, this.cropper.y2 - this.cropperScaledMinHeight ); break; case 'top': this.cropper.y1 = Math.min( this.moveStart.y1 + diffY, this.cropper.y2 - this.cropperScaledMinHeight ); break; case 'topright': this.cropper.x2 = Math.max( this.moveStart.x2 + diffX, this.cropper.x1 + this.cropperScaledMinWidth ); this.cropper.y1 = Math.min( this.moveStart.y1 + diffY, this.cropper.y2 - this.cropperScaledMinHeight ); break; case 'right': this.cropper.x2 = Math.max( this.moveStart.x2 + diffX, this.cropper.x1 + this.cropperScaledMinWidth ); break; case 'bottomright': this.cropper.x2 = Math.max( this.moveStart.x2 + diffX, this.cropper.x1 + this.cropperScaledMinWidth ); this.cropper.y2 = Math.max( this.moveStart.y2 + diffY, this.cropper.y1 + this.cropperScaledMinHeight ); break; case 'bottom': this.cropper.y2 = Math.max( this.moveStart.y2 + diffY, this.cropper.y1 + this.cropperScaledMinHeight ); break; case 'bottomleft': this.cropper.x1 = Math.min( this.moveStart.x1 + diffX, this.cropper.x2 - this.cropperScaledMinWidth ); this.cropper.y2 = Math.max( this.moveStart.y2 + diffY, this.cropper.y1 + this.cropperScaledMinHeight ); break; } if (this.maintainAspectRatio) { this.checkAspectRatio(); } } private checkAspectRatio(): void { let overflowX = 0; let overflowY = 0; switch (this.moveStart.position) { case 'top': this.cropper.x2 = this.cropper.x1 + (this.cropper.y2 - this.cropper.y1) * this.aspectRatio; overflowX = Math.max(this.cropper.x2 - this.maxSize.width, 0); overflowY = Math.max(0 - this.cropper.y1, 0); if (overflowX > 0 || overflowY > 0) { this.cropper.x2 -= overflowY * this.aspectRatio > overflowX ? overflowY * this.aspectRatio : overflowX; this.cropper.y1 += overflowY * this.aspectRatio > overflowX ? overflowY : overflowX / this.aspectRatio; } break; case 'bottom': this.cropper.x2 = this.cropper.x1 + (this.cropper.y2 - this.cropper.y1) * this.aspectRatio; overflowX = Math.max(this.cropper.x2 - this.maxSize.width, 0); overflowY = Math.max(this.cropper.y2 - this.maxSize.height, 0); if (overflowX > 0 || overflowY > 0) { this.cropper.x2 -= overflowY * this.aspectRatio > overflowX ? overflowY * this.aspectRatio : overflowX; this.cropper.y2 -= overflowY * this.aspectRatio > overflowX ? overflowY : overflowX / this.aspectRatio; } break; case 'topleft': this.cropper.y1 = this.cropper.y2 - (this.cropper.x2 - this.cropper.x1) / this.aspectRatio; overflowX = Math.max(0 - this.cropper.x1, 0); overflowY = Math.max(0 - this.cropper.y1, 0); if (overflowX > 0 || overflowY > 0) { this.cropper.x1 += overflowY * this.aspectRatio > overflowX ? overflowY * this.aspectRatio : overflowX; this.cropper.y1 += overflowY * this.aspectRatio > overflowX ? overflowY : overflowX / this.aspectRatio; } break; case 'topright': this.cropper.y1 = this.cropper.y2 - (this.cropper.x2 - this.cropper.x1) / this.aspectRatio; overflowX = Math.max(this.cropper.x2 - this.maxSize.width, 0); overflowY = Math.max(0 - this.cropper.y1, 0); if (overflowX > 0 || overflowY > 0) { this.cropper.x2 -= overflowY * this.aspectRatio > overflowX ? overflowY * this.aspectRatio : overflowX; this.cropper.y1 += overflowY * this.aspectRatio > overflowX ? overflowY : overflowX / this.aspectRatio; } break; case 'right': case 'bottomright': this.cropper.y2 = this.cropper.y1 + (this.cropper.x2 - this.cropper.x1) / this.aspectRatio; overflowX = Math.max(this.cropper.x2 - this.maxSize.width, 0); overflowY = Math.max(this.cropper.y2 - this.maxSize.height, 0); if (overflowX > 0 || overflowY > 0) { this.cropper.x2 -= overflowY * this.aspectRatio > overflowX ? overflowY * this.aspectRatio : overflowX; this.cropper.y2 -= overflowY * this.aspectRatio > overflowX ? overflowY : overflowX / this.aspectRatio; } break; case 'left': case 'bottomleft': this.cropper.y2 = this.cropper.y1 + (this.cropper.x2 - this.cropper.x1) / this.aspectRatio; overflowX = Math.max(0 - this.cropper.x1, 0); overflowY = Math.max(this.cropper.y2 - this.maxSize.height, 0); if (overflowX > 0 || overflowY > 0) { this.cropper.x1 += overflowY * this.aspectRatio > overflowX ? overflowY * this.aspectRatio : overflowX; this.cropper.y2 -= overflowY * this.aspectRatio > overflowX ? overflowY : overflowX / this.aspectRatio; } break; } } private doAutoCrop(): void { if (this.autoCrop) { this.crop(); } } private getImagePosition(): XCropperPosition { const sourceImageElement = this.sourceImage.nativeElement; const ratio = this.originalSize.width / sourceImageElement.offsetWidth; return { x1: Math.round(this.cropper.x1 * ratio), y1: Math.round(this.cropper.y1 * ratio), x2: Math.min( Math.round(this.cropper.x2 * ratio), this.originalSize.width ), y2: Math.min( Math.round(this.cropper.y2 * ratio), this.originalSize.height ), }; } private cropToOutputType( outputType: XOutputType, cropCanvas: HTMLCanvasElement, output: XImageCroppedEvent ): XImageCroppedEvent | Promise { switch (outputType) { case 'file': return this.cropToFile(cropCanvas).then((result: Blob | null) => { output.file = result; this.imageCropped.emit(output); return output; }); case 'both': return this.cropToFile(cropCanvas).then((result: Blob | null) => { output.base64 = this.cropToBase64(cropCanvas); output.file = result; this.imageCropped.emit(output); return output; }); default: output.base64 = this.cropToBase64(cropCanvas); this.imageCropped.emit(output); return output; } } private cropToBase64(cropCanvas: HTMLCanvasElement): string { const imageBase64 = cropCanvas.toDataURL( 'image/' + this.format, this.getQuality() ); this.imageCroppedBase64.emit(imageBase64); return imageBase64; } private cropToFile(cropCanvas: HTMLCanvasElement): Promise { return this.getCanvasBlob(cropCanvas).then((result: Blob | null) => { if (result) { this.imageCroppedFile.emit(result); } return result; }); } private getCanvasBlob(cropCanvas: HTMLCanvasElement): Promise { return new Promise((resolve) => { cropCanvas.toBlob( (result: Blob | null) => this.zone.run(() => resolve(result)), 'image/' + this.format, this.getQuality() ); }); } private getQuality(): number { return Math.min(1, Math.max(0, this.imageQuality / 100)); } private getResizeRatio(width: number): number { return this.resizeToWidth > 0 && (!this.onlyScaleDown || width > this.resizeToWidth) ? this.resizeToWidth / width : 1; } private getClientX(event: any): number { return ( event.clientX || (event.touches && event.touches[0] && event.touches[0].clientX) ); } private getClientY(event: any): number { return ( event.clientY || (event.touches && event.touches[0] && event.touches[0].clientY) ); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XImageCropperService } from './x-image-cropper.service'; import { XImageCropperComponent } from './x-image-cropper.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ providers: [XImageCropperService], declarations: [XImageCropperComponent], entryComponents: [XImageCropperComponent], imports: [CommonModule, XBaseComponentModule, XIconModule], exports: [XBaseComponentModule, XIconModule, XImageCropperComponent] }) export class XImageCropperModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.service.ts import { toFileBlob, blobToFile, XDialogResult, isNullOrUndefined, } from 'x-framework-core'; import { MatDialog, MatDialogRef, MatDialogConfig, } from '@angular/material/dialog'; import { XImageCroppedEvent, XImageCropperResult, XImageCropperProperties, } from './x-image-cropper.typings'; import { XImageCropperComponent } from './x-image-cropper.component'; import { Injectable, Output, EventEmitter, Inject } from '@angular/core'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; @Injectable({ providedIn: 'root', }) export class XImageCropperService { // //#region Props ... // private dialogMaxWidth: number; private dialogMinWidth: number; // private sourceFile: File; private DIALOG_REF: MatDialogRef; // // tslint:disable-next-line:no-output-on-prefix @Output() onResult = new EventEmitter(); // minAllowedImageSize: number; maxAllowedImageSize: number; //#endregion // //#region Constructor ... constructor( private dialog: MatDialog, @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig ) { // this.minAllowedImageSize = config.minAllowedImageSize; this.maxAllowedImageSize = config.maxAllowedImageSize; // this.dialogMinWidth = Math.min(window.innerWidth * 0.8, 300); this.dialogMaxWidth = Math.min(window.innerWidth * 0.8, 400); } //#endregion // //#region Public Actions ... /** * show Image Cropper ... * @param file the source image file ... * @param props Image Cropper Properties ... */ showCropper(file: File, props?: XImageCropperProperties) { // this.sourceFile = file; // // Prepare Cropper Props ... let cropperProps: XImageCropperProperties; if (props) { cropperProps = props; if (!props.imagefile) { cropperProps.imagefile = file; } cropperProps.maxSingleFileThumbSize = this.maxAllowedImageSize; } else { cropperProps = this.getDefaultCropperProperties(file); } // const config: MatDialogConfig = { width: this.dialogMinWidth + 'px', minWidth: this.dialogMinWidth + 'px', maxWidth: this.dialogMaxWidth + 'px', data: { props: cropperProps, }, }; // // Show Cropper inside a Dialog ... this.DIALOG_REF = this.dialog.open(XImageCropperComponent, config); this.DIALOG_REF.disableClose = true; // //#region Register Event Handlers ... // // Subscribe to Event Listener for catching Cropper Change ... const cropperComponent = this.DIALOG_REF ? this.DIALOG_REF.componentInstance : null; if (cropperComponent) { // if (cropperProps.startCropImage) { cropperComponent.startCropImage.asObservable().subscribe(() => { cropperProps.startCropImage(); }); } // if (cropperProps.imageCropped) { cropperComponent.imageCropped .asObservable() .subscribe((event: XImageCroppedEvent) => { cropperProps.imageCropped(event); }); } // if (cropperProps.imageCroppedBase64) { cropperComponent.imageCroppedBase64 .asObservable() .subscribe((data: string) => { cropperProps.imageCroppedBase64(data); }); } // if (cropperProps.imageCroppedFile) { cropperComponent.imageCroppedFile .asObservable() .subscribe((mFile: Blob) => { cropperProps.imageCroppedFile(mFile); }); } // if (cropperProps.imageLoaded) { cropperComponent.imageLoaded.asObservable().subscribe(() => { cropperProps.imageLoaded(); }); } // if (cropperProps.cropperReady) { cropperComponent.cropperReady.asObservable().subscribe(() => { cropperProps.cropperReady(); }); } // if (cropperProps.loadImageFailed) { cropperComponent.loadImageFailed.asObservable().subscribe(() => { cropperProps.loadImageFailed(); }); } } //#endregion // // Handle Dialog Result ... this.DIALOG_REF.afterClosed().subscribe((result) => { // if (isNullOrUndefined(result) || result.result !== XDialogResult.Ok) { // // Cancel Cropper ... this.onResult.emit({ result: XDialogResult.Cancel }); } else { // // Use Cropper Result ... const res: XImageCroppedEvent = result.event as XImageCroppedEvent; // let mFile: File; if (res.file) { // mFile = this.toFile(res.file); this.sourceFile = mFile; } // this.onResult.emit({ result: result.result, data: res.base64, file: mFile, }); } }); } /** * close opened Dialog manually ... */ closeCropper() { // if (this.DIALOG_REF != null) { this.DIALOG_REF.close(); } // this.DIALOG_REF = null; } //#endregion // //#region Private Actions ... /** * Prepare Default Properties for Image Cropper ... */ private getDefaultCropperProperties(file: File) { return { // imagefile: file, // aspectRatio: 1, maintainAspectRatio: true, // resizeToWidth: this.dialogMinWidth, cropperMinWidth: this.minAllowedImageSize, cropperMinHeight: this.minAllowedImageSize, // onlyScaleDown: true, roundCropper: true, // format: 'png', outputType: 'both', // maxSingleFileThumbSize: this.maxAllowedImageSize, } as XImageCropperProperties; } /** * Generate a File Blob Object based on Source Image and Cropped file ... */ private toFile(file: Blob): File { // if (!this.sourceFile) { return null; } // const fileBlob = toFileBlob(this.sourceFile); // return blobToFile(file, fileBlob.name); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-image-cropper\x-image-cropper.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XDialogResult, XOneOrManyType, XStandardType } from 'x-framework-core'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Definitions ... export interface XCropperPosition { x1: number; y1: number; x2: number; y2: number; } export interface XDimensions { width: number; height: number; } export interface XImageCroppedEvent { base64?: string | null; file?: Blob | null; width: number; height: number; cropperPosition: XCropperPosition; imagePosition: XCropperPosition; } export interface XMoveStart { active: boolean; type: string | null; position: string | null; x1: number; y1: number; x2: number; y2: number; clientX: number; clientY: number; } export interface XImageCropperProperties { // imageChangedEvent?: (event: any) => void; // imagefile?: File; imageBase64?: string; // format?: XImageFormat; outputType?: XOutputType; alignImage?: XImageAlign; cropper?: XCropperPosition; // autoCrop?: boolean; aspectRatio?: number; imageQuality?: number; resizeToWidth?: number; roundCropper?: boolean; onlyScaleDown?: boolean; cropperMinWidth?: number; cropperMinHeight?: number; maintainAspectRatio?: boolean; // maxSingleFileThumbSize: number; // startCropImage?: () => void; imageCropped?: (event: XImageCroppedEvent) => void; imageCroppedBase64?: (data: string) => void; imageCroppedFile?: (file: Blob) => void; imageLoaded?: () => void; cropperReady?: () => void; loadImageFailed?: () => void; } export interface XImageCropperResult { result: XDialogResult; data?: string; file?: File; } export type XOutputType = 'base64' | 'file' | 'both'; export type XImageFormat = 'png' | 'jpeg' | 'bmp' | 'webp' | 'ico'; export type XImageAlign = 'left' | 'center'; //#endregion export enum XImageCropperAction { // RotateLeft = 'rotate-left', RotateRight = 'rotate-right', FlipHorizontal = 'flip-horizontal', FlipVertical = 'flip-vertical', // Refresh = 'refresh', } export type XImageCropperActionIdentifier = XImageCropperAction | string; export interface XImageCropperActionModel extends XBaseActionModel {} // //#region Container ... export interface IXImageCropperContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // imageFileChanged: File; imageChangedEvent: any; imageBase64: string; format: XImageFormat; outputType: XOutputType; maintainAspectRatio: boolean; aspectRatio: number; resizeToWidth: number; cropperMinWidth: number; cropperMinHeight: number; roundCropper: boolean; onlyScaleDown: boolean; imageQuality: number; autoCrop: boolean; alignImage: XImageAlign; cropper: XCropperPosition; // startCropImage: EventEmitter; imageCropped: EventEmitter; imageCroppedBase64: EventEmitter; imageCroppedFile: EventEmitter; imageLoaded: EventEmitter; cropperReady: EventEmitter; loadImageFailed: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XImageCropperContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly imageFileChanged: File; readonly imageChangedEvent: any; readonly imageBase64: string; readonly format: XImageFormat = 'png'; readonly outputType: XOutputType = 'both'; readonly maintainAspectRatio: boolean = true; readonly aspectRatio: number = 1; readonly resizeToWidth: number = 0; readonly cropperMinWidth: number = 0; readonly cropperMinHeight: number = 0; readonly roundCropper: boolean = false; readonly onlyScaleDown: boolean = false; readonly imageQuality: number = 92; readonly autoCrop: boolean = true; readonly alignImage: XImageAlign = 'center'; readonly cropper: XCropperPosition = { x1: -100, y1: -100, x2: 10000, y2: 10000, }; // readonly startCropImage: EventEmitter = new EventEmitter(); readonly imageCropped: EventEmitter = new EventEmitter(); readonly imageCroppedBase64: EventEmitter = new EventEmitter(); readonly imageCroppedFile: EventEmitter = new EventEmitter(); readonly imageLoaded: EventEmitter = new EventEmitter(); readonly cropperReady: EventEmitter = new EventEmitter(); readonly loadImageFailed: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XImageCropperContainerComponent extends XBaseContainerComponent implements IXImageCropperContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() imageFileChanged: File = this.propertyProvider.imageFileChanged; @Input() imageChangedEvent: any = this.propertyProvider.imageChangedEvent; @Input() imageBase64: string = this.propertyProvider.imageBase64; @Input() format: XImageFormat = this.propertyProvider.format; @Input() outputType: XOutputType = this.propertyProvider.outputType; @Input() maintainAspectRatio: boolean = this.propertyProvider.maintainAspectRatio; @Input() aspectRatio: number = this.propertyProvider.aspectRatio; @Input() resizeToWidth: number = this.propertyProvider.resizeToWidth; @Input() cropperMinWidth: number = this.propertyProvider.cropperMinWidth; @Input() cropperMinHeight: number = this.propertyProvider.cropperMinHeight; @Input() roundCropper: boolean = this.propertyProvider.roundCropper; @Input() onlyScaleDown: boolean = this.propertyProvider.onlyScaleDown; @Input() imageQuality: number = this.propertyProvider.imageQuality; @Input() autoCrop: boolean = this.propertyProvider.autoCrop; @Input() alignImage: XImageAlign = this.propertyProvider.alignImage; @Input() cropper: XCropperPosition = this.propertyProvider.cropper; // @Output() startCropImage: EventEmitter = new EventEmitter(); @Output() imageCropped: EventEmitter = new EventEmitter(); @Output() imageCroppedBase64: EventEmitter = new EventEmitter(); @Output() imageCroppedFile: EventEmitter = new EventEmitter(); @Output() imageLoaded: EventEmitter = new EventEmitter(); @Output() cropperReady: EventEmitter = new EventEmitter(); @Output() loadImageFailed: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XImageCropperContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXImageCropperContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), imageFileChanged: this.getValue( container ? container.imageFileChanged : this.imageFileChanged ), imageChangedEvent: this.getValue( container ? container.imageChangedEvent : this.imageChangedEvent ), imageBase64: this.getValue( container ? container.imageBase64 : this.imageBase64 ), format: this.getValue(container ? container.format : this.format), outputType: this.getValue( container ? container.outputType : this.outputType ), maintainAspectRatio: this.getValue( container ? container.maintainAspectRatio : this.maintainAspectRatio ), aspectRatio: this.getValue( container ? container.aspectRatio : this.aspectRatio ), resizeToWidth: this.getValue( container ? container.resizeToWidth : this.resizeToWidth ), cropperMinWidth: this.getValue( container ? container.cropperMinWidth : this.cropperMinWidth ), cropperMinHeight: this.getValue( container ? container.cropperMinHeight : this.cropperMinHeight ), roundCropper: this.getValue( container ? container.roundCropper : this.roundCropper ), onlyScaleDown: this.getValue( container ? container.onlyScaleDown : this.onlyScaleDown ), imageQuality: this.getValue( container ? container.imageQuality : this.imageQuality ), autoCrop: this.getValue(container ? container.autoCrop : this.autoCrop), alignImage: this.getValue( container ? container.alignImage : this.alignImage ), cropper: this.getValue(container ? container.cropper : this.cropper), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // startCropImage: this.startCropImage, imageCropped: this.imageCropped, imageCroppedBase64: this.imageCroppedBase64, imageCroppedFile: this.imageCroppedFile, imageLoaded: this.imageLoaded, cropperReady: this.cropperReady, loadImageFailed: this.loadImageFailed, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.component.html
{{ getResourceValue(option.title) | async }} {{ getResourceValue(option.title) | async }}
{{ item | json }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.component.scss ion-item-option > ion-item { --background: transparent !important; } ion-list, ion-item.item, ion-item-divider { --background: transparent !important; } ion-item-divider { --color: var(--ion-color-dark-shade); } ion-item.item.mobile { --ion-safe-area-end: 0px; --padding-start: 8px; --inner-padding-start: 0px; --padding-end: 8px; --inner-padding-end: 0px; } h1, h2, h3, h4, h5, h6 { margin: 0; } .x-menu { z-index: 10; } .x-check { z-index: 1; } x-card { width: inherit; height: inherit; } :host ::ng-deep .button-solid { --color: unset !important; --background: unset !important; --box-shadow: unset !important; } .x-list-toolbar { &.sticky { top: 0; position: sticky; position: -webkit-sticky; z-index: 200; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.component.ts import { nameof, toArray, hasChild, isFunction, removeItem, XOneOrManyType, isNullOrUndefined, isNullOrEmptyString, } from 'x-framework-core'; import { XListItem, XListAction, XListActionModel, XListItemSlideOption, XListContainerComponent, } from './x-list.typings'; import { XActionBarItem, XActionBarAction, XActionBarActionModel, DefaultActionBarItemIds, defaultActionBarAddItem, defaultActionBarRemoveItem, XActionBarActionFiredModel, defaultActionBarSelectAllItem, defaultActionBarDeSelectAllItem, defaultActionBarInverseSelectionItem, } from '../x-action-bar/x-action-bar.typings'; import { map, concatMap } from 'rxjs/operators'; import { IonItemSliding } from '@ionic/angular'; import { XPopoverResult, XPopoverOption, XPopoverComponentProps, } from '../dialogs/x-popover/x-popover.typings'; import { moveItemInArray } from '@angular/cdk/drag-drop'; import { XButtonType } from '../x-button/x-button.typings'; import { Subject, Subscription, BehaviorSubject, of } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; import { toPopoverOptions } from '../dialogs/x-popover/x-popover.tools'; import { XSearchBarAction } from '../x-search-bar/x-search-bar.typings'; import { XPopoverComponent } from '../dialogs/x-popover/x-popover.component'; @Component({ // tslint:disable-next-line: component-selector selector: 'x-list', templateUrl: './x-list.component.html', styleUrls: ['./x-list.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XListComponent extends XListContainerComponent { // //#region Props ... // private SELECTED_ITEMS: XListItem[] = []; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // private ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION: Subscription; // private HIDE_ADD = false; private DISABLE_ADD = false; private addDisablerSubject = new BehaviorSubject(false); // private HIDE_REMOVE = false; private DISABLE_REMOVE = false; private removeDisablerSubject = new BehaviorSubject(true); // private HIDE_SELECT_ALL = false; private DISABLE_SELECT_ALL = false; private selectAllDisablerSubject = new BehaviorSubject(true); // private HIDE_DESELECT_ALL = false; private DISABLE_DESELECT_ALL = false; private deSelectAllDisablerSubject = new BehaviorSubject(true); // private HIDE_INVERSE_SELECTION = false; private DISABLE_INVERSE_SELECTION = false; private inverseSelectionDisablerSubject = new BehaviorSubject(true); // readonly ButtonTypes = Object.assign({}, XButtonType); // filteredItems: XListItem[] = []; // get count() { return this.items ? this.getValue(this.items) : of(0); } get filteredItemsCount() { return this.filteredItems ? this.filteredItems.length : 0; } get selectedItems() { return this.SELECTED_ITEMS; } //#endregion // //#region LifeCycle ... async onInit() { super.onInit(); // // await this.handleStartup(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); const isActionBarActionProviderChanged = changeKeys.includes( nameof('actionBarActionProvider') ); if (isActionProviderChanged || isActionBarActionProviderChanged) { this.registerActionProvider(); } // const isItemsChanged = changeKeys.includes(nameof('items')); if (isItemsChanged) { // await this.handleStartup(); this.itemsChanged.emit(); } // const isActionBarActionsChanged = changeKeys.includes( nameof('actionBarActions') ); const isActionBarHideActionsChanged = changeKeys.includes( nameof('actionBarHideActions') ); if (isActionBarActionsChanged || isActionBarHideActionsChanged) { await this.prepareActionBarActions(); } } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region UI Providers ... getStartSlides(item: XListItem) { return item && item.slideOptions ? item.slideOptions.filter((opt) => opt.slot === 'start') : null; } getEndSlides(item: XListItem) { return item && item.slideOptions ? item.slideOptions.filter((opt) => opt.slot === 'end') : null; } getOptionSlot(option: XListItemSlideOption) { return this.getOptionOnlyIcon(option).pipe( map((onlyIcon) => { return onlyIcon ? 'icon-only' : ''; }) ); } getOptionIconSlot(option: XListItemSlideOption) { return this.getOptionOnlyIcon(option).pipe( concatMap((onlyIcon) => { return this.getOptionSlot(option).pipe( map((slot) => { return onlyIcon ? '' : slot; }) ); }) ); } getNonSlidingOptionIconSlot(option: XListItemSlideOption) { return this.getOptionOnlyIcon(option).pipe( map((onlyIcon) => { return onlyIcon ? 'icon-only' : 'end'; }) ); } getOptionOnlyIcon(option: XListItemSlideOption) { return this.getValue(!isNullOrUndefined(option) ? option.onlyIcon : false); } getIonItemLine() { return this.getValue(this.showDivider).pipe( map((showDivider) => (showDivider ? 'full' : 'none')) ); } //#endregion // //#region UI Handlers ... handleActionItemSelected(item: XListItem) { // if (this.selectableItems) { item.isSelected = !item.isSelected; this.issueSelectionChanged(); } // this.itemSelected.emit(item); } handleDoReorderItems(ev: CustomEvent | any) { // const to = ev.detail.to; // tslint:disable-next-line:no-shadowed-variable const from = ev.detail.from; moveItemInArray(this.filteredItems, from, to); // this.orderChanged.emit(); ev.detail.complete(); } async handleMoreButtonClicked( event: Event, slide: IonItemSliding, item: XListItem ) { // if (!isNullOrUndefined(slide)) { await slide.closeOpened(); } // // Disable Only Icons for Menu Options ... const options: XPopoverOption[] = toArray(toPopoverOptions(item)); options.forEach((o) => { // o.onlyIcon = false; // o.slot = 'end'; // o.handler = undefined; }); // // Prepare PopOver Component Props ... const componentProps: XPopoverComponentProps = { options, }; // // Present Context Menu Options ... const popOver = await this.managerService.dialogService.presentPopover({ event, componentProps, translucent: true, showBackdrop: true, component: XPopoverComponent, }); // // Extract Data from PopOver ... const { data } = await popOver.onWillDismiss(); if (!data) { return; } // const result = data as XPopoverResult; if ( isNullOrUndefined(result.option) || isNullOrEmptyString(result.option.id) ) { return; } // this.handleActionOptionSelected(slide, result.option.id, item); } async handleActionOptionSelected( slide: IonItemSliding, id: string, item: XListItem ) { // if (isNullOrEmptyString(id) || isNullOrUndefined(item)) { return; } // // if (!isNullOrUndefined) const action = item.slideOptions.find((i) => i.id === id); if ( !isNullOrUndefined(action) && !isNullOrUndefined(action.handler) && isFunction(action.handler) ) { await this.getValueAsync(action.handler()); } // if (this.closeOptionsAfterSelect && !isNullOrUndefined(slide)) { // slide.closeOpened().then(() => { // this.optionSelected.emit({ id, data: item, }); }); } else { // this.optionSelected.emit({ id, data: item, }); } } async handleActionRemoveItems() { // if (!this.hasChild(this.SELECTED_ITEMS)) { return; } // const items = this.SELECTED_ITEMS.map((i) => i.data); // const confirmRemove = await this.getValueAsync(this.confirmRemove); if (confirmRemove) { await this.managerService.dialogService.presentAreYouSureYesNoDialog( () => { this.removeItems.emit({ items, }); } ); } else { this.removeItems.emit({ items, }); } } async handleActionBarActionFired(model: XActionBarActionFiredModel) { // if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) { return; } // switch (model.action) { // case DefaultActionBarItemIds.SelectAll: await this.selectAll(); break; // case DefaultActionBarItemIds.DeSelectAll: await this.deselectAll(); break; // case DefaultActionBarItemIds.InverseSelection: await this.inverseSelection(); break; // case DefaultActionBarItemIds.Remove: // await this.handleActionRemoveItems(); break; } // this.actionBarActionFired.emit(model); } //#endregion // //#region Actions ... async selectAll() { // this.filteredItems.forEach((item) => { if (!item.disabled) { // item.isSelected = true; this.changeDetector.markForCheck(); } }); // this.issueSelectionChanged(); this.handleChangeDetection(); } async deselectAll() { // this.filteredItems.forEach((item) => { if (!item.disabled) { // item.isSelected = false; this.changeDetector.markForCheck(); } }); // this.issueSelectionChanged(); this.handleChangeDetection(); } async inverseSelection() { // this.filteredItems.forEach((item) => { if (!item.disabled) { // item.isSelected = !item.isSelected; this.changeDetector.markForCheck(); } }); // this.issueSelectionChanged(); this.handleChangeDetection(); } async clearFilter(fill = false) { this.filteredItems = []; // if (fill) { // const items = await this.getValueAsync(this.items); this.filteredItems = items; } // this.handleChangeDetection(); } async filterItems(query: string) { // this.searchBarQueryChange.emit(query); // await this.clearFilter(); const items = await this.getValueAsync(this.items); // if (isNullOrEmptyString(query)) { // this.filteredItems = items; this.handleChangeDetection(); return; } // const result = await this.getValueAsync( this.filteringHandler(query, items) ); this.filteredItems = result; // this.handleChangeDetection(); } //#endregion // //#region Private ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // if (!this.actionBarActionProvider) { this.actionBarActionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XListAction.Add: // const newItem = model.payload as XListItem; if (newItem) { // const items = await this.getArrayValueAsync(this.items); this.items = [...items, newItem]; this.itemsChanged.emit(); this.handleChangeDetection(); } break; // case XListAction.Set: // const newItems = model.payload as XListItem[]; if (newItems) { // this.items = [...newItems]; this.itemsChanged.emit(); this.handleChangeDetection(); } break; // case XListAction.Remove: // const mustRemoveItem = model.payload as XListItem; if (mustRemoveItem) { // const items = await this.getArrayValueAsync(this.items); this.items = [...removeItem(items, mustRemoveItem)]; this.itemsChanged.emit(); this.handleChangeDetection(); } break; // case XListAction.SelectAll: await this.selectAll(); break; // case XListAction.DeselectAll: await this.deselectAll(); break; // case XListAction.InverseSelection: await this.inverseSelection(); break; // case XListAction.Refresh: this.handleChangeDetection(); break; } }); // // Handle ActionBar Provider ... this.ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION = this.actionBarActionProvider .asObservable() .subscribe((model) => { // if (!model) { return; } // switch (model.action) { // case XActionBarAction.EnableAction: // switch (model.id) { // case DefaultActionBarItemIds.Add: // this.DISABLE_ADD = false; this.addDisablerSubject.next(false); break; // case DefaultActionBarItemIds.Remove: // this.DISABLE_REMOVE = false; this.removeDisablerSubject.next(false); break; // case DefaultActionBarItemIds.SelectAll: // this.DISABLE_SELECT_ALL = false; this.selectAllDisablerSubject.next(false); break; // case DefaultActionBarItemIds.DeSelectAll: // this.DISABLE_DESELECT_ALL = false; this.deSelectAllDisablerSubject.next(false); break; // case DefaultActionBarItemIds.InverseSelection: // this.DISABLE_INVERSE_SELECTION = false; this.inverseSelectionDisablerSubject.next(false); break; } break; // case XActionBarAction.DisbaleAction: // switch (model.id) { // case DefaultActionBarItemIds.Add: // this.DISABLE_ADD = true; this.addDisablerSubject.next(true); break; // case DefaultActionBarItemIds.Remove: // this.DISABLE_REMOVE = true; this.removeDisablerSubject.next(true); break; // case DefaultActionBarItemIds.SelectAll: // this.DISABLE_SELECT_ALL = true; this.selectAllDisablerSubject.next(true); break; // case DefaultActionBarItemIds.DeSelectAll: // this.DISABLE_DESELECT_ALL = true; this.deSelectAllDisablerSubject.next(true); break; // case DefaultActionBarItemIds.InverseSelection: // this.DISABLE_INVERSE_SELECTION = true; this.inverseSelectionDisablerSubject.next(true); break; } break; } }); } private unregisterActionProvider() { // if (this.ACTION_PROVIDER_SUBSCRIPTION) { // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } // if (this.ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION) { // this.ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION = null; } } private async handleStartup() { // await this.prepareActionBarActions(); // this.SELECTED_ITEMS = []; // const items = await this.getValueAsync( isNullOrUndefined(this.items) ? [] : this.items ); if (!hasChild(items)) { this.filteredItems = []; } else { this.filteredItems = items; } // this.issueSelectionChanged(); // this.handleChangeDetection(); } private handleChangeDetection() { // this.actionBarActionProvider.next({ action: XActionBarAction.Refresh, }); // this.searchBarActionProvider.next({ action: XSearchBarAction.Refresh, }); // this.detectChanges(); } private issueSelectionChanged() { // this.SELECTED_ITEMS = []; if (!this.selectableItems) { return; } // const selectedItems = this.filteredItems.filter((item) => item.isSelected); this.SELECTED_ITEMS = [...selectedItems]; // this.selectionChanged.emit(selectedItems); this.prepareActionBarActionsSubjects(selectedItems); } // //#region ActionBar Preparations ... private async prepareActionBarActions() { // //#region Prepare Default Actions ... const hideActions = await this.getArrayValueAsync( this.actionBarHideActions ); // let idx = 0; const defaultActions: XOneOrManyType = []; // // Remove ... const removeId = DefaultActionBarItemIds.Remove.toString(); if (!hideActions.includes(removeId)) { // defaultActions.push({ // ...defaultActionBarRemoveItem, // index: idx, disabled: this.removeDisablerSubject.asObservable(), }); // idx++; } // // Add ... const addId = DefaultActionBarItemIds.Add.toString(); if (!hideActions.includes(addId)) { // defaultActions.push({ // ...defaultActionBarAddItem, // index: idx, disabled: this.addDisablerSubject.asObservable(), }); // idx++; } // // Select All ... const selectAllId = DefaultActionBarItemIds.SelectAll.toString(); if (!hideActions.includes(selectAllId)) { // defaultActions.push({ // ...defaultActionBarSelectAllItem, // index: idx, disabled: this.selectAllDisablerSubject.asObservable(), }); // idx++; } // // Inverse Selection ... const inverseSelectionId = DefaultActionBarItemIds.InverseSelection.toString(); if (!hideActions.includes(inverseSelectionId)) { // defaultActions.push({ // ...defaultActionBarInverseSelectionItem, // index: idx, disabled: this.inverseSelectionDisablerSubject.asObservable(), }); // idx++; } // // De Select All ... const deselectAllId = DefaultActionBarItemIds.DeSelectAll.toString(); if (!hideActions.includes(deselectAllId)) { // defaultActions.push({ // ...defaultActionBarDeSelectAllItem, // index: idx, disabled: this.deSelectAllDisablerSubject.asObservable(), }); // idx++; } //#endregion // const useDefaultActions = await this.getValueAsync(this.useDefaultActions); if (!this.actionBarActions && !!useDefaultActions) { // this.actionBarActions = defaultActions; return; } // const actions = await this.getArrayValueAsync(this.actionBarActions); if (!hasChild(actions) && !!useDefaultActions) { // this.actionBarActions = defaultActions; return; } // this.actionBarActions = actions; } private async prepareActionBarActionsSubjects(items: XListItem[]) { // const listItems = await this.getValueAsync(this.items); // // Check Select All ... if (!hasChild(listItems)) { // // Remove ... if (!this.DISABLE_REMOVE) { this.removeDisablerSubject.next(true); } // // Select All ... if (!this.DISABLE_SELECT_ALL) { this.selectAllDisablerSubject.next(true); } // // Deselect All ... if (!this.DISABLE_DESELECT_ALL) { this.deSelectAllDisablerSubject.next(true); } // // Inverse Selection ... if (!this.DISABLE_INVERSE_SELECTION) { this.inverseSelectionDisablerSubject.next(true); } } else { // // DeSelectAll ... if (!hasChild(items)) { // // Remove ... if (!this.DISABLE_REMOVE) { this.removeDisablerSubject.next(true); } // // Deselect All ... if (!this.DISABLE_DESELECT_ALL) { this.deSelectAllDisablerSubject.next(true); } // // Inverse Selection ... if (!this.DISABLE_INVERSE_SELECTION) { this.inverseSelectionDisablerSubject.next(true); } } else { // // Remove ... if (!this.DISABLE_REMOVE) { this.removeDisablerSubject.next(false); } // // Deselect All ... if (!this.DISABLE_DESELECT_ALL) { this.deSelectAllDisablerSubject.next(false); } // // Inverse Selection ... if (!this.DISABLE_INVERSE_SELECTION) { this.inverseSelectionDisablerSubject.next(false); } } // if (listItems.length === items.length) { // // Select All ... if (!this.DISABLE_SELECT_ALL) { this.selectAllDisablerSubject.next(true); } // // Inverse Selection ... if (!this.DISABLE_INVERSE_SELECTION) { this.inverseSelectionDisablerSubject.next(true); } } else { // // Select All ... if (!this.DISABLE_SELECT_ALL) { this.selectAllDisablerSubject.next(false); } } } // this.handleChangeDetection(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XListComponent } from './x-list.component'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XEmptyModule } from '../x-empty/x-empty.module'; import { XActionBarModule } from '../x-action-bar/x-action-bar.module'; import { XSearchBarModule } from '../x-search-bar/x-search-bar.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XListComponent], imports: [ XIconModule, XCardModule, XEmptyModule, CommonModule, XActionBarModule, XSearchBarModule, XBaseComponentModule, ], exports: [ XIconModule, XCardModule, XEmptyModule, CommonModule, XListComponent, XActionBarModule, XSearchBarModule, XBaseComponentModule, ], }) export class XListModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-list\x-list.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, Injectable, ElementRef, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { isFile, hasChild, toJsonString, XStandardType, XOneOrManyType, toNormalString, XColorIdentifier, fileToJsonString, XResourceIdentifier, XBaseRangeRequestDto, XColorWithBrightness, } from 'x-framework-core'; import { XBaseComponentContainer, IXBaseComponentContainer, XBaseComponentContainerComponent, } from '../classes/i-x-base.container'; import { XCardEmptyActionSearchBarContainer, IXCardEmptyActionSearchBarContainer, XCardEmptyActionSearchBarContainerComponent, } from '../classes/i-x-card-empty.container'; import { XActionBarItem, XActionBarActionModel, XActionBarActionIdentifier, XActionBarActionFiredModel, } from '../x-action-bar/x-action-bar.typings'; import { XSearchBarActionModel, XSearchBarTypeIdentifier, XSearchBarEventIdentifier, } from '../x-search-bar/x-search-bar.typings'; import { concatMap, map } from 'rxjs/operators'; import { ViewportRuler } from '@angular/cdk/overlay'; import { Subject, forkJoin, Observable } from 'rxjs'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { XCardActionModel } from '../x-card/x-card.typings'; import { XEmptyActionModel } from '../x-empty/x-empty.typings'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Definitions ... export type XListItemOptionSlot = 'end' | 'start'; export interface XListItemSlideOption { id: string; icon?: XStandardType; title?: XStandardType; color?: XStandardType; onlyIcon?: XStandardType; slot: XStandardType; handler?: (info?: any) => XStandardType; disabled?: XStandardType; } export interface XListItem { data: T; hide?: XStandardType; disabled?: XStandardType; isSelected?: boolean; href?: XOneOrManyType; showDetailedIcon?: XStandardType; slideOptions?: XListItemSlideOption[]; } export interface XListItemOptionSelectedEvent { id: string; data: any; } export enum XListAction { // Add = 'add', Set = 'set', Remove = 'remove', // SelectAll = 'select_all', DeselectAll = 'deselect_all', InverseSelection = 'inverse_selection', // Refresh = 'refresh', } export type XListActionIdentifier = XListAction | string; export interface XListActionModel extends XBaseActionModel {} export type XListFilteringHandler = ( query: string, source: XListItem[] ) => XStandardType[]>; export function itemToJson(item: any) { return isFile(item) ? fileToJsonString(item) : toJsonString(item); } export const defaultListFilteringHandler: XListFilteringHandler = ( query: string, items: XListItem[] ) => { // if (!query || !hasChild(items)) { return []; } // const result = items.filter((i) => toNormalString(itemToJson(i.data)).includes(toNormalString(query)) ); // return result; }; //#endregion // //#region Container ... export interface IXListContainer extends IXCardEmptyActionSearchBarContainer { // actionProvider: Subject; cssClass: XStandardType>; // actionBarHideActions: XStandardType< XOneOrManyType >; // useDefaultActions: XStandardType; // showToolbar: XStandardType; stickyToolbar: XStandardType; // color: XStandardType; foregroundColor: XStandardType; // enableReordering: XStandardType; showDivider: XStandardType; showOptionsAsSlide: XStandardType; closeOptionsAfterSelect: XStandardType; showOptionsAsMenu: XStandardType; // selectableItems: XStandardType; clickableItems: XStandardType; itemTemplate: TemplateRef; slidingOptionTemplate: TemplateRef; nonSlidingOptionTemplate: TemplateRef; // itemSelected: EventEmitter>; optionSelected: EventEmitter; confirmRemove: XStandardType; removeItems: EventEmitter>; // selectionChanged: EventEmitter[]>; orderChanged: EventEmitter; items: XStandardType[]>; showItemOptions: XStandardType; itemsChanged: EventEmitter; filteringHandler: XListFilteringHandler; } @Injectable({ providedIn: 'root', }) export class XListContainer extends XCardEmptyActionSearchBarContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly actionBarHideActions: XStandardType< XOneOrManyType >; readonly useDefaultActions: XStandardType = true; readonly showToolbar: XStandardType = false; readonly stickyToolbar: XStandardType = true; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly enableReordering: XStandardType = false; readonly showDivider: XStandardType = true; readonly showOptionsAsSlide: XStandardType = false; readonly closeOptionsAfterSelect: XStandardType = true; readonly showOptionsAsMenu: XStandardType = false; // readonly selectableItems: XStandardType = false; readonly clickableItems: XStandardType = false; readonly itemTemplate: TemplateRef; readonly slidingOptionTemplate: TemplateRef; readonly nonSlidingOptionTemplate: TemplateRef; // readonly itemSelected: EventEmitter> = new EventEmitter< XListItem >(); readonly optionSelected: EventEmitter = new EventEmitter(); readonly confirmRemove: XStandardType = true; readonly removeItems: EventEmitter> = new EventEmitter>(); // readonly selectionChanged: EventEmitter[]> = new EventEmitter< XListItem[] >(); readonly orderChanged: EventEmitter = new EventEmitter(); readonly items: XStandardType[]> = []; readonly showItemOptions: XStandardType = true; readonly itemsChanged: EventEmitter = new EventEmitter(); readonly filteringHandler: XListFilteringHandler = defaultListFilteringHandler; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XListContainerComponent extends XCardEmptyActionSearchBarContainerComponent implements IXListContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() actionBarHideActions: XStandardType< XOneOrManyType > = this.propertyProvider.actionBarHideActions; @Input() useDefaultActions: XStandardType = this.propertyProvider.useDefaultActions; @Input() showToolbar: XStandardType = this.propertyProvider.showToolbar; @Input() stickyToolbar: XStandardType = this.propertyProvider.stickyToolbar; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Input() enableReordering: XStandardType = this.propertyProvider.enableReordering; @Input() showDivider: XStandardType = this.propertyProvider.showDivider; @Input() showOptionsAsSlide: XStandardType = this.propertyProvider.showOptionsAsSlide; @Input() closeOptionsAfterSelect: XStandardType = this.propertyProvider.closeOptionsAfterSelect; @Input() showOptionsAsMenu: XStandardType = this.propertyProvider.showOptionsAsMenu; @Input() selectableItems: XStandardType = this.propertyProvider.selectableItems; @Input() clickableItems: XStandardType = this.propertyProvider.clickableItems; @Input() itemTemplate: TemplateRef = this.propertyProvider.itemTemplate; @Input() slidingOptionTemplate: TemplateRef = this.propertyProvider.slidingOptionTemplate; @Input() nonSlidingOptionTemplate: TemplateRef = this.propertyProvider.nonSlidingOptionTemplate; // @Output() itemSelected: EventEmitter> = new EventEmitter(); @Output() optionSelected: EventEmitter = new EventEmitter(); @Input() confirmRemove: XStandardType = this.propertyProvider.confirmRemove; @Output() removeItems: EventEmitter> = new EventEmitter(); // @Output() selectionChanged: EventEmitter[]> = new EventEmitter(); @Output() orderChanged: EventEmitter = new EventEmitter(); // @Input() items: XStandardType[]> = this.propertyProvider.items; @Input() showItemOptions: XStandardType = this.propertyProvider.showItemOptions; @Output() itemsChanged: EventEmitter = new EventEmitter(); // @Input() filteringHandler: XListFilteringHandler = this.propertyProvider.filteringHandler; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XListContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXListContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ cssClass: this.getValue( container ? container.cssClass : this.cssClass ), actionBarHideActions: this.getValue( container ? container.actionBarHideActions : this.actionBarHideActions ), useDefaultActions: this.getValue( container ? container.useDefaultActions : this.useDefaultActions ), showToolbar: this.getValue( container ? container.showToolbar : this.showToolbar ), stickyToolbar: this.getValue( container ? container.stickyToolbar : this.stickyToolbar ), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), enableReordering: this.getValue( container ? container.enableReordering : this.enableReordering ), showDivider: this.getValue( container ? container.showDivider : this.showDivider ), showOptionsAsSlide: this.getValue( container ? container.showOptionsAsSlide : this.showOptionsAsSlide ), closeOptionsAfterSelect: this.getValue( container ? container.closeOptionsAfterSelect : this.closeOptionsAfterSelect ), showOptionsAsMenu: this.getValue( container ? container.showOptionsAsMenu : this.showOptionsAsMenu ), selectableItems: this.getValue( container ? container.selectableItems : this.selectableItems ), clickableItems: this.getValue( container ? container.clickableItems : this.clickableItems ), itemTemplate: this.getValue( container ? container.itemTemplate : this.itemTemplate ), slidingOptionTemplate: this.getValue( container ? container.slidingOptionTemplate : this.slidingOptionTemplate ), nonSlidingOptionTemplate: this.getValue( container ? container.nonSlidingOptionTemplate : this.nonSlidingOptionTemplate ), confirmRemove: this.getValue( container ? container.confirmRemove : this.confirmRemove ), items: this.getValue(container ? container.items : this.items), showItemOptions: this.getValue( container ? container.showItemOptions : this.showItemOptions ), filteringHandler: this.getValue( container ? container.filteringHandler : this.filteringHandler ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // itemsChanged: this.itemsChanged, itemSelected: this.itemSelected, optionSelected: this.optionSelected, removeItems: this.removeItems, selectionChanged: this.selectionChanged, orderChanged: this.orderChanged, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentListContainer = { [TKey in keyof IXListContainer as `list${Capitalize< string & TKey >}`]: IXListContainer[TKey]; }; export interface IXComponentListContainer extends TXComponentListContainer, IXBaseComponentContainer { showList: XStandardType; } @Injectable({ providedIn: 'root', }) export class XComponentListContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // //#region Self ... // readonly showList: XStandardType = true; // readonly listActionProvider: Subject = this.propertyProvider.actionProvider; readonly listCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly listActionBarHideActions: XStandardType< XOneOrManyType > = this.propertyProvider.actionBarHideActions; readonly listUseDefaultActions: XStandardType = this.propertyProvider.useDefaultActions; readonly listShowToolbar: XStandardType = this.propertyProvider.showToolbar; readonly listStickyToolbar: XStandardType = this.propertyProvider.stickyToolbar; // readonly listColor: XStandardType = this.propertyProvider.color; readonly listForegroundColor: XStandardType = this.propertyProvider.foregroundColor; // readonly listEnableReordering: XStandardType = this.propertyProvider.enableReordering; readonly listShowDivider: XStandardType = this.propertyProvider.showDivider; readonly listShowOptionsAsSlide: XStandardType = this.propertyProvider.showOptionsAsSlide; readonly listCloseOptionsAfterSelect: XStandardType = this.propertyProvider.closeOptionsAfterSelect; readonly listShowOptionsAsMenu: XStandardType = this.propertyProvider.showOptionsAsMenu; // readonly listSelectableItems: XStandardType = this.propertyProvider.selectableItems; readonly listClickableItems: XStandardType = this.propertyProvider.clickableItems; readonly listItemTemplate: TemplateRef = this.propertyProvider.itemTemplate; readonly listSlidingOptionTemplate: TemplateRef = this.propertyProvider.slidingOptionTemplate; readonly listNonSlidingOptionTemplate: TemplateRef = this.propertyProvider.nonSlidingOptionTemplate; // readonly listItemSelected: EventEmitter> = this.propertyProvider.itemSelected; readonly listOptionSelected: EventEmitter = this.propertyProvider.optionSelected; readonly listConfirmRemove: XStandardType = this.propertyProvider.confirmRemove; readonly listRemoveItems: EventEmitter> = this.propertyProvider.removeItems; // readonly listSelectionChanged: EventEmitter[]> = this.propertyProvider.selectionChanged; readonly listOrderChanged: EventEmitter = this.propertyProvider.orderChanged; readonly listItems: XStandardType[]> = this.propertyProvider.items; readonly listShowItemOptions: XStandardType = this.propertyProvider.showItemOptions; readonly listItemsChanged: EventEmitter = this.propertyProvider.itemsChanged; readonly listFilteringHandler: XListFilteringHandler = this.propertyProvider.filteringHandler; //#endregion // //#region List Card ... readonly listIsInPage: XStandardType = this.propertyProvider.isInPage; readonly listWrapWithCard: XStandardType = this.propertyProvider.wrapWithCard; readonly listCardShowFooter: XStandardType = this.propertyProvider.cardShowFooter; readonly listCardShowActions: XStandardType = this.propertyProvider.cardShowActions; readonly listCardColor: XStandardType = this.propertyProvider.cardColor; readonly listCardForegroundColor: XStandardType = this.propertyProvider.cardForegroundColor; readonly listCardTitle: XStandardType = this.propertyProvider.cardTitle; readonly listCardActionProvider: Subject = this.propertyProvider.cardActionProvider; readonly listCardSubTitle: XStandardType = this.propertyProvider.cardSubTitle; readonly listCardCssClass: XStandardType> = this.propertyProvider.cardCssClass; //#endregion // //#region List Empty ... // readonly listShowEmpty: XStandardType = this.propertyProvider.showEmpty; readonly listEmptyHasRefresh: XStandardType = this.propertyProvider.emptyHasRefresh; readonly listEmptyActionProvider: Subject = this.propertyProvider.emptyActionProvider; readonly listEmptyCssClass: XStandardType> = this.propertyProvider.emptyCssClass; readonly listEmptyColor: XStandardType = this.propertyProvider.emptyColor; readonly listEmptyForegroundColor: XStandardType = this.propertyProvider.emptyForegroundColor; readonly listEmptyMessageColor: XStandardType = this.propertyProvider.emptyMessageColor; readonly listEmptyForegroundMessageColor: XStandardType = this.propertyProvider.emptyForegroundMessageColor; readonly listEmptyRefreshButtonColor: XStandardType = this.propertyProvider.emptyRefreshButtonColor; readonly listEmptyForegroundRefreshButtonColor: XStandardType = this.propertyProvider.emptyForegroundRefreshButtonColor; readonly listEmptyMessage: XStandardType = this.propertyProvider.emptyMessage; readonly listEmptyRefreshIcon: XStandardType = this.propertyProvider.emptyRefreshIcon; readonly listEmptyRefresh: EventEmitter = this.propertyProvider.emptyRefresh; //#endregion // //#region ActionBar ... // readonly listShowActionBar: XStandardType = this.propertyProvider.showActionBar; // readonly listActionBarActionProvider: Subject = this.propertyProvider.actionBarActionProvider; readonly listActionBarCssClass: XStandardType> = this.propertyProvider.actionBarCssClass; // readonly listActionBarColor: XStandardType = this.propertyProvider.actionBarColor; readonly listActionBarForegroundColor: XStandardType = this.propertyProvider.actionBarForegroundColor; // readonly listActionBarActions: XStandardType> = this.propertyProvider.actionBarActions; // readonly listActionBarActionFired: EventEmitter = this.propertyProvider.actionBarActionFired; //#endregion // //#region SearchBar ... // readonly listShowSearchBar: XStandardType = this.propertyProvider.showSearchBar; // readonly listSearchBarActionProvider: Subject = this.propertyProvider.searchBarActionProvider; readonly listSearchBarCssClass: XStandardType> = this.propertyProvider.searchBarCssClass; // readonly listSearchBarColor: XStandardType = this.propertyProvider.searchBarColor; readonly listSearchBarForegroundColor: XStandardType = this.propertyProvider.searchBarForegroundColor; // readonly listSearchBarSearchInputColor: XStandardType = this.propertyProvider.searchBarSearchInputColor; readonly listSearchBarForegroundSearchInputColor: XStandardType = this.propertyProvider.searchBarForegroundSearchInputColor; // readonly listSearchBarType: XStandardType = this.propertyProvider.searchBarType; readonly listSearchBarTitle: XStandardType = this.propertyProvider.searchBarTitle; readonly listSearchBarValue: XStandardType = this.propertyProvider.searchBarValue; readonly listSearchBarEnterKeyHint: XStandardType = this.propertyProvider.searchBarEnterKeyHint; readonly listSearchBarKeyboardType: XStandardType = this.propertyProvider.searchBarKeyboardType; readonly listSearchBarSpellcheck: XStandardType = this.propertyProvider.searchBarSpellcheck; readonly listSearchBarDebounce: XStandardType = this.propertyProvider.searchBarDebounce; // readonly listSearchBarShowCancelButton: XStandardType = this.propertyProvider.searchBarShowCancelButton; readonly listSearchBarCancelButtonIcon: XStandardType = this.propertyProvider.searchBarCancelButtonIcon; readonly listSearchBarCancelButtonTitle: XStandardType = this.propertyProvider.searchBarCancelButtonTitle; readonly listSearchBarCancelButtonIconColor: XStandardType = this.propertyProvider.searchBarCancelButtonIconColor; // readonly listSearchBarShowClearButton: XStandardType = this.propertyProvider.searchBarShowClearButton; readonly listSearchBarClearButtonIcon: XStandardType = this.propertyProvider.searchBarClearButtonIcon; readonly listSearchBarClearButtonIconColor: XStandardType = this.propertyProvider.searchBarClearButtonIconColor; // readonly listSearchBarSearchButtonIcon: XStandardType = this.propertyProvider.searchBarSearchButtonIcon; readonly listSearchBarSearchButtonIconColor: XStandardType = this.propertyProvider.searchBarSearchButtonIconColor; // readonly listSearchBarQueryChange: EventEmitter = this.propertyProvider.searchBarQueryChange; readonly listSearchBarOnEvent: EventEmitter = this.propertyProvider.searchBarOnEvent; //#endregion //#endregion // //#region Constructor ... constructor(protected propertyProvider: XListContainer) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XComponentListContainerComponent extends XBaseComponentContainerComponent implements IXComponentListContainer { // //#region Props ... // //#region Self ... // @Input() showList: XStandardType = this.propertyProvider.showList; // @Input() listActionProvider: Subject = this.propertyProvider.listActionProvider; @Input() listCssClass: XStandardType> = this.propertyProvider.listCssClass; // @Input() listActionBarHideActions: XStandardType< XOneOrManyType > = this.propertyProvider.listActionBarHideActions; @Input() listUseDefaultActions: XStandardType = this.propertyProvider.listUseDefaultActions; @Input() listShowToolbar: XStandardType = this.propertyProvider.listShowToolbar; @Input() listStickyToolbar: XStandardType = this.propertyProvider.listStickyToolbar; // @Input() listColor: XStandardType = this.propertyProvider.listColor; @Input() listForegroundColor: XStandardType = this.propertyProvider.listForegroundColor; // @Input() listEnableReordering: XStandardType = this.propertyProvider.listEnableReordering; @Input() listShowDivider: XStandardType = this.propertyProvider.listShowDivider; @Input() listShowOptionsAsSlide: XStandardType = this.propertyProvider.listShowOptionsAsSlide; @Input() listCloseOptionsAfterSelect: XStandardType = this.propertyProvider.listCloseOptionsAfterSelect; @Input() listShowOptionsAsMenu: XStandardType = this.propertyProvider.listShowOptionsAsMenu; // @Input() listSelectableItems: XStandardType = this.propertyProvider.listSelectableItems; @Input() listClickableItems: XStandardType = this.propertyProvider.listClickableItems; @Input() listItemTemplate: TemplateRef = this.propertyProvider.listItemTemplate; @Input() listSlidingOptionTemplate: TemplateRef = this.propertyProvider.listSlidingOptionTemplate; @Input() listNonSlidingOptionTemplate: TemplateRef = this.propertyProvider.listNonSlidingOptionTemplate; // @Output() listItemSelected: EventEmitter> = new EventEmitter(); @Output() listOptionSelected: EventEmitter = new EventEmitter(); @Input() listConfirmRemove: XStandardType = this.propertyProvider.listConfirmRemove; @Output() listRemoveItems: EventEmitter> = new EventEmitter(); // @Output() listSelectionChanged: EventEmitter[]> = new EventEmitter(); @Output() listOrderChanged: EventEmitter = new EventEmitter(); @Input() listItems: XStandardType[]> = this.propertyProvider.listItems; @Input() listShowItemOptions: XStandardType = this.propertyProvider.listShowItemOptions; @Output() listItemsChanged: EventEmitter = new EventEmitter(); @Input() listFilteringHandler: XListFilteringHandler = this.propertyProvider.listFilteringHandler; //#endregion // //#region List Card ... @Input() listIsInPage: XStandardType = this.propertyProvider.listIsInPage; @Input() listWrapWithCard: XStandardType = this.propertyProvider.listWrapWithCard; @Input() listCardShowFooter: XStandardType = this.propertyProvider.listCardShowFooter; @Input() listCardShowActions: XStandardType = this.propertyProvider.listCardShowActions; @Input() listCardColor: XStandardType = this.propertyProvider.listCardColor; @Input() listCardForegroundColor: XStandardType = this.propertyProvider.listCardForegroundColor; @Input() listCardTitle: XStandardType = this.propertyProvider.listCardTitle; @Input() listCardActionProvider: Subject = this.propertyProvider.listCardActionProvider; @Input() listCardSubTitle: XStandardType = this.propertyProvider.listCardSubTitle; @Input() listCardCssClass: XStandardType> = this.propertyProvider.listCardCssClass; //#endregion // //#region List Empty ... // @Input() listShowEmpty: XStandardType = this.propertyProvider.listShowEmpty; @Input() listEmptyHasRefresh: XStandardType = this.propertyProvider.listEmptyHasRefresh; @Input() listEmptyActionProvider: Subject = this.propertyProvider.listEmptyActionProvider; @Input() listEmptyCssClass: XStandardType> = this.propertyProvider.listEmptyCssClass; @Input() listEmptyColor: XStandardType = this.propertyProvider.listEmptyColor; @Input() listEmptyForegroundColor: XStandardType = this.propertyProvider.listEmptyForegroundColor; @Input() listEmptyMessageColor: XStandardType = this.propertyProvider.listEmptyMessageColor; @Input() listEmptyForegroundMessageColor: XStandardType = this.propertyProvider.listEmptyForegroundMessageColor; @Input() listEmptyRefreshButtonColor: XStandardType = this.propertyProvider.listEmptyRefreshButtonColor; @Input() listEmptyForegroundRefreshButtonColor: XStandardType = this.propertyProvider.listEmptyForegroundRefreshButtonColor; @Input() listEmptyMessage: XStandardType = this.propertyProvider.listEmptyMessage; @Input() listEmptyRefreshIcon: XStandardType = this.propertyProvider.listEmptyRefreshIcon; @Output() listEmptyRefresh: EventEmitter = new EventEmitter(); //#endregion // //#region ActionBar ... // @Input() listShowActionBar: XStandardType = this.propertyProvider.listShowActionBar; // @Input() listActionBarActionProvider: Subject = this.propertyProvider.listActionBarActionProvider; @Input() listActionBarCssClass: XStandardType> = this.propertyProvider.listActionBarCssClass; // @Input() listActionBarColor: XStandardType = this.propertyProvider.listActionBarColor; @Input() listActionBarForegroundColor: XStandardType = this.propertyProvider.listActionBarForegroundColor; // @Input() listActionBarActions: XStandardType> = this.propertyProvider.listActionBarActions; // @Output() listActionBarActionFired: EventEmitter = new EventEmitter(); //#endregion // //#region SearchBar ... // @Input() listShowSearchBar: XStandardType = this.propertyProvider.listShowSearchBar; // @Input() listSearchBarActionProvider: Subject = this.propertyProvider.listSearchBarActionProvider; @Input() listSearchBarCssClass: XStandardType> = this.propertyProvider.listSearchBarCssClass; // @Input() listSearchBarColor: XStandardType = this.propertyProvider.listSearchBarColor; @Input() listSearchBarForegroundColor: XStandardType = this.propertyProvider.listSearchBarForegroundColor; // @Input() listSearchBarSearchInputColor: XStandardType = this.propertyProvider.listSearchBarSearchInputColor; @Input() listSearchBarForegroundSearchInputColor: XStandardType = this.propertyProvider.listSearchBarForegroundSearchInputColor; // @Input() listSearchBarType: XStandardType = this.propertyProvider.listSearchBarType; @Input() listSearchBarTitle: XStandardType = this.propertyProvider.listSearchBarTitle; @Input() listSearchBarValue: XStandardType = this.propertyProvider.listSearchBarValue; @Input() listSearchBarEnterKeyHint: XStandardType = this.propertyProvider.listSearchBarEnterKeyHint; @Input() listSearchBarKeyboardType: XStandardType = this.propertyProvider.listSearchBarKeyboardType; @Input() listSearchBarSpellcheck: XStandardType = this.propertyProvider.listSearchBarSpellcheck; @Input() listSearchBarDebounce: XStandardType = this.propertyProvider.listSearchBarDebounce; // @Input() listSearchBarShowCancelButton: XStandardType = this.propertyProvider.listSearchBarShowCancelButton; @Input() listSearchBarCancelButtonIcon: XStandardType = this.propertyProvider.listSearchBarCancelButtonIcon; @Input() listSearchBarCancelButtonTitle: XStandardType = this.propertyProvider.listSearchBarCancelButtonTitle; @Input() listSearchBarCancelButtonIconColor: XStandardType = this.propertyProvider.listSearchBarCancelButtonIconColor; // @Input() listSearchBarShowClearButton: XStandardType = this.propertyProvider.listSearchBarShowClearButton; @Input() listSearchBarClearButtonIcon: XStandardType = this.propertyProvider.listSearchBarClearButtonIcon; @Input() listSearchBarClearButtonIconColor: XStandardType = this.propertyProvider.listSearchBarClearButtonIconColor; // @Input() listSearchBarSearchButtonIcon: XStandardType = this.propertyProvider.listSearchBarSearchButtonIcon; @Input() listSearchBarSearchButtonIconColor: XStandardType = this.propertyProvider.listSearchBarSearchButtonIconColor; // @Output() listSearchBarQueryChange: EventEmitter = new EventEmitter(); @Output() listSearchBarOnEvent: EventEmitter = new EventEmitter(); //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XComponentListContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXComponentListContainer ): Observable { return forkJoin({ // showList: this.getValue(container ? container.showList : this.showList), listCssClass: this.getValue( container ? container.listCssClass : this.listCssClass ), listActionBarHideActions: this.getValue( container ? container.listActionBarHideActions : this.listActionBarHideActions ), listUseDefaultActions: this.getValue( container ? container.listUseDefaultActions : this.listUseDefaultActions ), listShowToolbar: this.getValue( container ? container.listShowToolbar : this.listShowToolbar ), listStickyToolbar: this.getValue( container ? container.listStickyToolbar : this.listStickyToolbar ), listColor: this.getValue( container ? container.listColor : this.listColor ), listForegroundColor: this.getValue( container ? container.listForegroundColor : this.listForegroundColor ), listEnableReordering: this.getValue( container ? container.listEnableReordering : this.listEnableReordering ), listShowDivider: this.getValue( container ? container.listShowDivider : this.listShowDivider ), listShowOptionsAsSlide: this.getValue( container ? container.listShowOptionsAsSlide : this.listShowOptionsAsSlide ), listCloseOptionsAfterSelect: this.getValue( container ? container.listCloseOptionsAfterSelect : this.listCloseOptionsAfterSelect ), listShowOptionsAsMenu: this.getValue( container ? container.listShowOptionsAsMenu : this.listShowOptionsAsMenu ), listSelectableItems: this.getValue( container ? container.listSelectableItems : this.listSelectableItems ), listClickableItems: this.getValue( container ? container.listClickableItems : this.listClickableItems ), listItemTemplate: this.getValue( container ? container.listItemTemplate : this.listItemTemplate ), listSlidingOptionTemplate: this.getValue( container ? container.listSlidingOptionTemplate : this.listSlidingOptionTemplate ), listNonSlidingOptionTemplate: this.getValue( container ? container.listNonSlidingOptionTemplate : this.listNonSlidingOptionTemplate ), listConfirmRemove: this.getValue( container ? container.listConfirmRemove : this.listConfirmRemove ), listItems: this.getValue( container ? container.listItems : this.listItems ), listShowItemOptions: this.getValue( container ? container.listShowItemOptions : this.listShowItemOptions ), listFilteringHandler: this.getValue( container ? container.listFilteringHandler : this.listFilteringHandler ), listIsInPage: this.getValue( container ? container.listIsInPage : this.listIsInPage ), listWrapWithCard: this.getValue( container ? container.listWrapWithCard : this.listWrapWithCard ), listCardShowFooter: this.getValue( container ? container.listCardShowFooter : this.listCardShowFooter ), listCardShowActions: this.getValue( container ? container.listCardShowActions : this.listCardShowActions ), listCardColor: this.getValue( container ? container.listCardColor : this.listCardColor ), listCardForegroundColor: this.getValue( container ? container.listCardForegroundColor : this.listCardForegroundColor ), listCardTitle: this.getValue( container ? container.listCardTitle : this.listCardTitle ), listCardSubTitle: this.getValue( container ? container.listCardSubTitle : this.listCardSubTitle ), listCardCssClass: this.getValue( container ? container.listCardCssClass : this.listCardCssClass ), listShowEmpty: this.getValue( container ? container.listShowEmpty : this.listShowEmpty ), listEmptyHasRefresh: this.getValue( container ? container.listEmptyHasRefresh : this.listEmptyHasRefresh ), listEmptyCssClass: this.getValue( container ? container.listEmptyCssClass : this.listEmptyCssClass ), listEmptyColor: this.getValue( container ? container.listEmptyColor : this.listEmptyColor ), listEmptyForegroundColor: this.getValue( container ? container.listEmptyForegroundColor : this.listEmptyForegroundColor ), listEmptyMessageColor: this.getValue( container ? container.listEmptyMessageColor : this.listEmptyMessageColor ), listEmptyForegroundMessageColor: this.getValue( container ? container.listEmptyForegroundMessageColor : this.listEmptyForegroundMessageColor ), listEmptyRefreshButtonColor: this.getValue( container ? container.listEmptyRefreshButtonColor : this.listEmptyRefreshButtonColor ), listEmptyForegroundRefreshButtonColor: this.getValue( container ? container.listEmptyForegroundRefreshButtonColor : this.listEmptyForegroundRefreshButtonColor ), listEmptyMessage: this.getValue( container ? container.listEmptyMessage : this.listEmptyMessage ), listEmptyRefreshIcon: this.getValue( container ? container.listEmptyRefreshIcon : this.listEmptyRefreshIcon ), listShowActionBar: this.getValue( container ? container.listShowActionBar : this.listShowActionBar ), listActionBarCssClass: this.getValue( container ? container.listActionBarCssClass : this.listActionBarCssClass ), listActionBarColor: this.getValue( container ? container.listActionBarColor : this.listActionBarColor ), listActionBarForegroundColor: this.getValue( container ? container.listActionBarForegroundColor : this.listActionBarForegroundColor ), listActionBarActions: this.getValue( container ? container.listActionBarActions : this.listActionBarActions ), listShowSearchBar: this.getValue( container ? container.listShowSearchBar : this.listShowSearchBar ), listSearchBarCssClass: this.getValue( container ? container.listSearchBarCssClass : this.listSearchBarCssClass ), listSearchBarColor: this.getValue( container ? container.listSearchBarColor : this.listSearchBarColor ), listSearchBarForegroundColor: this.getValue( container ? container.listSearchBarForegroundColor : this.listSearchBarForegroundColor ), listSearchBarSearchInputColor: this.getValue( container ? container.listSearchBarSearchInputColor : this.listSearchBarSearchInputColor ), listSearchBarForegroundSearchInputColor: this.getValue( container ? container.listSearchBarForegroundSearchInputColor : this.listSearchBarForegroundSearchInputColor ), listSearchBarType: this.getValue( container ? container.listSearchBarType : this.listSearchBarType ), listSearchBarTitle: this.getValue( container ? container.listSearchBarTitle : this.listSearchBarTitle ), listSearchBarValue: this.getValue( container ? container.listSearchBarValue : this.listSearchBarValue ), listSearchBarEnterKeyHint: this.getValue( container ? container.listSearchBarEnterKeyHint : this.listSearchBarEnterKeyHint ), listSearchBarKeyboardType: this.getValue( container ? container.listSearchBarKeyboardType : this.listSearchBarKeyboardType ), listSearchBarSpellcheck: this.getValue( container ? container.listSearchBarSpellcheck : this.listSearchBarSpellcheck ), listSearchBarDebounce: this.getValue( container ? container.listSearchBarDebounce : this.listSearchBarDebounce ), listSearchBarShowCancelButton: this.getValue( container ? container.listSearchBarShowCancelButton : this.listSearchBarShowCancelButton ), listSearchBarCancelButtonIcon: this.getValue( container ? container.listSearchBarCancelButtonIcon : this.listSearchBarCancelButtonIcon ), listSearchBarCancelButtonTitle: this.getValue( container ? container.listSearchBarCancelButtonTitle : this.listSearchBarCancelButtonTitle ), listSearchBarCancelButtonIconColor: this.getValue( container ? container.listSearchBarCancelButtonIconColor : this.listSearchBarCancelButtonIconColor ), listSearchBarShowClearButton: this.getValue( container ? container.listSearchBarShowClearButton : this.listSearchBarShowClearButton ), listSearchBarClearButtonIcon: this.getValue( container ? container.listSearchBarClearButtonIcon : this.listSearchBarClearButtonIcon ), listSearchBarClearButtonIconColor: this.getValue( container ? container.listSearchBarClearButtonIconColor : this.listSearchBarClearButtonIconColor ), listSearchBarSearchButtonIcon: this.getValue( container ? container.listSearchBarSearchButtonIcon : this.listSearchBarSearchButtonIcon ), listSearchBarSearchButtonIconColor: this.getValue( container ? container.listSearchBarSearchButtonIconColor : this.listSearchBarSearchButtonIconColor ), }).pipe( map((data) => { return { // ...data, // listActionProvider: container ? container.listActionProvider : this.listActionProvider, // listItemSelected: this.listItemSelected, listOptionSelected: this.listOptionSelected, listRemoveItems: this.listRemoveItems, listSelectionChanged: this.listSelectionChanged, listOrderChanged: this.listOrderChanged, listItemsChanged: this.listItemsChanged, // listCardActionProvider: container ? container.listCardActionProvider : this.listCardActionProvider, listEmptyActionProvider: container ? container.listEmptyActionProvider : this.listEmptyActionProvider, // listEmptyRefresh: this.listEmptyRefresh, // listActionBarActionProvider: container ? container.listActionBarActionProvider : this.listActionBarActionProvider, // listActionBarActionFired: this.listActionBarActionFired, // listSearchBarActionProvider: container ? container.listSearchBarActionProvider : this.listSearchBarActionProvider, // listSearchBarQueryChange: this.listSearchBarQueryChange, listSearchBarOnEvent: this.listSearchBarOnEvent, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.component.html
{{ item.data.display_name }} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.component.scss :host { --map-height: 200px; --map-controls-offest: 5px; } :host ::ng-deep .x-auto-size-flex { flex-grow: 0 !important; flex-shrink: 1 !important; flex-basis: auto !important; } .x-map { position: relative; } .x-map-inner { height: var(--map-height); width: 100%; } .x-map-top, .x-map-bottom { width: 100%; position: absolute; background-color: transparent; } .x-map-top { top: 0; } .x-map-bottom { bottom: 0; } .x-map-plugins-wrapper { margin: .5em; } .x-map-plugin { &.ol-control { padding: 0; position: relative; margin-top: 0 !important; } button { padding: 3px; width: fit-content; display: inline-block; } } // //#region Search Result ... // $duration: 250ms; $transform-show: scaleY(1); $transform-hide: scaleY(0); // .x-map-search-list { // position: absolute; // z-index: 110; // top: 0; left: 0; right: 0; height: 0; // transform: $transform-hide; -ms-transform: $transform-hide; -webkit-transform: $transform-hide; // transition: transform; -webkit-transition: transform; // transition-duration: $duration; -webkit-transition-duration: $duration; // &.open { // height: auto; // transform: $transform-show; -ms-transform: $transform-show; -webkit-transform: $transform-show; // transition-duration: $duration; -webkit-transition-duration: $duration; } // &.has-search { top: 56px; } } //#endregion // //#region Ol Theme ... :host ::ng-deep { .x-content.mat-card-content { padding: 0 !important; } .ol-control { margin-top: var(--map-controls-offest); } .ol-box { box-sizing: border-box; border-radius: 2px; border: 2px solid blue; } .ol-mouse-position { top: 8px; right: 8px; position: absolute; } .ol-scale-line { background: rgba(0, 60, 136, 0.3); border-radius: 4px; bottom: 8px; left: 8px; padding: 2px; position: absolute; } .ol-scale-line-inner { border: 1px solid #eee; border-top: none; color: #eee; font-size: 10px; text-align: center; margin: 1px; will-change: contents, width; transition: all 0.25s; } .ol-scale-bar { position: absolute; bottom: 8px; left: 8px; } .ol-scale-step-marker { width: 1px; height: 15px; background-color: #000000; float: right; z-index: 10; } .ol-scale-step-text { position: absolute; bottom: -5px; font-size: 12px; z-index: 11; color: #000000; text-shadow: -2px 0 #ffffff, 0 2px #ffffff, 2px 0 #ffffff, 0 -2px #ffffff; } .ol-scale-text { position: absolute; font-size: 14px; text-align: center; bottom: 25px; color: #000000; text-shadow: -2px 0 #ffffff, 0 2px #ffffff, 2px 0 #ffffff, 0 -2px #ffffff; } .ol-scale-singlebar { position: relative; height: 10px; z-index: 9; border: 1px solid black; } .ol-unsupported { display: none; } .ol-viewport, .ol-unselectable { -webkit-touch-callout: none; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); } .ol-selectable { -webkit-touch-callout: default; -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; } .ol-grabbing { cursor: -webkit-grabbing; cursor: -moz-grabbing; cursor: grabbing; } .ol-grab { cursor: move; cursor: -webkit-grab; cursor: -moz-grab; cursor: grab; } .ol-control { position: absolute; background-color: rgba(255, 255, 255, 0.4); border-radius: 4px; padding: 2px; } .ol-control:hover { background-color: rgba(255, 255, 255, 0.6); } .ol-zoom { top: 0.5em; left: 0.5em; } .ol-rotate { top: 0.5em; right: 0.5em; transition: opacity 0.25s linear, visibility 0s linear; } .ol-rotate.ol-hidden { opacity: 0; visibility: hidden; transition: opacity 0.25s linear, visibility 0s linear 0.25s; } .ol-zoom-extent { top: 4.643em; left: 0.5em; } .ol-full-screen { right: 0.5em; top: 0.5em; } .ol-control button { display: block; margin: 1px; padding: 0; color: white; font-size: 1.14em; font-weight: bold; text-decoration: none; text-align: center; height: 1.375em; width: 1.375em; line-height: 0.4em; background-color: rgba(0, 60, 136, 0.5); border: none; border-radius: 2px; } .ol-control button::-moz-focus-inner { border: none; padding: 0; } .ol-zoom-extent button { line-height: 1.4em; } .ol-compass { display: block; font-weight: normal; font-size: 1.2em; will-change: transform; } .ol-touch .ol-control button { font-size: 1.5em; } .ol-touch .ol-zoom-extent { top: 5.5em; } .ol-control button:hover, .ol-control button:focus { text-decoration: none; background-color: rgba(0, 60, 136, 0.7); } .ol-zoom .ol-zoom-in { border-radius: 2px 2px 0 0; } .ol-zoom .ol-zoom-out { border-radius: 0 0 2px 2px; } .ol-attribution { text-align: right; bottom: 0.5em; right: 0.5em; max-width: calc(100% - 1.3em); } .ol-attribution ul { margin: 0; padding: 0 0.5em; color: #000; text-shadow: 0 0 2px #fff; } .ol-attribution li { display: inline; list-style: none; } .ol-attribution li:not(:last-child):after { content: ' '; } .ol-attribution img { max-height: 2em; max-width: inherit; vertical-align: middle; } .ol-attribution ul, .ol-attribution button { display: inline-block; } .ol-attribution.ol-collapsed ul { display: none; } .ol-attribution:not(.ol-collapsed) { background: rgba(255, 255, 255, 0.8); } .ol-attribution.ol-uncollapsible { bottom: 0; right: 0; border-radius: 4px 0 0; } .ol-attribution.ol-uncollapsible img { margin-top: -0.2em; max-height: 1.6em; } .ol-attribution.ol-uncollapsible button { display: none; } .ol-zoomslider { top: 4.5em; left: 0.5em; height: 200px; } .ol-zoomslider button { position: relative; height: 10px; } .ol-touch .ol-zoomslider { top: 5.5em; } .ol-overviewmap { left: 0.5em; bottom: 0.5em; } .ol-overviewmap.ol-uncollapsible { bottom: 0; left: 0; border-radius: 0 4px 0 0; } .ol-overviewmap .ol-overviewmap-map, .ol-overviewmap button { display: inline-block; } .ol-overviewmap .ol-overviewmap-map { border: 1px solid #7b98bc; height: 150px; margin: 2px; width: 150px; } .ol-overviewmap:not(.ol-collapsed) button { bottom: 1px; left: 2px; position: absolute; } .ol-overviewmap.ol-collapsed .ol-overviewmap-map, .ol-overviewmap.ol-uncollapsible button { display: none; } .ol-overviewmap:not(.ol-collapsed) { background: rgba(255, 255, 255, 0.8); } .ol-overviewmap-box { border: 2px dotted rgba(0, 60, 136, 0.7); } .ol-overviewmap .ol-overviewmap-box:hover { cursor: move; } // // Disable Attribution ... .ol-attribution { display: none !important; } } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.component.ts import { of, Subject, forkJoin, Observable, throwError, Subscription, } from 'rxjs'; import { Component, ViewChild, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { XMapAction, XMapCSSVar, XPlaceResult, XMapLocation, XMapActionModel, XMapItemPosition, XMapContainerComponent, XMapItemPositionIdentifier, } from './x-map.typings'; import { DragPan, DragZoom, PinchZoom, DragRotate, Interaction, PinchRotate, KeyboardPan, KeyboardZoom, MouseWheelZoom, DoubleClickZoom, } from 'ol/interaction'; import { tap, map, concatMap, catchError, debounceTime, distinctUntilChanged, } from 'rxjs/operators'; import { nameof, XHeader, applyLocale, applyFinally, XContentType, generateUuid, XExceptionIDs, XStandardType, toNormalString, isNullOrUndefined, isNullOrEmptyString, } from 'x-framework-core'; import { Point } from 'ol/geom'; import BaseLayer from 'ol/layer/Base'; import { MapOptions } from 'ol/PluggableMap'; import { XSearchBarEvent, XSearchBarEventIdentifier, } from '../x-search-bar/x-search-bar.typings'; import { toMapLocation } from './x-map.tools'; import { fromLonLat, transform } from 'ol/proj'; import { HttpHeaders } from '@angular/common/http'; import { XListItem } from '../x-list/x-list.typings'; import { OSM, Vector as VectorSource } from 'ol/source'; import { Map, View, Feature, Overlay, Kinetic } from 'ol'; import { Zoom, Rotate, ZoomSlider, Control } from 'ol/control'; import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'; import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings'; import { XSearchBarComponent } from '../x-search-bar/x-search-bar.component'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-map', templateUrl: './x-map.component.html', styleUrls: ['./x-map.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XMapComponent extends XMapContainerComponent { // //#region Props ... // private ZOOM_DELTA = 2; private IMPORTANT_ZOOM = 18; private MAP: Map = undefined; private ANIMATION_DURATION = 500; private MARKER: VectorLayer; private ZOOM_CONTROL = new Zoom(); private IS_MAP_INITIALIZED = false; private MARKER_POSITION: XMapLocation; private ROTATE_CONTROL = new Rotate(); private ACTION_WAITIONG_DURATION = 500; private MAP_OPTIONS: MapOptions = undefined; private ZOOM_SLIDER_CONTROL = new ZoomSlider(); private positionProvider = new Subject(); private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private searchFilterSubject$ = new Subject(); // readonly SlotNames = Object.assign({}, XSlotName); readonly componentId = generateUuid('XMapComponent'); readonly SlotLayouts = Object.assign({}, XSlotLayout); readonly ItemPositions = Object.assign({}, XMapItemPosition); // isSearching = false; searchPaneOpen = false; currentPosition: string = ''; searchResult: XPlaceResult[] = []; showMapView: XStandardType = false; searchResultListItems: XListItem[] = []; // get isInitialized() { return this.IS_MAP_INITIALIZED; } get map() { return this.MAP; } get options() { return this.MAP_OPTIONS as MapOptions; } get hasMarker() { return !isNullOrUndefined(this.MARKER); } get markerPosition() { return this.MARKER_POSITION; } get currentZoom() { return !this.isInitialized ? -1 : this.MAP.getView().getZoom(); } get currentLatitude() { // if (!this.isInitialized) { return -1; } // const lonLat = this.map.getView().getCenter(); const location = toMapLocation(lonLat); // return +location.latitude; } get currentLongitude() { // if (!this.isInitialized) { return -1; } // const lonLat = this.map.getView().getCenter(); const location = toMapLocation(lonLat); // return +location.longitude; } @ViewChild('mapView') mapView: ElementRef; @ViewChild('pluginsBar') pluginsBar: ElementRef; @ViewChild('searchBar') searchBar: XSearchBarComponent; //#endregion // //#region LifeCycles ... async afterViewInit() { super.afterViewInit(); // await this.initializeMap(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region CanSelect Change ... const isCanSelectChanged = changeKeys.includes( nameof('canSelect') ); if (isCanSelectChanged) { await this.applyCanSelect(); } //#endregion // //#region ActionProvider changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Location Info changed ... // const isZoomChanged = changeKeys.includes(nameof('zoom')); // const isLatitudeChanged = changeKeys.includes( // nameof('latitude') // ); // const isLongitudeChanged = changeKeys.includes( // nameof('longitude') // ); // const isAddMarkerOnSelectedLocationChanged = changeKeys.includes( // nameof('addMarkerOnSelectedLocation') // ); // if ( // isZoomChanged || // isLatitudeChanged || // isLongitudeChanged || // isAddMarkerOnSelectedLocationChanged // ) { // await this.applyLocationInfo(); // } //#endregion // //#region Show Zoom changed ... const isShowZoomChanged = changeKeys.includes( nameof('showZoom') ); if (isShowZoomChanged) { await this.applyZoom(); } //#endregion // //#region Show Rotate changed ... const isShowRotateChanged = changeKeys.includes( nameof('showRotate') ); if (isShowRotateChanged) { await this.applyRotate(); } //#endregion // //#region Show Zoom Slider changed ... const isShowZoomSliderChanged = changeKeys.includes( nameof('showZoomSlider') ); if (isShowZoomSliderChanged) { await this.applyZoomSlider(); } //#endregion // //#region Offset Height Handling ... const isShowSearchBarChanged = changeKeys.includes( nameof('showSearchBar') ); const isSearchBarPositionChanged = changeKeys.includes( nameof('searchBarPosition') ); const isShowSelectedLoactionChanged = changeKeys.includes( nameof('showSelectedLocation') ); const isSelectedLocationPositionChanged = changeKeys.includes( nameof('selectedLocationPosition') ); if ( isShowRotateChanged || isShowZoomChanged || isShowZoomSliderChanged || isShowSearchBarChanged || isSearchBarPositionChanged || isShowSelectedLoactionChanged || isSelectedLocationPositionChanged ) { await this.applyContentOffset(); } //#endregion } registerViewHandlers() { super.registerViewHandlers(); // // Register Action Provider ... this.registerActionProvider(); // // Register Search ... this.registerPluginHandler(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Providers ... async getCenter( latitude?: number | XStandardType, longitude?: number | XStandardType ) { // const desiredLatitude = await this.getNormallizedLatitued(latitude); const desiredLongitude = await this.getNormallizedLongitude(longitude); const result = fromLonLat([desiredLongitude, desiredLatitude]); // return result; } //#endregion // //#region UI Providers ... canShowPlugins(position: XMapItemPositionIdentifier) { return this.getValue(position).pipe( concatMap((pos) => isNullOrEmptyString(pos) ? of(false) : forkJoin({ // // progressBar: forkJoin({ // canShow: this.getValue(this.showProgressBar), // position: this.getValue(this.progressBarPosition), // }), // locator: forkJoin({ canShow: this.getValue(this.showLocator), position: this.getValue(this.locatorPosition), }), // clearMarker: forkJoin({ canShow: this.getValue(this.showClearMarker), position: this.getValue(this.clearMarkerPosition), }), // goMarkedPlace: forkJoin({ canShow: this.getValue(this.showGoMarkedPlace), position: this.getValue(this.goMarkedPlacePosition), }), // selectedLocation: forkJoin({ canShow: this.getValue(this.showSelectedLocation), position: this.getValue(this.selectedLocationPosition), }), }).pipe( map((info) => { return { pos, info, }; }), map((data) => { return ( // // ProgressBar ... // (data.info.progressBar.canShow && // data.info.progressBar.position === data.pos) || // // Locator ... (data.info.locator.canShow && data.info.locator.position === data.pos) || // // ClearMarker ... (data.info.clearMarker.canShow && data.info.clearMarker.position === data.pos) || // // Go Marked Place ... (data.info.goMarkedPlace.canShow && data.info.goMarkedPlace.position === data.pos) || // // Selected Location ... (data.info.selectedLocation.canShow && data.info.selectedLocation.position === data.pos) ); }) ) ) ); } //#endregion // //#region UI Handlers ... async handleSeach(query: string) { // this.searchBarQueryChange.emit(query); // if (this.isSearching) { // setTimeout( async () => await this.handleSeach(query), this.ACTION_WAITIONG_DURATION ); // return; } // if (isNullOrEmptyString(query)) { // this.searchResult = []; this.isSearching = false; this.searchPaneOpen = false; this.searchResultListItems = []; await this.setLoadingState(false); return; } // query = toNormalString(query); this.searchFilterSubject$.next(query); } async handleSearchBarEvents(event: XSearchBarEventIdentifier) { // switch (event) { // case XSearchBarEvent.FOCUS: // setTimeout(() => { // this.searchPaneOpen = this.hasChild(this.searchResult) && this.hasChild(this.searchResultListItems); // this.detectChanges(); }, this.ACTION_WAITIONG_DURATION); break; // case XSearchBarEvent.BLUR: // setTimeout(() => { // this.searchPaneOpen = false; this.detectChanges(); }, this.ACTION_WAITIONG_DURATION); break; } } async handleChangeLocation(item: XListItem) { // const zoom = this.IMPORTANT_ZOOM - 4; const addMarker = await this.getValueAsync( this.addMarkerOnSelectedLocation ); if (addMarker) { await this.addMarker(item.data.lat, item.data.lon, zoom); } else { await this.setCenter(item.data.lat, item.data.lon, zoom); } } async handleLocationResultClickOutside(event: any) { // this.searchPaneOpen = false; this.detectChanges(); } async handleGoMarkedPlace() { await this.goMarkedPlace(); } async handleClearMarker() { await this.clearMarker(); } async handleLocate() { await this.locate(); } async handleSlectedLocationClicked(message: string) { // message = applyLocale(message, 'en-US'); this.managerService.saveToClipboard(message); } //#endregion // //#region Actions ... async updateMap() { // // Recalling ... if (!this.isInitialized) { setTimeout(async () => { await this.updateMap(); }, this.ACTION_WAITIONG_DURATION); // return; } // //#region Update ... this.MAP.render(); this.detectChanges(); this.MAP.updateSize(); this.MAP.renderSync(); this.managerService.dispatchResizeEvent(); if (this.mapView && this.mapView.nativeElement) { // const mapView = this.mapView.nativeElement as HTMLElement; mapView.blur(); mapView.focus(); } //#endregion // setTimeout(async () => { await this.updateMap(); }, this.ACTION_WAITIONG_DURATION); } async setZoom(zoom?: number | XStandardType) { // const desiredZoom = await this.getNormallizedZoom(zoom); // if (!this.isInitialized) { // setTimeout(async () => { await this.setZoom(zoom); }, this.ACTION_WAITIONG_DURATION); // return; } // this.map.getView().animate({ zoom: desiredZoom, duration: this.ANIMATION_DURATION, }); } async setCenter( latitude?: number | XStandardType, longitude?: number | XStandardType, zoom?: number | XStandardType ) { // const desiredZoom = await this.getNormallizedZoom(zoom); const center = await this.getCenter(latitude, longitude); // if (!this.isInitialized) { // setTimeout(async () => { await this.setCenter(latitude, longitude, zoom); }, this.ACTION_WAITIONG_DURATION); // return; } // this.map.getView().animate({ center, zoom: desiredZoom, duration: this.ANIMATION_DURATION, }); } async addMarker( latitude?: number | XStandardType, longitude?: number | XStandardType, zoom?: number | XStandardType ) { // if (!this.isInitialized) { // setTimeout(async () => { await this.addMarker(latitude, longitude, zoom); }, this.ACTION_WAITIONG_DURATION); // return; } // const desiredZoom = await this.getNormallizedZoom(zoom); const desiredLat = await this.getNormallizedLatitued(latitude); const desiredLong = await this.getNormallizedLongitude(longitude); // if (this.MARKER) { // this.MAP.removeLayer(this.MARKER); this.MARKER = null; this.actionProvider.next({ action: XMapAction.HasNotMarker }); } // this.MARKER_POSITION = { zoom: desiredZoom.toString(), latitude: desiredLat.toString(), longitude: desiredLong.toString(), }; // const markerStyle = await this.getValueAsync(this.markerStyle); // this.MARKER = new VectorLayer({ source: new VectorSource({ features: [ new Feature({ geometry: new Point( transform([desiredLong, desiredLat], 'EPSG:4326', 'EPSG:3857') ), }), ], }), style: markerStyle, }); // // Netify Selected Location ... await this.updateSelectedLocation(latitude, longitude); this.actionProvider.next({ action: XMapAction.HasMarker }); // // Emit Location Selected Event ... this.locationSelected.emit(this.MARKER_POSITION); // this.MAP.addLayer(this.MARKER); // setTimeout(async () => { await this.setCenter(desiredLat, desiredLong, desiredZoom); }, this.ACTION_WAITIONG_DURATION); } async clearMarker() { // if (!this.MARKER) { return; } // if (!this.isInitialized) { // setTimeout(async () => { await this.clearMarker(); }, this.ACTION_WAITIONG_DURATION); // return; } // this.MAP.removeLayer(this.MARKER); this.MARKER = null; this.MARKER_POSITION = null; // this.positionProvider.next(''); this.actionProvider.next({ action: XMapAction.HasNotMarker, }); } async goMarkedPlace() { // if (!this.hasMarker) { return; } // if (!this.isInitialized) { // setTimeout(async () => { await this.goMarkedPlace(); }, this.ACTION_WAITIONG_DURATION); // return; } // await this.setCenter( +this.markerPosition.latitude, +this.markerPosition.longitude ); } async locate() { // await this.setLoadingState(true); const location = await this.getValueAsync( applyFinally( this.managerService.geoLocationService.getCurrentLocation().pipe( catchError((err) => { // this.showError(err); // return throwError(err); }) ), async () => await this.setLoadingState(false) ) ); // if (!isNullOrUndefined(location)) { // this.zoom = this.IMPORTANT_ZOOM; this.latitude = location.coords.latitude; this.longitude = location.coords.longitude; // await this.addMarker( location.coords.latitude, location.coords.longitude, this.zoom ); } } //#endregion // //#region Private ... private async prepareMapOptions() { // this.MAP = null; this.MAP_OPTIONS = null; this.showMapView = false; // const zoom = 0; // await this.getNormallizedZoom(); // const desiredLatitude = 0; // await this.getNormallizedLatitued(); const desiredLongitude = 0; // await this.getNormallizedLongitude(); const center = fromLonLat([desiredLatitude, desiredLongitude]); // const view = new View({ zoom, center, }); // const layers: BaseLayer[] = []; layers.push( new TileLayer({ source: new OSM(), }) ); // const controls: Control[] = await this.getControls(); // const interactions: Interaction[] = await this.getInteractions(); // const overlays: Overlay[] = []; // this.MAP_OPTIONS = { view, layers, controls, overlays, target: this.componentId, interactions, keyboardEventTarget: this.componentId, }; } private async initializeMap() { // if (!isNullOrUndefined(this.MAP)) { this.MAP = null; } // await this.prepareMapOptions(); // this.MAP = new Map(this.options); // //#region Attached Events ... // // Map Event Handler ... this.MAP.on('rendercomplete', async (e: any) => { // this.isReady.emit(); // this.IS_MAP_INITIALIZED = true; // this.managerService.dispatchResizeEvent(); Promise.resolve().then(() => this.managerService.dispatchResizeEvent()); setTimeout( () => this.managerService.dispatchResizeEvent(), this.ACTION_WAITIONG_DURATION ); }); // // Zoom End ... this.MAP.on('moveend', async (e: any) => { // const zoom = this.map.getView().getZoom(); const lonLat = this.map.getView().getCenter(); const location = toMapLocation(lonLat); location.zoom = zoom.toString(); // this.zoom = zoom; // this.viewChanged.emit(location); }); //#endregion // this.showMapView = true; await this.applyContentOffset(); await this.updateMap(); await this.applyCanSelect(); // await this.applyLocationInfo(); } private async getInteractions() { // const result: Interaction[] = []; // const delta = this.ZOOM_DELTA; const duration = this.ANIMATION_DURATION; // const dragPan = true; const pinchZoom = true; const onFocusOnly = true; const pinchRotate = true; const keyboardPan = true; const keyboardZoom = true; const shiftDragZoom = true; const mouseWheelZoom = true; const doubleClickZoom = true; const altShiftDragRotate = true; // //#region Preperation ... // // DragRotate ... const kinetic = new Kinetic(-0.005, 0.05, 100); if (altShiftDragRotate) { result.push(new DragRotate()); } // // DoubleClickZoom ... if (doubleClickZoom) { result.push( new DoubleClickZoom({ delta, duration, }) ); } // // DragPan ... if (dragPan) { result.push( new DragPan({ onFocusOnly, kinetic, }) ); } // // PinchRotate ... if (pinchRotate) { result.push(new PinchRotate()); } // // PinchZoom ... if (pinchZoom) { result.push( new PinchZoom({ duration, }) ); } // // KeyboardPan ... if (keyboardPan) { result.push(new KeyboardPan()); } // // KeyboardZoom ... if (keyboardZoom) { result.push( new KeyboardZoom({ delta, duration, }) ); } // // MouseWheelZoom ... if (mouseWheelZoom) { result.push( new MouseWheelZoom({ duration, onFocusOnly, }) ); } // // DragZoom ... if (shiftDragZoom) { result.push( new DragZoom({ duration, }) ); } //#endregion // return result; } private async getControls() { // const result: Control[] = []; // //#region Adding Controls ... // // Zoom ... const showZoom = await this.getValueAsync(this.showZoom); if (showZoom) { result.push(this.ZOOM_CONTROL); } // // Rotate ... const showRotate = await this.getValueAsync(this.showRotate); if (showRotate) { result.push(this.ROTATE_CONTROL); } // // ZoomSlider ... const showZoomSlider = await this.getValueAsync(this.showZoomSlider); if (showZoomSlider) { result.push(this.ZOOM_SLIDER_CONTROL); } //#endregion // return result; } private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XMapAction.AddMarker: // if (model.payload) { // const result: XMapLocation = model.payload; if (result) { // const lat = +result.latitude; const long = +result.longitude; const zoom = +result.zoom; // await this.addMarker(lat, long, zoom); } } break; // case XMapAction.ClearMarker: await this.clearMarker(); break; // case XMapAction.GoMarkedPlace: await this.goMarkedPlace(); break; // case XMapAction.SetCenter: // if (model.payload) { // const result: XMapLocation = model.payload; if (result) { // const zoom = +result.zoom; const lat = +result.latitude; const long = +result.longitude; // await this.setCenter(lat, long, zoom); } } break; // case XMapAction.SetZoom: // if (model.payload) { // const zoom = +model.payload; await this.setZoom(zoom); } break; // case XMapAction.Locate: await this.locate(); break; // case XMapAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } private registerPluginHandler() { // // Register Query Change ... this.applyTakeUntilWrapper( this.searchFilterSubject$ .asObservable() .pipe(debounceTime(800), distinctUntilChanged()) ).subscribe(async (query) => { await this.handleSearchAction(query); }); // // Register LocationProvider ... this.applyTakeUntilWrapper(this.positionProvider.asObservable()).subscribe( (position) => { // this.currentPosition = position; this.detectChanges(); } ); } private async getNormallizedLatitued( latitude?: number | XStandardType ) { const result = await this.getValueAsync(latitude || this.latitude || 0); return result || 0; } private async getNormallizedLongitude( longitude?: number | XStandardType ) { const result = await this.getValueAsync(longitude || this.longitude || 0); return result || 0; } private async getNormallizedZoom(zoom?: number | XStandardType) { // let result = 0; if (!zoom) { result = await this.getValueAsync(this.zoom); } else { result = await this.getValueAsync(zoom); } // result = result > this.IMPORTANT_ZOOM ? this.IMPORTANT_ZOOM : result < 0 ? 0 : result; // return result || 0; } private async getSummarySelectedLocationMessage( latitude?: number | XStandardType, longitude?: number | XStandardType ) { // const desiredLat = await this.getNormallizedLatitued(latitude); const desiredLong = await this.getNormallizedLongitude(longitude); // const mLat = this.applyLocale(desiredLat.toString()); const mLong = this.applyLocale(desiredLong.toString()); // const result = `${mLat}, ${mLong}`; return result; } // private async applyLocationInfo() { // if (!this.isInitialized) { // setTimeout( async () => await this.applyLocationInfo(), this.ACTION_WAITIONG_DURATION ); // return; } // const normallizedZoom = await this.getNormallizedZoom(); const latitude = await this.getNormallizedLatitued(); const longitude = await this.getNormallizedLongitude(); // const addMarker = await this.getValueAsync( this.addMarkerOnSelectedLocation ); const zoom = addMarker ? this.IMPORTANT_ZOOM : normallizedZoom; // if (this.longitude && this.latitude) { // setTimeout(async () => { // if (addMarker) { await this.addMarker(latitude, longitude, zoom); } else { await this.setCenter(latitude, longitude, zoom); } }, this.ACTION_WAITIONG_DURATION); // return; } // if (this.zoom) { // setTimeout(async () => { await this.setZoom(normallizedZoom); }, 1000); // return; } } private async applyContentOffset() { // let result = 5; // const showSerach = await this.getValueAsync(this.showSearchBar); if (showSerach) { // const searchBarPosition = await this.getValueAsync( this.searchBarPosition ); // if (searchBarPosition === XMapItemPosition.TOP && this.searchBar) { // const searchBarHeight = this.searchBar.getElementBoundaryHeight(); if (searchBarHeight === 0) { // setTimeout( async () => await this.applyContentOffset(), this.ACTION_WAITIONG_DURATION ); // return; } // result += searchBarHeight; } } // const canShowPluginBarAtTop = await this.getValueAsync( this.canShowPlugins(this.ItemPositions.TOP) ); if (canShowPluginBarAtTop && this.pluginsBar) { // const pluginsBarHeight = this.pluginsBar.nativeElement.getBoundingClientRect().height; if (pluginsBarHeight === 0) { // setTimeout( async () => await this.applyContentOffset(), this.ACTION_WAITIONG_DURATION ); // return; } // result += pluginsBarHeight; } // this.setCssVar(XMapCSSVar.MapControlOffset, `${result}px`); } private async applyCanSelect() { // if (!this.isInitialized) { // setTimeout( async () => await this.applyCanSelect(), this.ACTION_WAITIONG_DURATION ); // return; } // // Add Marker on Map Clicked ... const canSelect = await this.getValueAsync(this.canSelect); if (canSelect) { this.MAP.on('click', async (args: any) => { // this.searchPaneOpen = false; // const lonlat = transform(args.coordinate, 'EPSG:3857', 'EPSG:4326'); // // tslint:disable-next-line:no-shadowed-variable const lat = lonlat[1] as number; // // tslint:disable-next-line:no-shadowed-variable const long = lonlat[0] as number; // // , this.IMPORTANT_ZOOM - 6 await this.addMarker(lat, long); }); } } // //#region Plugin Handlers ... private async applyZoom(forceUpdate = true) { // if (!this.isInitialized) { // setTimeout( async () => await this.applyZoom(), this.ACTION_WAITIONG_DURATION ); // return; } // const showZoom = await this.getValueAsync(this.showZoom); if (showZoom) { this.map.addControl(this.ZOOM_CONTROL); } else { this.map.removeControl(this.ZOOM_CONTROL); } // if (forceUpdate) { await this.updateMap(); } } private async applyRotate(forceUpdate = true) { // if (!this.isInitialized) { // setTimeout( async () => await this.applyRotate(), this.ACTION_WAITIONG_DURATION ); // return; } // const showRotate = await this.getValueAsync(this.showRotate); if (showRotate) { this.map.addControl(this.ROTATE_CONTROL); } else { this.map.removeControl(this.ROTATE_CONTROL); } // if (forceUpdate) { await this.updateMap(); } } private async applyZoomSlider(forceUpdate = true) { // if (!this.isInitialized) { // setTimeout( async () => await this.applyZoomSlider(), this.ACTION_WAITIONG_DURATION ); // return; } // const showZoomSlider = await this.getValueAsync(this.showZoomSlider); if (showZoomSlider) { this.map.addControl(this.ZOOM_SLIDER_CONTROL); } else { this.map.removeControl(this.ZOOM_SLIDER_CONTROL); } // if (forceUpdate) { await this.updateMap(); } } // //#region SelectedLocation Plugin ... private async updateSelectedLocation( latitude?: number | XStandardType, longitude?: number | XStandardType ) { // if (!this.isInitialized) { // setTimeout(async () => { await this.updateSelectedLocation(latitude, longitude); }, this.ACTION_WAITIONG_DURATION); // return; } // const message = await this.getSummarySelectedLocationMessage( latitude, longitude ); this.positionProvider.next(message); } //#endregion // //#region SearchBar Plugin ... private async handleSearchAction(query: string) { // const url = this.searchPlaceProvider(query); // this.searchResult = []; this.searchPaneOpen = false; this.searchResultListItems = []; // await this.setLoadingState(true); applyFinally(this.getPlaceResults(url), async () => { this.isSearching = false; await this.setLoadingState(false); }).subscribe( async (res) => { // this.searchResult = res; await this.prepareSearchListItems(); }, () => { this.showError(XExceptionIDs.ActionFailed); } ); } private getPlaceResults(url: string): Observable { // const headers: HttpHeaders = new HttpHeaders(); headers.set(XHeader.Accept, XContentType.AppJson); // return applyFinally( this.applyLoadingWrapper( this.managerService.httpClient .get(url, { headers }) .pipe( map((res) => { return res.map((r) => { // const mPlace: XPlaceResult = { display_name: r.display_name, lat: +r.lat, lon: +r.lon, }; // return mPlace; }); }), tap((res) => { if (!this.hasChild(res)) { this.searchPaneOpen = false; } }) ) ), () => this.setLoadingState(false) ); } private async prepareSearchListItems() { // if (!this.hasChild(this.searchResult)) { // this.searchPaneOpen = false; await this.setLoadingState(false); return; } // this.searchResultListItems = this.searchResult.map((r) => { // const li: XListItem = { data: r, }; // return li; }); // this.searchPaneOpen = true; await this.setLoadingState(false); // this.detectChanges(); } //#endregion //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XMapComponent } from './x-map.component'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XListModule } from '../x-list/x-list.module'; import { XMapContainerComponent } from './x-map.typings'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XMapDialogService } from './x-map-dialog/x-map-dialog.service'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XMapDialogComponent } from './x-map-dialog/x-map-dialog.component'; @NgModule({ imports: [ XListModule, XCardModule, XIconModule, CommonModule, XSlotterModule, XBaseComponentModule, ], exports: [ XListModule, XCardModule, XIconModule, CommonModule, XMapComponent, XSlotterModule, XMapDialogComponent, XBaseComponentModule, ], providers: [XMapDialogService], entryComponents: [XMapDialogComponent], declarations: [XMapComponent, XMapDialogComponent, XMapContainerComponent], }) export class XMapModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.tools.ts import { XMapLocation } from './x-map.typings'; import { isNullOrEmptyString, hasChild, isString, isArray, countChild } from 'x-framework-core'; /** * get given position link for open on Google Maps ... * * @param model map result model ... */ export function getGoogleMapLink(model: XMapLocation) { return `https://maps.google.com/?q=${model.latitude},${model.longitude}`; } /** * convert a point string to Map Result ... * * @param longLat the string which represent point ... */ export function fromLongLat(longLat: string) { // if (isNullOrEmptyString(longLat)) { return null; } // const longLatArr = longLat.toString().split(','); if (!hasChild(longLatArr) || longLatArr.length !== 2) { return null; } // const result: XMapLocation = { latitude: longLatArr[1], longitude: longLatArr[0], }; // return result; } export function toMapLocation(source: string | Array) { // if (isString(source)) { return fromLongLat(source as string); } // if (!isArray(source) || countChild(source as Array) < 2) { return null; } // const longLatArr = source as Array; // const result: XMapLocation = { latitude: longLatArr[1].toString(), longitude: longLatArr[0].toString(), }; // return result; } /** * convert a point object to point string ... * * @param point the map selected object to convert it ... */ export function toLongLat(point: XMapLocation) { return `${point.longitude},${point.latitude}`; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map.typings.ts import { Input, Inject, NgZone, Output, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XCardContainer, XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { XSearchBarActionModel, XSearchBarTypeIdentifier, XComponentSearchBarContainer, IXComponentSearchBarContainer, } from '../x-search-bar/x-search-bar.typings'; import { concatMap, map } from 'rxjs/operators'; import { ViewportRuler } from '@angular/cdk/overlay'; import { forkJoin, Observable, Subject } from 'rxjs'; import { Style, Circle, Stroke, Fill } from 'ol/style'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { IXBaseContainer } from '../classes/i-x-base.container'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export interface XPlaceResult { display_name: string; lat: number; lon: number; } export enum XMapItemPosition { TOP = 'top', BOTTOM = 'bottom', } export type XMapItemPositionIdentifier = XMapItemPosition | string; export enum XMapAction { // Locate = 'locate', // AddMarker = 'add_marker', HasMarker = 'has_marker', ClearMarker = 'clear-marker', HasNotMarker = 'has_not_marker', GoMarkedPlace = 'go-marked-place', // SetCenter = 'set_center', SetZoom = 'set_zoom', // Refresh = 'refresh', } export type XMapActionIdentifier = XMapAction | string; export interface XMapActionModel extends XBaseActionModel {} export enum XMapCSSVar { MapControlOffset = 'map-controls-offest', } export type XMapCSSVarIdentification = XMapCSSVar | string; export interface XMapLocation { zoom?: string; latitude?: string; longitude?: string; } export type XMapStyle = Style; export const defaultMarkerStyle: XMapStyle = new Style({ image: new Circle({ radius: 10, stroke: new Stroke({ color: 'rgb(255,0,0)', width: 5, }), fill: new Fill({ color: 'rgba(255,0,0,.3)', }), }), stroke: new Stroke({ color: 'rgb(255,0,0)', width: 5, }), fill: new Fill({ color: 'rgba(255,165,0,.3)', }), }); export const defaultMapSearchPlaceProvider = (query: string) => { return ( 'https://nominatim.openstreetmap.org/search?q=' + query + '&format=json&limit=5' ); }; // //#region Inside Card Container ... type TXMapContainer = IXComponentCardContainer & IXComponentSearchBarContainer; export interface IXMapContainer extends IXBaseContainer, TXMapContainer { // actionProvider: Subject; cssClass: XStandardType>; // zoom: XStandardType; latitude: XStandardType; longitude: XStandardType; canSelect: XStandardType; addMarkerOnSelectedLocation: XStandardType; // isReady: EventEmitter; viewChanged: EventEmitter; locationSelected: EventEmitter; // zoomChanged: EventEmitter; markerStyle: XStandardType; showProgressBar: XStandardType; progressBarColor: XStandardType; progressBarPosition: XStandardType; showSelectedLocation: XStandardType; selectedLocationPosition: XStandardType; showGoMarkedPlace: XStandardType; goMarkedPlacePosition: XStandardType; showClearMarker: XStandardType; clearMarkerPosition: XStandardType; showLocator: XStandardType; locatorPosition: XStandardType; showZoom: XStandardType; showRotate: XStandardType; showZoomSlider: XStandardType; // searchBarPosition: XStandardType; searchPlaceProvider: (query: string) => string; searchResultListColor: XStandardType; } @Injectable({ providedIn: 'root', }) export class XMapContainer extends XComponentCardContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly zoom: XStandardType = 0; readonly latitude: XStandardType = 0; readonly longitude: XStandardType = 0; readonly canSelect: XStandardType = true; readonly addMarkerOnSelectedLocation: XStandardType = true; // readonly isReady: EventEmitter = new EventEmitter(); readonly viewChanged: EventEmitter = new EventEmitter(); readonly locationSelected: EventEmitter = new EventEmitter(); // zoomChanged: EventEmitter; readonly markerStyle: XStandardType = defaultMarkerStyle; readonly showProgressBar: XStandardType = true; readonly progressBarColor: XStandardType = XColorWithBrightness.Warning; readonly progressBarPosition: XStandardType = XMapItemPosition.TOP; readonly showSelectedLocation: XStandardType = true; readonly selectedLocationPosition: XStandardType = XMapItemPosition.TOP; readonly showGoMarkedPlace: XStandardType = true; readonly goMarkedPlacePosition: XStandardType = XMapItemPosition.TOP; readonly showClearMarker: XStandardType = true; readonly clearMarkerPosition: XStandardType = XMapItemPosition.TOP; readonly showLocator: XStandardType = true; readonly locatorPosition: XStandardType = XMapItemPosition.TOP; readonly showZoom: XStandardType = true; readonly showRotate: XStandardType = true; readonly showZoomSlider: XStandardType = false; // readonly searchBarPosition: XStandardType = XMapItemPosition.TOP; readonly searchPlaceProvider: (query: string) => string = defaultMapSearchPlaceProvider; readonly searchResultListColor: XStandardType = XColorWithBrightness.Light; // //#region ComponentSearchBar ... // readonly showSearchBar: XStandardType = this.searchBarPropertyProvider.showSearchBar; // readonly searchBarActionProvider: Subject = this.searchBarPropertyProvider.searchBarActionProvider; readonly searchBarCssClass: XStandardType> = this.searchBarPropertyProvider.searchBarCssClass; // readonly searchBarColor: XStandardType = this.searchBarPropertyProvider.searchBarColor; readonly searchBarForegroundColor: XStandardType = this.searchBarPropertyProvider.searchBarForegroundColor; // readonly searchBarSearchInputColor: XStandardType = this.searchBarPropertyProvider.searchBarSearchInputColor; readonly searchBarForegroundSearchInputColor: XStandardType = this.searchBarPropertyProvider.searchBarForegroundSearchInputColor; // readonly searchBarType: XStandardType = this.searchBarPropertyProvider.searchBarType; readonly searchBarTitle: XStandardType = this.searchBarPropertyProvider.searchBarTitle; readonly searchBarValue: XStandardType = this.searchBarPropertyProvider.searchBarValue; readonly searchBarEnterKeyHint: XStandardType = this.searchBarPropertyProvider.searchBarEnterKeyHint; readonly searchBarKeyboardType: XStandardType = this.searchBarPropertyProvider.searchBarKeyboardType; readonly searchBarSpellcheck: XStandardType = this.searchBarPropertyProvider.searchBarSpellcheck; readonly searchBarDebounce: XStandardType = this.searchBarPropertyProvider.searchBarDebounce; // readonly searchBarShowCancelButton: XStandardType = this.searchBarPropertyProvider.searchBarShowCancelButton; readonly searchBarCancelButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonIcon; readonly searchBarCancelButtonTitle: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonTitle; readonly searchBarCancelButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarCancelButtonIconColor; // readonly searchBarShowClearButton: XStandardType = this.searchBarPropertyProvider.searchBarShowClearButton; readonly searchBarClearButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarClearButtonIcon; readonly searchBarClearButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarClearButtonIconColor; // readonly searchBarSearchButtonIcon: XStandardType = this.searchBarPropertyProvider.searchBarSearchButtonIcon; readonly searchBarSearchButtonIconColor: XStandardType = this.searchBarPropertyProvider.searchBarSearchButtonIconColor; // readonly searchBarQueryChange: EventEmitter = this.searchBarPropertyProvider.searchBarQueryChange; readonly searchBarOnEvent: EventEmitter = this.searchBarPropertyProvider.searchBarOnEvent; //#endregion //#endregion // //#region Constructor ... constructor( protected propertyProvider: XCardContainer, protected searchBarPropertyProvider: XComponentSearchBarContainer ) { super(propertyProvider); } //#endregion } @Injectable() @Component({ template: ``, }) export class XMapContainerComponent extends XComponentCardContainerComponent implements IXMapContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() zoom: XStandardType = this.propertyProvider.zoom; @Input() latitude: XStandardType = this.propertyProvider.latitude; @Input() longitude: XStandardType = this.propertyProvider.longitude; @Input() canSelect: XStandardType = this.propertyProvider.canSelect; @Input() addMarkerOnSelectedLocation: XStandardType = this.propertyProvider.addMarkerOnSelectedLocation; // @Output() isReady: EventEmitter = new EventEmitter(); @Output() viewChanged: EventEmitter = new EventEmitter(); @Output() locationSelected: EventEmitter = new EventEmitter(); // zoomChanged: EventEmitter; @Input() markerStyle: XStandardType = this.propertyProvider.markerStyle; @Input() showProgressBar: XStandardType = this.propertyProvider.showProgressBar; @Input() progressBarColor: XStandardType = this.propertyProvider.progressBarColor; @Input() progressBarPosition: XStandardType = this.propertyProvider.progressBarPosition; @Input() showSelectedLocation: XStandardType = this.propertyProvider.showSelectedLocation; @Input() selectedLocationPosition: XStandardType = this.propertyProvider.selectedLocationPosition; @Input() showGoMarkedPlace: XStandardType = this.propertyProvider.showGoMarkedPlace; @Input() goMarkedPlacePosition: XStandardType = this.propertyProvider.goMarkedPlacePosition; @Input() showClearMarker: XStandardType = this.propertyProvider.showClearMarker; @Input() clearMarkerPosition: XStandardType = this.propertyProvider.clearMarkerPosition; @Input() showLocator: XStandardType = this.propertyProvider.showLocator; @Input() locatorPosition: XStandardType = this.propertyProvider.locatorPosition; @Input() showZoom: XStandardType = this.propertyProvider.showZoom; @Input() showRotate: XStandardType = this.propertyProvider.showRotate; @Input() showZoomSlider: XStandardType = this.propertyProvider.showZoomSlider; // @Input() searchBarPosition: XStandardType = this.propertyProvider.searchBarPosition; @Input() searchPlaceProvider: (query: string) => string = this.propertyProvider.searchPlaceProvider; @Input() searchResultListColor: XStandardType = this.propertyProvider.searchResultListColor; // //#region ComponentSearchBar ... // @Input() showSearchBar: XStandardType = this.propertyProvider.showSearchBar; // @Input() searchBarActionProvider: Subject = this.propertyProvider.searchBarActionProvider; @Input() searchBarCssClass: XStandardType> = this.propertyProvider.searchBarCssClass; // @Input() searchBarColor: XStandardType = this.propertyProvider.searchBarColor; @Input() searchBarForegroundColor: XStandardType = this.propertyProvider.searchBarForegroundColor; // @Input() searchBarSearchInputColor: XStandardType = this.propertyProvider.searchBarSearchInputColor; @Input() searchBarForegroundSearchInputColor: XStandardType = this.propertyProvider.searchBarForegroundSearchInputColor; // @Input() searchBarType: XStandardType = this.propertyProvider.searchBarType; @Input() searchBarTitle: XStandardType = this.propertyProvider.searchBarTitle; @Input() searchBarValue: XStandardType = this.propertyProvider.searchBarValue; @Input() searchBarEnterKeyHint: XStandardType = this.propertyProvider.searchBarEnterKeyHint; @Input() searchBarKeyboardType: XStandardType = this.propertyProvider.searchBarKeyboardType; @Input() searchBarSpellcheck: XStandardType = this.propertyProvider.searchBarSpellcheck; @Input() searchBarDebounce: XStandardType = this.propertyProvider.searchBarDebounce; // @Input() searchBarShowCancelButton: XStandardType = this.propertyProvider.searchBarShowCancelButton; @Input() searchBarCancelButtonIcon: XStandardType = this.propertyProvider.searchBarCancelButtonIcon; @Input() searchBarCancelButtonTitle: XStandardType = this.propertyProvider.searchBarCancelButtonTitle; @Input() searchBarCancelButtonIconColor: XStandardType = this.propertyProvider.searchBarCancelButtonIconColor; // @Input() searchBarShowClearButton: XStandardType = this.propertyProvider.searchBarShowClearButton; @Input() searchBarClearButtonIcon: XStandardType = this.propertyProvider.searchBarClearButtonIcon; @Input() searchBarClearButtonIconColor: XStandardType = this.propertyProvider.searchBarClearButtonIconColor; // @Input() searchBarSearchButtonIcon: XStandardType = this.propertyProvider.searchBarSearchButtonIcon; @Input() searchBarSearchButtonIconColor: XStandardType = this.propertyProvider.searchBarSearchButtonIconColor; // @Output() searchBarQueryChange: EventEmitter = new EventEmitter(); @Output() searchBarOnEvent: EventEmitter = new EventEmitter(); //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XMapContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps(container?: IXMapContainer): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), zoom: this.getValue(container ? container.zoom : this.zoom), latitude: this.getValue( container ? container.latitude : this.latitude ), longitude: this.getValue( container ? container.longitude : this.longitude ), canSelect: this.getValue( container ? container.canSelect : this.canSelect ), addMarkerOnSelectedLocation: this.getValue( container ? container.addMarkerOnSelectedLocation : this.addMarkerOnSelectedLocation ), markerStyle: this.getValue( container ? container.markerStyle : this.markerStyle ), showProgressBar: this.getValue( container ? container.showProgressBar : this.showProgressBar ), progressBarColor: this.getValue( container ? container.progressBarColor : this.progressBarColor ), progressBarPosition: this.getValue( container ? container.progressBarPosition : this.progressBarPosition ), showSelectedLocation: this.getValue( container ? container.showSelectedLocation : this.showSelectedLocation ), selectedLocationPosition: this.getValue( container ? container.selectedLocationPosition : this.selectedLocationPosition ), showGoMarkedPlace: this.getValue( container ? container.showGoMarkedPlace : this.showGoMarkedPlace ), goMarkedPlacePosition: this.getValue( container ? container.goMarkedPlacePosition : this.goMarkedPlacePosition ), showClearMarker: this.getValue( container ? container.showClearMarker : this.showClearMarker ), clearMarkerPosition: this.getValue( container ? container.clearMarkerPosition : this.clearMarkerPosition ), showLocator: this.getValue( container ? container.showLocator : this.showLocator ), locatorPosition: this.getValue( container ? container.locatorPosition : this.locatorPosition ), showZoom: this.getValue( container ? container.showZoom : this.showZoom ), showRotate: this.getValue( container ? container.showRotate : this.showRotate ), showZoomSlider: this.getValue( container ? container.showZoomSlider : this.showZoomSlider ), searchBarPosition: this.getValue( container ? container.searchBarPosition : this.searchBarPosition ), searchPlaceProvider: this.getValue( container ? container.searchPlaceProvider : this.searchPlaceProvider ), searchResultListColor: this.getValue( container ? container.searchResultListColor : this.searchResultListColor ), showSearchBar: this.getValue( container ? container.showSearchBar : this.showSearchBar ), searchBarCssClass: this.getValue( container ? container.searchBarCssClass : this.searchBarCssClass ), searchBarColor: this.getValue( container ? container.searchBarColor : this.searchBarColor ), searchBarForegroundColor: this.getValue( container ? container.searchBarForegroundColor : this.searchBarForegroundColor ), searchBarSearchInputColor: this.getValue( container ? container.searchBarSearchInputColor : this.searchBarSearchInputColor ), searchBarForegroundSearchInputColor: this.getValue( container ? container.searchBarForegroundSearchInputColor : this.searchBarForegroundSearchInputColor ), searchBarType: this.getValue( container ? container.searchBarType : this.searchBarType ), searchBarTitle: this.getValue( container ? container.searchBarTitle : this.searchBarTitle ), searchBarValue: this.getValue( container ? container.searchBarValue : this.searchBarValue ), searchBarEnterKeyHint: this.getValue( container ? container.searchBarEnterKeyHint : this.searchBarEnterKeyHint ), searchBarKeyboardType: this.getValue( container ? container.searchBarKeyboardType : this.searchBarKeyboardType ), searchBarSpellcheck: this.getValue( container ? container.searchBarSpellcheck : this.searchBarSpellcheck ), searchBarDebounce: this.getValue( container ? container.searchBarDebounce : this.searchBarDebounce ), searchBarShowCancelButton: this.getValue( container ? container.searchBarShowCancelButton : this.searchBarShowCancelButton ), searchBarCancelButtonIcon: this.getValue( container ? container.searchBarCancelButtonIcon : this.searchBarCancelButtonIcon ), searchBarCancelButtonTitle: this.getValue( container ? container.searchBarCancelButtonTitle : this.searchBarCancelButtonTitle ), searchBarCancelButtonIconColor: this.getValue( container ? container.searchBarCancelButtonIconColor : this.searchBarCancelButtonIconColor ), searchBarShowClearButton: this.getValue( container ? container.searchBarShowClearButton : this.searchBarShowClearButton ), searchBarClearButtonIcon: this.getValue( container ? container.searchBarClearButtonIcon : this.searchBarClearButtonIcon ), searchBarClearButtonIconColor: this.getValue( container ? container.searchBarClearButtonIconColor : this.searchBarClearButtonIconColor ), searchBarSearchButtonIcon: this.getValue( container ? container.searchBarSearchButtonIcon : this.searchBarSearchButtonIcon ), searchBarSearchButtonIconColor: this.getValue( container ? container.searchBarSearchButtonIconColor : this.searchBarSearchButtonIconColor ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // isReady: this.isReady, viewChanged: this.viewChanged, locationSelected: this.locationSelected, // searchBarActionProvider: container ? container.searchBarActionProvider : this.searchBarActionProvider, // searchBarQueryChange: this.searchBarQueryChange, searchBarOnEvent: this.searchBarOnEvent, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.component.html

{{ getTitle() | async }}

### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.component.scss :host { --x-map-height: 200px; } ::ng-deep.fullscreen-dialog { // width: 80vw !important; max-width: 80vw !important; // height: 80vh !important; max-height: 80vh !important; // &.mobile { // width: 100vw !important; max-width: 100vw !important; // height: 100vh !important; max-height: 100vh !important; } // .mat-dialog-container { padding: 0 !important; } } :host ::ng-deep x-map { // --map-height: var(--x-map-height); } .x-map-dialog-container { height: 100%; } x-icon { --size: 24px; } .toolbar-area { margin: 8px; } .toolbar-item { width: auto; height: 48px; } .toolbar-button { width: 32px; margin: { left: 4px; right: 4px; } } h1, h2, h3, h4, h5, h6 { margin: 0 !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.component.ts import { Inject, NgZone, Component, Renderer2, ElementRef, ChangeDetectorRef, ChangeDetectionStrategy, } from '@angular/core'; import { XColor, isFunction, XResourceIDs, XDialogResult, isNullOrUndefined, isNullOrEmptyString, XColorWithBrightness, } from 'x-framework-core'; import { XMapAction, XMapLocation, XMapActionModel, XMapItemPosition, defaultMarkerStyle, defaultMapSearchPlaceProvider, } from '../x-map.typings'; import { ViewChild } from '@angular/core'; import { Subject, Subscription } from 'rxjs'; import { concatMap, map } from 'rxjs/operators'; import { XSearchBarType, XSearchBarShowButton, XSearchBarActionModel, XSearchBarEnterKeyHint, } from '../../x-search-bar/x-search-bar.typings'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XBasePage } from '../../classes/x-base-page'; import { XManagerService } from 'x-framework-services'; import { XIconNames } from '../../x-icon/x-icon.typings'; import { XSlotName } from '../../x-slotter/x-slotter.typings'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { XMapDialogConfig, XMapdialogCssVar } from './x-map-dialog.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-map-dialog', templateUrl: './x-map-dialog.component.html', styleUrls: ['./x-map-dialog.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XMapDialogComponent extends XBasePage { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly selectIcon = XIconNames.checked; readonly backIcon = XIconNames.arrow_back; // readonly SlotNames = Object.assign({}, XSlotName); readonly MapItemPositions = Object.assign({}, XMapItemPosition); // hasMarker: boolean; selectedLocation: XMapLocation; actionProvider = new Subject(); // @ViewChild('mapDialogContainer') mapDialogContainer: ElementRef; @ViewChild('mapDialogToolbar') mapDialogToolbar: ElementRef; //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: any, public dialogRef: MatDialogRef ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // this.preventBack = true; } async afterViewInit() { super.afterViewInit(); // await this.applyMapSize(); } public registerViewHandlers(): void { // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider.subscribe( (action) => { switch (action.action) { // case XMapAction.HasMarker: // this.hasMarker = true; this.detectChanges(); break; // case XMapAction.HasNotMarker: this.hasMarker = false; this.detectChanges(); break; } } ); } public onDestroy(): void { // if (!isNullOrUndefined(this.ACTION_PROVIDER_SUBSCRIPTION)) { // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } } //#endregion // //#region UI Providers ... /** * retrieve map dialog config ... */ getData() { return this.getValue(this.data as XMapDialogConfig); } /** * determines map dialog config exists or not ... */ hasData() { return !isNullOrUndefined(this.getData()); } /** * determines dialog can select result or not ... */ dialogCanSelect() { return ( this.hasMarker && !isNullOrUndefined(this.selectedLocation) && !isNullOrEmptyString(this.selectedLocation.latitude) && !isNullOrEmptyString(this.selectedLocation.longitude) ); } /** * retrieve dialog title ... */ getTitle() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.title)) ); } // get markerStyle() { return this.getData().pipe( concatMap((config) => this.getValue(config.markerStyle)), map((style) => (style ? style : defaultMarkerStyle)) ); } get cssClass() { return this.getData().pipe( concatMap((config) => this.getArrayValue(config.cssClass)) ); } get progressBarColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.progressBarColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Warning)) ); } get canSelect() { return this.getData().pipe( concatMap((config) => this.getValue(config.canSelect ? config.canSelect : true) ) ); } // get latitude() { return this.getData().pipe( concatMap((config) => this.getValue(config.latitude)) ); } get longitude() { return this.getData().pipe( concatMap((config) => this.getValue(config.longitude)) ); } // get zoom() { return this.getData().pipe( concatMap((config) => this.getValue(config.zoom)) ); } // get showRotate() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showRotate)), map((canShow) => (isNullOrUndefined(canShow) ? true : canShow)) ); } get showZoom() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showZoom)), map((canShow) => (isNullOrUndefined(canShow) ? true : canShow)) ); } get showZoomSlider() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showZoomSlider)), map((canShow) => (isNullOrUndefined(canShow) ? false : canShow)) ); } get showLocator() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showLocator)), map((canShow) => (isNullOrUndefined(canShow) ? true : canShow)) ); } get showClearMarker() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showClearMarker)), map((canShow) => (isNullOrUndefined(canShow) ? true : canShow)) ); } get showGoMarkedPlace() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showGoMarkedPlace)), map((canShow) => (isNullOrUndefined(canShow) ? true : canShow)) ); } get showSelectedLocation() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showSelectedLocation)), map((canShow) => (isNullOrUndefined(canShow) ? true : canShow)) ); } get showSearchBar() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showSearchBar)), map((canShow) => (isNullOrUndefined(canShow) ? true : canShow)) ); } get searchResultListColor() { return this.getData().pipe( concatMap((config) => this.getValue(config.searchResultListColor)), map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light)) ); } // // // get isInPage() { // return this.getData().pipe( // concatMap((config) => this.getOptionalValue(config.isInPage)) // ); // } // get wrapWithCard() { // return this.getData().pipe( // concatMap((config) => this.getOptionalValue(config.wrapWithCard)) // ); // } // get cardColor() { // return this.getData().pipe( // concatMap((config) => this.getValue(config.progressBarColor)), // map((color) => (!isNullOrEmptyString(color) ? color : XColor.Light)) // ); // } // get cardForegroundColor() { // return this.getData().pipe( // concatMap((config) => this.getOptionalValue(config.cardForegroundColor)) // ); // } // get cardTitle() { // return this.getData().pipe( // concatMap((config) => this.getResourceValue(config.cardTitle)) // ); // } // get cardSubTitle() { // return this.getData().pipe( // concatMap((config) => this.getResourceValue(config.cardSubTitle)) // ); // } // get cardShowFooter() { // return this.getData().pipe( // concatMap((config) => this.getOptionalValue(config.cardShowFooter)) // ); // } // get showProgressBar() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.showProgressBar)), map((result) => (isNullOrUndefined(result) ? true : result)) ); } // get progressBarPosition() { // return this.getData().pipe( // concatMap((config) => this.getOptionalValue(config.progressBarPosition)), // map((result) => // isNullOrEmptyString(result) ? XMapItemPosition.TOP : result // ) // ); // } get locatorPosition() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.locatorPosition)), map((result) => isNullOrEmptyString(result) ? XMapItemPosition.TOP : result ) ); } get clearMarkerPosition() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.clearMarkerPosition)), map((result) => isNullOrEmptyString(result) ? XMapItemPosition.TOP : result ) ); } get goMarkedPlacePosition() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.goMarkedPlacePosition) ), map((result) => isNullOrEmptyString(result) ? XMapItemPosition.TOP : result ) ); } get selectedLocationPosition() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.selectedLocationPosition) ), map((result) => isNullOrEmptyString(result) ? XMapItemPosition.TOP : result ) ); } // //#region Search ... get searchPlaceProvider() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchPlaceProvider)), map((provider) => !provider || !isFunction(provider) ? defaultMapSearchPlaceProvider : provider ) ); } get searchBarType() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarType)), map((data) => (isNullOrEmptyString(data) ? XSearchBarType.Search : data)) ); } get searchBarValue() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarValue)) ); } get searchBarColor() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarColor)), map((data) => isNullOrEmptyString(data) ? XColorWithBrightness.Primary : data ) ); } get searchBarTitle() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarTitle)), map((data) => !data || isNullOrEmptyString(data.toString()) ? XResourceIDs.search : data ) ); } // get searchBarPosition() { // return this.getData().pipe( // concatMap((config) => this.getOptionalValue(config.searchBarPosition)), // map((data) => (isNullOrEmptyString(data) ? XMapItemPosition.TOP : data)) // ); // } get searchBarCssClass() { return this.getData().pipe( concatMap((config) => this.getArrayValue(config.searchBarCssClass)) ); } get searchBarDebounce() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarDebounce)), map((data) => isNullOrUndefined(data) ? this.config.defaultSearchDebounceTime : data ) ); } get searchBarClearButtonIcon() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarClearButtonIcon) ), map((data) => !data || isNullOrEmptyString(data.toString()) ? XIconNames.clear : data ) ); } get searchBarSearchInputColor() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarSearchInputColor) ), map((data) => isNullOrEmptyString(data) ? XColorWithBrightness.Primary : data ) ); } get searchBarSpellcheck() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarSpellcheck)) ); } get searchBarSearchButtonIcon() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarSearchButtonIcon) ), map((data) => !data || isNullOrEmptyString(data.toString()) ? XIconNames.search : data ) ); } get searchBarKeyboardType() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarKeyboardType) ), map((data) => (isNullOrEmptyString(data) ? XSearchBarType.Search : data)) ); } get searchBarEnterKeyHint() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarEnterKeyHint) ), map((data) => isNullOrEmptyString(data) ? XSearchBarEnterKeyHint.Search : data ) ); } get searchBarClearIconColor() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarClearButtonIconColor) ), map((data) => isNullOrEmptyString(data) ? XColorWithBrightness.Light : data ) ); } get searchBarActionProvider() { return this.getData().pipe( map((data) => !isNullOrUndefined(data.searchBarActionProvider) ? data.searchBarActionProvider : new Subject() ) ); } get searchBarSearchButtonIconColor() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarSearchButtonIconColor) ), map((data) => isNullOrEmptyString(data) ? XColorWithBrightness.Light : data ) ); } get searchBarForegroundColor() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarForegroundColor) ) ); } get searchBarShowCancelButton() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarShowCancelButton) ), map((data) => isNullOrEmptyString(data) ? XSearchBarShowButton.Never : data ) ); } get searchBarCancelButtonIcon() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarCancelButtonIcon) ), map((data) => !data || isNullOrEmptyString(data.toString()) ? XIconNames.cancel : data ) ); } get searchBarCancelButtonTitle() { return this.getData().pipe( concatMap((config) => this.getResourceValue(config.searchBarCancelButtonTitle) ) ); } get searchBarForegroundSearchInputColor() { return this.getData().pipe( concatMap((config) => this.getOptionalValue(config.searchBarForegroundSearchInputColor) ) ); } //#endregion //#endregion // //#region UI Handlers ... async handleBack() { this.dialogRef.close(); } async handleSelect() { // if (!this.dialogCanSelect()) { return; } // this.dialogRef.close({ result: XDialogResult.Ok, payload: this.selectedLocation, }); } async handleMapIsReady() { // const config = await this.getValueAsync(this.getData()); if (!config || !config.isReady) { return; } // config.isReady.emit(); } async handleSearchBarQueryChange(event: string) { // const config = await this.getValueAsync(this.getData()); if (!config || !config.searchBarQueryChange) { return; } // config.searchBarQueryChange.emit(event); } async handleMapLocationSelected(event: XMapLocation) { // this.selectedLocation = event; // const config = await this.getValueAsync(this.getData()); if (!config || !config.locationSelected) { return; } // config.locationSelected.emit(event); // this.detectChanges(); } //#endregion // //#region Private ... async applyMapSize() { // let result = 0; // //#region DialogHeight ... // if (!this.mapDialogContainer) { // setTimeout(async () => await this.applyMapSize(), 500); return; } const height = this.mapDialogContainer.nativeElement.getBoundingClientRect().height; if (height === 0) { // setTimeout(async () => await this.applyMapSize(), 500); return; } // result += height; //#endregion // //#region ToolbarHeight ... if (!this.mapDialogToolbar) { // setTimeout(async () => await this.applyMapSize(), 500); return; } const toolbarHeight = this.mapDialogToolbar.nativeElement.getBoundingClientRect().height; if (toolbarHeight === 0) { // setTimeout(async () => await this.applyMapSize(), 500); return; } // result -= toolbarHeight; //#endregion // this.setCssVar(XMapdialogCssVar.XMapHeight, `${result}px`); this.detectChanges(); // this.runTimedOut(() => { this.managerService.dispatchResizeEvent(); }); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.service.ts import { XColor, toPromise, XBaseService, XResourceIDs, XDialogResult, isNullOrUndefined, } from 'x-framework-core'; import { MatDialog, MatDialogRef, MatDialogConfig, } from '@angular/material/dialog'; import { XManagerService } from 'x-framework-services'; import { XMapLocation } from '../x-map.typings'; import { XMapDialogComponent } from './x-map-dialog.component'; import { Injectable, Output, EventEmitter, Inject } from '@angular/core'; import { XMapDialogResult, XMapDialogConfig } from './x-map-dialog.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; @Injectable({ providedIn: 'root', }) export class XMapDialogService extends XBaseService { // //#region Props ... private MOBILE_CLASS_NAME = 'mobile'; private DIALOG_REF: MatDialogRef; // isMobile$ = this.managerService.isMobileUi$; // tslint:disable-next-line:no-output-on-prefix @Output() onResult = new EventEmitter(); //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, private dialog: MatDialog, private managerService: XManagerService ) { super(config); } //#endregion // //#region Actions ... /** * Open Select Map Dialog ... */ async openDialog(config?: XMapDialogConfig) { // // Prevent Double Bubble ... if (this.DIALOG_REF) { return; } // // Prepare Config ... if (!config) { config = {}; } // //#region Default Config for Map Component ... // // Zoom ... if (config && !config.zoom) { config.zoom = 6; } // // canSelect ... let selectable = false; if (config && !isNullOrUndefined(config.canSelect)) { // selectable = await toPromise(config.canSelect); config.canSelect = selectable; } // // Set Default Title ... if (config && !config.title) { // if (selectable) { config.title = XResourceIDs.map_dialog_select_title; } else { config.title = XResourceIDs.map_dialog_title; } } // // Search Bar Color ... if (config && !config.searchBarColor) { config.searchBarColor = XColor.Primary; } // // Progress Bar Color ... if (config && !config.progressBarColor) { config.progressBarColor = XColor.Warning; } // // Search Result List Color ... if (config && !config.searchResultListColor) { config.searchResultListColor = XColor.Medium; } //#endregion // // Prepare Dialog Config ... const data: MatDialogConfig = { data: config, }; // data.panelClass = 'fullscreen-dialog'; // // Show Cropper inside a Dialog ... this.DIALOG_REF = this.dialog.open(XMapDialogComponent, data); this.DIALOG_REF.disableClose = true; // // Attach Mobile Class ... this.isMobile$.subscribe((isMobile) => { // if (isMobile) { if (this.DIALOG_REF) { this.DIALOG_REF.addPanelClass(this.MOBILE_CLASS_NAME); } } else { if (this.DIALOG_REF) { this.DIALOG_REF.removePanelClass(this.MOBILE_CLASS_NAME); } } }); // // Handle Backdrop ... this.DIALOG_REF.backdropClick().subscribe(() => { // // Cancel Dialog ... this.onResult.emit({ result: XDialogResult.Cancel }); // this.closeDialog(); }); // // Handle Dialog Result ... this.DIALOG_REF.afterClosed().subscribe((model: XMapDialogResult) => { // if (isNullOrUndefined(model) || model.result !== XDialogResult.Ok) { // // Cancel Dialog ... this.onResult.emit({ result: XDialogResult.Cancel }); } else { // // Handle Results ... this.onResult.emit(model); } // this.closeDialog(); }); } /** * Close Select Map Dialog ... */ closeDialog() { // // Prevent Go Forward ... if (!this.DIALOG_REF) { return; } // // Close Dialog ... this.DIALOG_REF.close(); this.DIALOG_REF = null; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-map\x-map-dialog\x-map-dialog.typings.ts import { XDialogResult } from 'x-framework-core'; import { XMapLocation, IXMapContainer } from '../x-map.typings'; import { XBaseDialogConfig } from '../../classes/i-x-base-dialog.container'; export interface XMapDialogResult { payload?: XMapLocation; result: XDialogResult; } export interface XMapDialogConfig extends XBaseDialogConfig, Pick< Partial, | 'zoom' | 'isReady' | 'latitude' | 'cssClass' | 'showZoom' | 'longitude' | 'canSelect' | 'showRotate' | 'showLocator' | 'markerStyle' | 'showSearchBar' | 'searchBarType' | 'actionProvider' | 'searchBarValue' | 'searchBarColor' | 'searchBarTitle' | 'searchBarColor' | 'showZoomSlider' | 'showProgressBar' | 'showClearMarker' | 'locatorPosition' | 'progressBarColor' | 'locationSelected' | 'searchBarCssClass' | 'showGoMarkedPlace' | 'searchBarDebounce' | 'searchPlaceProvider' | 'clearMarkerPosition' | 'searchBarSpellcheck' | 'searchBarQueryChange' | 'showSelectedLocation' | 'goMarkedPlacePosition' | 'searchBarKeyboardType' | 'searchBarEnterKeyHint' | 'searchResultListColor' | 'searchBarActionProvider' | 'searchBarClearButtonIcon' | 'searchBarForegroundColor' | 'selectedLocationPosition' | 'searchBarForegroundColor' | 'searchBarSearchButtonIcon' | 'searchBarSearchInputColor' | 'searchBarSearchInputColor' | 'searchBarShowCancelButton' | 'searchBarCancelButtonIcon' | 'searchBarCancelButtonTitle' | 'searchBarClearButtonIconColor' | 'searchBarSearchButtonIconColor' | 'searchBarForegroundSearchInputColor' > {} export enum XMapdialogCssVar { XMapHeight = 'x-map-height', } export type XMapdialogCssVarIdentifier = XMapdialogCssVar | string; ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.component.scss :host ::ng-deep a { pointer-events: none; } :host { width: inherit; height: inherit; } textarea { resize: none; } .x-editor { width: 100%; min-height: 300px; height: fit-content; } .x-toolbar-wrapper { margin-bottom: 0px; } .x-preview { text-align: justify; } .x-preview-wrapper { height: fit-content; min-height: 300px; border: 1px solid gray; padding: { left: 4px; right: 4px; } } .x-toolbar-icon { margin: { left: 4px; right: 4px; } } .no-border { border: 0; min-height: unset; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.component.ts import { ViewChild, Component, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { keys, nameof, insertText, XStandardType, isNullOrEmptyString, } from 'x-framework-core'; import { XMarkdownMode, XMarkdownAction, XMarkdownActionModel, XMarkdownToolbarItem, XMarkdownModeIdentifier, XMarkdownToolbarItemName, XMarkdownToolbarConfigProps, XMarkdownContainerComponent, defaultXMarkdownToolbarConfig, } from './x-markdown.typings'; import { map } from 'rxjs/operators'; import 'node_modules/prismjs/prism.js'; import 'node_modules/marked/marked.min.js'; import { Subject, Subscription } from 'rxjs'; import { XSlotLayout } from '../x-slotter/x-slotter.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-markdown', templateUrl: './x-markdown.component.html', styleUrls: ['./x-markdown.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XMarkdownComponent extends XMarkdownContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private TOOLBAR_CONFIG: XMarkdownToolbarConfigProps; // readonly SlotterLayouts = Object.assign({}, XSlotLayout); // innerContent: string = this.content; preparedMode: XMarkdownModeIdentifier; toolbarItems = keys(defaultXMarkdownToolbarConfig); // get preparedToolbarConfig() { return this.TOOLBAR_CONFIG; } // @ViewChild('markdownEditor', { static: false }) editor: ElementRef; //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.prepareMode(); await this.prepareToolbarConfig(null); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Content Chaned ... const isContentChanged = changeKeys.includes( nameof('content') ); if (isContentChanged && this.content !== this.innerContent) { this.innerContent = this.content; this.detectChanges(); } //#endregion // //#region Model Changed ... const isModeChanged = changeKeys.includes( nameof('mode') ); if (isModeChanged) { await this.prepareMode(); await this.prepareToolbarConfig(null); } //#endregion } registerViewHandlers() { super.registerViewHandlers(); // // Register Action Provider ... this.registerActionProvider(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region UI Providers ... // getSlotterLayout() { return this.isMobileUi$.pipe( map((isMobileUi) => isMobileUi ? XSlotLayout.VERTICAL : XSlotLayout.HORIZONTAL ) ); } // //#region Mode Detectors ... // isEditMode() { return this.getValueStream(this.mode).pipe( map((preparedMode) => preparedMode === XMarkdownMode.EDIT) ); } // isPreviewMode() { return this.getValueStream(this.mode).pipe( map((preparedMode) => preparedMode === XMarkdownMode.PREVIEW) ); } // isBothMode() { return this.getValueStream(this.mode).pipe( map((preparedMode) => preparedMode === XMarkdownMode.BOTH) ); } //#endregion // //#region Toolbar Providers ... hasToolbarItem(name: XMarkdownToolbarItemName | any) { // if (!this.TOOLBAR_CONFIG) { return false; } // const itesNamess = keys(this.TOOLBAR_CONFIG); const result = itesNamess.includes(name); // return result; } getToolbarItem(name: XMarkdownToolbarItemName | any) { // if (!this.hasToolbarItem(name)) { return null; } // const item = this.TOOLBAR_CONFIG[name]; const defaultItem = this.getDefaultItemConfig(name); // const result: XMarkdownToolbarItem = { ...defaultItem, ...item, }; // return result; } //#endregion //#endregion // //#region Ui Handlers ... handleContentChanged(content: string) { // if (!content) { content = ''; } // this.innerContent = content; this.contentChange.emit(content); } async handleToolbarItemClicked(name: XMarkdownToolbarItemName) { // switch (name) { // case 'preview': await this.handleToggleMode(); break; // case 'bold': await this.handleAddContent('**', true); break; // case 'code': await this.handleAddContent('`', true); break; // case 'heading': await this.handleAddContent('# ', false); break; // case 'image': await this.handleAddContent('![alt text](image url)', false); break; // case 'italic': await this.handleAddContent('*', true); break; // case 'link': await this.handleAddContent('[title](url)', false); break; // case 'ol': await this.handleAddContent('1. ', false); break; // case 'ul': await this.handleAddContent('- ', false); break; // case 'quote': await this.handleAddContent('> ', false); break; } // if (this.editor) { this.editor.nativeElement.focus(); } } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XMarkdownAction.Refresh: this.detectChanges(); break; // case XMarkdownAction.FireToolbarButtons: // if (!isNullOrEmptyString(model.payload)) { await this.handleToolbarItemClicked(model.payload); } break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async prepareMode() { this.preparedMode = await this.getValueAsync(this.mode); await this.changeMode(this.preparedMode); } private async prepareToolbarConfig( config: XStandardType ) { // if (!config) { this.TOOLBAR_CONFIG = defaultXMarkdownToolbarConfig; return; } // const cfg = await this.getValueAsync(config); // this.TOOLBAR_CONFIG = { ...cfg, }; // this.detectChanges(); } private getDefaultItemConfig(name: XMarkdownToolbarItemName) { return defaultXMarkdownToolbarConfig[name]; } private async changeMode(mode: XMarkdownModeIdentifier) { // this.mode = mode; this.preparedMode = mode; // this.detectChanges(); } private async handleToggleMode() { // const mode = await this.getValueAsync(this.mode); // switch (mode) { case XMarkdownMode.BOTH: await this.changeMode(XMarkdownMode.EDIT); break; case XMarkdownMode.EDIT: await this.changeMode(XMarkdownMode.BOTH); break; } } private getCurrentPosition() { // if (!this.editor) { return { start: -1, end: -1, }; } // const start = this.editor.nativeElement.selectionStart; const end = this.editor.nativeElement.selectionEnd; // const result = { start: start ? +start : -1, end: end ? +end : -1, }; // return result; } private async handleAddContent(content: string, double: boolean = false) { // if (!content) { return; } // const pos = this.getCurrentPosition(); // if (!pos) { return; } // let selectedContent: string; if (pos.start === pos.end) { selectedContent = ''; } else { // selectedContent = this.innerContent.substring(pos.start, pos.end); this.innerContent = this.innerContent.replace(selectedContent, ''); } // let insertedContent: string; if (isNullOrEmptyString(selectedContent)) { insertedContent = double ? `${content}${content}` : `${content}`; } else { insertedContent = double ? `${content}${selectedContent}${content}` : `${content}${selectedContent}`; } // const startPos = pos.start > -1 ? pos.start : this.innerContent.length; this.innerContent = insertText( this.innerContent || '', insertedContent, startPos ); this.contentChange.emit(this.innerContent); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.module.ts import { NgModule } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from './../x-icon/x-icon.module'; import { XMarkdownComponent } from './x-markdown.component'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XMarkdownComponent], imports: [ CommonModule, XIconModule, XCardModule, XSlotterModule, XBaseComponentModule, MarkdownModule.forRoot(), ], exports: [ XIconModule, XCardModule, MarkdownModule, XSlotterModule, XMarkdownComponent, XBaseComponentModule, ], }) export class XMarkdownModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-markdown\x-markdown.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XIconIdentifier, XIconNames } from '../x-icon/x-icon.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XMarkdownMode { EDIT = 'edit', PREVIEW = 'preview', BOTH = 'both', } export type XMarkdownModeIdentifier = XMarkdownMode | string; export enum XMarkdownToolbarItemSlot { START = 'start', END = 'end', } export type XMarkdownToolbarItemSlotIdentifier = | XMarkdownToolbarItemSlot | string; export type XMarkdownToolbarItemName = | 'image' | 'link' | 'ul' | 'ol' | 'quote' | 'code' | 'bold' | 'italic' | 'heading' | 'preview' | 'guide'; export interface XMarkdownToolbarItem { icon?: XIconIdentifier; title?: XResourceIdentifier; slot?: XMarkdownToolbarItemSlotIdentifier; } export type XMarkdownToolbarConfigProps = { [key in XMarkdownToolbarItemName]?: XMarkdownToolbarItem; }; export const defaultXMarkdownToolbarConfig: XMarkdownToolbarConfigProps = { heading: { icon: XIconNames.heading, title: XResourceIDs.x_markdown_heading, slot: XMarkdownToolbarItemSlot.START, }, bold: { icon: XIconNames.bold, title: XResourceIDs.x_markdown_bold, slot: XMarkdownToolbarItemSlot.START, }, italic: { icon: XIconNames.italic, title: XResourceIDs.x_markdown_italic, slot: XMarkdownToolbarItemSlot.START, }, quote: { icon: XIconNames.quote, title: XResourceIDs.x_markdown_quote, slot: XMarkdownToolbarItemSlot.START, }, code: { icon: XIconNames.code, title: XResourceIDs.x_markdown_code, slot: XMarkdownToolbarItemSlot.START, }, ol: { icon: XIconNames.ol, title: XResourceIDs.x_markdown_ol, slot: XMarkdownToolbarItemSlot.START, }, ul: { icon: XIconNames.ul, title: XResourceIDs.x_markdown_ul, slot: XMarkdownToolbarItemSlot.START, }, link: { icon: XIconNames.link, title: XResourceIDs.x_markdown_link, slot: XMarkdownToolbarItemSlot.START, }, image: { icon: XIconNames.image, title: XResourceIDs.x_markdown_image, slot: XMarkdownToolbarItemSlot.START, }, preview: { icon: XIconNames.preview, title: XResourceIDs.x_markdown_preview, slot: XMarkdownToolbarItemSlot.END, }, guide: { icon: XIconNames.guide, title: XResourceIDs.x_markdown_guide, slot: XMarkdownToolbarItemSlot.END, }, }; export enum XMarkdownAction { // FireToolbarButtons = 'fire_toolbar_buttons', // Refresh = 'refresh', } export type XMarkdownActionIdentifier = XMarkdownAction | string; export interface XMarkdownActionModel extends XBaseActionModel {} // //#region Inside Card Container ... export interface IXMarkdownContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // content: string; contentChange: EventEmitter; // mode: XStandardType; // editorBoxColor: XStandardType; previewBoxColor: XStandardType; // //#region Toolbar ... hasToolbar: XStandardType; toolbarCssClass: XStandardType>; toolbarColor: XStandardType; toolbarForegroundColor: XStandardType; toolbarConfig: XStandardType; //#endregion } @Injectable({ providedIn: 'root', }) export class XMarkdownContainer extends XComponentCardContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly content: string = ''; readonly contentChange = new EventEmitter(); // readonly mode: XStandardType = XMarkdownMode.BOTH; // readonly editorBoxColor: XStandardType = XColorWithBrightness.Transparent; readonly previewBoxColor: XStandardType = XColorWithBrightness.Transparent; // //#region Toolbar ... readonly hasToolbar: XStandardType = true; readonly toolbarCssClass: XStandardType>; readonly toolbarColor: XStandardType = XColorWithBrightness.Light; readonly toolbarForegroundColor: XStandardType = false; readonly toolbarConfig: XStandardType; //#endregion //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XMarkdownContainerComponent extends XComponentCardContainerComponent implements IXMarkdownContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() content: string = this.propertyProvider.content; @Output() contentChange: EventEmitter = new EventEmitter(); // @Input() mode: XStandardType = this.propertyProvider.mode; // @Input() editorBoxColor: XStandardType = this.propertyProvider.editorBoxColor; @Input() previewBoxColor: XStandardType = this.propertyProvider.previewBoxColor; // //#region Toolbar ... @Input() hasToolbar: XStandardType = this.propertyProvider.hasToolbar; @Input() toolbarCssClass: XStandardType> = this.propertyProvider.toolbarCssClass; @Input() toolbarColor: XStandardType = this.propertyProvider.toolbarColor; @Input() toolbarForegroundColor: XStandardType = this.propertyProvider.toolbarForegroundColor; @Input() toolbarConfig: XStandardType = this.propertyProvider.toolbarConfig; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XMarkdownContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXMarkdownContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // content: this.getValue( container ? container.content : this.content ), // mode: this.getValue(container ? container.mode : this.mode), // editorBoxColor: this.getValue( container ? container.editorBoxColor : this.editorBoxColor ), previewBoxColor: this.getValue( container ? container.previewBoxColor : this.previewBoxColor ), // hasToolbar: this.getValue( container ? container.hasToolbar : this.hasToolbar ), toolbarCssClass: this.getArrayValue( container ? container.toolbarCssClass : this.toolbarCssClass ), toolbarColor: this.getValue( container ? container.toolbarColor : this.toolbarColor ), toolbarForegroundColor: this.getValue( container ? container.toolbarForegroundColor : this.toolbarForegroundColor ), toolbarConfig: this.getValue( container ? container.toolbarConfig : this.toolbarConfig ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // contentChange: this.contentChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.component.html
{{ getTitle(key) | async }}
{{ getContent(key, preparedModel[key]) | async }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.component.scss :host { // --header-highlight-color: var(--x-color-light-shade); // --header-background-color: var(--x-color-light); --header-foreground-color: var(--x-color-light-contrast); // --content-background-color: var(--x-color-light); --content-foreground-color: var(--x-color-light-contrast); // --panel-background-color: var(--x-color-light); --panel-foreground-color: var(--x-color-light-contrast); } :host ::ng-deep .x-card { .x-actions { display: none; } .x-content { padding: 0px !important; margin: 0px; } } :host ::ng-deep .x-expandable-panel { // &.mobile { .mat-expansion-panel-header { margin: { top: 2px; bottom: 6px; } } } .mat-expansion-panel { // box-shadow: unset; color: var(--panel-foreground-color); background-color: var(--panel-background-color); // .mat-expansion-panel-body { color: var(--panel-foreground-color); background-color: var(--panel-background-color); } // .mat-expansion-panel-header { // color: var(--header-foreground-color); background-color: var(--header-background-color); // // Header HighLight ... &.cdk-keyboard-focused, &.cdk-program-focused, &:not(.mat-expanded):hover { background-color: var(--header-highlight-color); } &.mobile { .mat-content { flex-direction: column; } .x-model-presenter-title { .x-title-span { max-width: calc(80%); } } } .x-expandable-panel-header-title { // flex-grow: 0; margin-left: 4px !important; // .x-model-presenter-title { width: 100%; word-wrap: unset; white-space: pre; } // .x-model-presenter-title.hasLabel { .x-title-span::after { content: " : "; } } } .x-expandable-panel-header-description { // overflow: hidden; margin-left: 4px !important; // .x-model-presenter-content { width: 100%; } .x-end-bottom-slot { flex: 0 0 auto !important; } .x-start-top-slot { overflow: hidden; } .x-start-top-slot-inner-container { max-width: calc(90%); } } } // .mat-expansion-panel-content { color: var(--content-foreground-color); background-color: var(--content-background-color); } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.component.ts import { Component, QueryList, ContentChildren, ChangeDetectionStrategy, } from '@angular/core'; import { tap, map, filter, mergeMap, switchMap, concatMap, } from 'rxjs/operators'; import { keys, nameof, isDate, isArray, toArray, isNumber, isString, isObject, toXString, isFunction, parseXColor, isSameObject, XOneOrManyType, XModelProperty, toNormalString, getPropertyValue, setPropertyValue, isNullOrUndefined, isNullOrEmptyString, getXColorCssVariableName, } from 'x-framework-core'; import { XModelPresenterAction, XModelPresenterCssVars, XModelPresenterActionModel, XModelPresenterStartupState, XModelPresenterContainerComponent, } from './x-model-presenter.typings'; import { XExpandablePanelAction, XExpandablePanelActionModel, } from '../x-expandable-panel/x-expandable-panel.typings'; import { XSlotLayout, XSlotName } from '../x-slotter/x-slotter.typings'; import { of, from, Subject, forkJoin, Observable, Subscription } from 'rxjs'; import { XModelPresenterItemComponent } from './x-model-presenter-item/x-model-presenter-item.component'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-model-presenter', templateUrl: './x-model-presenter.component.html', styleUrls: ['./x-model-presenter.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XModelPresenterComponent< T = any > extends XModelPresenterContainerComponent { // //#region Props ... private MODEL: T; private keyPrefix = ''; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly SlotNames = Object.assign({}, XSlotName); readonly SlotLayouts = Object.assign({}, XSlotLayout); // get prefix() { return this.keyPrefix; } get preparedModel() { return this.MODEL; } // @ContentChildren(XModelPresenterItemComponent) items: QueryList; //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.prepareModel(); await this.handleStartupState(); } async afterViewInit() { super.afterViewInit(); // // prepare KeyPrefix ... const keyPrefix = this.element.nativeElement ? (this.element.nativeElement as HTMLElement).getAttribute('keyPrefix') : ''; if (!isNullOrEmptyString(keyPrefix)) { this.keyPrefix += `${keyPrefix}`; } } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Model Changed ... const isModelChanged = changeKeys.includes( nameof('model') ); // if (isModelChanged) { await this.prepareModel(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); const isPanelActionProviderChanged = changeKeys.includes( nameof('panelActionProvider') ); if (isActionProviderChanged || isPanelActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Color Changes ... // //#region Color Changed ... const isColorChanged = changeKeys.includes( nameof('color') ); if (isColorChanged) { await this.applyPanelColor(); } //#endregion // //#region Header Highlight Color Changed ... const isHeaderHighlightColorChanged = changeKeys.includes( nameof('headerHighlightColor') ); if (isHeaderHighlightColorChanged) { await this.applyHeaderHighlightColor(); } //#endregion // //#region Header Color Changed ... const isHeaderColorChanged = changeKeys.includes( nameof('headerColor') ); if (isHeaderColorChanged) { await this.applyHeaderColor(); } //#endregion // //#region Content Color Changed ... const isContentColorChanged = changeKeys.includes( nameof('contentColor') ); if (isContentColorChanged) { await this.applyContentColor(); } //#endregion //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... keys(model: T) { // let modelKeys = keys(model); // if (!this.hasChild(this.sortOrderModelKeys)) { return modelKeys; } // const sortOrderArray = toArray(this.sortOrderModelKeys) as string[]; const result: string[] = [ ...sortOrderArray.filter((k) => modelKeys.includes(k)), ...modelKeys.filter((k) => !sortOrderArray.includes(k)), ]; // return result; } canShowKey(key: string) { // return forkJoin({ key: this.getValue(key), model: this.getValue(this.model), prefix: this.getValue(this.keyPrefix), hiddenModelKeys: this.getArrayValue(this.hiddenModelKeys), hideOptionalValues: this.getValue(this.hideOptionalValues), availableModelKeys: this.getArrayValue(this.availableModelKeys), }).pipe( map((provider) => { // const value = provider.model[provider.key]; // const modelHasValue = !isNullOrUndefined(provider.model) && !isNullOrUndefined(value) && !isNullOrEmptyString(toXString(provider.model[provider.key])); const hasChildHiddens = this.hasChild(provider.hiddenModelKeys); const hasChildAvailables = this.hasChild(provider.availableModelKeys); // if (!hasChildAvailables && !hasChildHiddens) { // if (!modelHasValue && provider.hideOptionalValues) { return false; } // return true; } // const isInHiddens = provider.hiddenModelKeys.includes( provider.key as any ); const isInAvailables = provider.availableModelKeys.includes( provider.key as any ); // if ( (!hasChildAvailables && !isInHiddens) || (isInAvailables && !hasChildHiddens) || (isInAvailables && !isInHiddens) || (!isInAvailables && !isInHiddens && isNumber(provider.key) && !isNullOrEmptyString(provider.prefix)) ) { // if (!modelHasValue && provider.hideOptionalValues) { return false; } // return true; } // return false; }) ); } canShowLabelKey(key: string) { return this.getArrayValue(this.hiddenLabelModelKeys).pipe( map((hiddenLabelsModelKeys) => { // const hasChildHiddenLabels = this.hasChild(hiddenLabelsModelKeys); // if (!hasChildHiddenLabels) { return true; } // const isInHiddens = hiddenLabelsModelKeys.includes(key as any); return hasChildHiddenLabels && !isInHiddens; }) ); } getTitle(key: string): Observable { return this.getValue(this.modelKeyProvider).pipe( concatMap((provider) => { return isNullOrUndefined(provider) || !isFunction(provider) ? this.getValue(key) : this.getValue(provider(key as any)); }) ); } hasContentItem(key: string) { return of(this.items).pipe( concatMap((items) => { return isNullOrUndefined(items) ? of(false) : this.getArrayValue(items.toArray()).pipe( switchMap((items) => from(items).pipe( mergeMap((item) => this.getValue(item.name).pipe( map((name) => ({ name, item })) ) ), filter( (itemData) => toNormalString(itemData.name) === toNormalString(key) ), map((dataObject) => !isNullOrUndefined(dataObject)) ) ) ); }) ); } getContentItem( key: string, value: any ): Observable { return this.hasContentItem(key).pipe( concatMap((isExists) => { return !isExists ? of(null) : of(this.items).pipe( concatMap((items) => { return isNullOrUndefined(items) ? of(null) : this.getArrayValue(items.toArray()).pipe( switchMap((items) => from(items).pipe( mergeMap((item) => this.getValue(item.name).pipe( map((name) => ({ name, item })) ) ), filter( (itemData) => toNormalString(itemData.name) === toNormalString(key) ), tap((dataObject) => (dataObject.item.value = value)), map((dataObject) => dataObject.item) ) ) ); }) ); }) ); } getContent(key: string, value: any): Observable { return this.getValue(this.modelValueProvider).pipe( concatMap((provider) => { return isNullOrUndefined(provider) || !isFunction(provider) ? this.getValue(value) : this.getValue(provider(key as any, value)); }) ); } canDescribe(key: string, value: any) { return of(value).pipe( map( (eVal) => isDate(eVal) || isFunction(eVal) || (!isArray(eVal) && !isObject(eVal)) ) ); } getModelPresenterTitleClasses(key: string) { return [`x-model-presenter-${key}-title`]; } getModelPresenterContentClasses(key: string) { return [`x-model-presenter-${key}-content`]; } // //#region Neste ... getKeyPrefix(key: string) { // const result = isNullOrEmptyString(this.keyPrefix) ? `${key}` : `${this.keyPrefix}.${key}`; // return result; } getHiddenModelKeys(key: string) { return this.prepareNestedCollection(key, this.hiddenModelKeys); } getSortOrderModelKeys(key: string) { return this.prepareNestedCollection(key, this.sortOrderModelKeys); } getAvailableModelKeys(key: string) { return this.prepareNestedCollection(key, this.availableModelKeys); } getHiddenLabelModelKeys(key: string) { return this.prepareNestedCollection(key, this.hiddenLabelModelKeys); } //#endregion //#endregion // //#region UI Handlers ... //#endregion // //#region Actions ... async expandAll() { this.panelActionProvider.next({ action: XExpandablePanelAction.ExpandAll, }); } async collapseAll() { this.panelActionProvider.next({ action: XExpandablePanelAction.CollapseAll, }); } async setModelProperty(property: XModelProperty) { // if (!property || isNullOrEmptyString(property.key)) { return; } // const model = this.MODEL; const nodeValue = getPropertyValue(model, property.prefix); const modelKeys = isNullOrUndefined(nodeValue) ? [] : keys(nodeValue); if (!this.hasChild(modelKeys)) { return; } // const isExists = modelKeys.includes(property.key as string); if (!isExists) { return; } // // normalize value ... const normalValue = isString(property.value) ? !isNullOrEmptyString(property.value) && !isNullOrUndefined(property.value) ? property.value.toString().trim() : undefined : isNullOrUndefined(property.value) ? undefined : property.value; // if (nodeValue[property.key] === normalValue) { return; } // const setterPropertyPath = isNullOrEmptyString(property.prefix) ? `${property.key as string}` : `${property.prefix}.${property.key as string}`; // setPropertyValue(model, setterPropertyPath, normalValue); // this.MODEL = { ...model, }; this.detectChanges(); this.onModelChanged.emit(model); } async getModelProperty(key: keyof T | string) { // if (isNullOrEmptyString(key)) { return null; } // const model = await this.getValueAsync(this.model); const modelKeys = await this.getValueAsync(this.keys(model)); if (!this.hasChild(modelKeys)) { return null; } // const isExists = modelKeys.includes(key); if (!isExists) { return null; } // const result = model[key as any]; return result; } async getModelViewProperty(key: keyof T | string) { // if (isNullOrEmptyString(key)) { return null; } // const model = await this.getValueAsync(this.model); const modelKeys = await this.getValueAsync(this.keys(model)); if (!this.hasChild(modelKeys)) { return null; } // const isExists = modelKeys.includes(key); if (!isExists) { return null; } // const result = await this.getValueAsync( this.getContent(key, model[key as any]) ); return result; } async setModel(model: T) { // if (!model || isSameObject(model as any, this.MODEL as any)) { return; } // this.model = { ...model, }; this.MODEL = { ...model, }; // await this.prepareModel(); this.onModelChanged.emit(model); } async getModel() { // const result = await this.getValueAsync(this.model); return result; } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // if (!this.panelActionProvider) { this.panelActionProvider = new Subject(); } // let modelProperty: XModelProperty = null; // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XModelPresenterAction.Refresh: this.detectChanges(); break; // case XModelPresenterAction.ExpandAll: await this.expandAll(); break; // case XModelPresenterAction.CollapseAll: await this.collapseAll(); break; // case XModelPresenterAction.ClearProperty: // modelProperty = model.payload as XModelProperty; if ( !model.payload || isNullOrUndefined(model) || isNullOrUndefined(model.payload) || isNullOrEmptyString(model.action) ) { return; } // modelProperty.value = null; // await this.setModelProperty(modelProperty); break; // case XModelPresenterAction.SetProperty: // modelProperty = model.payload as XModelProperty; if ( !model.payload || isNullOrUndefined(model) || isNullOrUndefined(model.payload) || isNullOrEmptyString(model.action) ) { return; } // await this.setModelProperty(modelProperty); break; // case XModelPresenterAction.SetModel: // const resetModel = model.payload as T; if (!model || !model.payload || !resetModel) { return; } // await this.setModel(resetModel); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async prepareModel() { // this.MODEL = null; this.detectChanges(); // if (!this.model) { return; } // this.MODEL = await this.getValueAsync(this.model); this.detectChanges(); } private prepareNestedCollection( key: string, collection: XOneOrManyType ) { // return forkJoin({ key: this.getValue(key), prefix: this.getValue(this.getKeyPrefix(key)), model: this.getValue(this.preparedModel[key]), collection: this.getArrayValue(collection), }).pipe( map((provider) => { // const allAvailableCollectionItems = provider.collection; // const keySelector = isNullOrUndefined(provider.prefix) ? `${provider.key}.` : `${provider.prefix}.`; // const canFilter = !isNumber(provider.key) && !provider.prefix.includes(`${provider.key}.`); const result = canFilter ? allAvailableCollectionItems .filter((k) => k.includes(`${provider.key}.`)) .map((k) => k.replace(`${provider.key}.`, '')) : allAvailableCollectionItems; // return result; }) ); } private async handleStartupState() { // const state = await this.getValueAsync(this.startupState); if (isNullOrEmptyString(state)) { return; } // switch (state) { // case XModelPresenterStartupState.CollapseAll: await this.collapseAll(); break; // case XModelPresenterStartupState.ExpandAll: await this.expandAll(); break; } } // //#region Color Appliers ... private async applyPanelColor() { // const color = await this.getValueAsync(this.color); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XModelPresenterCssVars.PanelForegroundColor, `var(${fgColor})` ); this.setCssVar( XModelPresenterCssVars.PanelBackgroundColor, `var(${bgColor})` ); // this.detectChanges(); } private async applyHeaderColor() { // const color = await this.getValueAsync(this.headerColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XModelPresenterCssVars.HeaderForegroundColor, `var(${fgColor})` ); this.setCssVar( XModelPresenterCssVars.HeaderBackgroundColor, `var(${bgColor})` ); // this.detectChanges(); } private async applyHeaderHighlightColor() { // const color = await this.getValueAsync(this.headerHighlightColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XModelPresenterCssVars.HeaderHighlighColor, `var(${bgColor})` ); // this.detectChanges(); } private async applyContentColor() { // const color = await this.getValueAsync(this.contentColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XModelPresenterCssVars.ContentForegroundColor, `var(${fgColor})` ); this.setCssVar( XModelPresenterCssVars.ContentBackgroundColor, `var(${bgColor})` ); // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XModelPresenterComponent } from './x-model-presenter.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XExpandablePanelModule } from '../x-expandable-panel/x-expandable-panel.module'; import { XModelPresenterItemComponent } from './x-model-presenter-item/x-model-presenter-item.component'; @NgModule({ declarations: [XModelPresenterComponent, XModelPresenterItemComponent], imports: [ XCardModule, CommonModule, XBaseComponentModule, XExpandablePanelModule, ], exports: [ XCardModule, CommonModule, XBaseComponentModule, XExpandablePanelModule, XModelPresenterComponent, XModelPresenterItemComponent, ], }) export class XModelPresenterModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XModelFieldsType, XColorIdentifier, XModelKeyProvider, XModelValueProvider, XColorWithBrightness, } from 'x-framework-core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; import { XExpandablePanelActionModel } from '../x-expandable-panel/x-expandable-panel.typings'; export enum XModelPresenterStartupState { ExpandAll = 'expand-all', CollapseAll = 'collapse-all', } export type XModelPresenterStartupStateIdentifier = | XModelPresenterStartupState | string; export enum XModelPresenterAction { // ExpandAll = 'expand-all', CollapseAll = 'collapse-all', // ClearProperty = 'clear_property', SetProperty = 'set_property', // SetModel = 'set_model', // Refresh = 'refresh', } export type XModelPresenterActionIdentifier = XModelPresenterAction | string; export interface XModelPresenterActionModel extends XBaseActionModel {} export enum XModelPresenterCssVars { // HeaderHighlighColor = 'header-highlight-color', // HeaderForegroundColor = 'header-foreground-color', HeaderBackgroundColor = 'header-background-color', // ContentForegroundColor = 'content-foreground-color', ContentBackgroundColor = 'content-background-color', // PanelForegroundColor = 'panel-foreground-color', PanelBackgroundColor = 'panel-background-color', } export type XModelPresenterCssVarsIdentifier = XModelPresenterCssVars | string; // //#region Inside Card Container ... export interface IXModelPresenterContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; // headerColor: XStandardType; headerHighlightColor: XStandardType; contentColor: XStandardType; labelColor: XStandardType; valueColor: XStandardType; // showLabels: XStandardType; propertyActionTemplate: TemplateRef; startupState: XStandardType; // panelCssClass: XStandardType>; panelActionProvider: Subject; // model: XStandardType; // hideOptionalValues: XStandardType; availableModelKeys: XModelFieldsType; hiddenModelKeys: XModelFieldsType; hiddenLabelModelKeys: XModelFieldsType; sortOrderModelKeys: XModelFieldsType; modelKeyProvider: XModelKeyProvider; modelValueProvider: XModelValueProvider; // onModelChanged: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XModelPresenterContainer extends XComponentCardContainer implements Readonly> { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly headerColor: XStandardType = XColorWithBrightness.Light; readonly headerHighlightColor: XStandardType = XColorWithBrightness.LightShade; readonly contentColor: XStandardType = XColorWithBrightness.Dark; readonly labelColor: XStandardType = XColorWithBrightness.TertiaryShade; readonly valueColor: XStandardType = XColorWithBrightness.Dark; // readonly showLabels: XStandardType = true; readonly propertyActionTemplate: TemplateRef; readonly startupState: XStandardType = XModelPresenterStartupState.CollapseAll; // readonly panelCssClass: XStandardType>; readonly panelActionProvider: Subject = new Subject(); // readonly model: XStandardType; // readonly hideOptionalValues: XStandardType = false; readonly availableModelKeys: XModelFieldsType; readonly hiddenModelKeys: XModelFieldsType; readonly hiddenLabelModelKeys: XModelFieldsType; readonly sortOrderModelKeys: XModelFieldsType; readonly modelKeyProvider: XModelKeyProvider; readonly modelValueProvider: XModelValueProvider; // readonly onModelChanged: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XModelPresenterContainerComponent extends XComponentCardContainerComponent implements IXModelPresenterContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Input() headerColor: XStandardType = this.propertyProvider.headerColor; @Input() headerHighlightColor: XStandardType = this.propertyProvider.headerHighlightColor; @Input() contentColor: XStandardType = this.propertyProvider.contentColor; @Input() labelColor: XStandardType = this.propertyProvider.labelColor; @Input() valueColor: XStandardType = this.propertyProvider.valueColor; // @Input() showLabels: XStandardType = this.propertyProvider.showLabels; @Input() propertyActionTemplate: TemplateRef = this.propertyProvider.propertyActionTemplate; @Input() startupState: XStandardType = this.propertyProvider.startupState; // @Input() panelCssClass: XStandardType> = this.propertyProvider.panelCssClass; @Input() panelActionProvider: Subject = this.propertyProvider.panelActionProvider; // @Input() model: XStandardType = this.propertyProvider.model; // @Input() hideOptionalValues: XStandardType = this.propertyProvider.hideOptionalValues; @Input() availableModelKeys: XModelFieldsType = this.propertyProvider.availableModelKeys; @Input() hiddenModelKeys: XModelFieldsType = this.propertyProvider.hiddenModelKeys; @Input() hiddenLabelModelKeys: XModelFieldsType = this.propertyProvider.hiddenLabelModelKeys; @Input() sortOrderModelKeys: XModelFieldsType = this.propertyProvider.sortOrderModelKeys; @Input() modelKeyProvider: XModelKeyProvider = this.propertyProvider.modelKeyProvider; @Input() modelValueProvider: XModelValueProvider = this.propertyProvider.modelValueProvider; // @Output() onModelChanged: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XModelPresenterContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXModelPresenterContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), headerColor: this.getValue( container ? container.headerColor : this.headerColor ), headerHighlightColor: this.getValue( container ? container.headerHighlightColor : this.headerHighlightColor ), contentColor: this.getValue( container ? container.contentColor : this.contentColor ), labelColor: this.getValue( container ? container.labelColor : this.labelColor ), valueColor: this.getValue( container ? container.valueColor : this.valueColor ), showLabels: this.getValue( container ? container.showLabels : this.showLabels ), propertyActionTemplate: this.getValue( container ? container.propertyActionTemplate : this.propertyActionTemplate ), startupState: this.getValue( container ? container.startupState : this.startupState ), panelCssClass: this.getValue( container ? container.panelCssClass : this.panelCssClass ), model: this.getValue(container ? container.model : this.model), hideOptionalValues: this.getValue( container ? container.hideOptionalValues : this.hideOptionalValues ), availableModelKeys: this.getValue( container ? container.availableModelKeys : this.availableModelKeys ), hiddenModelKeys: this.getValue( container ? container.hiddenModelKeys : this.hiddenModelKeys ), hiddenLabelModelKeys: this.getValue( container ? container.hiddenLabelModelKeys : this.hiddenLabelModelKeys ), sortOrderModelKeys: this.getValue( container ? container.sortOrderModelKeys : this.sortOrderModelKeys ), modelKeyProvider: this.getValue( container ? container.modelKeyProvider : this.modelKeyProvider ), modelValueProvider: this.getValue( container ? container.modelValueProvider : this.modelValueProvider ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // panelActionProvider: container ? container.panelActionProvider : this.panelActionProvider, // onModelChanged: this.onModelChanged, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter-item\x-model-presenter-item.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter-item\x-model-presenter-item.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter-item\x-model-presenter-item.component.ts import { Input, Inject, NgZone, Renderer2, Component, ViewChild, ElementRef, TemplateRef, ChangeDetectorRef, } from '@angular/core'; import { XModelPresenterItemAction, XModelPresenterItemModel, } from './x-model-presenter-item.typings'; import { Subject, Subscription } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseComponent } from '../../classes/x-base-component'; import { XStandardType, XOneOrManyType, nameof } from 'x-framework-core'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from './../../config/x-framework-components.config'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-model-presenter-item', templateUrl: './x-model-presenter-item.component.html', styleUrls: ['./x-model-presenter-item.component.scss'], // changeDetection: ChangeDetectionStrategy.OnPush, }) export class XModelPresenterItemComponent extends XBaseComponent { // //#region Props ... // @ViewChild('content', { static: false }) content: TemplateRef; // @Input() name: XStandardType; @Input() value: XStandardType; // @Input() cssClass: XStandardType>; // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; @Input() actionProvider = new Subject(); //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Private ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XModelPresenterItemAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-model-presenter\x-model-presenter-item\x-model-presenter-item.typings.ts import { XBaseActionModel } from '../../classes/x-base-action.model'; export enum XModelPresenterItemAction { Refresh = 'refresh', } export type XModelPresenterItemActionIdentifier = XModelPresenterItemAction | string; export interface XModelPresenterItemModel extends XBaseActionModel {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.component.scss :host { height: 100%; --side-menu-width: 200px; --side-menu-min-width: 100px; --side-menu-max-width: 200px; --side-menu-content-height-gutter: 0px; --side-menu-content-offset-top: 0px; --side-menu-content-offset-bottom: 0px; --content-height-gutter: 0px; --content-offset-top: 0px; --content-offset-bottom: 0px; ion-refresher { padding-top: 90px; } ion-content { // height: calc(100% - var(--content-height-gutter)); overflow: auto; // --offset-top: var(--content-offset-top) !important; --offset-bottom: var(--content-offset-bottom) !important; // --padding-top: 0; --padding-end: 0; --padding-start: 0; --padding-bottom: 0; } } :host::ng-deep { ion-header, ion-footer { z-index: 10000 !important; } } .x-menu { // --width: var(--side-menu-width) !important; --min-width: var(--side-menu-min-width) !important; --max-width: var(--side-menu-max-width) !important; // ion-content { // height: calc(100% - var(--side-menu-content-height-gutter)) !important; overflow: auto !important; // --offset-top: var(--side-menu-content-offset-top) !important; --offset-bottom: var(--side-menu-content-offset-bottom) !important; // --padding-top: 0; --padding-end: 0; --padding-start: 0; --padding-bottom: 0; } } .split-pane-visible > .split-pane-side { border: 0 !important; width: var(--side-menu-width) !important; min-width: var(--side-menu-min-width) !important; max-width: var(--side-menu-max-width) !important; } .x-footer-offset, .x-toolbar-offset { visibility: hidden; } .x-page-side-wrapper { touch-action: pan-y; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.component.ts import { XMenuState, XMenuAction, XPageCSSVars, XPageLoadingEvent, } from './x-page.typings'; import { map } from 'rxjs/operators'; import { IonContent } from '@ionic/angular'; import { XFabItem } from '../x-fab/x-fab.typings'; import { isNullOrUndefined, nameof, XBehaviourEvent } from 'x-framework-core'; import { XPageContainerComponent } from './x-page.container'; import { XFooterComponent } from './x-footer/x-footer.component'; import { XToolbarComponent } from './x-toolbar/x-toolbar.component'; import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core'; import { XToolbarAction } from './x-toolbar/x-toolbar.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-page', templateUrl: './x-page.component.html', styleUrls: ['./x-page.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XPageComponent extends XPageContainerComponent { // //#region Props ... // readonly MenuStates = Object.assign({}, XMenuState); // scrollYOffset = 0; scrollXOffset = 0; // //#region View Childs ... // //#region Toolbar ... private TOOLBAR: XToolbarComponent; @ViewChild('toolbar', { static: false }) set toolbar(v: XToolbarComponent) { // if (!isNullOrUndefined(v)) { // this.TOOLBAR = v; this.applyContentSize(); } } get toolbar() { return this.TOOLBAR; } //#endregion // //#region Footer ... private FOOTER: XFooterComponent; @ViewChild('footer', { static: false }) set footer(v: XFooterComponent) { // if (!isNullOrUndefined(v)) { // this.FOOTER = v; this.applyContentSize(); } } get footer() { return this.FOOTER; } //#endregion //#endregion // //#region Side Props ... // private IS_SIDE_OPENED = false; get isSideOpened() { return this.IS_SIDE_OPENED; } private CAN_CLOSE_MENU = true; get canCloseMenu() { return this.CAN_CLOSE_MENU; } //#endregion //#endregion // //#region LifeCycle ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region CssVars ... // //#region SideMenuWidth ... const isSideMenuWidthChanged = changeKeys.includes( nameof('sideMenuWidth') ); const isSideMenuMinWidthChanged = changeKeys.includes( nameof('sideMenuMinWidth') ); const isSideMenuMaxWidthChanged = changeKeys.includes( nameof('sideMenuMaxWidth') ); if ( isSideMenuWidthChanged || isSideMenuMinWidthChanged || isSideMenuMaxWidthChanged ) { await this.applySideMenuWidth(); } //#endregion //#endregion } async afterViewInit() { super.afterViewInit(); // this.handleMenuStartState(); await this.applyContentSize(); } //#endregion // //#region Register Handlers ... registerViewHandlers() { super.registerViewHandlers(); // this.registerResizeHandler(); this.registerMenuActionProvider(); this.registerToolbarActionProvider(); } //#endregion // //#region UI Providers ... //#endregion // //#region UI Handlers ... async handleChangeSplitPane(event: CustomEvent | any) { // const canUseMenu = await this.canUseMenu(); if (!canUseMenu) { return; } // const isSideOpened = event.detail.visible; this.IS_SIDE_OPENED = isSideOpened; this.splitterStateChanged.emit(isSideOpened); // if (isSideOpened) { // this.CAN_CLOSE_MENU = false; this.menuState = XMenuState.Opened; await this.openMenu(); } else { // this.CAN_CLOSE_MENU = true; this.menuState = XMenuState.Closed; await this.closeMenu(); } } async handleMenuStateChanged(state: XMenuState) { // const canUseMenu = await this.canUseMenu(); if (!canUseMenu) { return; } // this.menuState = state; // this.menuStateChange.emit(state); } async handleRefresh(event: any) { // const loaderEvent: XPageLoadingEvent = { type: 'RefreshLoader', event, }; // this.refreshPage.emit(loaderEvent); } async handleLoadMore(event: any) { // const loaderEvent: XPageLoadingEvent = { type: 'InfinityScrollerLoader', event, }; // this.loadMore.emit(loaderEvent); } async cancelLoading(event: any) { // if (!event) { return; } // event.target.complete(); } async handleScrollStarted(event: XBehaviourEvent) { // this.scrolledEvent.emit(event); // this.closeActions(); } async handleScrollingEvent(event: XBehaviourEvent) { // this.scrolledEvent.emit(event); // this.scrollYOffset = event.event.detail.scrollTop as number; this.scrollXOffset = event.event.detail.scrollLeft as number; // await this.applyCaptureOffsets(); } isMenuOpen() { // return this.getValue(this.menuState).pipe( map((menuState) => { return ( menuState === XMenuState.WillOpen || menuState === XMenuState.Opened ); }) ); } //#endregion // //#region Actions ... async openMenu() { // const canUseMenu = await this.canUseMenu(); if (!canUseMenu || this.IS_SIDE_OPENED) { return; } // this.menuController.open(); } async closeMenu() { // const canUseMenu = await this.canUseMenu(); if (!canUseMenu || !this.CAN_CLOSE_MENU) { return; } // this.menuController.close(); } async toggleMenu() { // const canUseMenu = await this.canUseMenu(); if (!canUseMenu) { return; } // if (this.isMenuOpen()) { await this.closeMenu(); } else { await this.openMenu(); } } async scrollToTop(duration?: number) { // await this.waitForElement('ion-content[id="x-menu-wrapper"]').then( (el: any) => { el.scrollToTop(duration); } ); } async scrollToBottom(duration?: number) { // await this.waitForElement('ion-content[id="x-menu-wrapper"]').then( (el: any) => { el.scrollToBottom(duration); } ); } async scrollByPoint(x?: number, y?: number, duration?: number) { // await this.waitForElement('ion-content[id="x-menu-wrapper"]').then( (el: any) => { el.scrollByPoint(x, y, duration); } ); } async scrollToPoint(x?: number, y?: number, duration?: number) { // await this.waitForElement('ion-content[id="x-menu-wrapper"]').then( (el: any) => { el.scrollToPoint(x, y, duration); } ); } closeActions(delay: number = 1000) { // if (!this.actions) { return; } // setTimeout(() => { // if (!this.actions) { return; } // this.actions = { ...this.actions, activated: false, } as XFabItem; // this.detectChanges(); }, delay); } openActions(delay: number = 1000) { // if (!this.actions) { return; } // setTimeout(() => { // if (!this.actions) { return; } // this.actions = { ...this.actions, activated: true, } as XFabItem; // this.detectChanges(); }, delay); } //#endregion // //#region Private ... private async canUseMenu() { // if (!this.toolbarHasMenu || !this.toolbarShowMenu) { return false; } // const hasMenu = await this.toPromise(this.getValue(this.toolbarHasMenu)); const showMenu = await this.toPromise(this.getValue(this.toolbarShowMenu)); // if (!hasMenu || !showMenu) { return false; } // return true; } private async handleMenuStartState() { // const canUseMenu = await this.canUseMenu(); if (!canUseMenu || this.isSideOpened) { return; } // switch (this.menuState) { // case XMenuState.WillOpen: case XMenuState.Opened: await this.openMenu(); break; // case XMenuState.WillClose: case XMenuState.Closed: await this.closeMenu(); break; } } private registerMenuActionProvider() { // this.applyTakeUntilWrapper( this.menuActionProvider.asObservable() ).subscribe((action) => { // switch (action) { case XMenuAction.Open: this.openMenu(); break; case XMenuAction.Close: this.closeMenu(); break; case XMenuAction.Toggle: this.toggleMenu(); break; } }); } private registerToolbarActionProvider() { // if (isNullOrUndefined(this.toolbarActionProvider)) { return; } // this.applyTakeUntilWrapper( this.toolbarActionProvider.asObservable() ).subscribe(async (event) => { // if (isNullOrUndefined(event)) { return; } // if (event.action === XToolbarAction.ToggleMenu) { await this.toggleMenu(); } }); } private async registerResizeHandler() { // this.applyTakeUntilWrapper(this.ruler.change()).subscribe(async () => { await this.applyContentSize(); }); } private async getToolbarHeight() { // if (!this.toolbar) { return 0; } // const toolbarElm = this.toolbar.getElement(); // if (!toolbarElm) { return 0; } // return toolbarElm.getBoundingClientRect().height; } private async getFooterHeight() { // if (!this.footer) { return 0; } // const footerElm = this.footer.getElement(); // if (!footerElm) { return 0; } // return footerElm.getBoundingClientRect().height; } private async applyContentSize() { // const showToolbar = await this.getValueAsync(this.showToolbar); const toolbarHeight = await this.getToolbarHeight(); // const showFooter = await this.getValueAsync(this.showFooter); const footerHeight = await this.getFooterHeight(); // if ( (showToolbar && toolbarHeight === 0) || (showFooter && footerHeight === 0) ) { // setTimeout(() => this.applyContentSize(), 100); return; } // const topValue = showToolbar ? `-${toolbarHeight}px` : '0px'; const bottomValue = showFooter ? `-${footerHeight}px` : '0px'; // this.setCssVar(XPageCSSVars.ContentOffsetTop, topValue); this.setCssVar(XPageCSSVars.SideMenuContentOffsetTop, topValue); // this.setCssVar(XPageCSSVars.ContentOffsetBottom, bottomValue); this.setCssVar(XPageCSSVars.SideMenuContentOffsetBottom, bottomValue); // await this.applyCaptureOffsets(); // this.detectChanges(); } private async applySideMenuWidth() { // const sideMenuWidth = (await this.getValueAsync(this.sideMenuWidth)) || 200; const sideMenuMinWidth = (await this.getValueAsync(this.sideMenuMinWidth)) || 100; const sideMenuMaxWidth = (await this.getValueAsync(this.sideMenuMaxWidth)) || 200; // this.setCssVar(XPageCSSVars.SideMenuWidth, `${sideMenuWidth}px`); this.setCssVar(XPageCSSVars.SideMenuMinWidth, `${sideMenuMinWidth}px`); this.setCssVar(XPageCSSVars.SideMenuMaxWidth, `${sideMenuMaxWidth}px`); // this.detectChanges(); } private async applyCaptureOffsets() { // const showToolbar = await this.getValueAsync(this.showToolbar); const toolbarHeight = await this.getToolbarHeight(); // const showFooter = await this.getValueAsync(this.showFooter); const footerHeight = await this.getFooterHeight(); // if ( (showToolbar && toolbarHeight === 0) || (showFooter && footerHeight === 0) ) { // setTimeout(() => this.applyCaptureOffsets(), 100); return; } // this.captureTopOffset = -1 * this.scrollYOffset + -1 * toolbarHeight; // this.detectChanges(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.container.ts import { Input, NgZone, Output, Inject, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XSpinner, XStandardType, XOneOrManyType, XBehaviourEvent, XColorIdentifier, XSpinnerIdentifier, XBehaviourEventType, XColorWithBrightness, } from 'x-framework-core'; import { XPageSize, XSideSlot, XSideType, XMenuState, XMenuAction, XPageLoadingEvent, XMenuSlotIdentifier, XLogoSlotIdentifier, XPageSizeIdentifier, XSideSlotIdentifier, XSideTypeIdentifier, XBackSlotIdentifier, XTitleSlotIdentifier, XContentSlotIdentifier, } from './x-page.typings'; import { forkJoin } from 'rxjs'; import { map } from 'rxjs/operators'; import { XToolbarFooterContainer, IXToolbarFooterContainer, } from '../classes/i-x-toolbar-footer'; import { Observable, Subject } from 'rxjs'; import { MenuController } from '@ionic/angular'; import { XBasePage } from '../classes/x-base-page'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { IXBaseContainer } from '../classes/i-x-base.container'; import { XFooterActionModel } from './x-footer/x-footer.typings'; import { XFabActionModel, XFabItem } from '../x-fab/x-fab.typings'; import { XToolbarActionModel } from './x-toolbar/x-toolbar.typings'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; // //#region Container ... export interface IXPageContainer extends IXBaseContainer, IXToolbarFooterContainer { // cssClass: XStandardType>; // color: XStandardType; // enableCaptureMode: XStandardType; downloadCapturedImage: XStandardType; captureTopOffset: XStandardType; captureBottomOffset: XStandardType; imageCaptured: EventEmitter; // provideScrollEvents: XStandardType; scrollStartClasses: XOneOrManyType; scrollEndClasses: XOneOrManyType; scrollingClasses: XOneOrManyType; scrollBehaviour: XOneOrManyType; scrollEventActionProvider: Subject; scrolledEvent: EventEmitter; // toggleMenuWhen: XStandardType; hasSide: XStandardType; sideSlot: XStandardType; sideType: XStandardType; sideColor: XStandardType; sideMenuWidth: XStandardType; sideMenuMinWidth: XStandardType; sideMenuMaxWidth: XStandardType; menuState: XStandardType; menuActionProvider: Subject; splitterStateChanged: EventEmitter; menuStateChange: EventEmitter; // showPageRefresher: XStandardType; refreshPage: EventEmitter; refreshingText: XStandardType; refreshPullingText: XStandardType; refreshPullingIcon: XStandardType; refreshingSpinner: XStandardType; // showPageInfinityScroller: XStandardType; infinityScrollDisabled: XStandardType; infinityScrollThreshold: XStandardType; infinityScrollerLoadingText: XStandardType; infinityScrollerLoadingSpinner: XStandardType; loadMore: EventEmitter; // actions: XStandardType; actionsActionProvider: Subject; } @Injectable({ providedIn: 'root', }) export class XPageContainer extends XToolbarFooterContainer implements Readonly { // readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.LightShade; // readonly enableCaptureMode: XStandardType = false; readonly downloadCapturedImage: XStandardType = true; readonly captureTopOffset: XStandardType = 0; readonly captureBottomOffset: XStandardType = 0; readonly imageCaptured: EventEmitter = new EventEmitter< string | Blob >(); // readonly provideScrollEvents: XStandardType; readonly scrollStartClasses: XOneOrManyType; readonly scrollEndClasses: XOneOrManyType; readonly scrollingClasses: XOneOrManyType; readonly scrollBehaviour: XOneOrManyType; readonly scrollEventActionProvider: Subject = new Subject(); readonly scrolledEvent: EventEmitter = new EventEmitter(); // readonly toggleMenuWhen: XStandardType = XPageSize.Medium; readonly hasSide: XStandardType = true; readonly sideSlot: XStandardType = XSideSlot.Start; readonly sideType: XStandardType = XSideType.Overlay; readonly sideColor: XStandardType = XColorWithBrightness.PrimaryShade; readonly sideMenuWidth: XStandardType = 200; readonly sideMenuMinWidth: XStandardType = 100; readonly sideMenuMaxWidth: XStandardType = 200; readonly menuState: XStandardType = XMenuState.Opened; readonly menuActionProvider = new Subject(); readonly splitterStateChanged = new EventEmitter(); readonly menuStateChange = new EventEmitter(); // readonly showPageRefresher: XStandardType = false; readonly refreshPage: EventEmitter = new EventEmitter(); readonly refreshingText: XStandardType; readonly refreshPullingText: XStandardType; readonly refreshPullingIcon: XStandardType; readonly refreshingSpinner: XStandardType = XSpinner.Circular; // readonly showPageInfinityScroller: XStandardType = false; readonly infinityScrollDisabled: XStandardType = false; readonly infinityScrollThreshold: XStandardType = '200px'; readonly infinityScrollerLoadingText: XStandardType; readonly infinityScrollerLoadingSpinner: XStandardType = XSpinner.Circular; readonly loadMore: EventEmitter = new EventEmitter(); // readonly actions: XStandardType; readonly actionsActionProvider: Subject = new Subject(); } @Injectable() @Component({ template: ``, }) export abstract class XPageContainerComponent extends XBasePage implements IXPageContainer { // //#region Props ... // //#region Page ... // @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; // @Input() enableCaptureMode: XStandardType = this.propertyProvider.enableCaptureMode; @Input() downloadCapturedImage: XStandardType = this.propertyProvider.downloadCapturedImage; @Input() captureTopOffset: XStandardType = this.propertyProvider.captureTopOffset; @Input() captureBottomOffset: XStandardType = this.propertyProvider.captureBottomOffset; @Output() imageCaptured: EventEmitter = new EventEmitter(); // @Input() provideScrollEvents: XStandardType = this.propertyProvider.provideScrollEvents; @Input() scrollStartClasses: XOneOrManyType = this.propertyProvider.scrollStartClasses; @Input() scrollEndClasses: XOneOrManyType = this.propertyProvider.scrollEndClasses; @Input() scrollingClasses: XOneOrManyType = this.propertyProvider.scrollingClasses; @Input() scrollBehaviour: XOneOrManyType = this.propertyProvider.scrollBehaviour; @Input() scrollEventActionProvider: Subject = this.propertyProvider.scrollEventActionProvider; @Output() scrolledEvent: EventEmitter = new EventEmitter(); // @Input() toggleMenuWhen: XStandardType = this.propertyProvider.toggleMenuWhen; @Input() hasSide: XStandardType = this.propertyProvider.hasSide; @Input() sideSlot: XStandardType = this.propertyProvider.sideSlot; @Input() sideType: XStandardType = this.propertyProvider.sideType; @Input() sideColor: XStandardType = this.propertyProvider.sideColor; @Input() sideMenuWidth: XStandardType = this.propertyProvider.sideMenuWidth; @Input() sideMenuMinWidth: XStandardType = this.propertyProvider.sideMenuMinWidth; @Input() sideMenuMaxWidth: XStandardType = this.propertyProvider.sideMenuMaxWidth; @Input() menuState: XStandardType = this.propertyProvider.menuState; @Input() menuActionProvider: Subject = this.propertyProvider.menuActionProvider; @Output() splitterStateChanged: EventEmitter = new EventEmitter(); @Output() menuStateChange: EventEmitter = new EventEmitter(); // @Input() showPageRefresher: XStandardType = this.propertyProvider.showPageRefresher; @Output() refreshPage: EventEmitter = new EventEmitter(); @Input() refreshingText: XStandardType = this.propertyProvider.refreshingText; @Input() refreshPullingText: XStandardType = this.propertyProvider.refreshPullingText; @Input() refreshPullingIcon: XStandardType = this.propertyProvider.refreshPullingIcon; @Input() refreshingSpinner: XStandardType = this.propertyProvider.refreshingSpinner; // @Input() showPageInfinityScroller: XStandardType = this.propertyProvider.showPageInfinityScroller; @Input() infinityScrollDisabled: XStandardType = this.propertyProvider.infinityScrollDisabled; @Input() infinityScrollThreshold: XStandardType = this.propertyProvider.infinityScrollThreshold; @Input() infinityScrollerLoadingText: XStandardType = this.propertyProvider.infinityScrollerLoadingText; @Input() infinityScrollerLoadingSpinner: XStandardType = this.propertyProvider.infinityScrollerLoadingSpinner; @Output() loadMore: EventEmitter = new EventEmitter(); // @Input() actions: XStandardType = this.propertyProvider.actions; @Input() actionsActionProvider: Subject = this.propertyProvider.actionsActionProvider; //#endregion // //#region Toolbar ... // @Input() showToolbar: XStandardType = this.propertyProvider.showToolbar; // @Input() toolbarActionProvider: Subject = this.propertyProvider.toolbarActionProvider; @Input() toolbarCssClass: XStandardType> = this.propertyProvider.toolbarCssClass; // @Input() toolbarColor: XStandardType = this.propertyProvider.toolbarColor; // @Input() toolbarShowProgressBar: XStandardType = this.propertyProvider.toolbarShowProgressBar; @Input() toolbarProgressBarColor: XStandardType = this.propertyProvider.toolbarProgressBarColor; // @Input() toolbarShowTitle: XStandardType = this.propertyProvider.toolbarShowTitle; @Input() toolbarTitleSlot: XStandardType = this.propertyProvider.toolbarTitleSlot; @Input() toolbarTitle: XStandardType = this.propertyProvider.toolbarTitle; // @Input() toolbarShowSubTitle: XStandardType = this.propertyProvider.toolbarShowSubTitle; @Input() toolbarSubTitle: XStandardType = this.propertyProvider.toolbarSubTitle; // @Input() toolbarShowLogo: XStandardType = this.propertyProvider.toolbarShowLogo; @Input() toolbarLogoSlot: XStandardType = this.propertyProvider.toolbarLogoSlot; @Input() toolbarLogoUrl: XStandardType = this.propertyProvider.toolbarLogoUrl; // @Input() toolbarHasBack: XStandardType = this.propertyProvider.toolbarHasBack; @Input() toolbarShowBack: XStandardType = this.propertyProvider.toolbarShowBack; @Input() toolbarBackSlot: XStandardType = this.propertyProvider.toolbarBackSlot; @Input() toolbarBackHandler?: () => XStandardType = () => { this.managerService.historyService.back(); }; @Input() toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref; // @Input() toolbarHasMenu: XStandardType = this.propertyProvider.toolbarHasMenu; @Input() toolbarShowMenu: XStandardType = this.propertyProvider.toolbarShowMenu; @Input() toolbarAutoHideMenu: XStandardType = this.propertyProvider.toolbarAutoHideMenu; @Input() toolbarMenuSlot: XStandardType = this.propertyProvider.toolbarMenuSlot; // @Input() toolbarStartSlotButtonsTemplate: TemplateRef = this.propertyProvider.toolbarStartSlotButtonsTemplate; @Input() toolbarEndSlotButtonsTemplate: TemplateRef = this.propertyProvider.toolbarEndSlotButtonsTemplate; // @Input() toolbarContentSlot: XStandardType = this.propertyProvider.toolbarContentSlot; @Input() toolbarContentTemplate: TemplateRef = this.propertyProvider.toolbarContentTemplate; //#endregion // //#region Footer ... // @Input() showFooter: XStandardType = this.propertyProvider.showFooter; // @Input() footerActionProvider: Subject = this.propertyProvider.footerActionProvider; @Input() footerCssClass: XStandardType> = this.propertyProvider.footerCssClass; // @Input() footerColor: XStandardType = this.propertyProvider.footerColor; @Input() footerContentTemplate: TemplateRef = this.propertyProvider.footerContentTemplate; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, public menuController: MenuController, protected propertyProvider: XPageContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXPageContainer ): Observable { return forkJoin({ // //#region Page ... // cssClass: this.getValue(container ? container.cssClass : this.cssClass), // color: this.getValue(container ? container.color : this.color), // enableCaptureMode: this.getValue( container ? container.enableCaptureMode : this.enableCaptureMode ), downloadCapturedImage: this.getValue( container ? container.downloadCapturedImage : this.downloadCapturedImage ), captureTopOffset: this.getValue( container ? container.captureTopOffset : this.captureTopOffset ), captureBottomOffset: this.getValue( container ? container.captureBottomOffset : this.captureBottomOffset ), // provideScrollEvents: this.getValue( container ? container.provideScrollEvents : this.provideScrollEvents ), scrollStartClasses: this.getValue( container ? container.scrollStartClasses : this.scrollStartClasses ), scrollEndClasses: this.getValue( container ? container.scrollEndClasses : this.scrollEndClasses ), scrollingClasses: this.getValue( container ? container.scrollingClasses : this.scrollingClasses ), scrollBehaviour: this.getValue( container ? container.scrollBehaviour : this.scrollBehaviour ), // toggleMenuWhen: this.getValue( container ? container.toggleMenuWhen : this.toggleMenuWhen ), hasSide: this.getValue(container ? container.hasSide : this.hasSide), sideSlot: this.getValue(container ? container.sideSlot : this.sideSlot), sideType: this.getValue(container ? container.sideType : this.sideType), sideColor: this.getValue( container ? container.sideColor : this.sideColor ), sideMenuWidth: this.getValue( container ? container.sideMenuWidth : this.sideMenuWidth ), sideMenuMinWidth: this.getValue( container ? container.sideMenuMinWidth : this.sideMenuMinWidth ), sideMenuMaxWidth: this.getValue( container ? container.sideMenuMaxWidth : this.sideMenuMaxWidth ), menuState: this.getValue( container ? container.menuState : this.menuState ), // showPageRefresher: this.getValue( container ? container.showPageRefresher : this.showPageRefresher ), refreshingText: this.getValue( container ? container.refreshingText : this.refreshingText ), refreshPullingText: this.getValue( container ? container.refreshPullingText : this.refreshPullingText ), refreshPullingIcon: this.getValue( container ? container.refreshPullingIcon : this.refreshPullingIcon ), refreshingSpinner: this.getValue( container ? container.refreshingSpinner : this.refreshingSpinner ), // showPageInfinityScroller: this.getValue( container ? container.showPageInfinityScroller : this.showPageInfinityScroller ), infinityScrollDisabled: this.getValue( container ? container.infinityScrollDisabled : this.infinityScrollDisabled ), infinityScrollThreshold: this.getValue( container ? container.infinityScrollThreshold : this.infinityScrollThreshold ), infinityScrollerLoadingText: this.getValue( container ? container.infinityScrollerLoadingText : this.infinityScrollerLoadingText ), infinityScrollerLoadingSpinner: this.getValue( container ? container.infinityScrollerLoadingSpinner : this.infinityScrollerLoadingSpinner ), // actions: this.getValue(container ? container.actions : this.actions), //#endregion // //#region Toolbar ... showToolbar: this.getValue( container ? container.showToolbar : this.showToolbar ), toolbarCssClass: this.getValue( container ? container.toolbarCssClass : this.toolbarCssClass ), toolbarColor: this.getValue( container ? container.toolbarColor : this.toolbarColor ), toolbarShowProgressBar: this.getValue( container ? container.toolbarShowProgressBar : this.toolbarShowProgressBar ), toolbarProgressBarColor: this.getValue( container ? container.toolbarProgressBarColor : this.toolbarProgressBarColor ), toolbarShowTitle: this.getValue( container ? container.toolbarShowTitle : this.toolbarShowTitle ), toolbarTitleSlot: this.getValue( container ? container.toolbarTitleSlot : this.toolbarTitleSlot ), toolbarTitle: this.getValue( container ? container.toolbarTitle : this.toolbarTitle ), toolbarShowSubTitle: this.getValue( container ? container.toolbarShowSubTitle : this.toolbarShowSubTitle ), toolbarSubTitle: this.getValue( container ? container.toolbarSubTitle : this.toolbarSubTitle ), toolbarShowLogo: this.getValue( container ? container.toolbarShowLogo : this.toolbarShowLogo ), toolbarLogoSlot: this.getValue( container ? container.toolbarLogoSlot : this.toolbarLogoSlot ), toolbarLogoUrl: this.getValue( container ? container.toolbarLogoUrl : this.toolbarLogoUrl ), toolbarHasBack: this.getValue( container ? container.toolbarHasBack : this.toolbarHasBack ), toolbarShowBack: this.getValue( container ? container.toolbarShowBack : this.toolbarShowBack ), toolbarBackSlot: this.getValue( container ? container.toolbarBackSlot : this.toolbarBackSlot ), toolbarBackHandler: this.getValue( container ? container.toolbarBackHandler : this.toolbarBackHandler ), toolbarDefaultHref: this.getValue( container ? container.toolbarDefaultHref : this.toolbarDefaultHref ), toolbarHasMenu: this.getValue( container ? container.toolbarHasMenu : this.toolbarHasMenu ), toolbarShowMenu: this.getValue( container ? container.toolbarShowMenu : this.toolbarShowMenu ), toolbarAutoHideMenu: this.getValue( container ? container.toolbarAutoHideMenu : this.toolbarAutoHideMenu ), toolbarMenuSlot: this.getValue( container ? container.toolbarMenuSlot : this.toolbarMenuSlot ), toolbarStartSlotButtonsTemplate: this.getValue( container ? container.toolbarStartSlotButtonsTemplate : this.toolbarStartSlotButtonsTemplate ), toolbarEndSlotButtonsTemplate: this.getValue( container ? container.toolbarEndSlotButtonsTemplate : this.toolbarEndSlotButtonsTemplate ), toolbarContentSlot: this.getValue( container ? container.toolbarContentSlot : this.toolbarContentSlot ), toolbarContentTemplate: this.getValue( container ? container.toolbarContentTemplate : this.toolbarContentTemplate ), //#endregion // //#region Footer ... showFooter: this.getValue( container ? container.showFooter : this.showFooter ), footerCssClass: this.getValue( container ? container.footerCssClass : this.footerCssClass ), footerColor: this.getValue( container ? container.footerColor : this.footerColor ), footerContentTemplate: this.getValue( container ? container.footerContentTemplate : this.footerContentTemplate ), //#endregion }).pipe( map((data) => { return { // ...data, // toolbarActionProvider: container ? container.toolbarActionProvider : this.toolbarActionProvider, // footerActionProvider: container ? container.footerActionProvider : this.footerActionProvider, // menuActionProvider: container ? container.menuActionProvider : this.menuActionProvider, // scrollEventActionProvider: container ? container.scrollEventActionProvider : this.scrollEventActionProvider, // actionsActionProvider: container ? container.actionsActionProvider : this.actionsActionProvider, // imageCaptured: this.imageCaptured, splitterStateChanged: this.splitterStateChanged, menuStateChange: this.menuStateChange, scrolledEvent: this.scrolledEvent, refreshPage: this.refreshPage, loadMore: this.loadMore, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XPageComponent } from './x-page.component'; import { XFabModule } from './../x-fab/x-fab.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XButtonModule } from '../x-button/x-button.module'; import { XFooterComponent } from './x-footer/x-footer.component'; import { XToolbarComponent } from './x-toolbar/x-toolbar.component'; import { XNavigatorComponent } from './x-navigator/x-navigator.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XScreenCaptureModule } from '../x-screen-capture/x-screen-capture.module'; import { XExpandableListModule } from '../x-expandable-list/x-expandable-list.module'; import { XExpandablePanelModule } from '../x-expandable-panel/x-expandable-panel.module'; @NgModule({ imports: [ XFabModule, XIconModule, CommonModule, XButtonModule, XBaseComponentModule, XScreenCaptureModule, XExpandableListModule, XExpandablePanelModule, ], declarations: [ XPageComponent, XFooterComponent, XToolbarComponent, XNavigatorComponent, ], exports: [ XFabModule, XIconModule, CommonModule, XButtonModule, XPageComponent, XFooterComponent, XToolbarComponent, XNavigatorComponent, XBaseComponentModule, XScreenCaptureModule, XExpandableListModule, XExpandablePanelModule, ], }) export class XPageModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.typings.ts export enum XMenuState { WillOpen, Opened, WillClose, Closed, } export enum XMenuAction { Open, Close, Toggle, } export enum XPageSize { ExtraSmall = 'xs', Small = 'sm', Medium = 'md', Large = 'lg', ExtraLarge = 'xl', } export type XPageSizeIdentifier = XPageSize | string; export enum XSideType { Overlay = 'overlay', Reveal = 'reveal', Push = 'push', } export type XSideTypeIdentifier = XSideType | string; export enum XBackSlot { Start = 'start', End = 'end', } export type XBackSlotIdentifier = XBackSlot | string; export enum XMenuSlot { Start = 'start', End = 'end', } export type XMenuSlotIdentifier = XMenuSlot | string; export enum XLogoSlot { Start = 'start', End = 'end', } export type XLogoSlotIdentifier = XLogoSlot | string; export enum XTitleSlot { Start = 'start', End = 'end', } export type XTitleSlotIdentifier = XTitleSlot | string; export enum XContentSlot { Start = 'start', Middle = 'middle', End = 'end', } export type XContentSlotIdentifier = XContentSlot | string; export enum XSideSlot { Start = 'start', End = 'end', } export type XSideSlotIdentifier = XSideSlot | string; export interface XPageLoadingEvent { type: 'InfinityScrollerLoader' | 'RefreshLoader'; event: any; } export enum XPageCSSVars { SideMenuWidth = 'side-menu-width', SideMenuMinWidth = 'side-menu-min-width', SideMenuMaxWidth = 'side-menu-max-width', SideMenuContentHeightGutter = 'side-menu-content-height-gutter', SideMenuContentOffsetTop = 'side-menu-content-offset-top', SideMenuContentOffsetBottom = 'side-menu-content-offset-bottom', ContentHeightGutter = 'content-height-gutter', ContentOffsetTop = 'content-offset-top', ContentOffsetBottom = 'content-offset-bottom', } export type XPageCSSVarsIdentifier = XPageCSSVars | string; ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-footer\x-footer.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-footer\x-footer.component.scss :host { position: absolute; bottom: 0; left: 0; right: 0; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-footer\x-footer.component.ts import { XFooterAction, XFooterActionModel, XFooterContainerComponent, } from './x-footer.typings'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-footer', templateUrl: './x-footer.component.html', styleUrls: ['./x-footer.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XFooterComponent extends XFooterContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper( this.actionProvider.asObservable() ).subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XFooterAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-footer\x-footer.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, XBaseComponentContainer, IXBaseComponentContainer, XBaseComponentContainerComponent, } from '../../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; export enum XFooterAction { Refresh = 'refresh', } export type XFooterActionIdentifier = XFooterAction | string; export interface XFooterActionModel extends XBaseActionModel {} // //#region Container ... export interface IXFooterContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; contentTemplate: TemplateRef; } @Injectable({ providedIn: 'root' }) export class XFooterContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly contentTemplate: TemplateRef; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XFooterContainerComponent extends XBaseContainerComponent implements IXFooterContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() contentTemplate: TemplateRef = this.propertyProvider.contentTemplate; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XFooterContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXFooterContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), color: this.getValue(container ? container.color : this.color), contentTemplate: this.getValue( container ? container.contentTemplate : this.contentTemplate ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentFooterContainer = { [TKey in keyof IXFooterContainer as `footer${Capitalize< string & TKey >}`]: IXFooterContainer[TKey]; }; export interface IXComponentFooterContainer extends TXComponentFooterContainer, IXBaseComponentContainer { showFooter: XStandardType; } @Injectable({ providedIn: 'root' }) export class XComponentFooterContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // readonly showFooter: XStandardType = true; // readonly footerActionProvider: Subject = this.propertyProvider.actionProvider; readonly footerCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly footerColor: XStandardType = this.propertyProvider.color; readonly footerContentTemplate: TemplateRef = this.propertyProvider.contentTemplate; //#endregion // //#region Constructor ... constructor(protected propertyProvider: XFooterContainer) { super(); } //#endregion } @Injectable({ providedIn: 'root' }) @Component({ template: ` `, }) export abstract class XComponentFooterContainerComponent extends XBaseComponentContainerComponent implements IXComponentFooterContainer { // //#region Props ... // @Input() showFooter: XStandardType = this.propertyProvider.showFooter; // @Input() footerActionProvider: Subject = this.propertyProvider.footerActionProvider; @Input() footerCssClass: XStandardType> = this.propertyProvider.footerCssClass; // @Input() footerColor: XStandardType = this.propertyProvider.footerColor; @Input() footerContentTemplate: TemplateRef = this.propertyProvider.footerContentTemplate; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XComponentFooterContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXComponentFooterContainer ): Observable { return forkJoin({ // showFooter: this.getValue( container ? container.showFooter : this.showFooter ), footerCssClass: this.getValue( container ? container.footerCssClass : this.footerCssClass ), footerColor: this.getValue( container ? container.footerColor : this.footerColor ), footerContentTemplate: this.getValue( container ? container.footerContentTemplate : this.footerContentTemplate ), }).pipe( map((data) => { return { // ...data, // footerActionProvider: container ? container.footerActionProvider : this.footerActionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.component.scss .nav-item > * { display: inline-block; position: relative; margin: 0; padding: 0; } .x-nav-item-title { max-width: 150px; margin: 4px; } .nav-item-parent { .x-nav-item-title { font-size: 10pt; font-weight: bold; } } .nav-item-child { .x-nav-item-title { font-size: 9pt; font-weight: normal; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.component.ts import { XNavigatorAction, XNavigatorActionModel, XNavigatorItemIconSlot, XNavigatorContainerComponent, XNavigatorListItem, } from './x-navigator.typings'; import { map } from 'rxjs/operators'; import { Observable, Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; import { XStandardType, XOneOrManyType, nameof } from 'x-framework-core'; import { XExpandableListItem } from '../../x-expandable-list/x-expandable-list.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-navigator', templateUrl: './x-navigator.component.html', styleUrls: ['./x-navigator.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XNavigatorComponent extends XNavigatorContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private EXPANDABLE_LIST_ITEMS: XOneOrManyType>; get preparedItems() { return this.EXPANDABLE_LIST_ITEMS; } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.prepareItems(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Items Changed ... const isItemsChanged = changeKeys.includes( nameof('items') ); if (isItemsChanged) { await this.prepareItems(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... isEndSlotted() { return this.getValue(this.iconSlot).pipe( map((iconSlot) => iconSlot === XNavigatorItemIconSlot.End) ); } isStartSlotted() { return this.getValue(this.iconSlot).pipe( map((iconSlot) => iconSlot === XNavigatorItemIconSlot.Start) ); } //#endregion // //#region UI Actions ... //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper( this.actionProvider.asObservable() ).subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XNavigatorAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async prepareItems() { // this.EXPANDABLE_LIST_ITEMS = null; this.detectChanges(); // const items = await this.getArrayValueAsync(this.items); const preparedItems = await Promise.all( items.map(async (i) => await this.toExpandableListItem(i)) ); // this.EXPANDABLE_LIST_ITEMS = [ ...preparedItems ]; // this.detectChanges(); } private async toExpandableListItem(item: XNavigatorListItem) { // const result: XExpandableListItem = { // ...item, data: '', childs: [ ...(await Promise.all( (item.childs ? await this.getArrayValueAsync(item.childs) : []).map( async (c) => await this.toExpandableListItem(c) ) )), ], }; // return result; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.tools.ts import { XPage, isArray, toArray, hasChild, mergeRoutes, XOneOrManyType, } from 'x-framework-core'; import { XNavigatorListItem } from './x-navigator.typings'; export function extractParent(source: XOneOrManyType): any { // if (!source) { return null; } // const isArrayOfPages = isArray(source); const page = source as XPage; const pages = source as XPage[]; // if (isArrayOfPages) { // // Handle Array of Pages ... return pages.filter((p) => hasChild(p.childs)); } else { // // Handle On Page ... return extractParent(page.childs); } } export function extractChilds(source: XOneOrManyType) { // if (!source) { return null; } // const isArrayOfPages = isArray(source); const page = source as XPage; const pages = source as XPage[]; // if (isArrayOfPages) { // // Handle Array of Pages ... return pages.filter((p) => !hasChild(p.childs)); } else { // // Handle On Page ... return extractParent(page.childs); } } export function toFlat(pages: XOneOrManyType) { // if (!pages || !hasChild(pages)) { return []; } // let result: XPage[] = []; // const pPages = toArray(pages); pPages.forEach((p) => { // result.push(p); // if (p.childs && hasChild(p.childs)) { // const childsFlat = toFlat(p.childs); result = result.concat(childsFlat); } }); // return result; } export function toNavigatiorListItem(page: XPage) { // if (!page) { return null; } // const pageRoute = mergeRoutes(page.route); // const result: XNavigatorListItem = { id: page.id ? `${page.id}_(${pageRoute})` : `${page.name}_(${pageRoute})`, opened: false, hidden: false, disabled: false, icon: page.icon, href: page.route, replaceUrl: true, title: page.title, description: page.description, childs: hasChild(page.childs) ? toArray(page.childs).map((c) => toNavigatiorListItem(c)) : null, }; // return result; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-navigator\x-navigator.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../../x-icon/x-icon.typings'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; import { XExpandableListItem } from '../../x-expandable-list/x-expandable-list.typings'; export type XNavigatorListItemBase = Pick< XExpandableListItem, | 'id' | 'href' | 'title' | 'opened' | 'hidden' | 'disabled' | 'replaceUrl' | 'description' >; export interface XNavigatorListItem extends XNavigatorListItemBase { icon?: XStandardType; childs?: XStandardType>; } export enum XNavigatorItemIconSlot { Start = 'start', End = 'end', } export type XNavigatorItemIconSlotIdentifier = XNavigatorItemIconSlot | string; export enum XNavigatorStartupState { ExpandAll = 'expand-all', CollapseAll = 'collapse-all', } export type XNavigatorStartupStateIdentifier = XNavigatorStartupState | string; export enum XNavigatorAction { Refresh = 'refresh', } export type XNavigatorActionIdentifier = XNavigatorAction | string; export interface XNavigatorActionModel extends XBaseActionModel {} // //#region Container ... export interface IXNavigatorContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // itemCssClass: XStandardType>; items: XStandardType>; // closeSiblings: XStandardType; iconSlot: XStandardType; startupState: XStandardType; // showChildIcon: XStandardType; showChildDetailIcon: XStandardType; showParentIcon: XStandardType; showParentDetailIcon: XStandardType; disableParentRouting: XStandardType; // childColor: XStandardType; childActiveColor: XStandardType; parentColor: XStandardType; parentActiveColor: XStandardType; highlightColor: XStandardType; dividerColor: XStandardType; // itemSelected: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XNavigatorContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly itemCssClass: XStandardType>; readonly items: XStandardType>; // readonly closeSiblings: XStandardType = true; readonly iconSlot: XStandardType = XNavigatorItemIconSlot.Start; readonly startupState: XStandardType = XNavigatorStartupState.ExpandAll; // readonly showChildIcon: XStandardType = true; readonly showChildDetailIcon: XStandardType = true; readonly showParentIcon: XStandardType = true; readonly showParentDetailIcon: XStandardType = true; readonly disableParentRouting: XStandardType = true; // readonly childColor: XStandardType = XColorWithBrightness.PrimaryShade; readonly childActiveColor: XStandardType = XColorWithBrightness.Dark; readonly parentColor: XStandardType = XColorWithBrightness.TertiaryTint; readonly parentActiveColor: XStandardType = XColorWithBrightness.Dark; readonly highlightColor: XStandardType = XColorWithBrightness.Warning; readonly dividerColor: XStandardType = XColorWithBrightness.Dark; // readonly itemSelected: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XNavigatorContainerComponent extends XBaseContainerComponent implements IXNavigatorContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() itemCssClass: XStandardType> = this.propertyProvider.itemCssClass; @Input() items: XStandardType> = this.propertyProvider.items; // @Input() closeSiblings: XStandardType = this.propertyProvider.closeSiblings; @Input() iconSlot: XStandardType = this.propertyProvider.iconSlot; @Input() startupState: XStandardType = this.propertyProvider.startupState; // @Input() showChildIcon: XStandardType = this.propertyProvider.showChildIcon; @Input() showChildDetailIcon: XStandardType = this.propertyProvider.showChildDetailIcon; @Input() showParentIcon: XStandardType = this.propertyProvider.showParentIcon; @Input() showParentDetailIcon: XStandardType = this.propertyProvider.showParentDetailIcon; @Input() disableParentRouting: XStandardType = this.propertyProvider.disableParentRouting; // @Input() childColor: XStandardType = this.propertyProvider.childColor; @Input() childActiveColor: XStandardType = this.propertyProvider.childActiveColor; @Input() parentColor: XStandardType = this.propertyProvider.parentColor; @Input() parentActiveColor: XStandardType = this.propertyProvider.parentActiveColor; @Input() highlightColor: XStandardType = this.propertyProvider.highlightColor; @Input() dividerColor: XStandardType = this.propertyProvider.dividerColor; // @Output() itemSelected: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XNavigatorContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXNavigatorContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), itemCssClass: this.getValue( container ? container.itemCssClass : this.itemCssClass ), items: this.getValue(container ? container.items : this.items), closeSiblings: this.getValue( container ? container.closeSiblings : this.closeSiblings ), iconSlot: this.getValue(container ? container.iconSlot : this.iconSlot), startupState: this.getValue( container ? container.startupState : this.startupState ), showChildIcon: this.getValue( container ? container.showChildIcon : this.showChildIcon ), showChildDetailIcon: this.getValue( container ? container.showChildDetailIcon : this.showChildDetailIcon ), showParentIcon: this.getValue( container ? container.showParentIcon : this.showParentIcon ), showParentDetailIcon: this.getValue( container ? container.showParentDetailIcon : this.showParentDetailIcon ), disableParentRouting: this.getValue( container ? container.disableParentRouting : this.disableParentRouting ), childColor: this.getValue( container ? container.childColor : this.childColor ), childActiveColor: this.getValue( container ? container.childActiveColor : this.childActiveColor ), parentColor: this.getValue( container ? container.parentColor : this.parentColor ), parentActiveColor: this.getValue( container ? container.parentActiveColor : this.parentActiveColor ), highlightColor: this.getValue( container ? container.highlightColor : this.highlightColor ), dividerColor: this.getValue( container ? container.dividerColor : this.dividerColor ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // itemSelected: this.itemSelected, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-toolbar\x-toolbar.component.html

{{ getValue(title) | async }}

{{ getValue(subTitle) | async }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-toolbar\x-toolbar.component.scss .x-toolbar-slot, .x-toolbar-start-slot, .x-toolbar-middle-slot, .x-toolbar-end-slot { visibility: inherit; } .x-toolbar-start-slot, .x-toolbar-middle-slot, .x-toolbar-end-slot { margin: { left: 4px; right: 4px; } } .x-toolbar-slot-container { display: flex; } .x-toolbar-slot { display: flex; flex: 1; } .x-toolbar-slot > *, .x-toolbar-slot-container > * { margin: { left: 2px; right: 2px; } width: max-content; } ion-thumbnail { width: 48px !important; height: 48px !important; } ion-img { object-fit: contain !important; } :host { --menu-button-transform: rotate(90deg); --menu-button-transform-duration: 500ms; } :host.menu-opened { ion-menu-button { // transform: var(--menu-button-transform); -ms-transform: var(--menu-button-transform); -webkit-transform: var(--menu-button-transform); // transition: transform; -webkit-transition: transform; // transition-duration: var(--menu-button-transform-duration); -webkit-transition-duration: var(--menu-button-transform-duration); } } ion-menu-button { // transition-duration: var(--menu-button-transform-duration); -webkit-transition-duration: var(--menu-button-transform-duration); } .x-toolbar-title-wrapper { padding-inline-end: 16px; padding-inline-start: 0; display: block; margin: { top: auto; bottom: auto; } } .x-toolbar-title, .x-toolbar-sub-title { display: block !important; } .x-toolbar-back { } .mobile { max-width: 150px; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-toolbar\x-toolbar.component.ts import { XParam, nameof, isNullOrEmptyString, XColorWithBrightness, } from 'x-framework-core'; import { XToolbarAction, XToolbarActionModel, XToolbarContainerComponent, } from './x-toolbar.typings'; import { map } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs'; import { XIconNames } from '../../x-icon/x-icon.typings'; import { XMenuSlot, XBackSlot } from './../x-page.typings'; import { XButtonType } from '../../x-button/x-button.typings'; import { Component, ChangeDetectionStrategy } from '@angular/core'; import { XLogoSlot, XTitleSlot, XContentSlot } from '../x-page.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-toolbar', templateUrl: './x-toolbar.component.html', styleUrls: ['./x-toolbar.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XToolbarComponent extends XToolbarContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly IconNames = Object.assign({}, XIconNames); readonly ButtonTypes = Object.assign({}, XButtonType); readonly ColorNames = Object.assign({}, XColorWithBrightness); //#endregion // //#region LifeCycle ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Reading Query Params ... //#endregion // //#region Providers ... getBackHref() { // const isContainReturnUrl = this.managerService.isContainQueryParam( XParam.ReturnUrl ); // return !isNullOrEmptyString(this.defaultHref) ? this.defaultHref : !isContainReturnUrl ? null : this.managerService.getQueryParamValOfType(XParam.ReturnUrl); } canBack() { // return this.getValue(this.hasBack).pipe( map((hasBack) => { // if ( !hasBack && this.managerService.isContainQueryParam(XParam.HasBack) ) { hasBack = hasBack || this.managerService.getQueryParamValOfType(XParam.HasBack); } // return hasBack; }) ); } // //#region Slot Providers ... isEndSlotBack() { return this.getValue(this.backSlot).pipe( map((slot) => slot === XBackSlot.End) ); } isStartSlotBack() { return this.getValue(this.backSlot).pipe( map((slot) => slot === XBackSlot.Start) ); } isEndSlotMenu() { return this.getValue(this.menuSlot).pipe( map((slot) => slot === XMenuSlot.End) ); } isStartSlotMenu() { return this.getValue(this.menuSlot).pipe( map((slot) => slot === XMenuSlot.Start) ); } isEndSlotLogo() { return this.getValue(this.logoSlot).pipe( map((slot) => slot === XLogoSlot.End) ); } isStartSlotLogo() { return this.getValue(this.logoSlot).pipe( map((slot) => slot === XLogoSlot.Start) ); } isEndSlotTitle() { return this.getValue(this.titleSlot).pipe( map((slot) => slot === XTitleSlot.End) ); } isStartSlotTitle() { return this.getValue(this.titleSlot).pipe( map((slot) => slot === XTitleSlot.Start) ); } isEndSlotContent() { return this.getValue(this.contentSlot).pipe( map((slot) => slot === XContentSlot.End) ); } isMiddleSlotContent() { return this.getValue(this.contentSlot).pipe( map((slot) => slot === XContentSlot.Middle) ); } isStartSlotContent() { return this.getValue(this.contentSlot).pipe( map((slot) => slot === XContentSlot.Start) ); } //#endregion //#endregion // //#region Handlers ... handleMenuButtonClicked() { this.actionProvider.next({ action: XToolbarAction.ToggleMenu }); } async handleBackButtonClicked(event: any) { // if (this.backHandler) { // if (event && event.preventDefault) { event.preventDefault(); } // await this.getValueAsync(this.backHandler()); return; } // const hasReturnUrl = this.managerService.isContainQueryParam( XParam.ReturnUrl ); const hasDefaultHref = !isNullOrEmptyString(this.defaultHref); const returnUrl = hasReturnUrl ? this.managerService.getQueryParamValOfType(XParam.ReturnUrl) : hasDefaultHref ? this.defaultHref : ''; // if (!isNullOrEmptyString(returnUrl)) { // await this.managerService.navigateByUrl(returnUrl); return; } // this.managerService.historyService.back(); } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper( this.actionProvider.asObservable() ).subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XToolbarAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-toolbar\x-toolbar.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XBackSlot, XLogoSlot, XMenuSlot, XTitleSlot, XContentSlot, XBackSlotIdentifier, XLogoSlotIdentifier, XMenuSlotIdentifier, XTitleSlotIdentifier, XContentSlotIdentifier, } from '../x-page.typings'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, XBaseComponentContainer, IXBaseComponentContainer, XBaseComponentContainerComponent, } from '../../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; export enum XToolbarAction { Refresh = 'refresh', ToggleMenu = 'ToggleMenu', } export type XToolbarActionIdentifier = XToolbarAction | string; export interface XToolbarActionModel extends XBaseActionModel {} // //#region Container ... export interface IXToolbarContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; // showProgressBar: XStandardType; progressBarColor: XStandardType; // showTitle: XStandardType; titleSlot: XStandardType; title: XStandardType; // showSubTitle: XStandardType; subTitle: XStandardType; // showLogo: XStandardType; logoSlot: XStandardType; logoUrl: XStandardType; // hasBack: XStandardType; showBack: XStandardType; backSlot: XStandardType; backHandler?: () => XStandardType; defaultHref: string; // hasMenu: XStandardType; showMenu: XStandardType; autoHideMenu: XStandardType; menuSlot: XStandardType; // startSlotButtonsTemplate: TemplateRef; endSlotButtonsTemplate: TemplateRef; // contentSlot: XStandardType; contentTemplate: TemplateRef; } @Injectable({ providedIn: 'root', }) export class XToolbarContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Primary; // readonly showProgressBar: XStandardType = false; readonly progressBarColor: XStandardType = XColorWithBrightness.Warning; // readonly showTitle: XStandardType = true; readonly titleSlot: XStandardType = XTitleSlot.End; readonly title: XStandardType; // readonly showSubTitle: XStandardType = false; readonly subTitle: XStandardType; // readonly showLogo: XStandardType = false; readonly logoSlot: XStandardType = XLogoSlot.Start; readonly logoUrl: XStandardType; // readonly hasBack: XStandardType = true; readonly showBack: XStandardType = false; readonly backSlot: XStandardType = XBackSlot.Start; readonly backHandler?: () => XStandardType; readonly defaultHref: string; // readonly hasMenu: XStandardType = true; readonly showMenu: XStandardType = false; readonly autoHideMenu: XStandardType = true; readonly menuSlot: XStandardType = XMenuSlot.Start; // readonly startSlotButtonsTemplate: TemplateRef; readonly endSlotButtonsTemplate: TemplateRef; // readonly contentSlot: XStandardType = XContentSlot.End; readonly contentTemplate: TemplateRef; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XToolbarContainerComponent extends XBaseContainerComponent implements IXToolbarContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; // @Input() showProgressBar: XStandardType = this.propertyProvider.showProgressBar; @Input() progressBarColor: XStandardType = this.propertyProvider.progressBarColor; // @Input() showTitle: XStandardType = this.propertyProvider.showTitle; @Input() titleSlot: XStandardType = this.propertyProvider.titleSlot; @Input() title: XStandardType = this.propertyProvider.title; // @Input() showSubTitle: XStandardType = this.propertyProvider.showSubTitle; @Input() subTitle: XStandardType = this.propertyProvider.subTitle; // @Input() showLogo: XStandardType = this.propertyProvider.showLogo; @Input() logoSlot: XStandardType = this.propertyProvider.logoSlot; @Input() logoUrl: XStandardType = this.propertyProvider.logoUrl; // @Input() hasBack: XStandardType = this.propertyProvider.hasBack; @Input() showBack: XStandardType = this.propertyProvider.showBack; @Input() backSlot: XStandardType = this.propertyProvider.backSlot; @Input() backHandler?: () => XStandardType = this.propertyProvider.backHandler; @Input() defaultHref: string = this.propertyProvider.defaultHref; // @Input() hasMenu: XStandardType = this.propertyProvider.hasMenu; @Input() showMenu: XStandardType = this.propertyProvider.showMenu; @Input() autoHideMenu: XStandardType = this.propertyProvider.autoHideMenu; @Input() menuSlot: XStandardType = this.propertyProvider.menuSlot; // @Input() startSlotButtonsTemplate: TemplateRef = this.propertyProvider.startSlotButtonsTemplate; @Input() endSlotButtonsTemplate: TemplateRef = this.propertyProvider.endSlotButtonsTemplate; // @Input() contentSlot: XStandardType = this.propertyProvider.contentSlot; @Input() contentTemplate: TemplateRef = this.propertyProvider.contentTemplate; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XToolbarContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXToolbarContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), color: this.getValue(container ? container.color : this.color), showProgressBar: this.getValue( container ? container.showProgressBar : this.showProgressBar ), progressBarColor: this.getValue( container ? container.progressBarColor : this.progressBarColor ), showTitle: this.getValue( container ? container.showTitle : this.showTitle ), titleSlot: this.getValue( container ? container.titleSlot : this.titleSlot ), title: this.getValue(container ? container.title : this.title), showSubTitle: this.getValue( container ? container.showSubTitle : this.showSubTitle ), subTitle: this.getValue(container ? container.subTitle : this.subTitle), showLogo: this.getValue(container ? container.showLogo : this.showLogo), logoSlot: this.getValue(container ? container.logoSlot : this.logoSlot), logoUrl: this.getValue(container ? container.logoUrl : this.logoUrl), hasBack: this.getValue(container ? container.hasBack : this.hasBack), showBack: this.getValue(container ? container.showBack : this.showBack), backSlot: this.getValue(container ? container.backSlot : this.backSlot), backHandler: this.getValue( container ? container.backHandler : this.backHandler ), defaultHref: this.getValue( container ? container.defaultHref : this.defaultHref ), hasMenu: this.getValue(container ? container.hasMenu : this.hasMenu), showMenu: this.getValue(container ? container.showMenu : this.showMenu), autoHideMenu: this.getValue( container ? container.autoHideMenu : this.autoHideMenu ), menuSlot: this.getValue(container ? container.menuSlot : this.menuSlot), startSlotButtonsTemplate: this.getValue( container ? container.startSlotButtonsTemplate : this.startSlotButtonsTemplate ), endSlotButtonsTemplate: this.getValue( container ? container.endSlotButtonsTemplate : this.endSlotButtonsTemplate ), contentSlot: this.getValue( container ? container.contentSlot : this.contentSlot ), contentTemplate: this.getValue( container ? container.contentTemplate : this.contentTemplate ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentToolbarContainer = { [TKey in keyof IXToolbarContainer as `toolbar${Capitalize< string & TKey >}`]: IXToolbarContainer[TKey]; }; export interface IXComponentToolbarContainer extends TXComponentToolbarContainer, IXBaseComponentContainer { showToolbar: XStandardType; } @Injectable({ providedIn: 'root', }) export class XComponentToolbarContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // readonly showToolbar: XStandardType = true; // readonly toolbarActionProvider: Subject = this.propertyProvider.actionProvider; readonly toolbarCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly toolbarColor: XStandardType = this.propertyProvider.color; // readonly toolbarShowProgressBar: XStandardType = this.propertyProvider.showProgressBar; readonly toolbarProgressBarColor: XStandardType = this.propertyProvider.progressBarColor; // readonly toolbarShowTitle: XStandardType = this.propertyProvider.showTitle; readonly toolbarTitleSlot: XStandardType = this.propertyProvider.titleSlot; readonly toolbarTitle: XStandardType = this.propertyProvider.title; // readonly toolbarShowSubTitle: XStandardType = this.propertyProvider.showSubTitle; readonly toolbarSubTitle: XStandardType = this.propertyProvider.subTitle; // readonly toolbarShowLogo: XStandardType = this.propertyProvider.showLogo; readonly toolbarLogoSlot: XStandardType = this.propertyProvider.logoSlot; readonly toolbarLogoUrl: XStandardType = this.propertyProvider.logoUrl; // readonly toolbarHasBack: XStandardType = this.propertyProvider.hasBack; readonly toolbarShowBack: XStandardType = this.propertyProvider.showBack; readonly toolbarBackSlot: XStandardType = this.propertyProvider.backSlot; readonly toolbarBackHandler?: () => XStandardType = this.propertyProvider.backHandler; readonly toolbarDefaultHref: string = this.propertyProvider.defaultHref; // readonly toolbarHasMenu: XStandardType = this.propertyProvider.hasMenu; readonly toolbarShowMenu: XStandardType = this.propertyProvider.showMenu; readonly toolbarAutoHideMenu: XStandardType = this.propertyProvider.autoHideMenu; readonly toolbarMenuSlot: XStandardType = this.propertyProvider.menuSlot; // readonly toolbarStartSlotButtonsTemplate: TemplateRef = this.propertyProvider.startSlotButtonsTemplate; readonly toolbarEndSlotButtonsTemplate: TemplateRef = this.propertyProvider.endSlotButtonsTemplate; // readonly toolbarContentSlot: XStandardType = this.propertyProvider.contentSlot; readonly toolbarContentTemplate: TemplateRef = this.propertyProvider.contentTemplate; //#endregion // //#region Constructor ... constructor(protected propertyProvider: XToolbarContainer) { super(); } //#endregion } @Injectable({ providedIn: 'root', }) @Component({ template: ` `, }) export abstract class XComponentToolbarContainerComponent extends XBaseComponentContainerComponent implements IXComponentToolbarContainer { // //#region Props ... // @Input() showToolbar: XStandardType = this.propertyProvider.showToolbar; // @Input() toolbarActionProvider: Subject = this.propertyProvider.toolbarActionProvider; @Input() toolbarCssClass: XStandardType> = this.propertyProvider.toolbarCssClass; // @Input() toolbarColor: XStandardType = this.propertyProvider.toolbarColor; // @Input() toolbarShowProgressBar: XStandardType = this.propertyProvider.toolbarShowProgressBar; @Input() toolbarProgressBarColor: XStandardType = this.propertyProvider.toolbarProgressBarColor; // @Input() toolbarShowTitle: XStandardType = this.propertyProvider.toolbarShowTitle; @Input() toolbarTitleSlot: XStandardType = this.propertyProvider.toolbarTitleSlot; @Input() toolbarTitle: XStandardType = this.propertyProvider.toolbarTitle; // @Input() toolbarShowSubTitle: XStandardType = this.propertyProvider.toolbarShowSubTitle; @Input() toolbarSubTitle: XStandardType = this.propertyProvider.toolbarSubTitle; // @Input() toolbarShowLogo: XStandardType = this.propertyProvider.toolbarShowLogo; @Input() toolbarLogoSlot: XStandardType = this.propertyProvider.toolbarLogoSlot; @Input() toolbarLogoUrl: XStandardType = this.propertyProvider.toolbarLogoUrl; // @Input() toolbarHasBack: XStandardType = this.propertyProvider.toolbarHasBack; @Input() toolbarShowBack: XStandardType = this.propertyProvider.toolbarShowBack; @Input() toolbarBackSlot: XStandardType = this.propertyProvider.toolbarBackSlot; @Input() toolbarBackHandler?: () => XStandardType = this.propertyProvider.toolbarBackHandler; @Input() toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref; // @Input() toolbarHasMenu: XStandardType = this.propertyProvider.toolbarHasMenu; @Input() toolbarShowMenu: XStandardType = this.propertyProvider.toolbarShowMenu; @Input() toolbarAutoHideMenu: XStandardType = this.propertyProvider.toolbarAutoHideMenu; @Input() toolbarMenuSlot: XStandardType = this.propertyProvider.toolbarMenuSlot; // @Input() toolbarStartSlotButtonsTemplate: TemplateRef = this.propertyProvider.toolbarStartSlotButtonsTemplate; @Input() toolbarEndSlotButtonsTemplate: TemplateRef = this.propertyProvider.toolbarEndSlotButtonsTemplate; // @Input() toolbarContentSlot: XStandardType = this.propertyProvider.toolbarContentSlot; @Input() toolbarContentTemplate: TemplateRef = this.propertyProvider.toolbarContentTemplate; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XComponentToolbarContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXComponentToolbarContainer ): Observable { return forkJoin({ // showToolbar: this.getValue( container ? container.showToolbar : this.showToolbar ), // toolbarCssClass: this.getValue( container ? container.toolbarCssClass : this.toolbarCssClass ), toolbarColor: this.getValue( container ? container.toolbarColor : this.toolbarColor ), toolbarShowProgressBar: this.getValue( container ? container.toolbarShowProgressBar : this.toolbarShowProgressBar ), toolbarProgressBarColor: this.getValue( container ? container.toolbarProgressBarColor : this.toolbarProgressBarColor ), toolbarShowTitle: this.getValue( container ? container.toolbarShowTitle : this.toolbarShowTitle ), toolbarTitleSlot: this.getValue( container ? container.toolbarTitleSlot : this.toolbarTitleSlot ), toolbarTitle: this.getValue( container ? container.toolbarTitle : this.toolbarTitle ), toolbarShowSubTitle: this.getValue( container ? container.toolbarShowSubTitle : this.toolbarShowSubTitle ), toolbarSubTitle: this.getValue( container ? container.toolbarSubTitle : this.toolbarSubTitle ), toolbarShowLogo: this.getValue( container ? container.toolbarShowLogo : this.toolbarShowLogo ), toolbarLogoSlot: this.getValue( container ? container.toolbarLogoSlot : this.toolbarLogoSlot ), toolbarLogoUrl: this.getValue( container ? container.toolbarLogoUrl : this.toolbarLogoUrl ), toolbarHasBack: this.getValue( container ? container.toolbarHasBack : this.toolbarHasBack ), toolbarShowBack: this.getValue( container ? container.toolbarShowBack : this.toolbarShowBack ), toolbarBackSlot: this.getValue( container ? container.toolbarBackSlot : this.toolbarBackSlot ), toolbarBackHandler: this.getValue( container ? container.toolbarBackHandler : this.toolbarBackHandler ), toolbarDefaultHref: this.getValue( container ? container.toolbarDefaultHref : this.toolbarDefaultHref ), toolbarHasMenu: this.getValue( container ? container.toolbarHasMenu : this.toolbarHasMenu ), toolbarShowMenu: this.getValue( container ? container.toolbarShowMenu : this.toolbarShowMenu ), toolbarAutoHideMenu: this.getValue( container ? container.toolbarAutoHideMenu : this.toolbarAutoHideMenu ), toolbarMenuSlot: this.getValue( container ? container.toolbarMenuSlot : this.toolbarMenuSlot ), toolbarStartSlotButtonsTemplate: this.getValue( container ? container.toolbarStartSlotButtonsTemplate : this.toolbarStartSlotButtonsTemplate ), toolbarEndSlotButtonsTemplate: this.getValue( container ? container.toolbarEndSlotButtonsTemplate : this.toolbarEndSlotButtonsTemplate ), toolbarContentSlot: this.getValue( container ? container.toolbarContentSlot : this.toolbarContentSlot ), toolbarContentTemplate: this.getValue( container ? container.toolbarContentTemplate : this.toolbarContentTemplate ), }).pipe( map((data) => { return { // ...data, // toolbarActionProvider: container ? container.toolbarActionProvider : this.toolbarActionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.component.ts import { ChangeDetectionStrategy, Component } from '@angular/core'; import { XProgressBarAction, XProgressBarActionModel, XProgressBarContainerComponent, XProgressBarType } from './x-progress-bar.typings'; import { Subject, Subscription } from 'rxjs'; import { nameof } from 'x-framework-core'; @Component({ selector: 'x-progress-bar', templateUrl: './x-progress-bar.component.html', styleUrls: ['./x-progress-bar.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XProgressBarComponent extends XProgressBarContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly PresentTypes = Object.assign({}, XProgressBarType); //#endregion // //#region LifeCycle ... onChange (changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy () { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Handlers ... registerViewHandlers () { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Reading Query Params ... //#endregion // //#region Providers ... //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider () { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.applyTakeUntilWrapper( this.actionProvider.asObservable() ).subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XProgressBarAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider () { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XProgressBarComponent } from './x-progress-bar.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XProgressBarComponent], imports: [CommonModule, XBaseComponentModule], exports: [XBaseComponentModule, XProgressBarComponent], }) export class XProgressBarModule { } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-progress-bar\x-progress-bar.typings.ts import { Subject, forkJoin, Observable, } from 'rxjs'; import { Input, NgZone, Inject, Renderer2, Component, Injectable, ElementRef, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseComponentContainer, XBaseContainerComponent, IXBaseComponentContainer, } from '../classes/i-x-base.container'; import { XManagerService } from 'x-framework-services'; import { ViewportRuler } from '@angular/cdk/scrolling'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Prop Definitions ... export enum XProgressBarType { Buffer = 'buffer', Determinate = 'determinate', Indeterminate = 'indeterminate', } export type XProgressBarTypeIdentifier = XProgressBarType | string; //#endregion // //#region Action Provider export enum XProgressBarAction { Refresh = 'refresh', } export type XProgressBarActionIdentifier = XProgressBarAction | string; export interface XProgressBarActionModel extends XBaseActionModel { } //#endregion // //#region Container ... export interface IXProgressBarContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; // type: XStandardType; // value: XStandardType; buffer: XStandardType; } @Injectable({ providedIn: 'root', }) export class XProgressBarContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Warning; // readonly type: XStandardType = XProgressBarType.Indeterminate; // readonly value: XStandardType; readonly buffer: XStandardType; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XProgressBarContainerComponent extends XBaseContainerComponent implements IXProgressBarContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; // @Input() type: XStandardType = this.propertyProvider.type; // @Input() value: XStandardType = this.propertyProvider.value; @Input() buffer: XStandardType = this.propertyProvider.buffer; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XProgressBarContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps ( container?: IXProgressBarContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), // color: this.getValue(container ? container.color : this.color), // type: this.getValue(container ? container.type : this.type), // value: this.getValue(container ? container.value : this.value), buffer: this.getValue(container ? container.buffer : this.buffer), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentProgressBarContainer = { [TKey in keyof IXProgressBarContainer as `progressBar${Capitalize< string & TKey >}`]: IXProgressBarContainer[TKey]; }; export interface IXComponentProgressBarContainer extends TXComponentProgressBarContainer, IXBaseComponentContainer { showProgressBar: XStandardType; } @Injectable({ providedIn: 'root', }) export class XComponentProgressBarContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // readonly showProgressBar: XStandardType = false; // readonly progressBarActionProvider = this.propertyProvider.actionProvider; readonly progressBarCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly progressBarColor: XStandardType = this.propertyProvider.color; // readonly progressBarType: XStandardType = this.propertyProvider.type; // readonly progressBarValue: XStandardType = this.propertyProvider.value; readonly progressBarBuffer: XStandardType = this.propertyProvider.buffer; //#endregion // //#region Constructor ... constructor(protected propertyProvider: XProgressBarContainer) { super(); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.component.scss .x-overlay { top: 0px; left: 0px; width: 100vw; height: 100vh; position: absolute; &.enabled { background-color: rgba(204, 204, 204, 0.6); } } .x-rectangle { position: absolute; &.drawing { border: 1px solid #ff0000; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.component.ts import { ViewChild, Component, ElementRef, ChangeDetectionStrategy, } from '@angular/core'; import { nameof } from 'x-framework-core'; import { XScreenCaptureDimensions } from './x-screen-capture.typings'; import { XScreenCaptureContainerComponent } from './x-screen-capture.container'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-screen-capture', templateUrl: './x-screen-capture.component.html', styleUrls: ['./x-screen-capture.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XScreenCaptureComponent extends XScreenCaptureContainerComponent { // //#region Props ... // rect: HTMLElement; captureZone: HTMLElement; // isDrawing = false; // clippingDimensions: XScreenCaptureDimensions = { x: 0, y: 0, width: 0, height: 0, }; // mouse = { x: 0, y: 0, startX: 0, startY: 0, }; // //#region View Childs ... // private RECT: ElementRef; // @ViewChild('rect', { static: false }) set rectangle(v: ElementRef) { // this.RECT = v; this.rect = v.nativeElement; } // get rectangle() { return this.RECT; } // private OVERLAY: ElementRef; // @ViewChild('over', { static: false }) set overlay(v: ElementRef) { // this.OVERLAY = v; this.captureZone = v.nativeElement; } // get overlay() { return this.OVERLAY; } // private CONTENT: ElementRef; // @ViewChild('content', { static: false }) set content(v: ElementRef) { this.CONTENT = v; } // get content() { return this.CONTENT; } //#endregion //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // const isEnableChanged = changeKeys.includes( nameof('enable') ); if (isEnableChanged) { // const enable = await this.getValueAsync(this.enable); this.reAssignElements(enable); this.detectChanges(); } } async afterViewInit() { super.afterViewInit(); // this.reAssignElements(); } //#endregion // //#region UI Handlers ... async handleMouseMoved(event: MouseEvent) { this.drawRect(event); } async handleMouseStarted(event: MouseEvent) { this.startCapture(event); } async handleMouseFinished(event: MouseEvent) { this.endCapture(event); } //#endregion // //#region Private ... private reAssignElements(enabled?: boolean) { // if (!this.OVERLAY || !this.RECT || !this.CONTENT) { return; } // this.rect = this.RECT.nativeElement; this.captureZone = this.OVERLAY.nativeElement; // if (enabled === true) { this.captureZone.style.cursor = 'crosshair'; } else { this.captureZone.style.cursor = 'default'; } } private setRectangle() { // this.rect.style.left = this.clippingDimensions.x + 'px'; this.rect.style.top = this.clippingDimensions.y + 'px'; this.rect.style.width = this.clippingDimensions.width + 'px'; this.rect.style.height = this.clippingDimensions.height + 'px'; } private startCapture(e: any) { // if (!this.captureZone) { // this.reAssignElements(); } // this.setMousePosition(e); // this.isDrawing = true; this.detectChanges(); // this.mouse.startX = this.mouse.x; this.mouse.startY = this.mouse.y; this.clippingDimensions = { x: this.mouse.x, y: this.mouse.y, width: 0, height: 0, }; // this.setRectangle(); this.captureZone.style.cursor = 'crosshair'; this.detectChanges(); } private drawRect(e: any) { // if (!this.captureZone) { return; } // if (this.isDrawing) { // this.setMousePosition(e); // this.clippingDimensions = { x: this.mouse.x - this.mouse.startX < 0 ? this.mouse.x : this.mouse.startX, y: this.mouse.y - this.mouse.startY < 0 ? this.mouse.y : this.mouse.startY, width: Math.abs(this.mouse.x - this.mouse.startX), height: Math.abs(this.mouse.y - this.mouse.startY), }; // this.setRectangle(); } } private setMousePosition(e: any) { // if (!this.captureZone) { return; } // // tslint:disable-next-line: deprecation const ev = e || window.event; // Moz || IE if (ev.pageX) { // Moz // this.mouse.x = ev.pageX + window.pageXOffset; this.mouse.y = ev.pageY + window.pageYOffset; } else if (ev.clientX) { // IE // this.mouse.x = ev.clientX + document.body.scrollLeft; this.mouse.y = ev.clientY + document.body.scrollTop; } } private async endCapture(ev: MouseEvent) { // if (!ev || !this.captureZone) { return; } // this.captureZone.style.cursor = 'default'; this.isDrawing = false; this.detectChanges(); // const captureDocument = document.body; // const topOffset = await this.getValueAsync(this.topOffset); if (topOffset !== 0) { this.clippingDimensions = { ...this.clippingDimensions, y: this.clippingDimensions.y + topOffset, }; } // const bottomOffset = await this.getValueAsync(this.bottomOffset); if (bottomOffset !== 0) { this.clippingDimensions = { ...this.clippingDimensions, y: this.clippingDimensions.y + bottomOffset, }; } // const canDownload = await this.getOptionalValueAsync( this.downloadCapturedImage ); if (canDownload === true) { // const blob = await this.screenCaptureService.captureAndDownload( captureDocument, null, this.clippingDimensions ); // this.imageCaptured.emit(blob); } else { // const blob = await this.screenCaptureService.capture( captureDocument, null, this.clippingDimensions ); // this.imageCaptured.emit(blob); } // this.clippingDimensions = { x: 0, y: 0, width: 0, height: 0, }; // this.setRectangle(); // this.reAssignElements(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.container.ts import { Input, Inject, NgZone, Output, Renderer2, Component, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { forkJoin, Observable } from 'rxjs'; import { XStandardType } from 'x-framework-core'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XScreenCaptureService } from './x-screen-capture.service'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; // //#region Container ... export interface IXScreenCaptureContainer extends IXBaseContainer { enable: XStandardType; topOffset: XStandardType; bottomOffset: XStandardType; downloadCapturedImage: XStandardType; imageCaptured: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XScreenCaptureContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly enable: XStandardType = false; readonly topOffset: XStandardType = 0; readonly bottomOffset: XStandardType = 0; readonly downloadCapturedImage: XStandardType = true; readonly imageCaptured: EventEmitter = new EventEmitter< string | Blob >(); //#endregion } @Injectable({ providedIn: 'root', }) @Component({ template: ` `, }) export abstract class XScreenCaptureContainerComponent extends XBaseContainerComponent implements IXScreenCaptureContainer { // //#region Props ... @Input() enable: XStandardType = this.propertyProvider.enable; @Input() topOffset: XStandardType = this.propertyProvider.topOffset; @Input() bottomOffset: XStandardType = this.propertyProvider.bottomOffset; @Input() downloadCapturedImage: XStandardType = this.propertyProvider.downloadCapturedImage; @Output() imageCaptured: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, public screenCaptureService: XScreenCaptureService, protected propertyProvider: XScreenCaptureContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXScreenCaptureContainer ): Observable { return forkJoin({ // enable: this.getValue(container ? container.enable : this.enable), topOffset: this.getValue( container ? container.topOffset : this.topOffset ), bottomOffset: this.getValue( container ? container.bottomOffset : this.bottomOffset ), downloadCapturedImage: this.getValue( container ? container.downloadCapturedImage : this.downloadCapturedImage ), }).pipe( map((data) => { return { // ...data, // imageCaptured: this.imageCaptured, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XScreenCaptureComponent } from './x-screen-capture.component'; @NgModule({ declarations: [XScreenCaptureComponent], imports: [CommonModule, XBaseComponentModule], exports: [XBaseComponentModule, XScreenCaptureComponent], }) export class XScreenCaptureModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.service.ts import { XMimeType, blobToImage, XBaseService, generateUuid, canvasToBlob, dataUrlToImage, canvasToDataUrl, clipImageToCanvas, downloadArrayBufferedFile, } from 'x-framework-core'; import { XScreenCaptureType, XScreenCaptureOptions, XScreenCaptureDimensions, XScreenCaptureTypeIdentifier, } from './x-screen-capture.typings'; import * as domToImage from 'dom-to-image'; import { Injectable, Inject } from '@angular/core'; import { XNotificationService } from 'x-framework-services'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; @Injectable({ providedIn: 'root', }) export class XScreenCaptureService extends XBaseService { // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, private notificationService: XNotificationService ) { super(config); } //#endregion /** * Capture Element with Options as specified type ... * * @param screen an instance of HTMLElement ... */ async capture( screen: HTMLElement, type?: XScreenCaptureTypeIdentifier, options?: XScreenCaptureOptions, clippingDimensions?: XScreenCaptureDimensions ) { // if (!screen) { return null; } // if (!type) { type = XScreenCaptureType.PNG; } // if (!options) { options = {}; } // this.playCaptureNotification(); // try { // switch (type) { // // PNG ... case XScreenCaptureType.PNG: // const pngDataUrl = await domToImage.default.toPng(screen, options); if (!clippingDimensions) { return pngDataUrl; } else { // const pngImage = await dataUrlToImage(pngDataUrl); if (!pngImage) { return null; } // const pngClippedCanvas = await clipImageToCanvas( pngImage, clippingDimensions.x, clippingDimensions.y, clippingDimensions.width, clippingDimensions.height ); if (!pngClippedCanvas) { return null; } // return canvasToDataUrl(pngClippedCanvas, XMimeType.ImagePNG); } // // JPeg ... case XScreenCaptureType.JPeg: // const jPegDataUrl = await domToImage.default.toJpeg(screen, options); if (!clippingDimensions) { return jPegDataUrl; } else { // const jPegImage = await dataUrlToImage(jPegDataUrl); if (!jPegImage) { return null; } // const jPegClippedCanvas = await clipImageToCanvas( jPegImage, clippingDimensions.x, clippingDimensions.y, clippingDimensions.width, clippingDimensions.height ); if (!jPegClippedCanvas) { return null; } // return canvasToDataUrl(jPegClippedCanvas, XMimeType.ImageJPEG); } // // SVG ... case XScreenCaptureType.SVG: // const svgDataUrl = await domToImage.default.toSvg(screen, options); if (!clippingDimensions) { return svgDataUrl; } else { // const svgImage = await dataUrlToImage(svgDataUrl); if (!svgImage) { return null; } // const svgClippedCanvas = await clipImageToCanvas( svgImage, clippingDimensions.x, clippingDimensions.y, clippingDimensions.width, clippingDimensions.height ); if (!svgClippedCanvas) { return null; } // return canvasToDataUrl(svgClippedCanvas, XMimeType.ImageSVG); } // // To Blob ... case XScreenCaptureType.Blob: // const blob = await domToImage.default.toBlob(screen, options); if (!clippingDimensions) { return blob; } else { // const blobImage = await blobToImage(blob); if (!blobImage) { return null; } // const blobClippedCanvas = await clipImageToCanvas( blobImage, clippingDimensions.x, clippingDimensions.y, clippingDimensions.width, clippingDimensions.height ); if (!blobClippedCanvas) { return null; } // return await canvasToBlob(blobClippedCanvas); } } } catch {} // return null; } /** * Capture Element with Options as Blob object and Download it ... * * @param screen an instance of HTMLElement ... * @param fileName downloaded file name ... */ async captureAndDownload( screen: HTMLElement, options?: XScreenCaptureOptions, clippingDimensions?: XScreenCaptureDimensions, fileName?: string ) { // this.playCaptureNotification(); // const fName = fileName ? fileName : `${generateUuid()}.png`; // try { // const blob = await domToImage.default.toBlob(screen, options); // if (!blob) { return null; } // if (!clippingDimensions) { // downloadArrayBufferedFile(fName, blob); return blob; } else { // const blobImage = await blobToImage(blob); if (!blobImage) { return null; } // const blobClippedCanvas = await clipImageToCanvas( blobImage, clippingDimensions.x, clippingDimensions.y, clippingDimensions.width, clippingDimensions.height ); if (!blobClippedCanvas) { return null; } // const clippedBlob = await canvasToBlob(blobClippedCanvas); if (!clippedBlob) { return null; } // downloadArrayBufferedFile(fName, clippedBlob); return clippedBlob; } } catch {} // return null; } /** * play Capture Notification Sound ... */ playCaptureNotification() { this.notificationService.playCaptureNotification(); } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-screen-capture\x-screen-capture.typings.ts import { Options } from 'dom-to-image'; // tslint:disable-next-line:no-empty-interface export interface XScreenCaptureOptions extends Options {} export enum XScreenCaptureType { SVG = 'svg', PNG = 'png', Blob = 'blob', JPeg = 'jpeg', } export type XScreenCaptureTypeIdentifier = XScreenCaptureType | string; export interface XScreenCaptureDimensions { x: number; y: number; width: number; height: number; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.component.scss :host { --clear-icon-color: var(--x-color-danger); --cancel-icon-color: var(--x-color-primary); --search-icon-color: var(--x-color-primary); } :host::ng-deep { .searchbar-clear-icon { color: var(--clear-icon-color) !important; } .searchbar-search-icon { color: var(--search-icon-color) !important; } .searchbar-cancel-button { color: var(--cancel-icon-color) !important; } } .x-search-bar { padding: { left: 3px; right: 3px; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.component.ts import { nameof, parseXColor, isNullOrEmptyString, getXColorCssVariableName, } from 'x-framework-core'; import { XSearchBarEvent, XSearchBarAction, XSearchBarCssVars, XSearchBarActionModel, XSearchBarContainerComponent, } from './x-search-bar.typings'; import { filter } from 'rxjs/operators'; import { Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-search-bar', templateUrl: './x-search-bar.component.html', styleUrls: ['./x-search-bar.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XSearchBarComponent extends XSearchBarContainerComponent { // //#region Props ... // protected applyThemeColors: boolean = true; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; readonly SearchBarEvents = Object.assign({}, XSearchBarEvent); //#endregion // //#region LifeCycles ... afterViewInit() { super.afterViewInit(); // // Handle Start Value for start searching ... this.getValue(this.value) .pipe(filter((query) => !isNullOrEmptyString(query))) .subscribe((query) => { this.queryChange.emit(query); }); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region Action Provider ... const isActionProviderChaged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChaged) { this.registerActionProvider(); } //#endregion // //#region Colors ... // const isCancelButtonIconColorChanged = changeKeys.includes( nameof('cancelButtonIconColor') ); if (isCancelButtonIconColorChanged) { await this.applyCancelButtonIconColor(); } // const isClearButtonIconColorChanged = changeKeys.includes( nameof('clearButtonIconColor') ); if (isClearButtonIconColorChanged) { await this.applyClearButtonIconColor(); } // const isSearchButtonIconColorChanged = changeKeys.includes( nameof('searchButtonIconColor') ); if (isSearchButtonIconColorChanged) { await this.applySearchButtonIconColor(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Register Handlers ... registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... //#endregion // //#region UI Handlers ... // handleSearchQueryValueChange(event: CustomEvent | any) { // const query = event && event.detail && event.detail.value ? event.detail.value.toString().trim().toLowerCase() : ''; // this.queryChange.emit(query); } //#endregion // //#region Actions ... //#endregion // //#region Private ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XSearchBarAction.ClearValue: // this.value = ''; this.detectChanges(); break; // case XSearchBarAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } // //#region Color Appliers ... private async applyCancelButtonIconColor() { // const color = await this.getValueAsync(this.cancelButtonIconColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XSearchBarCssVars.CancelIconColor, `var(${bgColor})`); this.setCssVar( XSearchBarCssVars.CancelIconColor, `var(${bgColor})`, document.body ); // this.detectChanges(); } private async applyClearButtonIconColor() { // const color = await this.getValueAsync(this.clearButtonIconColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XSearchBarCssVars.ClearIconColor, `var(${bgColor})`); this.setCssVar( XSearchBarCssVars.ClearIconColor, `var(${bgColor})`, document.body ); // this.detectChanges(); } private async applySearchButtonIconColor() { // const color = await this.getValueAsync(this.searchButtonIconColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XSearchBarCssVars.SearchIconColor, `var(${bgColor})`); this.setCssVar( XSearchBarCssVars.SearchIconColor, `var(${bgColor})`, document.body ); // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XSearchBarComponent } from './x-search-bar.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XSearchBarComponent], imports: [ CommonModule, XBaseComponentModule, ], exports: [ CommonModule, XSearchBarComponent, XBaseComponentModule, ], }) export class XSearchBarModule { } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-search-bar\x-search-bar.typings.ts import { XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseComponentContainer, XBaseContainerComponent, IXBaseComponentContainer, XBaseComponentContainerComponent, } from '../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XSearchBarAction { ClearValue = 'clear_value', Refresh = 'refresh', } export type XSearchBarActionIdentifier = XSearchBarAction | string; export interface XSearchBarActionModel extends XBaseActionModel {} export enum XSearchBarType { None = 'none', Text = 'text', Tel = 'tel', Url = 'url', Email = 'email', Numeric = 'numeric', Decimal = 'decimal', Search = 'search', } export type XSearchBarTypeIdentifier = XSearchBarType | string; export enum XSearchBarEnterKeyHint { Done = 'done', Go = 'go', Next = 'next', Previous = 'previous', Search = 'search', Send = 'send', Enter = 'enter', } export type XSearchBarEnterKeyHintIdentifier = XSearchBarEnterKeyHint | string; export enum XSearchBarShowButton { Always = 'always', Focus = 'focus', Never = 'never', } export type XSearchBarShowButtonIdentifier = XSearchBarShowButton | string; export enum XSearchBarCssVars { // ClearIconColor = 'clear-icon-color', CancelIconColor = 'cancel-icon-color', SearchIconColor = 'search-icon-color', } export type XSearchBarCssVarsIdentifier = XSearchBarCssVars | string; export enum XSearchBarEvent { FOCUS = 'focus', BLUR = 'blur', CANCEL = 'cancel', CLEAR = 'clear', INPUT = 'input', } export type XSearchBarEventIdentifier = XSearchBarEvent | string; // //#region Container ... export interface IXSearchBarContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; // searchInputColor: XStandardType; foregroundSearchInputColor: XStandardType; // type: XStandardType; title: XStandardType; value: XStandardType; enterKeyHint: XStandardType; keyboardType: XStandardType; spellcheck: XStandardType; debounce: XStandardType; // showCancelButton: XStandardType; cancelButtonIcon: XStandardType; cancelButtonTitle: XStandardType; cancelButtonIconColor: XStandardType; // showClearButton: XStandardType; clearButtonIcon: XStandardType; clearButtonIconColor: XStandardType; // searchButtonIcon: XStandardType; searchButtonIconColor: XStandardType; // queryChange: EventEmitter; onEvent: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XSearchBarContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; // readonly searchInputColor: XStandardType = XColorWithBrightness.Light; readonly foregroundSearchInputColor: XStandardType = false; // readonly type: XStandardType = XSearchBarType.Search; readonly title: XStandardType = XResourceIDs.search; readonly value: XStandardType; readonly enterKeyHint: XStandardType = XSearchBarEnterKeyHint.Search; readonly keyboardType: XStandardType = XSearchBarType.Search; readonly spellcheck: XStandardType = false; readonly debounce: XStandardType = this.config.defaultSearchDebounceTime || 500; // readonly showCancelButton: XStandardType = XSearchBarShowButton.Never; readonly cancelButtonIcon: XStandardType; readonly cancelButtonTitle: XStandardType; readonly cancelButtonIconColor: XStandardType = XColorWithBrightness.Primary; // readonly showClearButton: XStandardType = XSearchBarShowButton.Always; readonly clearButtonIcon: XStandardType; readonly clearButtonIconColor: XStandardType = XColorWithBrightness.Danger; // readonly searchButtonIcon: XStandardType; readonly searchButtonIconColor: XStandardType = XColorWithBrightness.Primary; // readonly queryChange: EventEmitter = new EventEmitter(); readonly onEvent: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig ) { super(); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XSearchBarContainerComponent extends XBaseContainerComponent implements IXSearchBarContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; // @Input() searchInputColor: XStandardType = this.propertyProvider.searchInputColor; @Input() foregroundSearchInputColor: XStandardType = this.propertyProvider.foregroundSearchInputColor; // @Input() type: XStandardType = this.propertyProvider.type; @Input() title: XStandardType = this.propertyProvider.title; @Input() value: XStandardType = this.propertyProvider.value; @Input() enterKeyHint: XStandardType = this.propertyProvider.enterKeyHint; @Input() keyboardType: XStandardType = this.propertyProvider.keyboardType; @Input() spellcheck: XStandardType = this.propertyProvider.spellcheck; @Input() debounce: XStandardType = this.propertyProvider.debounce; // @Input() showCancelButton: XStandardType = this.propertyProvider.showCancelButton; @Input() cancelButtonIcon: XStandardType = this.propertyProvider.cancelButtonIcon; @Input() cancelButtonTitle: XStandardType = this.propertyProvider.cancelButtonTitle; @Input() cancelButtonIconColor: XStandardType = this.propertyProvider.cancelButtonIconColor; // @Input() showClearButton: XStandardType = this.propertyProvider.showClearButton; @Input() clearButtonIcon: XStandardType = this.propertyProvider.clearButtonIcon; @Input() clearButtonIconColor: XStandardType = this.propertyProvider.clearButtonIconColor; // @Input() searchButtonIcon: XStandardType = this.propertyProvider.searchButtonIcon; @Input() searchButtonIconColor: XStandardType = this.propertyProvider.searchButtonIconColor; // @Output() queryChange: EventEmitter = new EventEmitter(); @Output() onEvent: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XSearchBarContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXSearchBarContainer ): Observable { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), searchInputColor: this.getValue( container ? container.searchInputColor : this.searchInputColor ), foregroundSearchInputColor: this.getValue( container ? container.foregroundSearchInputColor : this.foregroundSearchInputColor ), type: this.getValue(container ? container.type : this.type), title: this.getValue(container ? container.title : this.title), value: this.getValue(container ? container.value : this.value), enterKeyHint: this.getValue( container ? container.enterKeyHint : this.enterKeyHint ), keyboardType: this.getValue( container ? container.keyboardType : this.keyboardType ), spellcheck: this.getValue( container ? container.spellcheck : this.spellcheck ), debounce: this.getValue(container ? container.debounce : this.debounce), showCancelButton: this.getValue( container ? container.showCancelButton : this.showCancelButton ), cancelButtonIcon: this.getValue( container ? container.cancelButtonIcon : this.cancelButtonIcon ), cancelButtonTitle: this.getValue( container ? container.cancelButtonTitle : this.cancelButtonTitle ), cancelButtonIconColor: this.getValue( container ? container.cancelButtonIconColor : this.cancelButtonIconColor ), showClearButton: this.getValue( container ? container.showCancelButton : this.showCancelButton ), clearButtonIcon: this.getValue( container ? container.clearButtonIcon : this.clearButtonIcon ), clearButtonIconColor: this.getValue( container ? container.clearButtonIconColor : this.clearButtonIconColor ), searchButtonIcon: this.getValue( container ? container.searchButtonIcon : this.searchButtonIcon ), searchButtonIconColor: this.getValue( container ? container.searchButtonIconColor : this.searchButtonIconColor ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // onEvent: this.onEvent, queryChange: this.queryChange, }; }) ); } //#endregion } //#endregion // //#region ComponentContainer ... type TXComponentSearchBarContainer = { [TKey in keyof IXSearchBarContainer as `searchBar${Capitalize< string & TKey >}`]: IXSearchBarContainer[TKey]; }; export interface IXComponentSearchBarContainer extends TXComponentSearchBarContainer, IXBaseComponentContainer { // showSearchBar: XStandardType; // searchBarActionProvider: Subject; searchBarCssClass: XStandardType>; // searchBarColor: XStandardType; searchBarForegroundColor: XStandardType; // searchBarSearchInputColor: XStandardType; searchBarForegroundSearchInputColor: XStandardType; // searchBarType: XStandardType; searchBarTitle: XStandardType; searchBarValue: XStandardType; searchBarEnterKeyHint: XStandardType; searchBarKeyboardType: XStandardType; searchBarSpellcheck: XStandardType; searchBarDebounce: XStandardType; // searchBarShowCancelButton: XStandardType; searchBarCancelButtonIcon: XStandardType; searchBarCancelButtonTitle: XStandardType; searchBarCancelButtonIconColor: XStandardType; // searchBarShowClearButton: XStandardType; searchBarClearButtonIcon: XStandardType; searchBarClearButtonIconColor: XStandardType; // searchBarSearchButtonIcon: XStandardType; searchBarSearchButtonIconColor: XStandardType; // searchBarQueryChange: EventEmitter; searchBarOnEvent: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XComponentSearchBarContainer extends XBaseComponentContainer implements Readonly { // //#region Props ... // readonly showSearchBar: XStandardType = true; // readonly searchBarActionProvider: Subject = this.propertyProvider.actionProvider; readonly searchBarCssClass: XStandardType> = this.propertyProvider.cssClass; // readonly searchBarColor: XStandardType = this.propertyProvider.color; readonly searchBarForegroundColor: XStandardType = this.propertyProvider.foregroundColor; // readonly searchBarSearchInputColor: XStandardType = this.propertyProvider.searchInputColor; readonly searchBarForegroundSearchInputColor: XStandardType = this.propertyProvider.foregroundSearchInputColor; // readonly searchBarType: XStandardType = this.propertyProvider.type; readonly searchBarTitle: XStandardType = this.propertyProvider.title; readonly searchBarValue: XStandardType = this.propertyProvider.value; readonly searchBarEnterKeyHint: XStandardType = this.propertyProvider.enterKeyHint; readonly searchBarKeyboardType: XStandardType = this.propertyProvider.keyboardType; readonly searchBarSpellcheck: XStandardType = this.propertyProvider.spellcheck; readonly searchBarDebounce: XStandardType = this.propertyProvider.debounce; // readonly searchBarShowCancelButton: XStandardType = this.propertyProvider.showCancelButton; readonly searchBarCancelButtonIcon: XStandardType = this.propertyProvider.cancelButtonIcon; readonly searchBarCancelButtonTitle: XStandardType = this.propertyProvider.cancelButtonTitle; readonly searchBarCancelButtonIconColor: XStandardType = this.propertyProvider.cancelButtonIconColor; // readonly searchBarShowClearButton: XStandardType = this.propertyProvider.showClearButton; readonly searchBarClearButtonIcon: XStandardType = this.propertyProvider.clearButtonIcon; readonly searchBarClearButtonIconColor: XStandardType = this.propertyProvider.clearButtonIconColor; // readonly searchBarSearchButtonIcon: XStandardType = this.propertyProvider.searchButtonIcon; readonly searchBarSearchButtonIconColor: XStandardType = this.propertyProvider.searchButtonIconColor; // readonly searchBarQueryChange: EventEmitter = this.propertyProvider.queryChange; readonly searchBarOnEvent: EventEmitter = this.propertyProvider.onEvent; //#endregion // //#region Constructor ... constructor(protected propertyProvider: XSearchBarContainer) { super(); } //#endregion } @Component({ template: ``, }) export abstract class XComponentSearchBarContainerComponent extends XBaseComponentContainerComponent implements IXComponentSearchBarContainer { // //#region Props ... // @Input() showSearchBar: XStandardType = this.propertyProvider.showSearchBar; // @Input() searchBarActionProvider: Subject = this.propertyProvider.searchBarActionProvider; @Input() searchBarCssClass: XStandardType> = this.propertyProvider.searchBarCssClass; // @Input() searchBarColor: XStandardType = this.propertyProvider.searchBarColor; @Input() searchBarForegroundColor: XStandardType = this.propertyProvider.searchBarForegroundColor; // @Input() searchBarSearchInputColor: XStandardType = this.propertyProvider.searchBarSearchInputColor; @Input() searchBarForegroundSearchInputColor: XStandardType = this.propertyProvider.searchBarForegroundSearchInputColor; // @Input() searchBarType: XStandardType = this.propertyProvider.searchBarType; @Input() searchBarTitle: XStandardType = this.propertyProvider.searchBarTitle; @Input() searchBarValue: XStandardType = this.propertyProvider.searchBarValue; @Input() searchBarEnterKeyHint: XStandardType = this.propertyProvider.searchBarEnterKeyHint; @Input() searchBarKeyboardType: XStandardType = this.propertyProvider.searchBarKeyboardType; @Input() searchBarSpellcheck: XStandardType = this.propertyProvider.searchBarSpellcheck; @Input() searchBarDebounce: XStandardType = this.propertyProvider.searchBarDebounce; // @Input() searchBarShowCancelButton: XStandardType = this.propertyProvider.searchBarShowCancelButton; @Input() searchBarCancelButtonIcon: XStandardType = this.propertyProvider.searchBarCancelButtonIcon; @Input() searchBarCancelButtonTitle: XStandardType = this.propertyProvider.searchBarCancelButtonTitle; @Input() searchBarCancelButtonIconColor: XStandardType = this.propertyProvider.searchBarCancelButtonIconColor; // @Input() searchBarShowClearButton: XStandardType = this.propertyProvider.searchBarShowClearButton; @Input() searchBarClearButtonIcon: XStandardType = this.propertyProvider.searchBarClearButtonIcon; @Input() searchBarClearButtonIconColor: XStandardType = this.propertyProvider.searchBarClearButtonIconColor; // @Input() searchBarSearchButtonIcon: XStandardType = this.propertyProvider.searchBarSearchButtonIcon; @Input() searchBarSearchButtonIconColor: XStandardType = this.propertyProvider.searchBarSearchButtonIconColor; // @Output() searchBarQueryChange: EventEmitter = new EventEmitter(); @Output() searchBarOnEvent: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XComponentSearchBarContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXComponentSearchBarContainer ): Observable { return forkJoin({ // showSearchBar: this.getValue( container ? container.showSearchBar : this.showSearchBar ), // searchBarCssClass: this.getArrayValue( container ? container.searchBarCssClass : this.searchBarCssClass ), // searchBarColor: this.getValue( container ? container.searchBarColor : this.searchBarColor ), searchBarForegroundColor: this.getValue( container ? container.searchBarForegroundColor : this.searchBarForegroundColor ), searchBarSearchInputColor: this.getValue( container ? container.searchBarSearchInputColor : this.searchBarSearchInputColor ), searchBarForegroundSearchInputColor: this.getValue( container ? container.searchBarForegroundSearchInputColor : this.searchBarForegroundSearchInputColor ), searchBarType: this.getValue( container ? container.searchBarType : this.searchBarType ), searchBarTitle: this.getValue( container ? container.searchBarTitle : this.searchBarTitle ), searchBarValue: this.getValue( container ? container.searchBarValue : this.searchBarValue ), searchBarEnterKeyHint: this.getValue( container ? container.searchBarEnterKeyHint : this.searchBarEnterKeyHint ), searchBarKeyboardType: this.getValue( container ? container.searchBarKeyboardType : this.searchBarKeyboardType ), searchBarSpellcheck: this.getValue( container ? container.searchBarSpellcheck : this.searchBarSpellcheck ), searchBarDebounce: this.getValue( container ? container.searchBarDebounce : this.searchBarDebounce ), searchBarShowCancelButton: this.getValue( container ? container.searchBarShowCancelButton : this.searchBarShowCancelButton ), searchBarCancelButtonIcon: this.getValue( container ? container.searchBarCancelButtonIcon : this.searchBarCancelButtonIcon ), searchBarCancelButtonTitle: this.getValue( container ? container.searchBarCancelButtonTitle : this.searchBarCancelButtonTitle ), searchBarCancelButtonIconColor: this.getValue( container ? container.searchBarCancelButtonIconColor : this.searchBarCancelButtonIconColor ), searchBarShowClearButton: this.getValue( container ? container.searchBarShowClearButton : this.searchBarShowClearButton ), searchBarClearButtonIcon: this.getValue( container ? container.searchBarClearButtonIcon : this.searchBarClearButtonIcon ), searchBarClearButtonIconColor: this.getValue( container ? container.searchBarClearButtonIconColor : this.searchBarClearButtonIconColor ), searchBarSearchButtonIcon: this.getValue( container ? container.searchBarSearchButtonIcon : this.searchBarSearchButtonIcon ), searchBarSearchButtonIconColor: this.getValue( container ? container.searchBarSearchButtonIconColor : this.searchBarSearchButtonIconColor ), }).pipe( map((data) => { return { // ...data, // searchBarActionProvider: container ? container.searchBarActionProvider : this.searchBarActionProvider, // searchBarOnEvent: this.searchBarOnEvent, searchBarQueryChange: this.searchBarQueryChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide.animation.providers.ts import { XSlideAnimationProvider } from './x-slider.typings'; // //#region Animations ... export const Coverflow: XSlideAnimationProvider = { coverflowEffect: { rotate: 50, stretch: 0, depth: 100, modifier: 1, slideShadows: true }, on: { beforeInit() { const swiper = this; swiper.classNames.push( `${swiper.params.containerModifierClass}coverflow` ); swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); swiper.params.watchSlidesProgress = true; swiper.originalParams.watchSlidesProgress = true; }, setTranslate() { const swiper = this; const { width: swiperWidth, height: swiperHeight, slides, $wrapperEl, slidesSizesGrid } = swiper; const params = swiper.params.coverflowEffect; const isHorizontal = swiper.isHorizontal(); const transform$$1 = swiper.translate; const center = isHorizontal ? -transform$$1 + swiperWidth / 2 : -transform$$1 + swiperHeight / 2; const rotate = isHorizontal ? params.rotate : -params.rotate; const translate = params.depth; // Each slide offset from center for (let i = 0, length = slides.length; i < length; i += 1) { const $slideEl = slides.eq(i); const slideSize = slidesSizesGrid[i]; const slideOffset = $slideEl[0].swiperSlideOffset; const offsetMultiplier = ((center - slideOffset - slideSize / 2) / slideSize) * params.modifier; let rotateY = isHorizontal ? rotate * offsetMultiplier : 0; let rotateX = isHorizontal ? 0 : rotate * offsetMultiplier; // var rotateZ = 0 let translateZ = -translate * Math.abs(offsetMultiplier); let translateY = isHorizontal ? 0 : params.stretch * offsetMultiplier; let translateX = isHorizontal ? params.stretch * offsetMultiplier : 0; // Fix for ultra small values if (Math.abs(translateX) < 0.001) { translateX = 0; } if (Math.abs(translateY) < 0.001) { translateY = 0; } if (Math.abs(translateZ) < 0.001) { translateZ = 0; } if (Math.abs(rotateY) < 0.001) { rotateY = 0; } if (Math.abs(rotateX) < 0.001) { rotateX = 0; } const slideTransform = `translate3d(${translateX}px,${translateY}px,${translateZ}px)` + ` rotateX(${rotateX}deg) rotateY(${rotateY}deg)`; $slideEl.transform(slideTransform); $slideEl[0].style.zIndex = -Math.abs(Math.round(offsetMultiplier)) + 1; if (params.slideShadows) { // Set shadows let $shadowBeforeEl = isHorizontal ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top'); let $shadowAfterEl = isHorizontal ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom'); if ($shadowBeforeEl.length === 0) { $shadowBeforeEl = swiper.$( `
` ); // $slideEl.append($shadowBeforeEl); } if ($shadowAfterEl.length === 0) { $shadowAfterEl = swiper.$( `
` ); // $slideEl.append($shadowAfterEl); } if ($shadowBeforeEl.length) { $shadowBeforeEl[0].style.opacity = offsetMultiplier > 0 ? offsetMultiplier : 0; } if ($shadowAfterEl.length) { $shadowAfterEl[0].style.opacity = -offsetMultiplier > 0 ? -offsetMultiplier : 0; } } } // Set correct perspective for IE10 if ( swiper.support.pointerEvents || swiper.support.prefixedPointerEvents ) { const ws = $wrapperEl[0].style; ws.perspectiveOrigin = `${center}px 50%`; } }, setTransition(duration) { const swiper = this; swiper.slides .transition(duration) .find( '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' ) .transition(duration); } } }; // export const Cube: XSlideAnimationProvider = { cubeEffect: { shadow: true, slideShadows: true, shadowOffset: 20, shadowScale: 0.94 }, on: { beforeInit() { const swiper = this; swiper.classNames.push(`${swiper.params.containerModifierClass}cube`); swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); const overwriteParams = { slidesPerView: 1, slidesPerColumn: 1, slidesPerGroup: 1, watchSlidesProgress: true, resistanceRatio: 0, spaceBetween: 0, centeredSlides: false, virtualTranslate: true }; this.params = Object.assign(this.params, overwriteParams); this.originalParams = Object.assign(this.originalParams, overwriteParams); }, setTranslate() { const swiper = this; const { $el, $wrapperEl, slides, width: swiperWidth, height: swiperHeight, rtlTranslate: rtl, size: swiperSize } = swiper; const params = swiper.params.cubeEffect; const isHorizontal = swiper.isHorizontal(); const isVirtual = swiper.virtual && swiper.params.virtual.enabled; let wrapperRotate = 0; let $cubeShadowEl; if (params.shadow) { if (isHorizontal) { $cubeShadowEl = $wrapperEl.find('.swiper-cube-shadow'); if ($cubeShadowEl.length === 0) { $cubeShadowEl = swiper.$('
'); $wrapperEl.append($cubeShadowEl); } $cubeShadowEl.css({ height: `${swiperWidth}px` }); } else { $cubeShadowEl = $el.find('.swiper-cube-shadow'); if ($cubeShadowEl.length === 0) { $cubeShadowEl = swiper.$('
'); $el.append($cubeShadowEl); } } } for (let i = 0; i < slides.length; i += 1) { const $slideEl = slides.eq(i); let slideIndex = i; if (isVirtual) { slideIndex = parseInt($slideEl.attr('data-swiper-slide-index'), 10); } let slideAngle = slideIndex * 90; let round = Math.floor(slideAngle / 360); if (rtl) { slideAngle = -slideAngle; round = Math.floor(-slideAngle / 360); } const progress = Math.max(Math.min($slideEl[0].progress, 1), -1); let tx = 0; let ty = 0; let tz = 0; if (slideIndex % 4 === 0) { tx = -round * 4 * swiperSize; tz = 0; } else if ((slideIndex - 1) % 4 === 0) { tx = 0; tz = -round * 4 * swiperSize; } else if ((slideIndex - 2) % 4 === 0) { tx = swiperSize + round * 4 * swiperSize; tz = swiperSize; } else if ((slideIndex - 3) % 4 === 0) { tx = -swiperSize; tz = 3 * swiperSize + swiperSize * 4 * round; } if (rtl) { tx = -tx; } if (!isHorizontal) { ty = tx; tx = 0; } const transform$$1 = `rotateX(${ isHorizontal ? 0 : -slideAngle }deg) rotateY(${ isHorizontal ? slideAngle : 0 }deg) translate3d(${tx}px, ${ty}px, ${tz}px)`; if (progress <= 1 && progress > -1) { wrapperRotate = slideIndex * 90 + progress * 90; if (rtl) { wrapperRotate = -slideIndex * 90 - progress * 90; } } $slideEl.transform(transform$$1); if (params.slideShadows) { // Set shadows let shadowBefore = isHorizontal ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top'); let shadowAfter = isHorizontal ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom'); if (shadowBefore.length === 0) { shadowBefore = swiper.$( `
` ); $slideEl.append(shadowBefore); } if (shadowAfter.length === 0) { shadowAfter = swiper.$( `
` ); $slideEl.append(shadowAfter); } if (shadowBefore.length) { shadowBefore[0].style.opacity = Math.max(-progress, 0); } if (shadowAfter.length) { shadowAfter[0].style.opacity = Math.max(progress, 0); } } } $wrapperEl.css({ '-webkit-transform-origin': `50% 50% -${swiperSize / 2}px`, '-moz-transform-origin': `50% 50% -${swiperSize / 2}px`, '-ms-transform-origin': `50% 50% -${swiperSize / 2}px`, 'transform-origin': `50% 50% -${swiperSize / 2}px` }); if (params.shadow) { if (isHorizontal) { $cubeShadowEl.transform( `translate3d(0px, ${swiperWidth / 2 + params.shadowOffset}px, ${-swiperWidth / 2}px) rotateX(90deg) rotateZ(0deg) scale(${params.shadowScale})` ); } else { const shadowAngle = Math.abs(wrapperRotate) - Math.floor(Math.abs(wrapperRotate) / 90) * 90; const multiplier = 1.5 - (Math.sin((shadowAngle * 2 * Math.PI) / 360) / 2 + Math.cos((shadowAngle * 2 * Math.PI) / 360) / 2); const scale1 = params.shadowScale; const scale2 = params.shadowScale / multiplier; const offset$$1 = params.shadowOffset; $cubeShadowEl.transform( `scale3d(${scale1}, 1, ${scale2}) translate3d(0px, ${swiperHeight / 2 + offset$$1}px, ${-swiperHeight / 2 / scale2}px) rotateX(-90deg)` ); } } const zFactor = swiper.browser.isSafari || swiper.browser.isUiWebView ? -swiperSize / 2 : 0; $wrapperEl.transform( `translate3d(0px,0,${zFactor}px) rotateX(${ swiper.isHorizontal() ? 0 : wrapperRotate }deg) rotateY(${swiper.isHorizontal() ? -wrapperRotate : 0}deg)` ); }, setTransition(duration) { const swiper = this; const { $el, slides } = swiper; slides .transition(duration) .find( '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' ) .transition(duration); if (swiper.params.cubeEffect.shadow && !swiper.isHorizontal()) { $el.find('.swiper-cube-shadow').transition(duration); } } } }; // export const Fade: XSlideAnimationProvider = { on: { beforeInit() { const swiper = this; swiper.classNames.push(`${swiper.params.containerModifierClass}fade`); const overwriteParams = { slidesPerView: 1, slidesPerColumn: 1, slidesPerGroup: 1, watchSlidesProgress: true, spaceBetween: 0, virtualTranslate: true }; swiper.params = Object.assign(swiper.params, overwriteParams); swiper.params = Object.assign(swiper.originalParams, overwriteParams); }, setTranslate() { const swiper = this; const { slides } = swiper; for (let i = 0; i < slides.length; i += 1) { const $slideEl = swiper.slides.eq(i); const offset$$1 = $slideEl[0].swiperSlideOffset; let tx = -offset$$1; if (!swiper.params.virtualTranslate) { tx -= swiper.translate; } let ty = 0; if (!swiper.isHorizontal()) { ty = tx; tx = 0; } const slideOpacity = swiper.params.fadeEffect.crossFade ? Math.max(1 - Math.abs($slideEl[0].progress), 0) : 1 + Math.min(Math.max($slideEl[0].progress, -1), 0); $slideEl .css({ opacity: slideOpacity }) .transform(`translate3d(${tx}px, ${ty}px, 0px)`); } }, setTransition(duration) { const swiper = this; const { slides, $wrapperEl } = swiper; slides.transition(duration); if (swiper.params.virtualTranslate && duration !== 0) { let eventTriggered = false; slides.transitionEnd(() => { if (eventTriggered) { return; } if (!swiper || swiper.destroyed) { return; } eventTriggered = true; swiper.animating = false; const triggerEvents = ['webkitTransitionEnd', 'transitionend']; // tslint:disable-next-line:prefer-for-of for (let i = 0; i < triggerEvents.length; i += 1) { $wrapperEl.trigger(triggerEvents[i]); } }); } } } }; // export const Flip: XSlideAnimationProvider = { on: { beforeInit() { const swiper = this; swiper.classNames.push(`${swiper.params.containerModifierClass}flip`); swiper.classNames.push(`${swiper.params.containerModifierClass}3d`); const overwriteParams = { slidesPerView: 1, slidesPerColumn: 1, slidesPerGroup: 1, watchSlidesProgress: true, spaceBetween: 0, virtualTranslate: true }; swiper.params = Object.assign(swiper.params, overwriteParams); swiper.originalParams = Object.assign( swiper.originalParams, overwriteParams ); }, setTranslate() { const swiper = this; const { $, slides, rtlTranslate: rtl } = swiper; for (let i = 0; i < slides.length; i += 1) { const $slideEl = slides.eq(i); let progress = $slideEl[0].progress; if (swiper.params.flipEffect.limitRotation) { progress = Math.max(Math.min($slideEl[0].progress, 1), -1); } const offset$$1 = $slideEl[0].swiperSlideOffset; const rotate = -180 * progress; let rotateY = rotate; let rotateX = 0; let tx = -offset$$1; let ty = 0; if (!swiper.isHorizontal()) { ty = tx; tx = 0; rotateX = -rotateY; rotateY = 0; } else if (rtl) { rotateY = -rotateY; } $slideEl[0].style.zIndex = -Math.abs(Math.round(progress)) + slides.length; if (swiper.params.flipEffect.slideShadows) { // Set shadows let shadowBefore = swiper.isHorizontal() ? $slideEl.find('.swiper-slide-shadow-left') : $slideEl.find('.swiper-slide-shadow-top'); let shadowAfter = swiper.isHorizontal() ? $slideEl.find('.swiper-slide-shadow-right') : $slideEl.find('.swiper-slide-shadow-bottom'); if (shadowBefore.length === 0) { shadowBefore = swiper.$( `
` ); $slideEl.append(shadowBefore); } if (shadowAfter.length === 0) { shadowAfter = swiper.$( `
` ); $slideEl.append(shadowAfter); } if (shadowBefore.length) { shadowBefore[0].style.opacity = Math.max(-progress, 0); } if (shadowAfter.length) { shadowAfter[0].style.opacity = Math.max(progress, 0); } } $slideEl.transform( `translate3d(${tx}px, ${ty}px, 0px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)` ); } }, setTransition(duration) { const swiper = this; const { slides, activeIndex, $wrapperEl } = swiper; slides .transition(duration) .find( '.swiper-slide-shadow-top, .swiper-slide-shadow-right, .swiper-slide-shadow-bottom, .swiper-slide-shadow-left' ) .transition(duration); if (swiper.params.virtualTranslate && duration !== 0) { let eventTriggered = false; // eslint-disable-next-line slides.eq(activeIndex).transitionEnd(function onTransitionEnd() { if (eventTriggered) { return; } if (!swiper || swiper.destroyed) { return; } eventTriggered = true; swiper.animating = false; const triggerEvents = ['webkitTransitionEnd', 'transitionend']; // tslint:disable-next-line:prefer-for-of for (let i = 0; i < triggerEvents.length; i += 1) { $wrapperEl.trigger(triggerEvents[i]); } }); } } } }; //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.component.scss :host { --paginator: var(--x-color-dark-tint); --paginator-active: var(--x-color-secondary); } ion-slides { --bullet-background: var(--paginator); --bullet-background-active: var(--paginator-active); } .no-pager { padding-bottom: 0 !important; } .slider { padding-bottom: 30px !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.component.ts import { Component, QueryList, ViewChild, ContentChildren, ChangeDetectionStrategy, } from '@angular/core'; import { nameof, isNullOrUndefined, isNullOrEmptyString, } from 'x-framework-core'; import { XSliderAction, XSliderConfig, XSliderAnimation, XSliderActionModel, defaultXSliderConfig, XSliderContainerComponent, XSliderAnimationIdentifier, defaultXSliderPaginationConfig, } from './x-slider.typings'; import { map } from 'rxjs/operators'; import { IonSlides } from '@ionic/angular'; import { Subject, Subscription } from 'rxjs'; import { XSlideComponent } from './x-slide/x-slide.component'; import { Coverflow, Cube, Fade, Flip } from './x-slide.animation.providers'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-slider', templateUrl: './x-slider.component.html', styleUrls: ['./x-slider.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XSliderComponent extends XSliderContainerComponent { // //#region Props ... // private LAST_ACTIVE_INDEX = 0; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // //#region Slider Config ... // private SLIDER_CONFIG: any; // get sliderConfig() { // if (!this.SLIDER_CONFIG) { this.SLIDER_CONFIG = this.getConfiguration(); } // return this.SLIDER_CONFIG; } //#endregion // //#region Slider ... // private SLIDER: IonSlides; // @ViewChild('slider', { static: false }) set slider(s: IonSlides) { this.SLIDER = s; this.handleConfigurationChanged(); } // get slider() { return this.SLIDER; } //#endregion // //#region Slides ... // private SLIDES: QueryList; // @ContentChildren(XSlideComponent) set slides(s: QueryList) { this.SLIDES = s; this.handleConfigurationChanged(); } // get slides() { return this.SLIDES; } //#endregion //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // const isConfigChanged = changeKeys.includes( nameof('options') ); const isAnimationChanged = changeKeys.includes( nameof('animation') ); // if (isConfigChanged || isAnimationChanged) { await this.handleConfigurationChanged(); } } afterContentInit() { super.afterContentInit(); // if (this.slider) { this.update(); } // this.managerService.dispatchResizeEvent(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Ui Action Providers ... hasPager() { return this.getValue(this.options).pipe( map((options) => options.pagination) ); } //#endregion // //#region UI Handlers ... async handleSlideChanged() { // if (isNullOrUndefined(this.slider)) { return; } // const index = await this.slider.getActiveIndex(); if (index === this.LAST_ACTIVE_INDEX) { return; } // this.LAST_ACTIVE_INDEX = index; this.onSlideChange.emit(index); } //#endregion // //#region Provided Actions ... length() { return this.slider.length(); } getActiveIndex() { return this.slider.getActiveIndex(); } getPreviousIndex() { return this.slider.getPreviousIndex(); } getSwiper() { return this.slider.getSwiper(); } isBeginning() { return this.slider.isBeginning(); } isEnd() { return this.slider.isEnd(); } lockSwipeToNext(lock: boolean) { return this.slider.lockSwipeToNext(lock); } lockSwipeToPrev(lock: boolean) { return this.slider.lockSwipeToPrev(lock); } lockSwipes(lock: boolean) { return this.slider.lockSwipes(lock); } slideNext(speed?: number, runCallbacks?: boolean) { return this.slider.slideNext(speed, runCallbacks); } slidePrev(speed?: number, runCallbacks?: boolean) { return this.slider.slidePrev(speed, runCallbacks); } slideTo(index: number, speed?: number, runCallbacks?: boolean) { return this.slider.slideTo(index, speed, runCallbacks); } startAutoplay() { return this.slider.startAutoplay(); } stopAutoplay() { return this.slider.stopAutoplay(); } update() { return this.slider.update(); } updateAutoHeight() { return this.slider.updateAutoHeight(); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XSliderAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async handleConfigurationChanged() { // const anim = await this.getValueAsync(this.animation); const options = await this.getValueAsync(this.options); // this.SLIDER_CONFIG = this.getConfiguration(anim, options); } private getConfiguration( animation?: XSliderAnimationIdentifier, config?: XSliderConfig ) { // let result: XSliderConfig; // if (isNullOrEmptyString(animation)) { animation = XSliderAnimation.Coverflow; } // if (!config) { config = defaultXSliderConfig; } // result = { ...defaultXSliderConfig, ...config, speed: config.speed && config.speed <= 15000 && config.speed >= 500 ? config.speed : defaultXSliderConfig.speed, initialSlide: this.slides && config.initialSlide <= this.slides.length && config.initialSlide >= 0 ? config.initialSlide : defaultXSliderConfig.initialSlide, }; // switch (animation) { case XSliderAnimation.Coverflow: result = { ...result, ...Coverflow, }; break; case XSliderAnimation.Cube: result = { ...result, ...Cube, }; break; case XSliderAnimation.Fade: result = { ...result, ...Fade, }; break; case XSliderAnimation.Flip: result = { ...result, ...Flip, }; break; } // if (result.pagination) { result.pagination = defaultXSliderPaginationConfig; } // return result; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XSliderComponent } from './x-slider.component'; import { XSlideComponent } from './x-slide/x-slide.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XSliderComponent, XSlideComponent], imports: [XCardModule, CommonModule, XBaseComponentModule, XIconModule], exports: [ XIconModule, XCardModule, XSlideComponent, XSliderComponent, XBaseComponentModule, ], }) export class XSliderModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slider.typings.ts import { Input, Inject, NgZone, Output, Renderer2, Component, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XOneOrManyType, XStandardType } from 'x-framework-core'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XSliderAnimation { Coverflow = 'coverflow', Cube = 'cube', Fade = 'fade', Flip = 'flip', } export type XSliderAnimationIdentifier = XSliderAnimation | string; export interface XSlideAnimationProvider { [key: string]: any; on: { [key: string]: any; beforeInit?: () => void; setTranslate?: () => void; setTransition?: (duration?: number) => void; }; } export interface XSliderPaginationConfig { el: string; type: string; clickable: boolean; } export type XSliderPagination = XSliderPaginationConfig | boolean; export const defaultXSliderPaginationConfig: XSliderPaginationConfig = { el: '.swiper-pagination', type: 'bullets', clickable: true, }; export interface XSliderConfig { lazy: boolean; zoom: boolean; autoplay: boolean; initialSlide: number; grabCursor: boolean; autoHeight: boolean; slidesPerView: number; loadPrevNext: boolean; preventClicks: boolean; pagination: XSliderPagination; speed: number; on?: any; } export const defaultXSliderConfig: XSliderConfig = { lazy: true, zoom: true, autoplay: true, initialSlide: 0, grabCursor: true, autoHeight: true, slidesPerView: 1, loadPrevNext: true, preventClicks: false, speed: 400, pagination: true, }; export enum XSliderAction { Refresh = 'refresh', } export type XSliderActionIdentifier = XSliderAction | string; export interface XSliderActionModel extends XBaseActionModel {} // //#region Inside Card Container ... export interface IXSliderContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // options: XStandardType; animation: XStandardType; // onSlideChange: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XSliderContainer extends XComponentCardContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly options: XStandardType = defaultXSliderConfig; readonly animation: XStandardType = XSliderAnimation.Coverflow; // readonly onSlideChange = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XSliderContainerComponent extends XComponentCardContainerComponent implements IXSliderContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() options: XStandardType = this.propertyProvider.options; @Input() animation: XStandardType = this.propertyProvider.animation; // @Output() onSlideChange: EventEmitter = this.propertyProvider.onSlideChange; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XSliderContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXSliderContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), options: this.getValue( container ? container.options : this.options ), animation: this.getValue( container ? container.animation : this.animation ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // onSlideChange: container ? container.onSlideChange : this.onSlideChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide\x-slide.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide\x-slide.component.scss .full-width { width: 100%; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide\x-slide.component.ts import { Component, ViewChild, TemplateRef, ChangeDetectionStrategy, } from '@angular/core'; import { XSlideAction, XSlideActionModel, XSlideContainerComponent, } from './x-slide.typings'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-slide', templateUrl: './x-slide.component.html', styleUrls: ['./x-slide.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XSlideComponent extends XSlideContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // @ViewChild('content', { static: true }) template!: TemplateRef; //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XSlideAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slider\x-slide\x-slide.typings.ts import { Input, NgZone, Inject, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../../classes/i-x-base.container'; import { ViewportRuler } from '@angular/cdk/overlay'; import { forkJoin, Observable, Subject } from 'rxjs'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; export enum XSlideAction { Refresh = 'refresh', } export type XSlideActionIdentifier = XSlideAction | string; export interface XSlideActionModel extends XBaseActionModel {} // //#region Container ... export interface IXSlideContainer extends IXBaseContainer { actionProvider: Subject; } @Injectable({ providedIn: 'root' }) export class XSlideContainer extends XBaseContainer implements Readonly { // //#region Props ... actionProvider: Subject = new Subject(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XSlideContainerComponent extends XBaseContainerComponent implements IXSlideContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XSlideContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXSlideContainer ): Observable { return forkJoin({ // }).pipe( map((data) => { return { // // // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.component.ts import { Component, QueryList, ContentChildren, ChangeDetectionStrategy, } from '@angular/core'; import { XSlotName, XSlotLayout, XSlotterAction, XSlotterActionModel, XSlotterContainerComponent, } from './x-slotter.typings'; import { map } from 'rxjs/operators'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; import { XSlotComponent } from './x-slot/x-slot.component'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-slotter', templateUrl: './x-slotter.component.html', styleUrls: ['./x-slotter.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XSlotterComponent extends XSlotterContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // //#region Slots Props ... // private SLOTS: QueryList; // @ContentChildren(XSlotComponent) set slots(s: QueryList) { // this.SLOTS = s; this.prepareSlots(); } // get slots() { return this.SLOTS; } // startOrTopSlots: XSlotComponent[] = []; cneterSlots: XSlotComponent[] = []; endOrBottomSlots: XSlotComponent[] = []; //#endregion //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Ui Providers ... hasSlots() { return this.slots && this.slots.length > 0; } getHasCenterSlot() { return this.applyTakeUntilWrapper(this.getValue(this.hasCenterSlot)); } getHasStartOrTopSlot() { return this.applyTakeUntilWrapper(this.getValue(this.hasStartOrTopSlot)); } getHasEndOrBottomSlot() { return this.applyTakeUntilWrapper(this.getValue(this.hasEndOrBottomSlot)); } isLayoutHorizontal() { return this.getValue(this.layout).pipe( map((layout) => layout === XSlotLayout.HORIZONTAL) ); } isLayoutVertical() { return this.getValue(this.layout).pipe( map((layout) => layout === XSlotLayout.VERTICAL) ); } getLayout() { return this.getValue(this.layout).pipe( map((layout) => { return layout === XSlotLayout.VERTICAL ? 'column' : 'row'; }) ); } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XSlotterAction.Refresh: await this.prepareSlots(); this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async prepareSlots() { // this.startOrTopSlots = []; this.cneterSlots = []; this.endOrBottomSlots = []; // this.detectChanges(); // if (!this.hasSlots()) { return; } // this.slots.forEach(async (slot) => { // const name = await this.getValueAsync(slot.name); switch (name) { case XSlotName.START: this.startOrTopSlots.push(slot); break; case XSlotName.TOP: this.startOrTopSlots.push(slot); break; case XSlotName.CENTER: this.cneterSlots.push(slot); break; case XSlotName.END: this.endOrBottomSlots.push(slot); break; case XSlotName.BOTTOM: this.endOrBottomSlots.push(slot); break; } // this.detectChanges(); }); // this.detectChanges(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XSlotterComponent } from './x-slotter.component'; import { XSlotComponent } from './x-slot/x-slot.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XSlotterComponent, XSlotComponent], imports: [CommonModule, XBaseComponentModule], exports: [XBaseComponentModule, XSlotterComponent, XSlotComponent] }) export class XSlotterModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slotter.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XOneOrManyType, XStandardType } from 'x-framework-core'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XSlotName { START = 'start', END = 'end', CENTER = 'center', TOP = 'top', BOTTOM = 'bottom', } export type XSlotNameIdentifier = XSlotName | string; export enum XSlotLayout { HORIZONTAL = 'horizontal', VERTICAL = 'vertical', } export type XSlotLayoutIdentifier = XSlotLayout | string; export enum XSlotterAction { Refresh = 'refresh', } export type XSlotterActionIdentifier = XSlotterAction | string; export interface XSlotterActionModel extends XBaseActionModel {} // //#region Container ... export interface IXSlotterContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // layout: XStandardType; // hasStartOrTopSlot: XStandardType; startTopSlotCssClass: XStandardType>; // hasCenterSlot: XStandardType; centerSlotCssClass: XStandardType>; // hasEndOrBottomSlot: XStandardType; endBottomSlotCssClass: XStandardType>; } @Injectable({ providedIn: 'root' }) export class XSlotterContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject; readonly cssClass: XStandardType>; // readonly layout: XStandardType = XSlotLayout.HORIZONTAL; // readonly hasStartOrTopSlot: XStandardType = true; readonly startTopSlotCssClass: XStandardType>; // readonly hasCenterSlot: XStandardType = true; readonly centerSlotCssClass: XStandardType>; // readonly hasEndOrBottomSlot: XStandardType = true; readonly endBottomSlotCssClass: XStandardType>; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XSlotterContainerComponent extends XBaseContainerComponent implements IXSlotterContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() layout: XStandardType = this.propertyProvider.layout; // @Input() hasStartOrTopSlot: XStandardType = this.propertyProvider.hasStartOrTopSlot; @Input() startTopSlotCssClass: XStandardType> = this.propertyProvider.startTopSlotCssClass; // @Input() hasCenterSlot: XStandardType = this.propertyProvider.hasCenterSlot; @Input() centerSlotCssClass: XStandardType> = this.propertyProvider.centerSlotCssClass; // @Input() hasEndOrBottomSlot: XStandardType = this.propertyProvider.hasEndOrBottomSlot; @Input() endBottomSlotCssClass: XStandardType> = this.propertyProvider.endBottomSlotCssClass; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XSlotterContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXSlotterContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), layout: this.getValue(container ? container.layout : this.layout), hasStartOrTopSlot: this.getValue( container ? container.hasStartOrTopSlot : this.hasStartOrTopSlot ), startTopSlotCssClass: this.getValue( container ? container.startTopSlotCssClass : this.startTopSlotCssClass ), hasCenterSlot: this.getValue( container ? container.hasCenterSlot : this.hasCenterSlot ), centerSlotCssClass: this.getValue( container ? container.centerSlotCssClass : this.centerSlotCssClass ), hasEndOrBottomSlot: this.getValue( container ? container.hasEndOrBottomSlot : this.hasEndOrBottomSlot ), endBottomSlotCssClass: this.getValue( container ? container.endBottomSlotCssClass : this.endBottomSlotCssClass ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slot\x-slot.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slot\x-slot.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slot\x-slot.component.ts import { XSlotAction, XSlotActionModel, XSlotContainerComponent, } from './x-slot.typings'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; import { Component, ViewChild, TemplateRef } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-slot', templateUrl: './x-slot.component.html', styleUrls: ['./x-slot.component.scss'], // changeDetection: ChangeDetectionStrategy.OnPush, }) export class XSlotComponent extends XSlotContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // @ViewChild('content', { static: false }) content: TemplateRef; //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } //#endregion // //#region Private ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XSlotAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-slotter\x-slot\x-slot.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XSlotNameIdentifier } from '../x-slotter.typings'; import { XOneOrManyType, XStandardType } from 'x-framework-core'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; export enum XSlotAction { Refresh = 'refresh', } export type XSlotActionIdentifier = XSlotAction | string; export interface XSlotActionModel extends XBaseActionModel {} // //#region Container ... export interface IXSlotContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // name: XStandardType; } @Injectable({ providedIn: 'root' }) export class XSlotContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider = new Subject(); readonly cssClass: XStandardType>; // readonly name: XStandardType; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XSlotContainerComponent extends XBaseContainerComponent implements IXSlotContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() name: XStandardType = this.propertyProvider.name; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XSlotContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXSlotContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), name: this.getValue(container ? container.name : this.name), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.component.scss :host { display: inline-block; position: relative; width: 28px; height: 28px; } ion-spinner { display: inline-block; position: relative; width: 28px; height: 28px; } .x-spinner { direction: ltr !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.component.ts import { XSpinnerAction, XSpinnerActionModel, XSpinnerContainerComponent, } from './x-spinner.typings'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-spinner', templateUrl: './x-spinner.component.html', styleUrls: ['./x-spinner.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XSpinnerComponent extends XSpinnerContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XSpinnerAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XSpinnerComponent } from './x-spinner.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XSpinnerComponent], imports: [CommonModule, XBaseComponentModule], exports: [XBaseComponentModule, XSpinnerComponent] }) export class XSpinnerModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-spinner\x-spinner.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { XSpinner, XStandardType, XOneOrManyType, XColorIdentifier, XSpinnerIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XSpinnerAction { Refresh = 'refresh', } export type XSpinnerActionIdentifier = XSpinnerAction | string; export interface XSpinnerActionModel extends XBaseActionModel {} // //#region Container ... export interface IXSpinnerContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // name: XStandardType; duration: XStandardType; color: XStandardType; paused: XStandardType; } @Injectable({ providedIn: 'root' }) export class XSpinnerContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject; readonly cssClass: XStandardType>; // readonly name: XStandardType = XSpinner.Circular; readonly duration: XStandardType = undefined; readonly color: XStandardType = XColorWithBrightness.SecondaryShade; readonly paused: XStandardType = false; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XSpinnerContainerComponent extends XBaseContainerComponent implements IXSpinnerContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() name: XStandardType = this.propertyProvider.name; @Input() duration: XStandardType = this.propertyProvider.duration; @Input() color: XStandardType = this.propertyProvider.color; @Input() paused: XStandardType = this.propertyProvider.paused; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XSpinnerContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXSpinnerContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), // name: this.getValue(container ? container.name : this.name), duration: this.getValue(container ? container.duration : this.duration), color: this.getValue(container ? container.color : this.color), paused: this.getValue(container ? container.paused : this.paused), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.component.html
{{ applyLocale(index + 1) }} {{ applyLocale(index + 1) }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.component.scss :host { // // TODO: add and handle cssVariable and color applier ... --icon-background-color: var(--x-color-tertiary); --icon-foreground-color: var(--x-color-tertiary-contrast); --title-foreground-color: var(--x-color-secondary); --header-background-color: var(--x-color-light); --header-foreground-color: var(--x-color-light-contrast); } :host(::ng-deep.disableHeader) { .mat-step-header { pointer-events: none; } } :host ::ng-deep .mat-step-header, :host ::ng-deep .mat-stepper-vertical, :host ::ng-deep .mat-stepper-horizontal, :host ::ng-deep .mat-horizontal-stepper-header-container { background-color: transparent !important; } :host ::ng-deep .mat-step-icon { color: var(--icon-foreground-color) !important; background-color: var(--icon-background-color) !important; } :host ::ng-deep .mat-step-label, :host ::ng-deep .mat-step-header { color: var(--header-foreground-color) !important; background-color: var(--header-background-color) !important; } :host ::ng-deep .mat-step-label { color: var(--title-foreground-color) !important; } :host ::ng-deep .mat-vertical-stepper-header { padding: { top: 4px; bottom: 4px; } } // $transition: opacity; $duration: 500ms; $delay: 0; button { // transition: $transition; -webkit-transition: $transition; // transition-delay: $delay; -webkit-transition-delay: $delay; // transition-duration: $duration; -webkit-transition-duration: $duration; } .x-step-actions { button { margin: { left: 4px; right: 4px; } } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.component.ts import { ViewChild, Component, QueryList, ContentChildren, } from '@angular/core'; import { nameof, mergeList, parseXColor, XStandardType, isNullOrEmptyString, XColorWithBrightness, getXColorCssVariableName, } from 'x-framework-core'; import { XStepperType, XStepperAction, XStepperCssVars, XStepperActionModel, XStepperLabelPosition, XStepperContainerComponent, } from './x-stepper.typings'; import { StepperOrientation, StepperSelectionEvent, STEPPER_GLOBAL_OPTIONS, } from '@angular/cdk/stepper'; import { concatMap, map } from 'rxjs/operators'; import { MatStepper } from '@angular/material/stepper'; import { Observable, Subject, Subscription } from 'rxjs'; import { XStepComponent } from './x-step/x-step.component'; import { XButtonType } from '../x-button/x-button.typings'; import { XSlotName } from '../x-slotter/x-slotter.typings'; import { XNPRButtonType } from '../classes/i-x-next-prev-reset.container'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-stepper', templateUrl: './x-stepper.component.html', styleUrls: ['./x-stepper.component.scss'], providers: [ { provide: STEPPER_GLOBAL_OPTIONS, useValue: { showError: true }, }, ], }) export class XStepperComponent extends XStepperContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly SlotNames = Object.assign({}, XSlotName); readonly NPRButtonTypes = Object.assign({}, XNPRButtonType); // @ViewChild('stepper', { static: false }) private stepper: MatStepper; // selected: string; // applyThemeColors = true; // //#region Steps Props ... // private STEPS: QueryList; // @ContentChildren(XStepComponent) set steps(s: QueryList) { // if (!s) { return; } // this.STEPS = s; this.detectChanges(); } // get steps() { return this.STEPS; } //#endregion //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Colors Changed ... // const isIconColorChanged = changeKeys.includes( nameof('iconColor') ); if (isIconColorChanged) { await this.applyIconColor(); } // const isTitleColorChanged = changeKeys.includes( nameof('titleColor') ); if (isTitleColorChanged) { await this.applyTitleColor(); } // const isHeaderColorChanged = changeKeys.includes( nameof('headerColor') ); if (isHeaderColorChanged) { await this.applyeaderColor(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerInstanceHandlers() { super.registerInstanceHandlers(); // this.registerActionProvider(); } //#endregion // //#region Task Handlers ... //#endregion // //#region UI Providers ... // //#region TypeDetectors ... getOrientation() { return this.getValue(this.type).pipe( map((result) => result as StepperOrientation) ); } isTypeHorizontal() { return this.getValue(this.type).pipe( map((type) => type === XStepperType.HORIZONTAL) ); } isTypeVertical() { return this.getValue(this.type).pipe( map((type) => type === XStepperType.VERTICAL) ); } //#endregion // getLabelPositionValue(): Observable<'bottom' | 'end'> { return this.getValue(this.labelPosition).pipe( map((position) => position === XStepperLabelPosition.END ? 'end' : 'bottom' ) ); } // hasSteps() { return this.steps && this.steps.length > 0 ? true : false; } hasActions(step: XStepComponent) { return this.getValue(step.hasNext).pipe( concatMap((hasNext) => this.getValue(step.hasPrev).pipe( map((hasPrev) => { return { hasNext, hasPrev, }; }) ) ), concatMap((hasNextPrev) => this.getValue(step.hasReset).pipe( map((hasReset) => { return { ...hasNextPrev, hasReset, }; }) ) ), map((info) => info.hasNext || info.hasPrev || info.hasReset) ); } // //#region Button Providers ... hasStepAction(step: XStepComponent, type: XNPRButtonType) { // switch (type) { // case this.NPRButtonTypes.Next: return this.getOptionalValue(this.hasNext).pipe( concatMap((cHas) => this.getOptionalValue(step.hasNext).pipe( map((sHas) => cHas || sHas) ) ) ); // case this.NPRButtonTypes.Prev: return this.getOptionalValue(this.hasPrev).pipe( concatMap((cHas) => this.getOptionalValue(step.hasPrev).pipe( map((sHas) => cHas || sHas) ) ) ); // case this.NPRButtonTypes.Reset: return this.getOptionalValue(this.hasReset).pipe( concatMap((cHas) => this.getOptionalValue(step.hasReset).pipe( map((sHas) => cHas || sHas) ) ) ); } } getButtonIcon(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtons(step, type).pipe( concatMap((btns) => btns.s && btns.s.icon ? this.getValue(btns.s.icon) : this.getValue(btns.c.icon) ) ); } getButtonType(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtons(step, type).pipe( concatMap((btns) => btns.s && btns.s.type ? this.getValue(btns.s.type) : this.getValue(btns.c.type) ), map((btnType) => !isNullOrEmptyString(btnType) ? btnType : XButtonType.Raised ) ); } getButtonTitle(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtons(step, type).pipe( concatMap((btns) => btns.s && btns.s.title ? this.getResourceValue(btns.s.title) : this.getResourceValue(btns.c.title) ) ); } getButtonColor(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtons(step, type).pipe( concatMap((btns) => btns.s && btns.s.color ? this.getValue(btns.s.color) : this.getValue(btns.c.color) ), map((btnColor) => !isNullOrEmptyString(btnColor) ? btnColor : XColorWithBrightness.Primary ) ); } getButtonIconColor(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtons(step, type).pipe( concatMap((btns) => btns.s && btns.s.iconColor ? this.getValue(btns.s.iconColor) : this.getValue(btns.c.iconColor) ), map((btnColor) => !isNullOrEmptyString(btnColor) ? btnColor : XColorWithBrightness.Primary ) ); } getButtonDisabled(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtonDisabled(step, type); } getButtonCssClass(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtons(step, type).pipe( concatMap((btns) => this.getArrayValue(btns.s.cssClass).pipe( concatMap((sCss) => this.getArrayValue(btns.c.cssClass).pipe( map((cCss) => mergeList(sCss, cCss)) ) ) ) ) ); } getButtonIconPosition(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtons(step, type).pipe( concatMap((btns) => btns.s && btns.s.iconPosition ? this.getValue(btns.s.iconPosition) : this.getValue(btns.c.iconPosition) ) ); } getButtonForegroundColor(step: XStepComponent, type: XNPRButtonType) { return this.getActionButtons(step, type).pipe( concatMap((btns) => btns.s && btns.s.foregroundColor ? this.getOptionalValue(btns.s.foregroundColor) : this.getOptionalValue(btns.c.foregroundColor) ) ); } //#endregion //#endregion // //#region UI Handlers ... async handleSelectionChanged(event: StepperSelectionEvent) { // if (this.uiDisabled || this.loading || !this.hasSteps()) { return; } const index = event.selectedIndex; const stepId = await this.getValueAsync(this.steps.toArray()[index].id); this.selectedChange.emit(stepId); } async handleNPRStep( stepper: MatStepper, step: XStepComponent, type: XNPRButtonType ) { // switch (type) { // case this.NPRButtonTypes.Next: await this.handleNextStep(stepper, step); break; // case this.NPRButtonTypes.Prev: await this.handlePrevStep(stepper, step); break; // case this.NPRButtonTypes.Reset: await this.handleReset(stepper, step); break; } } async handleNextStep( stepper: MatStepper, step: XStepComponent, force?: boolean ) { // if ( this.uiDisabled || this.loading || !stepper || !step || step.loading || step.uiDisabled || !this.hasSteps() ) { return; } // let nextId: string; const stepId = await this.getValueAsync(step.id); const stepIndex = await this.getStepIndex(stepId); if (stepIndex === -1) { return; } if (stepIndex < this.steps.length - 1) { nextId = await this.getValueAsync(this.steps.toArray()[stepIndex + 1].id); } // const button = await this.getValueAsync(step.nextButton); if (button.clicked) { button.clicked.emit(); } if (isNullOrEmptyString(nextId)) { return; } // if (!force) { // const isUiBusy = this.uiDisabled || this.loading; const canNextStep = await this.getValueAsync(this.canNext); const disableNextStep = await this.getValueAsync(step.disableNext); // if (isUiBusy || disableNextStep || !canNextStep) { return; } // const isConfirmedType = this.nextConfirmer ? this.nextConfirmer() : this.getValue(true); const isConfirmed = await this.getValueAsync(isConfirmedType); // if (!isConfirmed) { return; } // const isStepNextConfitmedType = step.nextConfirmer ? step.nextConfirmer() : this.getValue(true); const isStepNextConfirmed = await this.getValueAsync( isStepNextConfitmedType ); if (!isStepNextConfirmed) { return; } } // this.selected = nextId; this.selectedChange.emit(nextId); stepper.next(); this.onNext.emit(stepId); this.detectChanges(); } async handlePrevStep( stepper: MatStepper, step: XStepComponent, force?: boolean ) { // if ( this.uiDisabled || this.loading || !stepper || !step || step.loading || step.uiDisabled || !this.hasSteps() ) { return; } // let prevId: string; const stepId = await this.getValueAsync(step.id); const stepIndex = await this.getStepIndex(stepId); if (stepIndex === -1) { return; } prevId = await this.getValueAsync(this.steps.toArray()[stepIndex].id); // const button = await this.getValueAsync(step.prevButton); if (button.clicked) { button.clicked.emit(); } if (isNullOrEmptyString(prevId)) { return; } // if (!force) { const isUiBusy = this.uiDisabled || this.loading; const canPrevStep = await this.getValueAsync(this.canPrev); const disablePrevStep = await this.getValueAsync(step.disablePrev); if (isUiBusy || disablePrevStep || !canPrevStep) { return; } // const isConfirmedType = this.prevConfirmer ? this.prevConfirmer() : this.getValue(true); const isConfirmed = await this.getValueAsync(isConfirmedType); // if (!isConfirmed) { return; } // const isStepPrevConfitmedType = step.prevConfirmer ? step.prevConfirmer() : this.getValue(true); const isStepPrevConfirmed = await this.getValueAsync( isStepPrevConfitmedType ); if (!isStepPrevConfirmed) { return; } } // this.selected = prevId; this.selectedChange.emit(prevId); stepper.previous(); this.onPrev.emit(stepId); this.detectChanges(); } async handleReset( stepper: MatStepper, step: XStepComponent, force?: boolean ) { // if ( this.uiDisabled || this.loading || !stepper || !step || step.loading || step.uiDisabled || !this.hasSteps() ) { return; } // const stepId = await this.getValueAsync(step.id); const firstId = await this.getValueAsync(this.steps.toArray()[0].id); // const button = await this.getValueAsync(step.resetButton); if (button.clicked) { button.clicked.emit(); } // if (!force) { const isUiBusy = this.uiDisabled || this.loading; const canResetStep = await this.getValueAsync(this.canReset); const disableResetStep = await this.getValueAsync(step.disableReset); if (isUiBusy || disableResetStep || !canResetStep) { return; } // const isConfirmedType = this.resetConfirmer ? this.resetConfirmer() : this.getValue(true); const isConfirmed = await this.getValueAsync(isConfirmedType); // if (!isConfirmed) { return; } // const isStepResetConfitmedType = step.resetConfirmer ? step.resetConfirmer() : this.getValue(true); const isStepResetConfirmed = await this.getValueAsync( isStepResetConfitmedType ); if (!isStepResetConfirmed) { return; } } // this.selected = firstId; this.selectedChange.emit(firstId); stepper.reset(); this.onReset.emit(stepId); this.detectChanges(); } async handleToStep(stepper: MatStepper, step: XStepComponent) { // if ( this.uiDisabled || this.loading || !step || step.loading || step.uiDisabled || !this.hasSteps() || this.selected === (await this.getValueAsync(step.id)) ) { return; } // const stepId = await this.getValueAsync(step.id); const stepIndex = await this.getStepIndex(stepId); // this.selected = stepId; this.selectedChange.emit(stepId); stepper.selectedIndex = stepIndex; this.detectChanges(); } //#endregion // //#region Actions ... async next(force?: boolean) { // if (!this.selected || !this.stepper || !this.hasSteps()) { return; } // const stepId = await this.getValueAsync(this.selected); if (!stepId) { return; } // const step = await this.getStep(stepId); if (!step) { return; } // await this.handleNextStep(this.stepper, step, force); } async prev(force?: boolean) { // if (!this.selected || !this.stepper || !this.hasSteps()) { return; } // const stepId = await this.getValueAsync(this.selected); if (!stepId) { return; } // const step = await this.getStep(stepId); if (!step) { return; } // await this.handlePrevStep(this.stepper, step, force); } async reset(force?: boolean) { // if (!this.selected || !this.stepper || !this.hasSteps()) { return; } // const stepId = await this.getValueAsync(this.selected); if (!stepId) { return; } // const step = await this.getStep(stepId); if (!step) { return; } // await this.handleReset(this.stepper, step, force); } async to(id: XStandardType, force?: boolean) { // if (!id || !this.hasSteps() || !this.stepper) { return; } // const stepId = await this.getValueAsync(id); if (!stepId) { return; } // const stepIndex = await this.getStepIndex(stepId); if (stepIndex === -1) { return; } // const step = await this.getStep(stepId); if (!step) { return; } // const selectedIndex = await this.getStepIndex(this.selected); if (selectedIndex === -1 || selectedIndex === stepIndex) { return; } // if (stepIndex > selectedIndex) { // // next confirm ... // if (!force) { // const isUiBusy = this.uiDisabled || this.loading; const canNextStep = await this.getValueAsync(this.canNext); const disableNextStep = await this.getValueAsync(step.disableNext); // if (isUiBusy || disableNextStep || !canNextStep) { return; } // const isStepNextConfitmedType = step.nextConfirmer ? step.nextConfirmer() : this.getValue(true); const isStepNextConfirmed = await this.getValueAsync( isStepNextConfitmedType ); if (!isStepNextConfirmed) { return; } } // this.selected = stepId; this.selectedChange.emit(stepId); } else if (stepIndex < selectedIndex) { // // prev Confirm ... // if (!force) { const isUiBusy = this.uiDisabled || this.loading; const canPrevStep = await this.getValueAsync(this.canPrev); const disablePrevStep = await this.getValueAsync(step.disablePrev); if (isUiBusy || disablePrevStep || !canPrevStep) { return; } // const isStepPrevConfitmedType = step.prevConfirmer ? step.prevConfirmer() : this.getValue(true); const isStepPrevConfirmed = await this.getValueAsync( isStepPrevConfitmedType ); if (!isStepPrevConfirmed) { return; } } // this.selected = stepId; this.selectedChange.emit(stepId); } } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XStepperAction.NEXT: await this.next(model.force); break; // case XStepperAction.PREV: await this.prev(model.force); break; // case XStepperAction.RESET: await this.reset(model.force); break; // case XStepperAction.TO: if (model.payload) { await this.to(model.payload, model.force); } break; // case XStepperAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private getActionButtons(step: XStepComponent, type: XNPRButtonType) { // switch (type) { // case this.NPRButtonTypes.Next: return this.getValue(this.nextButton).pipe( concatMap((cButton) => this.getValue(step.nextButton).pipe( map((sButton) => ({ c: cButton, s: sButton })) ) ) ); // case this.NPRButtonTypes.Prev: return this.getValue(this.prevButton).pipe( concatMap((cButton) => this.getValue(step.prevButton).pipe( map((sButton) => ({ c: cButton, s: sButton })) ) ) ); // case this.NPRButtonTypes.Reset: return this.getValue(this.resetButton).pipe( concatMap((cButton) => this.getValue(step.resetButton).pipe( map((sButton) => ({ c: cButton, s: sButton })) ) ) ); } } private getActionButtonDisabled(step: XStepComponent, type: XNPRButtonType) { // switch (type) { // case this.NPRButtonTypes.Next: return this.getOptionalValue(this.disableNext).pipe( concatMap((cDisable) => this.getOptionalValue(step.disableNext).pipe( map( (sDisable) => this.uiDisabled || cDisable || step.uiDisabled || sDisable ) ) ) ); // case this.NPRButtonTypes.Prev: return this.getOptionalValue(this.disablePrev).pipe( concatMap((cDisable) => this.getOptionalValue(step.disablePrev).pipe( map( (sDisable) => this.uiDisabled || cDisable || step.uiDisabled || sDisable ) ) ) ); // case this.NPRButtonTypes.Reset: return this.getOptionalValue(this.disableReset).pipe( concatMap((cDisable) => this.getOptionalValue(step.disableReset).pipe( map( (sDisable) => this.uiDisabled || cDisable || step.uiDisabled || sDisable ) ) ) ); } } private async getStep(id: string) { // if (!id || !this.hasSteps()) { return null; } // return this.steps.toArray().find(async (p) => { const pId = await this.getValueAsync(p.id); return pId === id; }); } private async getStepIndex(id: string) { // if (!id || !this.hasSteps()) { return -1; } // let result = -1; const steps = this.steps.toArray(); if (!this.hasChild(steps)) { return result; } // for (let i = 0; i < steps.length; i++) { // const step = steps[i]; const stepId = await this.getValueAsync(step.id); if (stepId === id) { result = i; } } // return result; } // //#region Color Appliers ... private async applyIconColor() { // const color = await this.getValueAsync(this.iconColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XStepperCssVars.IconForegroundColor, `var(${fgColor})`); this.setCssVar(XStepperCssVars.IconBackgroundColor, `var(${bgColor})`); // this.detectChanges(); } private async applyTitleColor() { // const color = await this.getValueAsync(this.titleColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XStepperCssVars.TitleForegroundColor, `var(${bgColor})`); // this.detectChanges(); } private async applyeaderColor() { // const color = await this.getValueAsync(this.headerColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XStepperCssVars.HeaderForegroundColor, `var(${fgColor})`); this.setCssVar(XStepperCssVars.HeaderBackgroundColor, `var(${bgColor})`); // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule } from '@angular/forms'; import { XIconModule } from '../x-icon/x-icon.module'; import { XCardModule } from '../x-card/x-card.module'; import { XFormModule } from './../x-form/x-form.module'; import { XStepperComponent } from './x-stepper.component'; import { XStepComponent } from './x-step/x-step.component'; import { XButtonModule } from '../x-button/x-button.module'; import { XSlotterModule } from '../x-slotter/x-slotter.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XStepperComponent, XStepComponent], imports: [ XIconModule, XCardModule, XFormModule, CommonModule, XButtonModule, XSlotterModule, ReactiveFormsModule, XBaseComponentModule, ], exports: [ XIconModule, XCardModule, XFormModule, CommonModule, XButtonModule, XStepComponent, XSlotterModule, XStepperComponent, ReactiveFormsModule, XBaseComponentModule, ], }) export class XStepperModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-stepper.typings.ts import { Input, NgZone, Inject, Output, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { concatMap, map } from 'rxjs/operators'; import { XNextPrevResetAndHostContainer, IXNextPrevResetAndHostContainer, XNextPrevResetAndHostContainerComponent, } from '../classes/i-x-next-prev-reset.container'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XStepperType { HORIZONTAL = 'horizontal', VERTICAL = 'vertical', } export type XStepperTypeIdentifier = XStepperType | string; export enum XStepperLabelPosition { END = 'end', BOTTOM = 'bottom', } export type XStepperLabelPositionIdentifier = XStepperLabelPosition | string; export enum XStepperAction { NEXT = 'next', PREV = 'prev', RESET = 'reset', TO = 'to', // Refresh = 'refresh', } export type XStepperActionIdentifier = XStepperAction | string; export interface XStepperActionModel extends XBaseActionModel { force?: boolean; } export enum XStepperCssVars { // IconForegroundColor = 'icon-foreground-color', IconBackgroundColor = 'icon-background-color', // TitleForegroundColor = 'title-foreground-color', // HeaderForegroundColor = 'header-foreground-color', HeaderBackgroundColor = 'header-background-color', } export type XStepperCssVarsIdentifier = XStepperCssVars | string; export function defaultActionConfirmer() { return true; } // //#region Inside Card Container ... export interface IXStepperContainer extends IXNextPrevResetAndHostContainer { // actionProvider: Subject; cssClass: XStandardType>; // type: XStandardType; showLabel: XStandardType; labelPosition: XStandardType; // selectableHeaders: XStandardType; // selectedIndex: XStandardType; selectedChange: EventEmitter; // iconColor: XStandardType; titleColor: XStandardType; headerColor: XStandardType; } @Injectable({ providedIn: 'root', }) export class XStepperContainer extends XNextPrevResetAndHostContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly type: XStandardType = XStepperType.HORIZONTAL; readonly showLabel: XStandardType = true; readonly labelPosition: XStandardType = XStepperLabelPosition.END; // readonly selectableHeaders: XStandardType = false; // readonly selectedIndex: XStandardType; readonly selectedChange: EventEmitter = new EventEmitter(); // readonly iconColor: XStandardType = XColorWithBrightness.Tertiary; readonly titleColor: XStandardType = XColorWithBrightness.Secondary; readonly headerColor: XStandardType = XColorWithBrightness.Light; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XStepperContainerComponent extends XNextPrevResetAndHostContainerComponent implements IXStepperContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() type: XStandardType = this.propertyProvider.type; @Input() showLabel: XStandardType = this.propertyProvider.showLabel; @Input() labelPosition: XStandardType = this.propertyProvider.labelPosition; // @Input() selectableHeaders: XStandardType = this.propertyProvider.selectableHeaders; // @Input() selectedIndex: XStandardType = this.propertyProvider.selectedIndex; @Output() selectedChange: EventEmitter = new EventEmitter(); // @Input() iconColor: XStandardType = this.propertyProvider.iconColor; @Input() titleColor: XStandardType = this.propertyProvider.titleColor; @Input() headerColor: XStandardType = this.propertyProvider.headerColor; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XStepperContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXStepperContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), type: this.getValue(container ? container.type : this.type), showLabel: this.getValue( container ? container.showLabel : this.showLabel ), labelPosition: this.getValue( container ? container.labelPosition : this.labelPosition ), selectableHeaders: this.getValue( container ? container.selectableHeaders : this.selectableHeaders ), selectedIndex: this.getValue( container ? container.selectedIndex : this.selectedIndex ), iconColor: this.getValue( container ? container.iconColor : this.iconColor ), titleColor: this.getValue( container ? container.titleColor : this.titleColor ), headerColor: this.getValue( container ? container.headerColor : this.headerColor ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // selectedChange: this.selectedChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-step\x-step.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-step\x-step.component.scss ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-step\x-step.component.ts import { XStepAction, XStepActionModel, XStepContainerComponent, } from './x-step.typings'; import { Subject, Subscription } from 'rxjs'; import { XModalButtonRole, nameof } from 'x-framework-core'; import { Component, ViewChild, TemplateRef } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-step', templateUrl: './x-step.component.html', styleUrls: ['./x-step.component.scss'], }) export class XStepComponent extends XStepContainerComponent { // //#region Props ... private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // //#region ViewChilds ... // @ViewChild('label', { static: false }) label!: TemplateRef; // @ViewChild('content', { static: false }) content!: TemplateRef; // @ViewChild('actions', { static: false }) actions!: TemplateRef; //#endregion //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerInstanceHandlers() { super.registerInstanceHandlers(); // this.registerActionProvider(); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XStepAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private defaultStepperResetConfirmer() { // return new Promise((resolver) => { // this.managerService.dialogService.presentAreYouSureYesNoDialog( () => resolver(true), XModalButtonRole.Destructive, () => resolver(false) ); }); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-stepper\x-step\x-step.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { concatMap, map } from 'rxjs/operators'; import { XNextPrevResetContainer, IXNextPrevResetContainer, XNextPrevResetContainerComponent, } from '../../classes/i-x-next-prev-reset.container'; import { ViewportRuler } from '@angular/cdk/overlay'; import { forkJoin, Subject, Observable } from 'rxjs'; import { XManagerService } from 'x-framework-services'; import { generateUuid, XStandardType } from 'x-framework-core'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; export enum XStepAction { Refresh = 'refresh', } export type XStepActionIdentifier = XStepAction | string; export interface XStepActionModel extends XBaseActionModel { force?: boolean; } // //#region Container ... export interface IXStepContainer extends IXNextPrevResetContainer { actionProvider: Subject; id: XStandardType; hasCustomActions: XStandardType; } @Injectable({ providedIn: 'root', }) export class XStepContainer extends XNextPrevResetContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); readonly id: XStandardType; // = generateUuid('XStepComponent'); readonly hasCustomActions: XStandardType = false; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XStepContainerComponent extends XNextPrevResetContainerComponent implements IXStepContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() id: XStandardType = generateUuid('XStepComponent'); @Input() hasCustomActions: XStandardType = this.propertyProvider.hasCustomActions; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XStepContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXStepContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // id: this.getValue(container ? container.id : this.id), hasCustomActions: this.getValue( container ? container.hasCustomActions : this.hasCustomActions ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.component.html
{{ getResourceValue(item.title) | async }} {{ getItemBadgeNumber(item) | async }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.component.scss :host { // --highlight-foreground-color: var(--x-color-success-contrast); --highlight-background-color: var(--x-color-success); // --selected-foreground-color: var(--x-color-secondary-contrast); --selected-background-color: var(--x-color-secondary); // --badge-foreground-color: var(--x-color-dark-contrast); --badge-background-color: var(--x-color-dark); // --icon-color: var(--x-color-dark); // --foreground-color: var(--x-color-light-contrast); --background-color: var(--x-color-light); } x-icon { font-size: 12px; color: var(--icon-color); } ion-tab-button { --color: var(--foreground-color); --color-focused: var(--highlight-foreground-color); --color-selected: var(--selected-foreground-color); } ion-tab-button::part(native) { color: var(--foreground-color); &:hover { color: var(--highlight-foreground-color); } } ion-badge { color: var(--badge-foreground-color); background-color: var(--badge-background-color); } .tab-selected { background-color: var(--selected-background-color) !important; x-icon { color: var(--selected-foreground-color) !important; } } .x-tab-label { font-size: 9px !important; &:hover { color: var(--highlight-foreground-color); } } .x-nav-button:hover { color: var(--highlight-foreground-color); background-color: var(--highlight-background-color); x-icon { color: var(--highlight-foreground-color) !important; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.component.ts import { nameof, parseXColor, isNullOrEmptyString, getXColorCssVariableName, } from 'x-framework-core'; import { XTabNavigatorItem, XTabNavigatorAction, XTabNavigatorCssVars, XTabNavigatorItemLayout, XTabNavigatorActionModel, XTabNavigatorContainerComponent, } from './x-tab-navigator.typings'; import { map, concatMap } from 'rxjs/operators'; import { of, Observable, Subject, Subscription } from 'rxjs'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-tab-navigator', templateUrl: './x-tab-navigator.component.html', styleUrls: ['./x-tab-navigator.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XTabNavigatorComponent extends XTabNavigatorContainerComponent { // //#region Props ... // private PREPARED_ITEMS: XTabNavigatorItem[]; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; get preparedItems() { return this.PREPARED_ITEMS; } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.prepareItems(); await this.applyDefaultColors(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Items Changed ... const isItemsChanged = changeKeys.includes( nameof('items') ); if (isItemsChanged) { await this.prepareItems(); } //#endregion // //#region Colors Changed ... // // Color ... const isColorChanged = changeKeys.includes( nameof('color') ); if (isColorChanged) { await this.applyColor(); } // // Icon Color ... const isIconColorChanged = changeKeys.includes( nameof('iconColor') ); if (isIconColorChanged) { await this.applyIconColor(); } // // HighLight Color ... const isHighLightColorChanged = changeKeys.includes( nameof('highlightColor') ); if (isHighLightColorChanged) { await this.applyHighLightedColor(); } // // Selected Color ... const isSelectedColorChanged = changeKeys.includes( nameof('selectedColor') ); if (isSelectedColorChanged) { await this.applySelectedColor(); } // // Badge Color ... const isBadgeColorChanged = changeKeys.includes( nameof('badgeColor') ); if (isBadgeColorChanged) { await this.applyBadgeColor(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Ui Providers ... isDisabled(item: XTabNavigatorItem) { return (this.getOptionalValue(item.disabled) as Observable).pipe( map((disabled) => disabled || this.uiDisabled) ); } getItemRoute(item: XTabNavigatorItem) { return this.getArrayValue(item.href).pipe( map((href) => { // if (!this.hasChild(href)) { return undefined; } // if (href.length === 1) { return href[0]; } // const result = href.join('/').replace('//', '/'); return result; }) ); } getItemTooltip(item: XTabNavigatorItem) { return this.getResourceValue(item.description).pipe( concatMap((val) => { if (isNullOrEmptyString(val.toString())) { return this.getResourceValue(item.title); } else { return of(val); } }) ); } hideTabTitle(item: XTabNavigatorItem) { return this.getValue(this.hideTabLabelsOnSmallScreens).pipe( concatMap((hideOnMobile) => { return hideOnMobile ? this.isMobileUi$ : this.getValue(item.layout).pipe( map((layout) => layout === XTabNavigatorItemLayout.LABEL_HIDE) ); }) ); } hasBadgeNumber(item: XTabNavigatorItem) { return this.getValue(item.badge).pipe(map((badge) => badge > 0)); } getItemBadgeNumber(item: XTabNavigatorItem) { return (this.getOptionalValue(item.badge) as Observable).pipe( map((badge) => { if (!badge) { return this.applyLocale(0); } else { return this.applyLocale(badge); } }) ); } //#endregion // //#region Private ... private async prepareItems() { // const items = await this.getValueAsync(this.items); this.PREPARED_ITEMS = items; // this.detectChanges(); } // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XTabNavigatorAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // //#region Color Appliers ... private async applyDefaultColors() { // await this.applyColor(); await this.applyIconColor(); await this.applyBadgeColor(); await this.applySelectedColor(); await this.applyHighLightedColor(); } // // Color ... private async applyColor() { // const color = await this.getValueAsync(this.color); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XTabNavigatorCssVars.ForegroundColor, `var(${fgColor})`); this.setCssVar(XTabNavigatorCssVars.BackgroundColor, `var(${bgColor})`); // this.detectChanges(); } // // Icon Color ... private async applyIconColor() { // const color = await this.getValueAsync(this.iconColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XTabNavigatorCssVars.IconColor, `var(${bgColor})`); // this.detectChanges(); } // // HighLight Color ... private async applyHighLightedColor() { // const color = await this.getValueAsync(this.highlightColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XTabNavigatorCssVars.HighlightedForegroundColor, `var(${fgColor})` ); this.setCssVar( XTabNavigatorCssVars.HighlightedBackgroundColor, `var(${bgColor})` ); // this.detectChanges(); } // // Selected Color ... private async applySelectedColor() { // const color = await this.getValueAsync(this.selectedColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XTabNavigatorCssVars.SelectedForegroundColor, `var(${fgColor})` ); this.setCssVar( XTabNavigatorCssVars.SelectedBackgroundColor, `var(${bgColor})` ); // this.detectChanges(); } // // Badge Color ... private async applyBadgeColor() { // const color = await this.getValueAsync(this.badgeColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar( XTabNavigatorCssVars.BadgeForegroundColor, `var(${fgColor})` ); this.setCssVar( XTabNavigatorCssVars.BadgeBackgroundColor, `var(${bgColor})` ); // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XTabNavigatorComponent } from './x-tab-navigator.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XTabNavigatorComponent], imports: [CommonModule, XBaseComponentModule, XIconModule], exports: [XIconModule, XBaseComponentModule, XTabNavigatorComponent] }) export class XTabNavigatorModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.tools.ts import { XTabNavigatorItem, XTabNavigatorItemLayout, } from './x-tab-navigator.typings'; import { XPage } from 'x-framework-core'; export function toTabNavigatiorItem(page: XPage) { // if (!page) { return null; } // const result: XTabNavigatorItem = { id: page.id ? page.id : page.name, title: page.title, description: page.description, href: page.baseRoute, disabled: false, icon: page.icon, badge: 0, layout: XTabNavigatorItemLayout.ICON_TOP, }; // return result; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tab-navigator\x-tab-navigator.typings.ts import { Input, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XColorWithBrightness, XRouterTargetIdentifier, } from 'x-framework-core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XNavigatorListItem } from '../x-page/x-navigator/x-navigator.typings'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export interface XTabNavigatorItem extends Pick< XNavigatorListItem, 'id' | 'title' | 'description' | 'href' | 'disabled' > { // icon: XStandardType; badge?: XStandardType; // download?: XStandardType; routerTarget?: XStandardType; // layout: XStandardType; } export enum XTabNavigatorItemLayout { ICON_TOP = 'icon-top', ICON_END = 'icon-end', ICON_HIDE = 'icon-hide', ICON_START = 'icon-start', LABEL_HIDE = 'label-hide', ICON_BOTTOM = 'icon-bottom', } export type XTabNavigatorItemLayoutIdentifier = | XTabNavigatorItemLayout | string; export enum XTabNavigatorNavigatorSlot { TOP = 'top', BOTTOM = 'bottom', } export type XTabNavigatorNavigatorSlotIdentifier = | XTabNavigatorNavigatorSlot | string; export enum XTabNavigatorAction { Refresh = 'refresh', } export type XTabNavigatorActionIdentifier = XTabNavigatorAction | string; export interface XTabNavigatorActionModel extends XBaseActionModel {} export enum XTabNavigatorCssVars { // HighlightedForegroundColor = 'highlight-foreground-color', HighlightedBackgroundColor = 'highlight-background-color', // SelectedForegroundColor = 'selected-foreground-color', SelectedBackgroundColor = 'selected-background-color', // BadgeForegroundColor = 'badge-foreground-color', BadgeBackgroundColor = 'badge-background-color', // IconColor = 'icon-color', // ForegroundColor = 'foreground-color', BackgroundColor = 'background-color', } // //#region Container ... export interface IXTabNavigatorContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // navigatorSlot: XStandardType; hideTabLabelsOnSmallScreens: XStandardType; items: XStandardType; // color: XStandardType; foregroundColor: XStandardType; iconColor: XStandardType; badgeColor: XStandardType; highlightColor: XStandardType; selectedColor: XStandardType; } @Injectable({ providedIn: 'root' }) export class XTabNavigatorContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly navigatorSlot: XStandardType = XTabNavigatorNavigatorSlot.BOTTOM; readonly hideTabLabelsOnSmallScreens: XStandardType = true; readonly items: XStandardType = []; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; readonly iconColor: XStandardType = XColorWithBrightness.Dark; readonly badgeColor: XStandardType = XColorWithBrightness.WarningTint; readonly highlightColor: XStandardType = XColorWithBrightness.WarningShade; readonly selectedColor: XStandardType = XColorWithBrightness.TertiaryShade; //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XTabNavigatorContainerComponent extends XBaseContainerComponent implements IXTabNavigatorContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() navigatorSlot: XStandardType = this.propertyProvider.navigatorSlot; @Input() hideTabLabelsOnSmallScreens: XStandardType = this.propertyProvider.hideTabLabelsOnSmallScreens; @Input() items: XStandardType = this.propertyProvider.items; @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; @Input() iconColor: XStandardType = this.propertyProvider.iconColor; @Input() badgeColor: XStandardType = this.propertyProvider.badgeColor; @Input() highlightColor: XStandardType = this.propertyProvider.highlightColor; @Input() selectedColor: XStandardType = this.propertyProvider.selectedColor; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XTabNavigatorContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXTabNavigatorContainer ): Observable { return forkJoin({ // cssClass: this.getValue(container ? container.cssClass : this.cssClass), navigatorSlot: this.getValue( container ? container.navigatorSlot : this.navigatorSlot ), hideTabLabelsOnSmallScreens: this.getValue( container ? container.hideTabLabelsOnSmallScreens : this.hideTabLabelsOnSmallScreens ), items: this.getValue(container ? container.items : this.items), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), iconColor: this.getValue( container ? container.iconColor : this.iconColor ), badgeColor: this.getValue( container ? container.badgeColor : this.badgeColor ), highlightColor: this.getValue( container ? container.highlightColor : this.highlightColor ), selectedColor: this.getValue( container ? container.selectedColor : this.selectedColor ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.component.html
{{ title }}
{{ value }}
{{ preparedPaginatorOptions.pageInfoProvider( managerService.currentLocale, currentPage, pageSize, totalPages, totalItems ) }}
{{ applyLocale(pageSize) }}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.component.scss ::ng-deep :root, :host { // --divider-color: var(--x-color-dark); // --highlight-color: var(--x-color-warning-shade-contrast); --highlight-background-color: var(--x-color-warning-shade); // --odd-rows-background-color: inherit; --even-rows-background-color: inherit; // --check-box-border-color: var(--x-color-dark); --check-box-check-mark-color: var(--x-color-dark); } x-card { width: inherit; height: inherit; } .x-table { width: inherit; height: inherit; } mat-row, td.mat-cell, mat-header-row, mat-footer-row, th.mat-header-cell, td.mat-footer-cell { border-bottom-color: var(--divider-color) !important; } .mat-paginator, .mat-paginator-page-size .mat-select-trigger { color: unset !important; } .mat-paginator { background-color: unset !important; } .x-table-paginator-wrapper { width: 100%; } .x-page-select-icon { margin: { left: 4px; right: 4px; } } .x-table-cell, .x-table-header { flex: 1 !important; } .x-header-title { width: fit-content; } .x-table-selection { flex: none !important; } .x-table-cell { color: inherit !important; background-color: inherit !important; } .x-table-row { &:hover { color: var(--highlight-color) !important; background-color: var(--highlight-background-color) !important; } &:not(:hover):nth-child(odd) { background-color: var(--odd-rows-background-color) !important; } &:not(:hover):nth-child(even) { background-color: var(--even-rows-background-color) !important; } } .x-check-box { --border-color: var(--check-box-border-color, inherit) !important; --checkmark-color: var(--check-box-check-mark-color, inherit) !important; --background-checked: auto !important; --border-color-checked: auto !important; } .x-selection-master { visibility: hidden !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.component.ts import { nameof, XColor, toArray, XLocale, isNumber, hasChild, isFunction, applyLocale, XResourceIDs, XModalButtonRole, XPickerColumnOption, } from 'x-framework-core'; import { XTableAction, XTableActionModel, XTableColumnOption, XTableItemPosition, XTableActionButton, XTableActionOptions, XTablePaginatorOptions, XTableContainerComponent, X_TABLE_SELECTION_HEADER_IDENTIFIER, } from './x-table.typings'; import { Subject, Subscription } from 'rxjs'; import { map, concatMap } from 'rxjs/operators'; import { MatSort } from '@angular/material/sort'; import { XIconNames } from '../x-icon/x-icon.typings'; import { SelectionModel } from '@angular/cdk/collections'; import { MatPaginator } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-table', templateUrl: './x-table.component.html', styleUrls: ['./x-table.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XTableComponent extends XTableContainerComponent { // //#region Props ... private MODAL: any; private SORT: MatSort; private DATA: any[] = []; private PAGE_SIZE: number; private TOTAL_PAGES: number; private TOTAL_ITEMS: number; private CURRENT_PAGE: number; private PAGINATOR: MatPaginator; private IS_ROWS_SELECTABLE: boolean; private DISPLAYED_COLUMNS: string[] = []; private ACTION_OPTIONS: XTableActionOptions; private SELECTION_SUBSCRIPTION: Subscription; private SELECTION = new SelectionModel(); private COLUMNS_DATA: XTableColumnOption[]; private PAGINATOR_OPTIONS: XTablePaginatorOptions; private PAGINATOR_INIT_SUBSCRIPTION: Subscription; private PAGINATOR_PAGE_SUBSCRIPTION: Subscription; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private DATA_SOURCE = new MatTableDataSource(this.DATA); // pageNumberInput = false; selectionRowTitle = X_TABLE_SELECTION_HEADER_IDENTIFIER; // //#region Getters ... get data() { return this.DATA; } get isRowsSelectable() { return this.IS_ROWS_SELECTABLE; } get columnsData() { return this.COLUMNS_DATA; } get dataSource() { return this.DATA_SOURCE; } get displayedColumns() { return this.DISPLAYED_COLUMNS; } get selection() { return this.SELECTION; } get preparedPaginatorOptions() { return this.PAGINATOR_OPTIONS; } get pageSize() { return this.PAGE_SIZE; } get currentPage() { return this.CURRENT_PAGE; } get totalPages() { return this.TOTAL_PAGES; } get totalItems() { return this.TOTAL_ITEMS; } get selectedItems() { return this.isRowsSelectable && this.selection ? this.selection.selected : []; } get preparedActionOptions() { return this.ACTION_OPTIONS; } //#endregion // //#region Sort Props ... @ViewChild(MatSort, { static: false }) set sort(v: MatSort) { if (!v) { return; } // this.SORT = v; this.DATA_SOURCE.sort = v; } get sort() { return this.SORT; } //#endregion // //#region Paginator Props ... @ViewChild(MatPaginator, { static: false }) set paginator(v: MatPaginator) { if (!v) { return; } // this.PAGINATOR = v; this.DATA_SOURCE.paginator = v; this.registerPaginatorHandlers(); } get paginator() { return this.PAGINATOR; } //#endregion //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.preparePaginatorOptions(); } async afterViewInit() { super.afterViewInit(); // await this.prepareUIData(); await this.prepareSelection(); await this.prepareActionOptions(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // let isLoadingChanged = changeKeys.includes( nameof('loading') ); let isUiDisabledChanged = changeKeys.includes( nameof('uiDisabled') ); if (isLoadingChanged || isUiDisabledChanged) { await this.prepareActionOptions(); } // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // // Handle Prepare Data Source ... if ( changeKeys.includes(nameof('properties')) || changeKeys.includes(nameof('selectableRows')) ) { await this.prepareDataSource(); } // // Handle Prepare Selection ... if ( changeKeys.includes(nameof('allowMultiSelect')) || changeKeys.includes(nameof('initialSelectedValues')) ) { await this.prepareSelection(); } // // Handle Paginator Options ... if (changeKeys.includes(nameof('paginatorOptions'))) { await this.preparePaginatorOptions(); } // // Handle Action Options ... if (changeKeys.includes(nameof('actionOptions'))) { await this.prepareActionOptions(); } // // Handle UI Data ... if (changeKeys.includes(nameof('selectableRows'))) { await this.prepareUIData(); } } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Providers ... isSelectionRow(col: XTableColumnOption) { return this.getValue(col.name).pipe( map((colName) => colName === X_TABLE_SELECTION_HEADER_IDENTIFIER) ); } isSearchbarTopPositioned() { return this.getValue(this.searchBarPosition).pipe( map((pos) => pos === XTableItemPosition.TOP) ); } isPaginatorTopPositioned() { return this.getValue(this.paginatorPosition).pipe( map((pos) => pos === XTableItemPosition.TOP) ); } isActionBarTopPositioned() { return this.getValue(this.actionBarPosition).pipe( map((pos) => pos === XTableItemPosition.TOP) ); } getHeaderClass(col: XTableColumnOption) { return this.getValue(col.name).pipe( concatMap((colName) => this.getValue(this.headerCellCssClass).pipe( map((cssClass) => { return { colName, cssClass }; }) ) ), map((info) => { // let result: string[] = []; // const className = `x-table-header-${info.colName.toString()}`; const cssClasses = toArray(info.cssClass); // result = [className].concat(cssClasses); // return result; }) ); } getCellClass(col: XTableColumnOption) { return this.getValue(col.name).pipe( concatMap((colName) => this.getValue(this.cellCssClass).pipe( map((cssClass) => { return { colName, cssClass }; }) ) ), map((info) => { // let result: string[] = []; // const className = `x-table-cell-${info.colName.toString()}`; const cssClasses = toArray(info.cssClass); // result = [className].concat(cssClasses); // return result; }) ); } getColumnName(col: XTableColumnOption) { return this.getValue(col.name).pipe(map(name => name.toString())); } //#endregion // //#region UI Handlers ... async handleRowClicked(row: any) { // const isClickable = await this.getValueAsync(this.clickableRows); const isSelectable = await this.getValueAsync(this.selectableRows); // if (!isClickable && !this.selectableRows) { return; } // if (isSelectable && this.selection) { // if (this.uiDisabled || this.loading) { return; } // this.selection.toggle(row); } // if (isClickable) { // if (this.uiDisabled || this.loading) { return; } // this.rowClicked.emit(row); } } async handleRowSelected(event: CustomEvent | any, row: any) { // if (this.uiDisabled || this.loading) { return; } // const isSelectable = await this.getValueAsync(this.selectableRows); if (!isSelectable) { return; } // const selected = event.detail.checked as boolean; // if (!selected) { return; } // this.rowSelected.emit(row); } async handleFilterData(event: CustomEvent | any) { // if (this.uiDisabled || this.loading) { return; } // const query = event && event.detail && event.detail.value ? event.detail.value.toString().trim().toLowerCase() : ''; // await this.filterData(query); } async handlePageChange(event: CustomEvent | any) { // const selectedPage = (event.detail.value as number) || undefined; if (!selectedPage) { return; } // await this.toPage(selectedPage); } async handlePageSizeChange() { // if (!this.preparedPaginatorOptions || !this.pageSize) { return; } // const pageSizes = await this.getValueAsync( this.preparedPaginatorOptions.pageSizes ); if (!hasChild(pageSizes)) { return; } const options: XPickerColumnOption[] = pageSizes.map((ps) => { // const opt: XPickerColumnOption = { text: this.applyLocale(ps.toString()), value: ps, disabled: ps === this.pageSize, }; // return opt; }); // if (this.MODAL) { await this.managerService.dialogService.pickerController.dismiss(); this.MODAL = null; } // this.MODAL = await this.managerService.dialogService.presentPicker({ buttons: [ { text: this.resourceProvider('accept'), role: XModalButtonRole.Selected, handler: (value) => { if (!value) { return; } // const pageSize = value.pageSize.value; this.changePageSize(pageSize); this.detectChanges(); }, }, { text: this.resourceProvider('cancel'), role: XModalButtonRole.Cancel, }, ], columns: [{ name: 'pageSize', options }], }); // await this.MODAL.onWillDismiss(); this.MODAL = null; } async handleActionBarItemClick( action: XTableActionButton, selectedItems: any[] ) { // if (action && action.handler && isFunction(action.handler)) { await this.getValueAsync(action.handler(selectedItems)); } } //#endregion // //#region Actions ... isAllSelected() { const numSelected = this.selection.selected.length; const numRows = this.dataSource.data.length; return numSelected === numRows; } isAllFilteredSelected() { // if ( !this.dataSource || !hasChild(this.dataSource.filteredData) || this.selection.isEmpty() || !hasChild(this.selection.selected) ) { return false; } // const filteredData = this.dataSource.filteredData; const result = this.selection.selected.every((s) => filteredData.includes(s) ); // return result; } isSelected(item: any) { // if ( !item || !this.data || !this.selection || !this.isRowsSelectable || !this.data.includes(item) ) { return false; } // return this.selection.isSelected(item); } toggleSelectAll() { this.isAllSelected() ? this.selection.clear() : this.dataSource.data.forEach((row) => this.selection.select(row)); } selectAll() { // if ( !this.isRowsSelectable || !this.selection || !this.dataSource || !this.dataSource.data ) { return; } // this.dataSource.data.forEach((i) => this.selection.select(i)); } selectAllFilteredData() { // if ( !this.isRowsSelectable || !this.selection || !this.dataSource || !this.dataSource.data || !this.dataSource.filteredData ) { return; } // this.dataSource.filteredData.forEach((i) => this.selection.select(i)); } deselectAll() { // if ( !this.isRowsSelectable || !this.selection || !this.dataSource || !this.dataSource.data || !this.dataSource.filteredData ) { return; } // this.dataSource.filteredData.forEach((i) => this.selection.deselect(i)); } deselectAllFilteredData() { // if (!this.isRowsSelectable || !this.selection) { return; } // this.selection.clear(); } inverseSelection() { // if ( !this.isRowsSelectable || !this.selection || !this.dataSource || !this.dataSource.data ) { return; } // this.dataSource.data.forEach((i) => this.selection.toggle(i)); } async filterData(query: string) { // this.dataSource.filter = query.trim().toLowerCase(); this.prepareActionOptions(); // await this.firstPage(); } async firstPage() { // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // this.paginator.firstPage(); // this.detectChanges(); } async lastPage() { // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // this.paginator.lastPage(); // this.detectChanges(); } async nextPage() { // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // this.paginator.nextPage(); // this.detectChanges(); } async previousPage() { // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // this.paginator.previousPage(); // this.detectChanges(); } async toPage(index: number) { // const hasPaginator = await this.getValueAsync(this.showPaginator); if (!hasPaginator || !this.paginator) { return; } // index = index === 0 ? 1 : index; // this.paginator.pageIndex = index - 1; this.paginator.page.next({ pageIndex: index - 1, pageSize: this.pageSize, length: this.totalItems, }); // this.detectChanges(); } async changePageSize(size: number) { // if (!size || !this.paginator) { return; } // this.paginator.pageSize = size; this.paginator.page.emit({ pageIndex: 0, pageSize: size, length: this.totalItems, }); // this.detectChanges(); } //#endregion // //#region Private ... // //#region Action Provider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XTableAction.Refresh: this.detectChanges(); break; // case XTableAction.DE_SELECT_ALL: this.deselectAll(); break; // case XTableAction.INVERSE_SELECTION: this.inverseSelection(); break; // case XTableAction.SELECT_ALL: this.selectAll(); break; // case XTableAction.TOGGLE_SELECT_ALL: this.toggleSelectAll(); break; // case XTableAction.FIRST_PAGE: await this.firstPage(); break; // case XTableAction.LAST_PAGE: await this.lastPage(); break; // case XTableAction.NEXT_PAGE: await this.nextPage(); break; // case XTableAction.PREVIOUS_PAGE: await this.previousPage(); break; // case XTableAction.TO_PAGE: if (model.payload && isNumber(model.payload)) { await this.toPage(model.payload as number); } break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private async prepareUIData() { // this.IS_ROWS_SELECTABLE = await this.getValueAsync(this.selectableRows); // this.detectChanges(); } private async prepareDataSource() { // this.DATA = []; this.COLUMNS_DATA = []; this.DISPLAYED_COLUMNS = []; if (!this.properties) { return; } // const dataSource = await this.getValueAsync(this.properties.items); this.DATA = dataSource; // const isSelectableRows = await this.getValueAsync(this.selectableRows); const baseColumnsData = !isSelectableRows ? [] : [ { name: X_TABLE_SELECTION_HEADER_IDENTIFIER, } as XTableColumnOption, ]; this.COLUMNS_DATA = baseColumnsData.concat(this.properties.columns); // const displayedColumns = await Promise.all( this.COLUMNS_DATA.map( async (cd) => (await this.getValueAsync(cd.name)) as string ) ); this.DISPLAYED_COLUMNS = displayedColumns; // this.DATA_SOURCE.data = this.DATA; // this.detectChanges(); } private async prepareSelection() { // const isMultipleSelection = await this.getValueAsync(this.allowMultiSelect); const initialSelectedValues = await this.getValueAsync( this.initialSelectedValues ); // this.SELECTION = new SelectionModel( isMultipleSelection, initialSelectedValues ); // // notify event emitter when has initial selected values ... if (hasChild(initialSelectedValues)) { this.rowSelectionChanged.emit(initialSelectedValues); } // this.registerSelectionChangeHandler(); // this.detectChanges(); } private registerSelectionChangeHandler() { // // Unsubscribe Last ... if (this.SELECTION_SUBSCRIPTION) { this.SELECTION_SUBSCRIPTION.unsubscribe(); this.SELECTION_SUBSCRIPTION = null; } // // Subscribe New ... this.SELECTION_SUBSCRIPTION = this.applyTakeUntilWrapper( this.SELECTION.changed.asObservable() ).subscribe(async () => { // await this.prepareActionOptions(); this.rowSelectionChanged.emit(this.SELECTION.selected); }); } private async preparePaginatorOptions() { // const options = await this.getValueAsync(this.paginatorOptions); const defaultOptions = this.defaultPaginatorOptions(); const preparedOptions: XTablePaginatorOptions = { ...defaultOptions, ...options, }; // if (options) { // if (!options.first) { preparedOptions.first = undefined; } else { // const first = options.first; // if (first.disabled) { const firstDisabled = await this.getValueAsync(first.disabled); preparedOptions.first.disabled = defaultOptions.first.disabled && firstDisabled; } else { preparedOptions.first.disabled = defaultOptions.first.disabled; } // if (!first.icon) { preparedOptions.first.icon = defaultOptions.first.icon; } // if (!first.title) { preparedOptions.first.title = defaultOptions.first.title; } } // if (!options.last) { preparedOptions.last = undefined; } else { // const last = options.last; // if (last.disabled) { const lastDisabled = await this.getValueAsync(last.disabled); preparedOptions.last.disabled = defaultOptions.last.disabled && lastDisabled; } else { preparedOptions.last.disabled = defaultOptions.last.disabled; } // if (!last.icon) { preparedOptions.last.icon = defaultOptions.last.icon; } // if (!last.title) { preparedOptions.last.title = defaultOptions.last.title; } } // if (!options.next) { preparedOptions.next = undefined; } else { // const next = options.next; // if (next.disabled) { const nextDisabled = await this.getValueAsync(next.disabled); preparedOptions.next.disabled = defaultOptions.next.disabled && nextDisabled; } else { preparedOptions.next.disabled = defaultOptions.next.disabled; } // if (!next.icon) { preparedOptions.next.icon = defaultOptions.next.icon; } // if (!next.title) { preparedOptions.next.title = defaultOptions.next.title; } } // if (!options.prev) { preparedOptions.prev = undefined; } else { // const prev = options.prev; // if (prev.disabled) { const prevDisabled = await this.getValueAsync(prev.disabled); preparedOptions.prev.disabled = defaultOptions.prev.disabled && prevDisabled; } else { preparedOptions.prev.disabled = defaultOptions.prev.disabled; } // if (!prev.icon) { preparedOptions.prev.icon = defaultOptions.prev.icon; } // if (!prev.title) { preparedOptions.prev.title = defaultOptions.prev.title; } } } // this.PAGINATOR_OPTIONS = preparedOptions; // this.detectChanges(); } private async registerPaginatorHandlers() { // if (!this.paginator) { return; } // //#region Handle Paginator Ready ... // // Unsubscribe Last ... if (this.PAGINATOR_INIT_SUBSCRIPTION) { this.PAGINATOR_INIT_SUBSCRIPTION.unsubscribe(); this.PAGINATOR_INIT_SUBSCRIPTION = null; } // // Subscribe New ... this.PAGINATOR_INIT_SUBSCRIPTION = this.applyTakeUntilWrapper( this.paginator.initialized ).subscribe(async () => { // await this.preparePaginatorOptions(); // //#region Initial Page Info Reciever ... // this.PAGE_SIZE = this.paginator.pageSize; this.TOTAL_ITEMS = this.paginator.length; this.PAGE_SIZE = this.paginator.pageSize; this.CURRENT_PAGE = this.paginator.pageIndex + 1; // const totalPagesFloat = this.paginator.length / this.paginator.pageSize; this.TOTAL_PAGES = Math.floor(totalPagesFloat); // if ( totalPagesFloat > this.TOTAL_PAGES && totalPagesFloat < this.TOTAL_PAGES + 1 ) { this.TOTAL_PAGES++; } //#endregion // this.detectChanges(); }); //#endregion // //#region Handle Page Changes ... // // Unsubscribe last ... if (this.PAGINATOR_PAGE_SUBSCRIPTION) { this.PAGINATOR_PAGE_SUBSCRIPTION.unsubscribe(); this.PAGINATOR_PAGE_SUBSCRIPTION = null; } // // Subscribe New ... this.PAGINATOR_PAGE_SUBSCRIPTION = this.applyTakeUntilWrapper( this.paginator.page.asObservable() ).subscribe(async (res) => { // // ReNew Pagination Options ... await this.preparePaginatorOptions(); // // Handle Current Page ... this.PAGE_SIZE = res.pageSize; this.TOTAL_ITEMS = res.length; this.PAGE_SIZE = res.pageSize; this.CURRENT_PAGE = res.pageIndex + 1; this.pageChanged.emit(this.CURRENT_PAGE); // //#region Handle Calculation of Total pages ... const totalPagesFloat = res.length / res.pageSize; this.TOTAL_PAGES = Math.floor(totalPagesFloat); // if ( totalPagesFloat > this.TOTAL_PAGES && totalPagesFloat < this.TOTAL_PAGES + 1 ) { this.TOTAL_PAGES++; } //#endregion // this.detectChanges(); }); //#endregion } private defaultPaginatorOptions() { // const options: XTablePaginatorOptions = { pageSizes: this.config.pageSizes, pageSize: this.config.defaultPageSize, first: { title: 'first', icon: XIconNames.first, disabled: !this.paginator || !this.paginator.hasPreviousPage(), }, last: { title: 'last', icon: XIconNames.last, disabled: !this.paginator || !this.paginator.hasNextPage(), }, prev: { title: 'previous', icon: XIconNames.previous, disabled: !this.paginator || !this.paginator.hasPreviousPage(), }, next: { title: 'next', icon: XIconNames.next, disabled: !this.paginator || !this.paginator.hasNextPage(), }, pageInfoProvider: ( locale: XLocale, currentPage: number, pageSize: number, totalPages: number ) => { // const info = `${currentPage}/${totalPages}`; return applyLocale(info, locale); }, }; // return options; } private async prepareActionOptions() { // let preparedOptions: XTableActionOptions = {}; const options = await this.getValueAsync(this.actionOptions); const defaultOptions = this.defaultActionOptions(); // if (!options) { preparedOptions = defaultOptions; } else { // if (options.start) { preparedOptions.start = [...options.start, ...defaultOptions.start]; } else { preparedOptions.start = [...defaultOptions.start]; } // if (options.end) { preparedOptions.end = [...defaultOptions.end, ...options.end]; } else { preparedOptions.end = [...defaultOptions.end]; } } // this.ACTION_OPTIONS = preparedOptions; // this.detectChanges(); } private defaultActionOptions() { // const options: XTableActionOptions = { start: [ { title: XResourceIDs.delete, icon: XIconNames.remove, color: XColor.Danger, disabled: this.uiDisabled || this.loading || !this.selection || !hasChild(this.data) || !hasChild(this.selection.selected), hidden: !this.isRowsSelectable, handler: (items: any) => { // this.managerService.dialogService.presentActionModal({ header: XResourceIDs.are_you_sure, buttons: [], keyboardClose: true, backdropDismiss: true, hasOk: true, okHandler: () => { this.removeItems.emit(items); }, hasCancel: true, }); }, }, ], end: [ { title: XResourceIDs.select_all, icon: XIconNames.select_all, color: XColor.Tertiary, disabled: this.uiDisabled || this.loading || !this.selection || !hasChild(this.data) || this.isAllSelected(), hidden: !this.isRowsSelectable, handler: () => { this.selectAll(); }, }, { title: XResourceIDs.select_all_group, icon: XIconNames.select_all_group, color: XColor.Tertiary, disabled: this.uiDisabled || this.loading || !hasChild(this.dataSource.filteredData) || this.isAllFilteredSelected(), hidden: !this.dataSource || !this.isRowsSelectable || !this.dataSource.filter, handler: () => { this.selectAllFilteredData(); }, }, { title: XResourceIDs.deselect_all, icon: XIconNames.deselect_all, color: XColor.Tertiary, disabled: this.uiDisabled || this.loading || !this.selection || !hasChild(this.data) || !hasChild(this.selection.selected), hidden: !this.isRowsSelectable, handler: () => { this.deselectAll(); }, }, { title: XResourceIDs.deselect_all_group, icon: XIconNames.deselect_all_group, color: XColor.Tertiary, disabled: this.uiDisabled || this.loading || !this.selection || !hasChild(this.data) || !this.isAllFilteredSelected() || !hasChild(this.selection.selected), hidden: !this.isRowsSelectable || !this.dataSource.filter || !hasChild(this.dataSource.filteredData), handler: () => { this.deselectAllFilteredData(); }, }, { title: XResourceIDs.inverse_selection, icon: XIconNames.inverse_selection, color: XColor.Tertiary, disabled: this.uiDisabled || this.loading || !this.selection || !hasChild(this.data) || !hasChild(this.selection.selected), hidden: !this.isRowsSelectable, handler: () => { this.inverseSelection(); }, }, ], }; // return options; } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XTableComponent } from './x-table.component'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XEmptyModule } from '../x-empty/x-empty.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XTableComponent], imports: [ XCardModule, XIconModule, XEmptyModule, CommonModule, XBaseComponentModule, ], exports: [ XCardModule, XIconModule, XEmptyModule, XTableComponent, XBaseComponentModule, ], }) export class XTableModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-table\x-table.typings.ts import { Inject, Input, NgZone, Output, Component, Renderer2, Injectable, ElementRef, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XLocale, XResourceIDs, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XCardEmptyContainer, IXCardEmptyContainer, XCardEmptyContainerComponent, } from '../classes/i-x-card-empty.container'; import { concatMap, map } from 'rxjs/operators'; import { ViewportRuler } from '@angular/cdk/overlay'; import { forkJoin, Observable, Subject } from 'rxjs'; import { XManagerService } from 'x-framework-services'; import { XIconIdentifier } from '../x-icon/x-icon.typings'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export type XTableColumn = keyof T; export type XTableColumnIdentifier = XTableColumn | string; export interface XTableColumnOption { // hidden?: XStandardType; name: XTableColumnIdentifier; sortable?: XStandardType; icon?: XStandardType; customColumn?: XStandardType; title: XStandardType; description?: XStandardType; } export interface XTableConfig { // items: XStandardType; columns: XTableColumnOption[]; } export type XSortDirection = 'asc' | 'desc'; export enum XTableItemPosition { TOP = 'top', BOTTOM = 'bottom', } export type XTableItemPositionIdentifier = XTableItemPosition | string; export const X_TABLE_SELECTION_HEADER_IDENTIFIER = 'selection'; export interface XTableActionButton { hidden?: XStandardType; disabled?: XStandardType; icon?: XStandardType; color?: XStandardType; title?: XStandardType; handler?: (item?: any) => XStandardType; } export interface XTablePaginatorOptions { pageSizes?: XStandardType; pageSize?: XStandardType; first?: XTableActionButton; last?: XTableActionButton; next?: XTableActionButton; prev?: XTableActionButton; pageInfoProvider?: ( locale: XLocale, currentPage: number, pageSize: number, totalPages: number, totalItems: number ) => string; } export interface XTableActionOptions { end?: XTableActionButton[]; start?: XTableActionButton[]; } export enum XTableAction { // Refresh = 'refresh', // TOGGLE_SELECT_ALL = 'toggle-select-all', SELECT_ALL = 'select-all', DE_SELECT_ALL = 'deselect-all', INVERSE_SELECTION = 'inverse-selection', FIRST_PAGE = 'first-page', LAST_PAGE = 'last-page', NEXT_PAGE = 'next-page', PREVIOUS_PAGE = 'previous-page', TO_PAGE = 'to-page', } export type XTableActionIdentifier = XTableAction | string; export interface XTableActionModel extends XBaseActionModel {} // //#region Inside Card/Empty Container ... export interface IXTableContainer extends IXCardEmptyContainer { // //#region Other Props ... // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; foregroundColor: XStandardType; canClearSort: XStandardType; cellCssClass: XStandardType>; properties: XTableConfig; cellTemplate: TemplateRef; customCellTemplate: TemplateRef; //#endregion // //#region Header Props ... // showHeader: XStandardType; stickyHeader: XStandardType; headerCellCssClass: XStandardType>; // headerColor: XStandardType; headerForegroundColor: XStandardType; //#endregion // //#region Click Props ... clickableRows: XStandardType; rowClicked: EventEmitter; //#endregion // //#region Selection props ... selectableRows: XStandardType; rowSelected: EventEmitter; rowSelectionChanged: EventEmitter; allowMultiSelect: XStandardType; initialSelectedValues: XStandardType; //#endregion // //#region Filter/Search Props ... showSearchBar: XStandardType; searchBarPosition: XStandardType; searchBarColor: XStandardType; searchTitle: XStandardType; //#endregion // //#region Paginator Props ... showPaginator: XStandardType; paginatorPosition: XStandardType; paginatorColor: XStandardType; paginatorOptions: XStandardType; pageChanged: EventEmitter; //#endregion // //#region Action Props ... showActionBar: XStandardType; actionBarPosition: XStandardType; actionBarColor: XStandardType; actionOptions: XStandardType; removeItems: EventEmitter; //#endregion } @Injectable({ providedIn: 'root', }) export class XTableContainer extends XCardEmptyContainer implements Readonly { // //#region Props ... // //#region Other Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; readonly foregroundColor: XStandardType = false; readonly canClearSort: XStandardType = true; readonly cellCssClass: XStandardType>; readonly properties: XTableConfig; readonly cellTemplate: TemplateRef; readonly customCellTemplate: TemplateRef; //#endregion // //#region Header Props ... // readonly showHeader: XStandardType = true; readonly stickyHeader: XStandardType = true; readonly headerCellCssClass: XStandardType>; // readonly headerColor: XStandardType = XColorWithBrightness.Dark; readonly headerForegroundColor: XStandardType = false; //#endregion // //#region Click Props ... readonly clickableRows: XStandardType = false; readonly rowClicked: EventEmitter = new EventEmitter(); //#endregion // //#region Selection props ... readonly selectableRows: XStandardType = false; readonly rowSelected: EventEmitter = new EventEmitter(); readonly rowSelectionChanged: EventEmitter = new EventEmitter(); readonly allowMultiSelect: XStandardType = true; readonly initialSelectedValues: XStandardType = []; //#endregion // //#region Filter/Search Props ... readonly showSearchBar: XStandardType = false; readonly searchBarPosition: XStandardType = XTableItemPosition.TOP; readonly searchBarColor: XStandardType = XColorWithBrightness.Light; readonly searchTitle: XStandardType = XResourceIDs.search; //#endregion // //#region Paginator Props ... readonly showPaginator: XStandardType; readonly paginatorPosition: XStandardType = XTableItemPosition.BOTTOM; readonly paginatorColor: XStandardType = XColorWithBrightness.Light; readonly paginatorOptions: XStandardType; readonly pageChanged: EventEmitter = new EventEmitter(); //#endregion // //#region Action Props ... readonly showActionBar: XStandardType; readonly actionBarPosition: XStandardType = XTableItemPosition.TOP; readonly actionBarColor: XStandardType = XColorWithBrightness.Light; readonly actionOptions: XStandardType; readonly removeItems: EventEmitter = new EventEmitter(); //#endregion //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XTableContainerComponent extends XCardEmptyContainerComponent implements IXTableContainer { // //#region Props ... // //#region Other Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() canClearSort: XStandardType = this.propertyProvider.canClearSort; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() color: XStandardType = this.propertyProvider.color; @Input() foregroundColor: XStandardType = this.propertyProvider.foregroundColor; @Input() cellCssClass: XStandardType> = this.propertyProvider.cellCssClass; @Input() properties: XTableConfig = this.propertyProvider.properties; @Input() cellTemplate: TemplateRef = this.propertyProvider.cellTemplate; @Input() customCellTemplate: TemplateRef = this.propertyProvider.customCellTemplate; //#endregion // //#region Header Props ... @Input() showHeader: XStandardType = this.propertyProvider.showHeader; @Input() stickyHeader: XStandardType = this.propertyProvider.stickyHeader; @Input() headerColor: XStandardType = this.propertyProvider.headerColor; @Input() headerForegroundColor: XStandardType = this.propertyProvider.headerForegroundColor; @Input() headerCellCssClass: XStandardType> = this.propertyProvider.headerCellCssClass; //#endregion // //#region Click Props ... @Input() clickableRows: XStandardType = this.propertyProvider.clickableRows; @Output() rowClicked: EventEmitter = new EventEmitter(); //#endregion // //#region Selection props ... @Input() selectableRows: XStandardType = this.propertyProvider.selectableRows; @Output() rowSelected: EventEmitter = new EventEmitter(); @Output() rowSelectionChanged: EventEmitter = new EventEmitter(); @Input() allowMultiSelect: XStandardType = this.propertyProvider.allowMultiSelect; @Input() initialSelectedValues: XStandardType = this.propertyProvider.initialSelectedValues; //#endregion // //#region Filter/Search Props ... @Input() showSearchBar: XStandardType = this.propertyProvider.showSearchBar; @Input() searchBarPosition: XStandardType = this.propertyProvider.searchBarPosition; @Input() searchBarColor: XStandardType = this.propertyProvider.searchBarColor; @Input() searchTitle: XStandardType = this.propertyProvider.searchTitle; //#endregion // //#region Paginator Props ... @Input() showPaginator: XStandardType = this.propertyProvider.showPaginator; @Input() paginatorPosition: XStandardType = this.propertyProvider.paginatorPosition; @Input() paginatorColor: XStandardType = this.propertyProvider.paginatorColor; @Input() paginatorOptions: XStandardType = this.propertyProvider.paginatorOptions; @Output() pageChanged: EventEmitter = new EventEmitter(); //#endregion // //#region Action Props ... @Input() showActionBar: XStandardType = this.propertyProvider.showActionBar; @Input() actionBarPosition: XStandardType = this.propertyProvider.actionBarPosition; @Input() actionBarColor: XStandardType = this.propertyProvider.actionBarColor; @Input() actionOptions: XStandardType = this.propertyProvider.actionOptions; @Output() removeItems: EventEmitter = new EventEmitter(); //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XTableContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXTableContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // canClearSort: this.getValue( container ? container.canClearSort : this.canClearSort ), cssClass: this.getValue( container ? container.cssClass : this.cssClass ), color: this.getValue(container ? container.color : this.color), foregroundColor: this.getValue( container ? container.foregroundColor : this.foregroundColor ), cellCssClass: this.getValue( container ? container.cellCssClass : this.cellCssClass ), properties: this.getValue( container ? container.properties : this.properties ), cellTemplate: this.getValue( container ? container.cellTemplate : this.cellTemplate ), customCellTemplate: this.getValue( container ? container.customCellTemplate : this.customCellTemplate ), showHeader: this.getValue( container ? container.showHeader : this.showHeader ), stickyHeader: this.getValue( container ? container.stickyHeader : this.stickyHeader ), headerColor: this.getValue( container ? container.headerColor : this.headerColor ), headerForegroundColor: this.getValue( container ? container.headerForegroundColor : this.headerForegroundColor ), headerCellCssClass: this.getValue( container ? container.headerCellCssClass : this.headerCellCssClass ), clickableRows: this.getValue( container ? container.clickableRows : this.clickableRows ), selectableRows: this.getValue( container ? container.selectableRows : this.selectableRows ), allowMultiSelect: this.getValue( container ? container.allowMultiSelect : this.allowMultiSelect ), initialSelectedValues: this.getValue( container ? container.initialSelectedValues : this.initialSelectedValues ), showSearchBar: this.getValue( container ? container.showSearchBar : this.showSearchBar ), searchBarPosition: this.getValue( container ? container.searchBarPosition : this.searchBarPosition ), searchBarColor: this.getValue( container ? container.searchBarColor : this.searchBarColor ), searchTitle: this.getValue( container ? container.searchTitle : this.searchTitle ), showPaginator: this.getValue( container ? container.showPaginator : this.showPaginator ), paginatorPosition: this.getValue( container ? container.paginatorPosition : this.paginatorPosition ), paginatorColor: this.getValue( container ? container.paginatorColor : this.paginatorColor ), paginatorOptions: this.getValue( container ? container.paginatorOptions : this.paginatorOptions ), showActionBar: this.getValue( container ? container.showActionBar : this.showActionBar ), actionBarPosition: this.getValue( container ? container.actionBarPosition : this.actionBarPosition ), actionBarColor: this.getValue( container ? container.actionBarColor : this.actionBarColor ), actionOptions: this.getValue( container ? container.actionOptions : this.actionOptions ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // rowSelectionChanged: this.rowSelectionChanged, pageChanged: this.pageChanged, rowClicked: this.rowClicked, rowSelected: this.rowSelected, removeItems: this.removeItems, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.component.scss :host { // --tab-header-color: var(--x-color-primary); // --tab-indicator-color: var(--x-color-secondary); // --tab-paginator-foreground-color: var(--x-color-secondary-contrast); --tab-paginator-background-color: var(--x-color-secondary); // --active-tab-foreground-color: var(--x-color-secondary-contrast); --active-tab-background-color: var(--x-color-secondary); } :host ::ng-deep.mat-ink-bar { background-color: var(--tab-indicator-color) !important; } .x-wrapper { // width: inherit; height: inherit; } x-card { // width: inherit; height: inherit; } :host ::ng-deep .x-wrapper { .mat-tab-header { display: flex; } &.hide-header { .mat-tab-header { display: none; } } } :host ::ng-deep.swipable { // cursor: grab; // -webkit-user-select: none; /* Chrome all / Safari all */ -moz-user-select: none; /* Firefox all */ -ms-user-select: none; /* IE 10+ */ user-select: none; /* Likely future */ } :host ::ng-deep.mat-tab-label-active { opacity: 1 !important; // color: var(--active-tab-foreground-color) !important; background-color: var(--active-tab-background-color) !important; .mat-tab-label-content { // color: var(--active-tab-foreground-color) !important; background-color: var(--active-tab-background-color) !important; * { // color: var(--active-tab-foreground-color) !important; background-color: var(--active-tab-background-color) !important; } } } :host ::ng-deep .mat-tab-header-pagination { // background-color: var(--tab-paginator-background-color) !important; } :host ::ng-deep.mat-tab-header-pagination-chevron { border-color: var(--tab-paginator-foreground-color) !important; } :host ::ng-deep .mat-tab-labels { // background-color: var(--tab-header-color) !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.component.ts import { QueryList, Component, ContentChildren, ChangeDetectionStrategy, } from '@angular/core'; import { nameof, parseXColor, isNullOrEmptyString, getXColorCssVariableName, } from 'x-framework-core'; import { XTabAlign, XTabsAction, XTabsCssVars, XTabChangeEvent, XTabsActionModel, XTabsHeaderPosition, XTabsContainerComponent, } from './x-tabs.typings'; import { map, concatMap } from 'rxjs/operators'; import { XTabComponent } from './x-tab/x-tab.component'; import { MatTabChangeEvent } from '@angular/material/tabs'; import { of, Subject, Subscription, Observable } from 'rxjs'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-tabs', templateUrl: './x-tabs.component.html', styleUrls: ['./x-tabs.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XTabsComponent extends XTabsContainerComponent { // //#region Props ... // private TABS: QueryList; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // canPrev$ = new Subject(); canNext$ = new Subject(); // get tabs() { return this.TABS; } // @ContentChildren(XTabComponent) set tabs(s: QueryList) { this.TABS = s; } //#endregion // //#region LifeCycles ... async onInit() { super.onInit(); // await this.handleSelectedIndex(); await this.applyDefaultColors(); } async onChange(changeKeys: string[]) { super.onChange(changeKeys); // const hasSelectedIndex = changeKeys.includes( nameof('selectedIndex') ); if (hasSelectedIndex) { await this.handleSelectedIndex(); } // //#region Color Changed ... // // Tab Header Color ... const isTabHeaderColorChanged = changeKeys.includes( nameof('headerColor') ); if (isTabHeaderColorChanged) { await this.applyTabHeaderColor(); } // // Active Tab Color ... const isActiveTabColorChanged = changeKeys.includes( nameof('activeTabColor') ); if (isActiveTabColorChanged) { await this.applyActiveTabColor(); } // // Tab Indicator Color ... const isTabIndicatorColorChanged = changeKeys.includes( nameof('tabIndicatorColor') ); if (isTabIndicatorColorChanged) { await this.applyTabIndicatorColor(); } // // Tab Paginator Color ... const isTabPaginatorColorChanged = changeKeys.includes( nameof('tabPaginatorColor') ); if (isTabPaginatorColorChanged) { await this.applyTabPaginatorColor(); } //#endregion // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Task Handlers ... //#endregion // //#region UI Providers ... isDynamicHeight() { return this.getValue(this.dynamicHeight).pipe( map((isDynamic) => (isDynamic ? '' : undefined)) ); } isStretched() { return this.getValue(this.alignTabs).pipe( map((align) => (align === XTabAlign.STRETCH ? '' : undefined)) ); } getTabAlignValue() { return this.isStretched().pipe( concatMap((isStretched) => { if (isStretched) { return of(undefined); } else { return this.getValue(this.alignTabs); } }) ); } swipeDisabled() { return this.getValue(this.swipable).pipe( map((swipable) => !swipable || this.uiDisabled) ); } getHeaderPosition(): Observable<'above' | 'below'> { return this.getValue(this.headerPosition).pipe( map((position) => position === XTabsHeaderPosition.ABOVE ? 'above' : 'below' ) ); } //#endregion // //#region UI Handlers ... async handleSelectedTabChanged(event: MatTabChangeEvent) { // const mEvent: XTabChangeEvent = { index: event.index, tab: this.tabs.toArray()[event.index], }; // const canLoop = await this.canLoop(); // if (event.index === 0) { // this.canPrev$.next(false || canLoop); this.canNext$.next(true); } else if (event.index === this.tabs.length - 1) { // this.canPrev$.next(true); this.canNext$.next(false || canLoop); } else if (event.index > 0 && event.index < this.tabs.length) { // this.canPrev$.next(true); this.canNext$.next(true); } // this.selectedTabChange.emit(mEvent); this.selectedIndexChange.emit(mEvent.index); } async handleSwipeEnd() { await this.prev(); } async handleSwipeStart() { await this.next(); } //#endregion // //#region Actions ... length() { return this.tabs ? this.tabs.length : 0; } getTab(index: number) { return this.checkIndex(index) ? this.tabs.toArray()[index] : null; } async next() { // const isLocked = await this.isLocked(); if (isLocked) { return; } // const current = this.selectedIndex; const canLoop = await this.canLoop(); const next = this.checkIndex(current + 1) ? current + 1 : canLoop ? 0 : current; // this.selectedIndex = next; this.detectChanges(); } async prev() { // const isLocked = await this.isLocked(); if (isLocked) { return; } // const current = this.selectedIndex; const canLoop = await this.canLoop(); const prev = this.checkIndex(current - 1) ? current - 1 : canLoop ? this.tabs.length - 1 : current; // this.selectedIndex = prev; this.detectChanges(); } async first() { // const isLocked = await this.isLocked(); if (isLocked) { return; } // this.selectedIndex = 0; this.detectChanges(); } async last() { // const isLocked = await this.isLocked(); if (isLocked) { return; } // this.selectedIndex = this.tabs.length - 1; this.detectChanges(); } async to(index: number) { // const isLocked = await this.isLocked(); if (isLocked) { return; } // if (!this.checkIndex(index)) { return; } // this.selectedIndex = index; this.detectChanges(); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XTabsAction.FIRST: await this.first(); break; // case XTabsAction.LAST: await this.last(); break; // case XTabsAction.NEXT: await this.next(); break; // case XTabsAction.PREV: await this.prev(); break; // case XTabsAction.TO: if (model.payload) { await this.to(model.payload); } break; // case XTabsAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private checkIndex(index: number) { return this.tabs && index < this.tabs.length && index >= 0; } private async canLoop() { // const result = await this.getValueAsync(this.loopTabs); return result || false; } private async isLocked() { // const result = await this.getValueAsync(this.lock); return result || false; } private async handleSelectedIndex() { // const startIndex = await this.getValueAsync(this.selectedIndex); // if (!this.checkIndex(startIndex)) { // this.selectedIndex = 0; return; } // this.selectedIndex = startIndex; } // //#region Color Appliers ... private async applyDefaultColors() { // await this.applyActiveTabColor(); await this.applyTabHeaderColor(); await this.applyTabPaginatorColor(); await this.applyTabIndicatorColor(); } private async applyTabHeaderColor() { // const color = await this.getValueAsync(this.headerColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XTabsCssVars.TabHeaderColor, `var(${bgColor})`); // this.detectChanges(); } private async applyActiveTabColor() { // const color = await this.getValueAsync(this.activeTabColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XTabsCssVars.ActiveTabForegroundColor, `var(${fgColor})`); this.setCssVar(XTabsCssVars.ActiveTabBackgroundColor, `var(${bgColor})`); // this.detectChanges(); } private async applyTabIndicatorColor() { // const color = await this.getValueAsync(this.tabIndicatorColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XTabsCssVars.TabIndicatorColor, `var(${bgColor})`); // this.detectChanges(); } private async applyTabPaginatorColor() { // const color = await this.getValueAsync(this.tabPaginatorColor); if (!color) { return; } // const colorDescriptor = parseXColor(color); if (!colorDescriptor) { return; } // const fgColor = getXColorCssVariableName( colorDescriptor.name, true, colorDescriptor.brightnessLevel ); const bgColor = getXColorCssVariableName( colorDescriptor.name, false, colorDescriptor.brightnessLevel ); if (isNullOrEmptyString(fgColor) || isNullOrEmptyString(bgColor)) { return; } // this.setCssVar(XTabsCssVars.TabPaginatorForegroundColor, `var(${fgColor})`); this.setCssVar(XTabsCssVars.TabPaginatorBackgroundColor, `var(${bgColor})`); // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XTabsComponent } from './x-tabs.component'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XTabComponent } from './x-tab/x-tab.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XTabsContainerComponent } from './x-tabs.typings'; @NgModule({ declarations: [XTabsComponent, XTabComponent, XTabsContainerComponent], imports: [CommonModule, XBaseComponentModule, XIconModule, XCardModule], exports: [ XIconModule, XCardModule, XTabComponent, XTabsComponent, XBaseComponentModule ] }) export class XTabsModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tabs.typings.ts import { Input, Inject, NgZone, Output, Renderer2, Component, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { ViewportRuler } from '@angular/cdk/overlay'; import { forkJoin, Observable, Subject } from 'rxjs'; import { XManagerService } from 'x-framework-services'; import { XTabComponent } from './x-tab/x-tab.component'; import { MatTabChangeEvent } from '@angular/material/tabs'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XTabsHeaderPosition { ABOVE = 'above', BELOW = 'below', } export type XTabsHeaderPositionIdentifier = XTabsHeaderPosition | string; export interface XTabChangeEvent extends Pick { tab: XTabComponent; } export enum XTabAlign { START = 'start', CENTER = 'center', END = 'end', STRETCH = 'stretch', } export type XTabAlignIdentifier = XTabAlign | string; export enum XTabsAction { FIRST = 'first', LAST = 'last', PREV = 'prev', NEXT = 'next', TO = 'to', // Refresh = 'refresh', } export type XTabsActionIdentifier = XTabsAction | string; export interface XTabsActionModel extends XBaseActionModel {} export enum XTabsCssVars { // TabHeaderColor = 'tab-header-color', // TabIndicatorColor = 'tab-indicator-color', // ActiveTabForegroundColor = 'active-tab-foreground-color', ActiveTabBackgroundColor = 'active-tab-background-color', // TabPaginatorForegroundColor = 'tab-paginator-foreground-color', TabPaginatorBackgroundColor = 'tab-paginator-background-color', } export type XTabsCssVarsIdentifier = XTabsCssVars | string; // //#region Inside Card Container ... export interface IXTabsContainer extends IXComponentCardContainer { // actionProvider: Subject; cssClass: XStandardType>; // selectedIndex: number; selectedIndexChange: EventEmitter; // showHeader: XStandardType; disablePagination: XStandardType; alignTabs: XStandardType; dynamicHeight: XStandardType; animationDuration: XStandardType; disableRipple: XStandardType; headerPosition: XStandardType; // loopTabs: XStandardType; swipable: XStandardType; animationDone: EventEmitter; // lock: XStandardType; // color: XStandardType; headerColor: XStandardType; activeTabColor: XStandardType; tabIndicatorColor: XStandardType; tabPaginatorColor: XStandardType; // selectedTabChange: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XTabsContainer extends XComponentCardContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly selectedIndex: number = 0; readonly selectedIndexChange: EventEmitter = new EventEmitter(); // readonly showHeader: XStandardType = true; readonly disablePagination: XStandardType = false; readonly alignTabs: XStandardType = XTabAlign.START; readonly dynamicHeight: XStandardType = false; readonly disableRipple: XStandardType = false; readonly headerPosition: XStandardType = XTabsHeaderPosition.ABOVE; // readonly loopTabs: XStandardType = true; readonly swipable: XStandardType = false; readonly animationDuration: XStandardType = '500ms'; // readonly lock: XStandardType = false; // readonly color: XStandardType = XColorWithBrightness.Transparent; readonly headerColor: XStandardType = XColorWithBrightness.Primary; readonly activeTabColor: XStandardType = XColorWithBrightness.Secondary; readonly tabIndicatorColor: XStandardType = XColorWithBrightness.SecondaryTint; readonly tabPaginatorColor: XStandardType = XColorWithBrightness.SecondaryShade; // readonly animationDone: EventEmitter = new EventEmitter(); readonly selectedTabChange: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export class XTabsContainerComponent extends XComponentCardContainerComponent implements IXTabsContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() selectedIndex: number = this.propertyProvider.selectedIndex; @Output() selectedIndexChange: EventEmitter = new EventEmitter(); // @Input() showHeader: XStandardType = this.propertyProvider.showHeader; @Input() disablePagination: XStandardType = this.propertyProvider.disablePagination; @Input() alignTabs: XStandardType = this.propertyProvider.alignTabs; @Input() dynamicHeight: XStandardType = this.propertyProvider.dynamicHeight; @Input() disableRipple: XStandardType = this.propertyProvider.disableRipple; @Input() headerPosition: XStandardType = this.propertyProvider.headerPosition; // @Input() loopTabs: XStandardType = this.propertyProvider.loopTabs; @Input() swipable: XStandardType = this.propertyProvider.swipable; @Input() animationDuration: XStandardType = this.propertyProvider.animationDuration; // @Input() color: XStandardType = this.propertyProvider.color; @Input() headerColor: XStandardType = this.propertyProvider.headerColor; @Input() activeTabColor: XStandardType = this.propertyProvider.activeTabColor; @Input() tabIndicatorColor: XStandardType = this.propertyProvider.tabIndicatorColor; @Input() tabPaginatorColor: XStandardType = this.propertyProvider.tabPaginatorColor; // @Output() animationDone: EventEmitter = new EventEmitter(); @Output() selectedTabChange: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XTabsContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXTabsContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), selectedIndex: this.getValue( container ? container.selectedIndex : this.selectedIndex ), showHeader: this.getValue( container ? container.showHeader : this.showHeader ), disablePagination: this.getValue( container ? container.disablePagination : this.disablePagination ), alignTabs: this.getValue( container ? container.alignTabs : this.alignTabs ), dynamicHeight: this.getValue( container ? container.dynamicHeight : this.dynamicHeight ), animationDuration: this.getValue( container ? container.animationDuration : this.animationDuration ), disableRipple: this.getValue( container ? container.disableRipple : this.disableRipple ), headerPosition: this.getValue( container ? container.headerPosition : this.headerPosition ), loopTabs: this.getValue( container ? container.loopTabs : this.loopTabs ), swipable: this.getValue( container ? container.swipable : this.swipable ), lock: this.getValue(container ? container.lock : this.lock), color: this.getValue(container ? container.color : this.color), headerColor: this.getValue( container ? container.headerColor : this.headerColor ), activeTabColor: this.getValue( container ? container.activeTabColor : this.activeTabColor ), tabIndicatorColor: this.getValue( container ? container.tabIndicatorColor : this.tabIndicatorColor ), tabPaginatorColor: this.getValue( container ? container.tabPaginatorColor : this.tabPaginatorColor ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // animationDone: this.animationDone, selectedTabChange: this.selectedTabChange, selectedIndexChange: this.selectedIndexChange, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tab\x-tab.component.html ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tab\x-tab.component.scss .full-width { width: 100%; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tab\x-tab.component.ts import { Component, ViewChild, TemplateRef, ChangeDetectionStrategy, } from '@angular/core'; import { XTabAction, XTabActionModel, XTabContainerComponent, } from './x-tab.typings'; import { nameof } from 'x-framework-core'; import { Subject, Subscription } from 'rxjs'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-tab', templateUrl: './x-tab.component.html', styleUrls: ['./x-tab.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XTabComponent extends XTabContainerComponent { // //#region Props ... private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // @ViewChild('label', { static: false }) label!: TemplateRef; // @ViewChild('content', { static: false }) content!: TemplateRef; //#endregion // //#region LifeCycles ... onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XTabAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tabs\x-tab\x-tab.typings.ts import { Input, Inject, NgZone, Renderer2, ElementRef, ChangeDetectorRef, } from '@angular/core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../../classes/i-x-base.container'; import { forkJoin, Observable, Subject } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { Component, Injectable } from '@angular/core'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; export enum XTabAction { Refresh = 'refresh', } export type XTabActionIdentifier = XTabAction | string; export interface XTabActionModel extends XBaseActionModel {} // //#region Container ... export interface IXTabContainer extends IXBaseContainer { actionProvider: Subject; } @Injectable({ providedIn: 'root' }) export class XTabContainer extends XBaseContainer implements Readonly { // //#region Props ... readonly actionProvider: Subject = new Subject(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XTabContainerComponent extends XBaseContainerComponent implements IXTabContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XTabContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps(container?: IXTabContainer): Observable { return forkJoin({ // }).pipe( map((data) => { return { // // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-typings.ts // //#region Form Interfaces ... export interface XThemeBaseFormModel { name: string; } export interface XThemeDarkFormModel { // //#region Dark ... darkXColorPrimary: string; darkXColorPrimaryContrast: string; darkXColorPrimaryShade: string; darkXColorPrimaryShadeContrast: string; darkXColorPrimaryTint: string; darkXColorPrimaryTintContrast: string; darkXColorSecondary: string; darkXColorSecondaryContrast: string; darkXColorSecondaryShade: string; darkXColorSecondaryShadeContrast: string; darkXColorSecondaryTint: string; darkXColorSecondaryTintContrast: string; darkXColorTertiary: string; darkXColorTertiaryContrast: string; darkXColorTertiaryShade: string; darkXColorTertiaryShadeContrast: string; darkXColorTertiaryTint: string; darkXColorTertiaryTintContrast: string; darkXColorSuccess: string; darkXColorSuccessContrast: string; darkXColorSuccessShade: string; darkXColorSuccessShadeContrast: string; darkXColorSuccessTint: string; darkXColorSuccessTintContrast: string; darkXColorWarning: string; darkXColorWarningContrast: string; darkXColorWarningShade: string; darkXColorWarningShadeContrast: string; darkXColorWarningTint: string; darkXColorWarningTintContrast: string; darkXColorDanger: string; darkXColorDangerContrast: string; darkXColorDangerShade: string; darkXColorDangerShadeContrast: string; darkXColorDangerTint: string; darkXColorDangerTintContrast: string; darkXColorDark: string; darkXColorDarkContrast: string; darkXColorDarkShade: string; darkXColorDarkShadeContrast: string; darkXColorDarkTint: string; darkXColorDarkTintContrast: string; darkXColorMedium: string; darkXColorMediumContrast: string; darkXColorMediumShade: string; darkXColorMediumShadeContrast: string; darkXColorMediumTint: string; darkXColorMediumTintContrast: string; darkXColorLight: string; darkXColorLightContrast: string; darkXColorLightShade: string; darkXColorLightShadeContrast: string; darkXColorLightTint: string; darkXColorLightTintContrast: string; //#endregion } export interface XThemeLightFormModel { // //#region Light ... lightXColorPrimary: string; lightXColorPrimaryContrast: string; lightXColorPrimaryShade: string; lightXColorPrimaryShadeContrast: string; lightXColorPrimaryTint: string; lightXColorPrimaryTintContrast: string; lightXColorSecondary: string; lightXColorSecondaryContrast: string; lightXColorSecondaryShade: string; lightXColorSecondaryShadeContrast: string; lightXColorSecondaryTint: string; lightXColorSecondaryTintContrast: string; lightXColorTertiary: string; lightXColorTertiaryContrast: string; lightXColorTertiaryShade: string; lightXColorTertiaryShadeContrast: string; lightXColorTertiaryTint: string; lightXColorTertiaryTintContrast: string; lightXColorSuccess: string; lightXColorSuccessContrast: string; lightXColorSuccessShade: string; lightXColorSuccessShadeContrast: string; lightXColorSuccessTint: string; lightXColorSuccessTintContrast: string; lightXColorWarning: string; lightXColorWarningContrast: string; lightXColorWarningShade: string; lightXColorWarningShadeContrast: string; lightXColorWarningTint: string; lightXColorWarningTintContrast: string; lightXColorDanger: string; lightXColorDangerContrast: string; lightXColorDangerShade: string; lightXColorDangerShadeContrast: string; lightXColorDangerTint: string; lightXColorDangerTintContrast: string; lightXColorDark: string; lightXColorDarkContrast: string; lightXColorDarkShade: string; lightXColorDarkShadeContrast: string; lightXColorDarkTint: string; lightXColorDarkTintContrast: string; lightXColorMedium: string; lightXColorMediumContrast: string; lightXColorMediumShade: string; lightXColorMediumShadeContrast: string; lightXColorMediumTint: string; lightXColorMediumTintContrast: string; lightXColorLight: string; lightXColorLightContrast: string; lightXColorLightShade: string; lightXColorLightShadeContrast: string; lightXColorLightTint: string; lightXColorLightTintContrast: string; //#endregion } export interface XThemeFormModel extends XThemeBaseFormModel, XThemeDarkFormModel, XThemeLightFormModel {} //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XTabsModule } from '../x-tabs/x-tabs.module'; import { XListModule } from '../x-list/x-list.module'; import { XFormModule } from '../x-form/x-form.module'; import { XColorModule } from '../x-color/x-color.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; import { XColorPickerModule } from '../x-color-picker/x-color-picker.module'; import { XThemeManagerComponent } from './x-theme-manager/x-theme-manager.component'; import { XModelPresenterModule } from '../x-model-presenter/x-model-presenter.module'; @NgModule({ declarations: [XThemeManagerComponent], imports: [ XFormModule, XIconModule, XCardModule, XTabsModule, XListModule, XColorModule, CommonModule, XColorPickerModule, XBaseComponentModule, XModelPresenterModule, ], exports: [ XFormModule, XIconModule, XCardModule, XTabsModule, XListModule, XColorModule, CommonModule, XColorPickerModule, XBaseComponentModule, XModelPresenterModule, XThemeManagerComponent, ], providers: [], }) export class XThemeModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme.tools.ts import { XThemePack, XThemeType } from 'x-framework-core'; import { XThemeBaseFormModel, XThemeDarkFormModel, XThemeFormModel, XThemeLightFormModel } from './x-theme-typings'; /** * convert to XThemeFormModel * * @param theme an instance of XThemePack ... */ export function themeToForm(theme: XThemePack) { // if (!theme) { return getEmptyThemeFormModel(); } // return { name: theme.name, // //#region Dark ... darkXColorPrimary: theme.dark.colors.XColorPrimary || '', darkXColorPrimaryContrast: theme.dark.colors.XColorPrimaryContrast || '', darkXColorPrimaryShade: theme.dark.colors.XColorPrimaryShade || '', darkXColorPrimaryShadeContrast: theme.dark.colors.XColorPrimaryShadeContrast || '', darkXColorPrimaryTint: theme.dark.colors.XColorPrimaryTint || '', darkXColorPrimaryTintContrast: theme.dark.colors.XColorPrimaryTintContrast || '', darkXColorSecondary: theme.dark.colors.XColorSecondary || '', darkXColorSecondaryContrast: theme.dark.colors.XColorSecondaryContrast || '', darkXColorSecondaryShade: theme.dark.colors.XColorSecondaryShade || '', darkXColorSecondaryShadeContrast: theme.dark.colors.XColorSecondaryShadeContrast || '', darkXColorSecondaryTint: theme.dark.colors.XColorSecondaryTint || '', darkXColorSecondaryTintContrast: theme.dark.colors.XColorSecondaryTintContrast || '', darkXColorTertiary: theme.dark.colors.XColorTertiary || '', darkXColorTertiaryContrast: theme.dark.colors.XColorTertiaryContrast || '', darkXColorTertiaryShade: theme.dark.colors.XColorTertiaryShade || '', darkXColorTertiaryShadeContrast: theme.dark.colors.XColorTertiaryShadeContrast || '', darkXColorTertiaryTint: theme.dark.colors.XColorTertiaryTint || '', darkXColorTertiaryTintContrast: theme.dark.colors.XColorTertiaryTintContrast || '', darkXColorSuccess: theme.dark.colors.XColorSuccess || '', darkXColorSuccessContrast: theme.dark.colors.XColorSuccessContrast || '', darkXColorSuccessShade: theme.dark.colors.XColorSuccessShade || '', darkXColorSuccessShadeContrast: theme.dark.colors.XColorSuccessShadeContrast || '', darkXColorSuccessTint: theme.dark.colors.XColorSuccessTint || '', darkXColorSuccessTintContrast: theme.dark.colors.XColorSuccessTintContrast || '', darkXColorWarning: theme.dark.colors.XColorWarning || '', darkXColorWarningContrast: theme.dark.colors.XColorWarningContrast || '', darkXColorWarningShade: theme.dark.colors.XColorWarningShade || '', darkXColorWarningShadeContrast: theme.dark.colors.XColorWarningShadeContrast || '', darkXColorWarningTint: theme.dark.colors.XColorWarningTint || '', darkXColorWarningTintContrast: theme.dark.colors.XColorWarningTintContrast || '', darkXColorDanger: theme.dark.colors.XColorDanger || '', darkXColorDangerContrast: theme.dark.colors.XColorDangerContrast || '', darkXColorDangerShade: theme.dark.colors.XColorDangerShade || '', darkXColorDangerShadeContrast: theme.dark.colors.XColorDangerShadeContrast || '', darkXColorDangerTint: theme.dark.colors.XColorDangerTint || '', darkXColorDangerTintContrast: theme.dark.colors.XColorDangerTintContrast || '', darkXColorDark: theme.dark.colors.XColorDark || '', darkXColorDarkContrast: theme.dark.colors.XColorDarkContrast || '', darkXColorDarkShade: theme.dark.colors.XColorDarkShade || '', darkXColorDarkShadeContrast: theme.dark.colors.XColorDarkShadeContrast || '', darkXColorDarkTint: theme.dark.colors.XColorDarkTint || '', darkXColorDarkTintContrast: theme.dark.colors.XColorDarkTintContrast || '', darkXColorMedium: theme.dark.colors.XColorMedium || '', darkXColorMediumContrast: theme.dark.colors.XColorMediumContrast || '', darkXColorMediumShade: theme.dark.colors.XColorMediumShade || '', darkXColorMediumShadeContrast: theme.dark.colors.XColorMediumShadeContrast || '', darkXColorMediumTint: theme.dark.colors.XColorMediumTint || '', darkXColorMediumTintContrast: theme.dark.colors.XColorMediumTintContrast || '', darkXColorLight: theme.dark.colors.XColorLight || '', darkXColorLightContrast: theme.dark.colors.XColorLightContrast || '', darkXColorLightShade: theme.dark.colors.XColorLightShade || '', darkXColorLightShadeContrast: theme.dark.colors.XColorLightShadeContrast || '', darkXColorLightTint: theme.dark.colors.XColorLightTint || '', darkXColorLightTintContrast: theme.dark.colors.XColorLightTintContrast || '', //#endregion // //#region Light ... lightXColorPrimary: theme.light.colors.XColorPrimary || '', lightXColorPrimaryContrast: theme.light.colors.XColorPrimaryContrast || '', lightXColorPrimaryShade: theme.light.colors.XColorPrimaryShade || '', lightXColorPrimaryShadeContrast: theme.light.colors.XColorPrimaryShadeContrast || '', lightXColorPrimaryTint: theme.light.colors.XColorPrimaryTint || '', lightXColorPrimaryTintContrast: theme.light.colors.XColorPrimaryTintContrast || '', lightXColorSecondary: theme.light.colors.XColorSecondary || '', lightXColorSecondaryContrast: theme.light.colors.XColorSecondaryContrast || '', lightXColorSecondaryShade: theme.light.colors.XColorSecondaryShade || '', lightXColorSecondaryShadeContrast: theme.light.colors.XColorSecondaryShadeContrast || '', lightXColorSecondaryTint: theme.light.colors.XColorSecondaryTint || '', lightXColorSecondaryTintContrast: theme.light.colors.XColorSecondaryTintContrast || '', lightXColorTertiary: theme.light.colors.XColorTertiary || '', lightXColorTertiaryContrast: theme.light.colors.XColorTertiaryContrast || '', lightXColorTertiaryShade: theme.light.colors.XColorTertiaryShade || '', lightXColorTertiaryShadeContrast: theme.light.colors.XColorTertiaryShadeContrast || '', lightXColorTertiaryTint: theme.light.colors.XColorTertiaryTint || '', lightXColorTertiaryTintContrast: theme.light.colors.XColorTertiaryTintContrast || '', lightXColorSuccess: theme.light.colors.XColorSuccess || '', lightXColorSuccessContrast: theme.light.colors.XColorSuccessContrast || '', lightXColorSuccessShade: theme.light.colors.XColorSuccessShade || '', lightXColorSuccessShadeContrast: theme.light.colors.XColorSuccessShadeContrast || '', lightXColorSuccessTint: theme.light.colors.XColorSuccessTint || '', lightXColorSuccessTintContrast: theme.light.colors.XColorSuccessTintContrast || '', lightXColorWarning: theme.light.colors.XColorWarning || '', lightXColorWarningContrast: theme.light.colors.XColorWarningContrast || '', lightXColorWarningShade: theme.light.colors.XColorWarningShade || '', lightXColorWarningShadeContrast: theme.light.colors.XColorWarningShadeContrast || '', lightXColorWarningTint: theme.light.colors.XColorWarningTint || '', lightXColorWarningTintContrast: theme.light.colors.XColorWarningTintContrast || '', lightXColorDanger: theme.light.colors.XColorDanger || '', lightXColorDangerContrast: theme.light.colors.XColorDangerContrast || '', lightXColorDangerShade: theme.light.colors.XColorDangerShade || '', lightXColorDangerShadeContrast: theme.light.colors.XColorDangerShadeContrast || '', lightXColorDangerTint: theme.light.colors.XColorDangerTint || '', lightXColorDangerTintContrast: theme.light.colors.XColorDangerTintContrast || '', lightXColorDark: theme.light.colors.XColorDark || '', lightXColorDarkContrast: theme.light.colors.XColorDarkContrast || '', lightXColorDarkShade: theme.light.colors.XColorDarkShade || '', lightXColorDarkShadeContrast: theme.light.colors.XColorDarkShadeContrast || '', lightXColorDarkTint: theme.light.colors.XColorDarkTint || '', lightXColorDarkTintContrast: theme.light.colors.XColorDarkTintContrast || '', lightXColorMedium: theme.light.colors.XColorMedium || '', lightXColorMediumContrast: theme.light.colors.XColorMediumContrast || '', lightXColorMediumShade: theme.light.colors.XColorMediumShade || '', lightXColorMediumShadeContrast: theme.light.colors.XColorMediumShadeContrast || '', lightXColorMediumTint: theme.light.colors.XColorMediumTint || '', lightXColorMediumTintContrast: theme.light.colors.XColorMediumTintContrast || '', lightXColorLight: theme.light.colors.XColorLight || '', lightXColorLightContrast: theme.light.colors.XColorLightContrast || '', lightXColorLightShade: theme.light.colors.XColorLightShade || '', lightXColorLightShadeContrast: theme.light.colors.XColorLightShadeContrast || '', lightXColorLightTint: theme.light.colors.XColorLightTint || '', lightXColorLightTintContrast: theme.light.colors.XColorLightTintContrast || '', //#endregion } as XThemeFormModel; } /** * convert to XThemePack * * @param form an instance of XThemeFormModel ... */ export function formToTheme(form: XThemeFormModel) { // if (!form) { return getEmptyThemePack(); } // return { // name: form.name || '', // // Dark ... dark: { type: XThemeType.Dark, colors: { XColorPrimary: form.darkXColorPrimary || '', XColorPrimaryContrast: form.darkXColorPrimaryContrast || '', XColorPrimaryShade: form.darkXColorPrimaryShade || '', XColorPrimaryShadeContrast: form.darkXColorPrimaryShadeContrast || '', XColorPrimaryTint: form.darkXColorPrimaryTint || '', XColorPrimaryTintContrast: form.darkXColorPrimaryTintContrast || '', XColorSecondary: form.darkXColorSecondary || '', XColorSecondaryContrast: form.darkXColorSecondaryContrast || '', XColorSecondaryShade: form.darkXColorSecondaryShade || '', XColorSecondaryShadeContrast: form.darkXColorSecondaryShadeContrast || '', XColorSecondaryTint: form.darkXColorSecondaryTint || '', XColorSecondaryTintContrast: form.darkXColorSecondaryTintContrast || '', XColorTertiary: form.darkXColorTertiary || '', XColorTertiaryContrast: form.darkXColorTertiaryContrast || '', XColorTertiaryShade: form.darkXColorTertiaryShade || '', XColorTertiaryShadeContrast: form.darkXColorTertiaryShadeContrast || '', XColorTertiaryTint: form.darkXColorTertiaryTint || '', XColorTertiaryTintContrast: form.darkXColorTertiaryTintContrast || '', XColorSuccess: form.darkXColorSuccess || '', XColorSuccessContrast: form.darkXColorSuccessContrast || '', XColorSuccessShade: form.darkXColorSuccessShade || '', XColorSuccessShadeContrast: form.darkXColorSuccessShadeContrast || '', XColorSuccessTint: form.darkXColorSuccessTint || '', XColorSuccessTintContrast: form.darkXColorSuccessTintContrast || '', XColorWarning: form.darkXColorWarning || '', XColorWarningContrast: form.darkXColorWarningContrast || '', XColorWarningShade: form.darkXColorWarningShade || '', XColorWarningShadeContrast: form.darkXColorWarningShadeContrast || '', XColorWarningTint: form.darkXColorWarningTint || '', XColorWarningTintContrast: form.darkXColorWarningTintContrast || '', XColorDanger: form.darkXColorDanger || '', XColorDangerContrast: form.darkXColorDangerContrast || '', XColorDangerShade: form.darkXColorDangerShade || '', XColorDangerShadeContrast: form.darkXColorDangerShadeContrast || '', XColorDangerTint: form.darkXColorDangerTint || '', XColorDangerTintContrast: form.darkXColorDangerTintContrast || '', XColorDark: form.darkXColorDark || '', XColorDarkContrast: form.darkXColorDarkContrast || '', XColorDarkShade: form.darkXColorDarkShade || '', XColorDarkShadeContrast: form.darkXColorDarkShadeContrast || '', XColorDarkTint: form.darkXColorDarkTint || '', XColorDarkTintContrast: form.darkXColorDarkTintContrast || '', XColorMedium: form.darkXColorMedium || '', XColorMediumContrast: form.darkXColorMediumContrast || '', XColorMediumShade: form.darkXColorMediumShade || '', XColorMediumShadeContrast: form.darkXColorMediumShadeContrast || '', XColorMediumTint: form.darkXColorMediumTint || '', XColorMediumTintContrast: form.darkXColorMediumTintContrast || '', XColorLight: form.darkXColorLight || '', XColorLightContrast: form.darkXColorLightContrast || '', XColorLightShade: form.darkXColorLightShade || '', XColorLightShadeContrast: form.darkXColorLightShadeContrast || '', XColorLightTint: form.darkXColorLightTint || '', XColorLightTintContrast: form.darkXColorLightTintContrast || '', }, }, // // Light ... light: { type: XThemeType.Light, colors: { XColorPrimary: form.lightXColorPrimary || '', XColorPrimaryContrast: form.lightXColorPrimaryContrast || '', XColorPrimaryShade: form.lightXColorPrimaryShade || '', XColorPrimaryShadeContrast: form.lightXColorPrimaryShadeContrast || '', XColorPrimaryTint: form.lightXColorPrimaryTint || '', XColorPrimaryTintContrast: form.lightXColorPrimaryTintContrast || '', XColorSecondary: form.lightXColorSecondary || '', XColorSecondaryContrast: form.lightXColorSecondaryContrast || '', XColorSecondaryShade: form.lightXColorSecondaryShade || '', XColorSecondaryShadeContrast: form.lightXColorSecondaryShadeContrast || '', XColorSecondaryTint: form.lightXColorSecondaryTint || '', XColorSecondaryTintContrast: form.lightXColorSecondaryTintContrast || '', XColorTertiary: form.lightXColorTertiary || '', XColorTertiaryContrast: form.lightXColorTertiaryContrast || '', XColorTertiaryShade: form.lightXColorTertiaryShade || '', XColorTertiaryShadeContrast: form.lightXColorTertiaryShadeContrast || '', XColorTertiaryTint: form.lightXColorTertiaryTint || '', XColorTertiaryTintContrast: form.lightXColorTertiaryTintContrast || '', XColorSuccess: form.lightXColorSuccess || '', XColorSuccessContrast: form.lightXColorSuccessContrast || '', XColorSuccessShade: form.lightXColorSuccessShade || '', XColorSuccessShadeContrast: form.lightXColorSuccessShadeContrast || '', XColorSuccessTint: form.lightXColorSuccessTint || '', XColorSuccessTintContrast: form.lightXColorSuccessTintContrast || '', XColorWarning: form.lightXColorWarning || '', XColorWarningContrast: form.lightXColorWarningContrast || '', XColorWarningShade: form.lightXColorWarningShade || '', XColorWarningShadeContrast: form.lightXColorWarningShadeContrast || '', XColorWarningTint: form.lightXColorWarningTint || '', XColorWarningTintContrast: form.lightXColorWarningTintContrast || '', XColorDanger: form.lightXColorDanger || '', XColorDangerContrast: form.lightXColorDangerContrast || '', XColorDangerShade: form.lightXColorDangerShade || '', XColorDangerShadeContrast: form.lightXColorDangerShadeContrast || '', XColorDangerTint: form.lightXColorDangerTint || '', XColorDangerTintContrast: form.lightXColorDangerTintContrast || '', XColorDark: form.lightXColorDark || '', XColorDarkContrast: form.lightXColorDarkContrast || '', XColorDarkShade: form.lightXColorDarkShade || '', XColorDarkShadeContrast: form.lightXColorDarkShadeContrast || '', XColorDarkTint: form.lightXColorDarkTint || '', XColorDarkTintContrast: form.lightXColorDarkTintContrast || '', XColorMedium: form.lightXColorMedium || '', XColorMediumContrast: form.lightXColorMediumContrast || '', XColorMediumShade: form.lightXColorMediumShade || '', XColorMediumShadeContrast: form.lightXColorMediumShadeContrast || '', XColorMediumTint: form.lightXColorMediumTint || '', XColorMediumTintContrast: form.lightXColorMediumTintContrast || '', XColorLight: form.lightXColorLight || '', XColorLightContrast: form.lightXColorLightContrast || '', XColorLightShade: form.lightXColorLightShade || '', XColorLightShadeContrast: form.lightXColorLightShadeContrast || '', XColorLightTint: form.lightXColorLightTint || '', XColorLightTintContrast: form.lightXColorLightTintContrast || '', }, }, } as XThemePack; } /** * prepare an empty XThemePack instance ... */ export function getEmptyThemePack() { return { name: '', dark: { type: XThemeType.Dark, colors: { XColorPrimary: '', XColorPrimaryContrast: '', XColorPrimaryShade: '', XColorPrimaryShadeContrast: '', XColorPrimaryTint: '', XColorPrimaryTintContrast: '', XColorSecondary: '', XColorSecondaryContrast: '', XColorSecondaryShade: '', XColorSecondaryShadeContrast: '', XColorSecondaryTint: '', XColorSecondaryTintContrast: '', XColorTertiary: '', XColorTertiaryContrast: '', XColorTertiaryShade: '', XColorTertiaryShadeContrast: '', XColorTertiaryTint: '', XColorTertiaryTintContrast: '', XColorSuccess: '', XColorSuccessContrast: '', XColorSuccessShade: '', XColorSuccessShadeContrast: '', XColorSuccessTint: '', XColorSuccessTintContrast: '', XColorWarning: '', XColorWarningContrast: '', XColorWarningShade: '', XColorWarningShadeContrast: '', XColorWarningTint: '', XColorWarningTintContrast: '', XColorDanger: '', XColorDangerContrast: '', XColorDangerShade: '', XColorDangerShadeContrast: '', XColorDangerTint: '', XColorDangerTintContrast: '', XColorDark: '', XColorDarkContrast: '', XColorDarkShade: '', XColorDarkShadeContrast: '', XColorDarkTint: '', XColorDarkTintContrast: '', XColorMedium: '', XColorMediumContrast: '', XColorMediumShade: '', XColorMediumShadeContrast: '', XColorMediumTint: '', XColorMediumTintContrast: '', XColorLight: '', XColorLightContrast: '', XColorLightShade: '', XColorLightShadeContrast: '', XColorLightTint: '', XColorLightTintContrast: '', }, }, light: { type: XThemeType.Light, colors: { XColorPrimary: '', XColorPrimaryContrast: '', XColorPrimaryShade: '', XColorPrimaryShadeContrast: '', XColorPrimaryTint: '', XColorPrimaryTintContrast: '', XColorSecondary: '', XColorSecondaryContrast: '', XColorSecondaryShade: '', XColorSecondaryShadeContrast: '', XColorSecondaryTint: '', XColorSecondaryTintContrast: '', XColorTertiary: '', XColorTertiaryContrast: '', XColorTertiaryShade: '', XColorTertiaryShadeContrast: '', XColorTertiaryTint: '', XColorTertiaryTintContrast: '', XColorSuccess: '', XColorSuccessContrast: '', XColorSuccessShade: '', XColorSuccessShadeContrast: '', XColorSuccessTint: '', XColorSuccessTintContrast: '', XColorWarning: '', XColorWarningContrast: '', XColorWarningShade: '', XColorWarningShadeContrast: '', XColorWarningTint: '', XColorWarningTintContrast: '', XColorDanger: '', XColorDangerContrast: '', XColorDangerShade: '', XColorDangerShadeContrast: '', XColorDangerTint: '', XColorDangerTintContrast: '', XColorDark: '', XColorDarkContrast: '', XColorDarkShade: '', XColorDarkShadeContrast: '', XColorDarkTint: '', XColorDarkTintContrast: '', XColorMedium: '', XColorMediumContrast: '', XColorMediumShade: '', XColorMediumShadeContrast: '', XColorMediumTint: '', XColorMediumTintContrast: '', XColorLight: '', XColorLightContrast: '', XColorLightShade: '', XColorLightShadeContrast: '', XColorLightTint: '', XColorLightTintContrast: '', }, }, } as XThemePack; } /** * prepare an empty XThemeBaseFormModel instance ... */ export function getEmptyThemeBaseFormModel() { return { name: '', } as XThemeBaseFormModel; } /** * prepare an empty XThemeLightFormModel instance ... */ export function getEmptyThemeLightFormModel() { return { lightXColorPrimary: '', lightXColorPrimaryContrast: '', lightXColorPrimaryShade: '', lightXColorPrimaryShadeContrast: '', lightXColorPrimaryTint: '', lightXColorPrimaryTintContrast: '', lightXColorSecondary: '', lightXColorSecondaryContrast: '', lightXColorSecondaryShade: '', lightXColorSecondaryShadeContrast: '', lightXColorSecondaryTint: '', lightXColorSecondaryTintContrast: '', lightXColorTertiary: '', lightXColorTertiaryContrast: '', lightXColorTertiaryShade: '', lightXColorTertiaryShadeContrast: '', lightXColorTertiaryTint: '', lightXColorTertiaryTintContrast: '', lightXColorSuccess: '', lightXColorSuccessContrast: '', lightXColorSuccessShade: '', lightXColorSuccessShadeContrast: '', lightXColorSuccessTint: '', lightXColorSuccessTintContrast: '', lightXColorWarning: '', lightXColorWarningContrast: '', lightXColorWarningShade: '', lightXColorWarningShadeContrast: '', lightXColorWarningTint: '', lightXColorWarningTintContrast: '', lightXColorDanger: '', lightXColorDangerContrast: '', lightXColorDangerShade: '', lightXColorDangerShadeContrast: '', lightXColorDangerTint: '', lightXColorDangerTintContrast: '', lightXColorDark: '', lightXColorDarkContrast: '', lightXColorDarkShade: '', lightXColorDarkShadeContrast: '', lightXColorDarkTint: '', lightXColorDarkTintContrast: '', lightXColorMedium: '', lightXColorMediumContrast: '', lightXColorMediumShade: '', lightXColorMediumShadeContrast: '', lightXColorMediumTint: '', lightXColorMediumTintContrast: '', lightXColorLight: '', lightXColorLightContrast: '', lightXColorLightShade: '', lightXColorLightShadeContrast: '', lightXColorLightTint: '', lightXColorLightTintContrast: '', } as XThemeLightFormModel; } /** * prepare an empty XThemeDarkFormModel instance ... */ export function getEmptyThemeDarkFormModel() { return { darkXColorPrimary: '', darkXColorPrimaryContrast: '', darkXColorPrimaryShade: '', darkXColorPrimaryShadeContrast: '', darkXColorPrimaryTint: '', darkXColorPrimaryTintContrast: '', darkXColorSecondary: '', darkXColorSecondaryContrast: '', darkXColorSecondaryShade: '', darkXColorSecondaryShadeContrast: '', darkXColorSecondaryTint: '', darkXColorSecondaryTintContrast: '', darkXColorTertiary: '', darkXColorTertiaryContrast: '', darkXColorTertiaryShade: '', darkXColorTertiaryShadeContrast: '', darkXColorTertiaryTint: '', darkXColorTertiaryTintContrast: '', darkXColorSuccess: '', darkXColorSuccessContrast: '', darkXColorSuccessShade: '', darkXColorSuccessShadeContrast: '', darkXColorSuccessTint: '', darkXColorSuccessTintContrast: '', darkXColorWarning: '', darkXColorWarningContrast: '', darkXColorWarningShade: '', darkXColorWarningShadeContrast: '', darkXColorWarningTint: '', darkXColorWarningTintContrast: '', darkXColorDanger: '', darkXColorDangerContrast: '', darkXColorDangerShade: '', darkXColorDangerShadeContrast: '', darkXColorDangerTint: '', darkXColorDangerTintContrast: '', darkXColorDark: '', darkXColorDarkContrast: '', darkXColorDarkShade: '', darkXColorDarkShadeContrast: '', darkXColorDarkTint: '', darkXColorDarkTintContrast: '', darkXColorMedium: '', darkXColorMediumContrast: '', darkXColorMediumShade: '', darkXColorMediumShadeContrast: '', darkXColorMediumTint: '', darkXColorMediumTintContrast: '', darkXColorLight: '', darkXColorLightContrast: '', darkXColorLightShade: '', darkXColorLightShadeContrast: '', darkXColorLightTint: '', darkXColorLightTintContrast: '', } as XThemeDarkFormModel; } /** * prepare an empty XThemeFormModel instance ... */ export function getEmptyThemeFormModel() { return { ...getEmptyThemeBaseFormModel(), ...getEmptyThemeDarkFormModel(), ...getEmptyThemeLightFormModel(), } as XThemeFormModel; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-manager\x-theme-manager.component.html
{{ item.data.name }} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-manager\x-theme-manager.component.scss :host ::ng-deep x-color { --size: 24px !important; display: inline-block; } .actions { margin: { top: 8px; bottom: 8px; } } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-manager\x-theme-manager.component.ts import { nameof, assign, XParam, toArray, hasChild, XUiEvent, cloneJson, parseJson, isFunction, isSameType, XThemeType, XThemePack, isSameObject, XResourceIDs, XDialogResult, XExceptionIDs, XBaseKeyValue, XStandardType, XPickerOptions, toNormalString, XOneOrManyType, XModelProperty, XThemeDescriptor, XModalButtonRole, XModelKeyProvider, isNullOrUndefined, isNullOrEmptyString, XThemeTypeIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XThemeManagerTabs, XThemeManagerAction, XThemeManagerActionModel, XThemeManagerContainerComponent, } from './x-theme-manager.typings'; import { XTabsAction, XTabChangeEvent, XTabsActionModel, } from '../../x-tabs/x-tabs.typings'; import { XListItem, XListAction, XListActionModel, XListItemSlideOption, XListFilteringHandler, defaultListFilteringHandler, } from '../../x-list/x-list.typings'; import { Subject, Subscription } from 'rxjs'; import { XActionBarItem, XActionBarAction, XActionBarActionModel, DefaultActionBarItemIds, defaultActionBarSetItem, defaultActionBarUploadItem, XActionBarActionFiredModel, } from '../../x-action-bar/x-action-bar.typings'; import { XSearchBarType, XSearchBarAction, XSearchBarActionModel, XSearchBarEventIdentifier, } from '../../x-search-bar/x-search-bar.typings'; import { XFileUploadAction, XFileUploadActionModel, } from '../../x-file-upload/x-file-upload.typings'; import { getEmptyThemePack } from '../x-theme.tools'; import { XIconNames } from '../../x-icon/x-icon.typings'; import { XModelPresenterAction, XModelPresenterActionModel, } from '../../x-model-presenter/x-model-presenter.typings'; import { XButtonType } from '../../x-button/x-button.typings'; import { Component, ChangeDetectionStrategy } from '@angular/core'; import { XSlotLayout, XSlotName } from '../../x-slotter/x-slotter.typings'; import { XPopoverComponent } from '../../dialogs/x-popover/x-popover.component'; import { XColorPickerOutputFormat } from '../../x-color-picker/x-color-picker.typings'; import { XFileDropAreaActionModel } from '../../x-file-drop-area/x-file-drop-area.typings'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-theme-manager', templateUrl: './x-theme-manager.component.html', styleUrls: ['./x-theme-manager.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XThemeManagerComponent extends XThemeManagerContainerComponent { // //#region Props ... // private loadingObject: HTMLIonLoadingElement; private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // readonly SlotNames = Object.assign({}, XSlotName); readonly Tabs = Object.assign({}, XThemeManagerTabs); readonly SlotLayouts = Object.assign({}, XSlotLayout); readonly ButtonTypes = Object.assign({}, XButtonType); readonly ColorNames = Object.assign({}, XColorWithBrightness); readonly themeUploadListActionProvider = new Subject(); readonly allowedThemeExtensions: XStandardType> = [ '.json', ]; readonly themeUploadActionProvider = new Subject(); readonly themeUploadListActionBarHideActions: XStandardType< XOneOrManyType >; readonly themeModelPresenterActionProvider = new Subject(); readonly themeUploadListActionbarActions: XStandardType< XOneOrManyType >; readonly themeUploadFileDropAreaActionProvider = new Subject(); // canSaveTheme = false; listItems: XListItem[]; selectedTheme: XThemePack = null; uploadThemes: XOneOrManyType; currentTab: number = this.Tabs.List; baseTheme: Readonly = null; showList: XStandardType = true; hiddenThemModelKeys: XOneOrManyType = [ `${nameof('dark')}.${nameof('type')}`, `${nameof('light')}.${nameof('type')}`, ]; themeKeyProvider: XModelKeyProvider = (key) => { // let result = key as string; // switch (key) { // case nameof('name'): result = this.resourceProvider(this.ResourceIDs.theme); break; // case nameof('dark'): result = this.resourceProvider(this.ResourceIDs.theme_dark); break; // case nameof('light'): result = this.resourceProvider(this.ResourceIDs.theme_light); break; // case nameof('colors'): result = this.resourceProvider(this.ResourceIDs.colors); break; // default: result = key as string; break; } // return result; }; listActionProvider = new Subject(); tabsActionProvider = new Subject(); searchBarType: XStandardType = XSearchBarType.Search; searchBarActionProvider = new Subject(); actionBarActionProvider = new Subject(); actionBarActions: XStandardType>; themeModelPresenterActionActions: XOneOrManyType = [ { // ...defaultActionBarSetItem, // title: this.ResourceIDs.save, disabled: true, // handler: async (id) => { await this.handleUpdateTheme(); }, }, ]; listFilteringHandler: XListFilteringHandler = defaultListFilteringHandler; //#endregion // //#region LifeCycles ... async afterViewInit() { super.afterViewInit(); // await this.startUp(); } onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region UI Provider ... getColorValue(key: string, value: string) { return { key, value, } as XBaseKeyValue; } //#endregion // //#region UI Handler ... // async handleSelectedTabChanged(event: XTabChangeEvent) { this.currentTab = event.index; } async handleListRefresh() { // await this.startUp(); // if (!isNullOrUndefined(this.listEmptyRefresh)) { this.listEmptyRefresh.emit(); } } async handleListActionBarActionFired(model: XActionBarActionFiredModel) { // if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) { return; } // switch (model.action) { // case DefaultActionBarItemIds.Upload: await this.handleUploadTheme(); break; } // if (!isNullOrUndefined(this.listActionBarActionFired)) { this.listActionBarActionFired.emit(model); } } async handleListSearchBarOnEvent(event: XSearchBarEventIdentifier) { // if (!isNullOrUndefined(this.listSearchBarOnEvent)) { this.listSearchBarOnEvent.emit(event); } } async handleListSearchBarQueryChange(event: string) { // if (!isNullOrUndefined(this.listSearchBarQueryChange)) { this.listSearchBarQueryChange.emit(event); } } async handleThemeUploadActionFired(model: XActionBarActionFiredModel) { // // Validate Args ... if (isNullOrUndefined(model) || isNullOrEmptyString(model.action)) { return; } // switch (model.action) { // case DefaultActionBarItemIds.Upload: await this.handleThemesImport(); break; } } async handleThemeUploadFileChanged(files: XOneOrManyType) { this.uploadThemes = files; } // //#region ModelPresenter Handlers ... async handleThemePropertyActionMenuClicked( key: string, prefix: string, value: any ) { // if (isNullOrEmptyString(key)) { return; } // const onlyIcon = false; const slideOptions: XListItemSlideOption[] = []; // // Edit ... slideOptions.push({ id: 'property_edit', icon: await this.getValueAsync(this.propertyEditIcon), title: this.ResourceIDs.edit, color: isNullOrUndefined(value) ? await this.getValueAsync(this.emptyPropertyEditIconColor) : await this.getValueAsync(this.propertyEditIconColor), slot: 'start', onlyIcon, handler: async () => { await this.handleThemePropertyEdit(key, prefix, value); }, }); // // Menu Items ... const item: XListItem = { data: '', slideOptions, }; // const popOver = await this.managerService.dialogService.presentPopover({ component: XPopoverComponent, componentProps: assign({}, { key: XParam.Item, value: item }), translucent: true, showBackdrop: true, event, }); // const { data } = await popOver.onWillDismiss(); if (!data || !data.id || !data.data) { return; } // const optionId = data.id.toString() as string; const option = item && item.slideOptions ? item.slideOptions.find((so) => so.id === optionId) : null; if (!option) { return; } // const handler = option.handler; if (!handler || !isFunction(handler)) { return; } // // Run Handler ... await handler(); } async handleThemePropertyEdit(key: string, prefix: string, value: any) { // if (isNullOrEmptyString(key)) { return; } // await this.colorPickerDialogService.openDialog({ // title: key, // selectedColor: value, // showColorInput: true, showPresetColors: false, showCopyToClipboard: true, // cardColor: await this.getValueAsync(this.cardColor), cardForegroundColor: await this.getValueAsync(this.cardForegroundColor), // representColorFormats: [XColorPickerOutputFormat.XHEX], }); // const subscription = this.colorPickerDialogService.onResult .asObservable() .subscribe((result) => { // if ( result.result !== XDialogResult.Ok || !result.payload || isNullOrEmptyString(result.payload) ) { return; } // const value = result.payload as string; this.themeModelPresenterActionProvider.next({ action: XModelPresenterAction.SetProperty, payload: { key, value, prefix, } as XModelProperty, }); // subscription.unsubscribe(); }); } async handleThemeContentChanged(event: any) { // const isTheme = isSameType(event, this.selectedTheme); if (!isTheme) { return; } // const isThemeChanged = !isSameObject(this.baseTheme, this.selectedTheme); this.canSaveTheme = isThemeChanged; // toArray(this.themeModelPresenterActionActions)[0].disabled = !this.canSaveTheme; // this.themeChange.emit(isThemeChanged); this.handleChangeDetection(); } async handleUpdateTheme() { // if (!this.selectedTheme || !this.baseTheme || !this.canSaveTheme) { return; } // await this.managerService.dialogService.presentAreYouSureYesNoDialog( async () => { await this.updateTheme(this.selectedTheme); } ); } //#endregion //#endregion // //#region Actions ... async back() { // switch (this.currentTab) { // case this.Tabs.List: this.baseTheme = null; this.selectedTheme = null; break; // case this.Tabs.Details: await this.changeTab(this.Tabs.List); break; // case this.Tabs.Import: // this.uploadThemes = []; this.themeUploadActionProvider.next({ action: XFileUploadAction.CLEAR_LIST, }); await this.changeTab(this.Tabs.List); break; // case this.Tabs.Edit: this.baseTheme = null; this.selectedTheme = null; this.canSaveTheme = false; this.themeChange.emit(false); await this.changeTab(this.Tabs.List); break; } } async clearList() { // this.listItems = []; this.handleChangeDetection(); } async setTheme(theme: XThemePack, whichType: XThemeTypeIdentifier) { // if (!theme && isNullOrEmptyString(theme.name)) { return; } // const restart = await this.getOptionalValueAsync(this.restartAfterSetTheme); // const isSetted = await this.managerService.themeManagerService.setTheme( theme, whichType, true, restart ); if (isSetted) { // await this.prepareListItems(); // this.managerService.settingsService.restart(); } } async editTheme(theme: XThemePack) { // if (!theme || !isNullOrUndefined(this.loadingObject)) { return; } // await this.presentLoading(); // this.baseTheme = cloneJson(theme); this.selectedTheme = { ...theme, }; await this.changeTab(this.Tabs.Edit); this.handleChangeDetection(); } async cloneTheme(theme: XThemePack) { // if (!theme) { return; } // await this.managerService.dialogService.presentAlert({ subHeader: XResourceIDs.theme, message: XResourceIDs.theme_clone_title, inputs: [ { type: 'text', name: 'name', placeholder: XResourceIDs.theme_name_description, }, ], buttons: [ { text: XResourceIDs.clone, role: XModalButtonRole.Selected, cssClass: ['btn-selected'], handler: async (value) => { // if (value && value.name && !isNullOrEmptyString(value.name)) { // const themeName = toNormalString(theme.name); const clonedThemeName = toNormalString(value.name as string); const isCloned = await this.managerService.themeManagerService.cloneTheme( themeName, clonedThemeName, false ); // if (isCloned) { // this.showSuccess(); await this.prepareListItems(); } else { this.showError(XExceptionIDs.ActionFailed); } } else { this.showError(XExceptionIDs.InvalidData); } }, }, { text: XResourceIDs.cancel, role: XModalButtonRole.Cancel, cssClass: ['btn-cancel'], handler: () => {}, }, ], }); } async downloadTheme(theme: XThemePack) { // if (!theme) { return; } // await this.managerService.themeManagerService.exportTheme(theme.name); } async removeTheme(theme: XThemePack) { // if (!theme) { return; } // await this.managerService.dialogService.presentAreYouSureYesNoDialog(() => { this.managerService.themeManagerService .removeTheme(toNormalString(theme.name), false) .then((isRemoved) => { if (isRemoved) { // this.showSuccess(); this.prepareListItems(); } else { this.showError(); } }); }); } async previewTheme(theme: XThemePack) { // if (!theme || !isNullOrUndefined(this.loadingObject)) { return; } // await this.presentLoading(); // this.selectedTheme = { ...theme, }; await this.changeTab(this.Tabs.Details); this.handleChangeDetection(); } async saveTheme(theme: XThemePack) { // if (!theme) { return false; } // if ( isNullOrEmptyString(theme.name) || (await this.managerService.themeManagerService.isThemeExists(theme.name)) ) { this.showError(XExceptionIDs.Duplicate); return false; } // const isSaved = await this.managerService.themeManagerService.saveTheme( theme, false ); // if (isSaved) { // this.themeChange.emit(false); this.managerService.settingsService.restart(); } return isSaved; } async updateTheme(theme: XThemePack) { // if (!theme || isNullOrEmptyString(theme.name)) { return false; } // const isExists = await this.managerService.themeManagerService.isThemeExists(theme.name); if (!isExists) { this.showError(XExceptionIDs.NotFound); return false; } // const isUpdated = await this.managerService.themeManagerService.updateTheme( theme.name, theme, false, true ); // if (isUpdated) { // this.themeChange.emit(false); this.managerService.settingsService.restart(); } // return isUpdated; } //#endregion // //#region Private ... // //#region Handler Registerrers ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // switch (model.action) { // case XThemeManagerAction.Refresh: this.detectChanges(); break; // case XThemeManagerAction.Back: await this.back(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // //#region Private Actions ... private async startUp() { // this.tabChange.emit(this.currentTab); await this.prepareActionBarActions(); await this.prepareListItems(); } private async prepareListItems() { // this.listItems = null; // const loadingDialog = await this.managerService.dialogService.presentLoading({ showBackdrop: true, backdropDismiss: false, message: this.resourceProvider(XResourceIDs.loading), }); // const currentTheme = await this.managerService.themeManagerService.getCurrentTheme(); const themes = await this.managerService.themeManagerService.getThemes(); if (!currentTheme || !hasChild(themes)) { // await this.clearList(); await loadingDialog.dismiss(); return; } // // Prepare List Items ... this.listItems = themes.map((theme) => { // const isCurrent = toNormalString(theme.name) === toNormalString(currentTheme.name); // return { data: theme, slideOptions: [ // // Remove ... { id: 'delete_theme', icon: XIconNames.remove, title: this.ResourceIDs.delete, color: XColorWithBrightness.Danger, onlyIcon: true, disabled: this.uiDisabled || this.loading || isCurrent, slot: 'end', handler: () => { this.removeTheme(theme); }, }, // // Set As Current ... { id: 'set_theme', icon: XIconNames.checked, title: this.ResourceIDs.set, color: XColorWithBrightness.Success, onlyIcon: true, disabled: this.uiDisabled || this.loading || toNormalString(theme.name) === toNormalString(currentTheme.name), slot: 'start', handler: () => { // // Prepare Picker Options for Theme Setting ... const options: XPickerOptions = { buttons: [ { text: XResourceIDs.set, role: XModalButtonRole.Selected, cssClass: ['btn-selected'], handler: async (value) => { // if (!value || !value.type || !value.type.value) { return; } // const type = value.type.value as XThemeTypeIdentifier; await this.setTheme(theme, type); }, }, { text: XResourceIDs.cancel, role: XModalButtonRole.Cancel, cssClass: ['btn-cancel'], }, ], columns: [ { name: 'type', options: [ { text: XResourceIDs.theme_light, value: XThemeType.Light, }, { text: XResourceIDs.theme_dark, value: XThemeType.Dark, }, ], }, ], }; // // Present Theme Picker ... this.managerService.dialogService.presentPicker(options); }, }, // // Check For Change Mode ... ...(isCurrent ? [ // // Change Mode ... { id: 'change_theme_mode', icon: XIconNames.contrast, title: this.ResourceIDs.theme_mode, color: XColorWithBrightness.Success, onlyIcon: true, disabled: this.uiDisabled || this.loading, slot: 'start', handler: async () => { // const currentType = await this.managerService.themeManagerService.getCurrentThemeType(); const type = currentType === XThemeType.Light ? XThemeType.Dark : XThemeType.Light; await this.setTheme(theme, type); }, }, ] : []), // // Preview ... { id: 'preview_theme', icon: XIconNames.preview, title: this.ResourceIDs.details, color: XColorWithBrightness.Secondary, onlyIcon: true, disabled: this.uiDisabled || this.loading, slot: 'start', handler: async () => { await this.previewTheme(theme); }, }, // // Edit ... { id: 'edit_theme', icon: XIconNames.edit, title: this.ResourceIDs.edit, color: XColorWithBrightness.Tertiary, onlyIcon: true, disabled: this.uiDisabled || this.loading, // || isCurrent, slot: 'start', handler: () => { this.editTheme(theme); }, }, // // Clone ... { id: 'clone_theme', icon: XIconNames.copy, title: this.ResourceIDs.clone, color: XColorWithBrightness.Success, onlyIcon: true, disabled: this.uiDisabled || this.loading, slot: 'start', handler: async () => { await this.cloneTheme(theme); }, }, // // Download ... { id: 'download_theme', icon: XIconNames.download, title: this.ResourceIDs.download, color: XColorWithBrightness.SecondaryShade, onlyIcon: true, disabled: this.uiDisabled || this.loading, slot: 'start', handler: async () => { await this.downloadTheme(theme); }, }, ], } as XListItem; }); // await loadingDialog.dismiss(); // this.handleChangeDetection(); } private handleChangeDetection() { // this.tabsActionProvider.next({ action: XTabsAction.Refresh, }); // this.listActionProvider.next({ action: XListAction.Refresh, }); // this.actionBarActionProvider.next({ action: XActionBarAction.Refresh, }); // this.searchBarActionProvider.next({ action: XSearchBarAction.Refresh, }); // this.themeUploadActionProvider.next({ action: XFileUploadAction.Refresh, }); // this.themeUploadListActionProvider.next({ action: XListAction.Refresh, }); // this.themeModelPresenterActionProvider.next({ action: XModelPresenterAction.Refresh, }); // this.themeUploadFileDropAreaActionProvider.next({ action: XFileUploadAction.Refresh, }); // this.managerService.dispatchResizeEvent(); // this.detectChanges(); } private async presentLoading() { // this.loadingObject = await this.managerService.dialogService.presentLoading( { message: this.resourceProvider(this.ResourceIDs.loading), } ); } private async changeTab(tab?: XThemeManagerTabs) { // if (!tab) { tab = this.Tabs.List; } // // // Prevent go forward if args is not ready ... if (this.loading || this.uiDisabled || this.currentTab === tab) { return; } // //#region Pre Change Actions ... // // Based On Current Tab ... switch (this.currentTab) { // case this.Tabs.List: break; // case this.Tabs.Details: break; // case this.Tabs.Import: break; // case this.Tabs.Edit: break; } // // Based On Dest Tab ... switch (tab) { // case this.Tabs.List: this.baseTheme = null; this.selectedTheme = null; break; // case this.Tabs.Details: // if (isNullOrUndefined(this.selectedTheme)) { return; } break; // case this.Tabs.Import: break; // case this.Tabs.Edit: // if (isNullOrUndefined(this.selectedTheme)) { return; } break; } //#endregion // // Change Current Tab ... this.currentTab = tab; this.detectChanges(); // //#region Post Change Actions ... switch (tab) { // case this.Tabs.List: break; // case this.Tabs.Details: break; // case this.Tabs.Import: break; // case this.Tabs.Edit: break; } //#endregion // this.tabChange.emit(tab); this.handleChangeDetection(); } private async handleUploadTheme() { await this.changeTab(this.Tabs.Import); } private async handleThemesImport() { // if (!this.hasChild(this.uploadThemes)) { return; } // const emptyTheme = getEmptyThemePack(); const importedThemes = await this.getArrayValueAsync(this.uploadThemes); // importedThemes.forEach(async (themeFile) => { // const fileReader = new FileReader(); fileReader.readAsText(themeFile); fileReader.onloadend = async (e) => { // if (!e || !e.target || !e.target.result) { return; } // try { // // Check Theme Valid ... const themePack = parseJson(e.target.result.toString()); if (!themePack) { // await this.issueThemeError( themeFile.name, XExceptionIDs.InavlidFile ); // return; } // // Check Theme Type ... const isCorrectThemeType = isSameType(themePack, emptyTheme); if (!isCorrectThemeType) { // await this.issueThemeError( themeFile.name, XExceptionIDs.UnsupportedFileType ); // return; } // // Check Theme Name and Existance ... if ( isNullOrEmptyString(themePack.name) || (await this.managerService.themeManagerService.isThemeExists( themePack.name )) ) { // this.issueThemeError(themeFile.name, XExceptionIDs.Duplicate); // return; } // const isSaved = await this.saveTheme(themePack); if (isSaved) { await this.prepareListItems(); } else { // await this.issueThemeError( themeFile.name, XExceptionIDs.ActionFailed ); // return; } } catch { await this.issueThemeError(themeFile.name, XExceptionIDs.InavlidFile); } }; }); // await this.back(); } private async issueThemeError(fileName: string, exception: XExceptionIDs) { // if (isNullOrEmptyString(fileName)) { return; } // const message = `${this.managerService.localizationService.getErrorMessage( exception )}_${fileName}`; // await this.managerService.notificationService.presentDangerNotification({ dissmissable: true, message, }); } //#endregion // //#region ActionBar Actions ... private async prepareActionBarActions() { // //#region Prepare Default Actions ... const hideActions: string | string[] = []; // const defaultActions: XOneOrManyType = []; // // Import ... const importId = DefaultActionBarItemIds.Upload.toString(); if (!hideActions.includes(importId)) { defaultActions.push({ // ...defaultActionBarUploadItem, // title: XResourceIDs.import, color: XColorWithBrightness.Success, // index: 1, disabled: this.uiDisabled, }); } //#endregion // if (!this.actionBarActions) { // this.actionBarActions = defaultActions; this.handleChangeDetection(); return; } // const actions = await this.getArrayValueAsync(this.actionBarActions); if (!hasChild(actions)) { // this.actionBarActions = defaultActions; this.handleChangeDetection(); return; } // this.actionBarActions = actions; this.handleChangeDetection(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-theme\x-theme-manager\x-theme-manager.typings.ts import { Input, Inject, NgZone, Output, Renderer2, Component, Injectable, ElementRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XResourceIDs, XBorderStyle, XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, XBorderStyleIdentifier, } from 'x-framework-core'; import { XCardContainer, XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../../x-card/x-card.typings'; import { XComponentListContainer, IXComponentListContainer, } from '../../x-list/x-list.typings'; import { XFileContainer, IXFileContainer, } from '../../classes/i-x-file.container'; import { concatMap, map } from 'rxjs/operators'; import { XActionBarActionFiredModel, XComponentActionBarContainer, IXComponentActionBarContainer, } from '../../x-action-bar/x-action-bar.typings'; import { ViewportRuler } from '@angular/cdk/overlay'; import { forkJoin, Observable, Subject } from 'rxjs'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../../classes/x-base-action.model'; import { XIconIdentifier, XIconNames } from '../../x-icon/x-icon.typings'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../../tokens/x-injectable-tokens'; import { IXFileUploadContainer } from '../../x-file-upload/x-file-upload.typings'; import { XFileUploadContainer } from './../../x-file-upload/x-file-upload.typings'; import { XSearchBarEventIdentifier } from '../../x-search-bar/x-search-bar.typings'; import { XFrameworkComponentsConfig } from '../../config/x-framework-components.config'; import { XColorPickerDialogService } from '../../x-color-picker/x-color-picker-dialog/x-color-picker-dialog.service'; export enum XThemeManagerAction { // Back = 'back', Refresh = 'refresh', } export type XThemeManagerActionIdentifier = XThemeManagerAction | string; export interface XThemeManagerActionModel extends XBaseActionModel {} export enum XThemeManagerTabs { List, Details, Edit, Import, } // //#region Inside Card Container ... // type TXSelectedComponentListContainer = Pick< IXComponentListContainer, | 'listCssClass' | 'listShowDivider' // // List Empty ... | 'listShowEmpty' | 'listEmptyActionProvider' | 'listEmptyColor' | 'listEmptyCssClass' | 'listEmptyForegroundColor' | 'listEmptyForegroundMessageColor' | 'listEmptyForegroundRefreshButtonColor' | 'listEmptyHasRefresh' | 'listEmptyMessage' | 'listEmptyMessageColor' | 'listEmptyRefresh' | 'listEmptyRefreshButtonColor' | 'listEmptyRefreshIcon' // // List Search ... | 'listSearchBarValue' | 'listSearchBarColor' | 'listSearchBarDebounce' | 'listSearchBarSearchInputColor' | 'listSearchBarForegroundSearchInputColor' | 'listSearchBarCancelButtonIcon' | 'listSearchBarCancelButtonTitle' | 'listSearchBarClearButtonIcon' | 'listSearchBarClearButtonIconColor' | 'listSearchBarCssClass' | 'listSearchBarEnterKeyHint' | 'listSearchBarForegroundColor' | 'listSearchBarKeyboardType' | 'listActionBarActionFired' | 'listSearchBarOnEvent' | 'listSearchBarQueryChange' | 'listSearchBarSearchButtonIcon' | 'listSearchBarSearchButtonIconColor' | 'listSearchBarShowCancelButton' | 'listSearchBarSpellcheck' | 'listSearchBarTitle' | 'listShowSearchBar' >; // type TXSelectedComponentActionBarContainer = Pick< IXComponentActionBarContainer, | 'showActionBar' | 'actionBarColor' | 'actionBarCssClass' | 'actionBarForegroundColor' >; // type TXSelectedComponentFileUploadContainer = Pick< { [TKey in keyof IXFileUploadContainer as `themeUpload${Capitalize< string & TKey >}`]: IXFileUploadContainer[TKey]; }, // | 'themeUploadColor' | 'themeUploadCssClass' | 'themeUploadEmptyMessage' | 'themeUploadForegroundColor' | 'themeUploadFileDropAreaIcon' | 'themeUploadShowFileDropArea' | 'themeUploadFileDropAreaColor' | 'themeUploadFileDropAreaMessage' | 'themeUploadFileDropAreaCssClass' | 'themeUploadFileDropAreaErrorColor' | 'themeUploadFileDropAreaAccentColor' | 'themeUploadFileDropAreaSuccessColor' | 'themeUploadFileDropAreaForegroundColor' | 'themeUploadEmptyForegroundMessageColor' | 'themeUploadFileDropAreaSupportsMultipleFiles' >; // type TXSelectedFileContainer = Pick< IXFileContainer, | 'maxAllowedSize' | 'minAllowedFileSize' | 'maxAllowedFileSize' | 'maxAllowedFiles' >; // type TXThemeManagerContainer = IXComponentCardContainer & TXSelectedComponentActionBarContainer & TXSelectedComponentListContainer & TXSelectedComponentFileUploadContainer & TXSelectedFileContainer & {}; // export interface IXThemeManagerContainer extends TXThemeManagerContainer { // actionProvider: Subject; cssClass: XStandardType>; // color: XStandardType; // themeChange: EventEmitter; tabChange: EventEmitter>; // restartAfterSetTheme: XStandardType; colorViewBorderWidth: XStandardType; colorViewBorderStyle: XStandardType; // propertyLabelColor: XStandardType; propertyValueColor: XStandardType; colorViewBorderColor: XStandardType; // propertyActionMenuIconColor: XStandardType; propertyActionMenuIcon: XStandardType; propertyEditIconColor: XStandardType; propertyEditIcon: XStandardType; propertyClearIconColor: XStandardType; propertyClearIcon: XStandardType; emptyPropertyEditIconColor: XStandardType; // presenterHeaderColor: XStandardType; presenterContentColor: XStandardType; presenterHeaderHighlightColor: XStandardType; // saveColor: XStandardType; saveLabel: XStandardType; resetColor: XStandardType; resetLabel: XStandardType; } @Injectable({ providedIn: 'root', }) export class XThemeManagerContainer extends XComponentCardContainer implements Readonly { // //#region Props ... // //#region Self ... readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly color: XStandardType = XColorWithBrightness.Light; // readonly themeChange: EventEmitter = new EventEmitter(); readonly tabChange: EventEmitter> = new EventEmitter< XStandardType >(); // readonly restartAfterSetTheme: XStandardType = true; readonly colorViewBorderWidth: XStandardType = 1; readonly colorViewBorderStyle: XStandardType = XBorderStyle.Solid; // readonly propertyLabelColor: XStandardType = XColorWithBrightness.Tertiary; readonly propertyValueColor: XStandardType = XColorWithBrightness.Dark; readonly colorViewBorderColor: XStandardType = XColorWithBrightness.LightShade; // readonly propertyActionMenuIconColor: XStandardType = XColorWithBrightness.Dark; readonly propertyActionMenuIcon: XStandardType = XIconNames.menu_vertical; readonly propertyEditIconColor: XStandardType = XColorWithBrightness.Tertiary; readonly propertyEditIcon: XStandardType = XIconNames.edit; readonly propertyClearIconColor: XStandardType = XColorWithBrightness.Danger; readonly propertyClearIcon: XStandardType = XIconNames.clear; readonly emptyPropertyEditIconColor: XStandardType = XColorWithBrightness.Danger; // readonly presenterHeaderColor: XStandardType = XColorWithBrightness.Light; readonly presenterContentColor: XStandardType = XColorWithBrightness.Dark; readonly presenterHeaderHighlightColor: XStandardType = XColorWithBrightness.LightShade; // readonly saveColor: XStandardType = XColorWithBrightness.Tertiary; readonly saveLabel: XStandardType = XResourceIDs.save; // readonly resetColor: XStandardType = XColorWithBrightness.WarningShade; readonly resetLabel: XStandardType = XResourceIDs.reset; //#endregion // //#region ActionBar ... readonly showActionBar = this.actionBarPropertyProvider.showActionBar; readonly actionBarColor = this.actionBarPropertyProvider.actionBarColor; readonly actionBarCssClass = this.actionBarPropertyProvider.actionBarCssClass; readonly actionBarForegroundColor = this.actionBarPropertyProvider.actionBarForegroundColor; //#endregion // //#region List ... readonly listCssClass = this.listPropertyProvider.listCssClass; readonly listShowDivider = this.listPropertyProvider.listShowDivider; // //#region List Empty ... readonly listShowEmpty = this.listPropertyProvider.listShowEmpty; readonly listEmptyActionProvider = this.listPropertyProvider.listEmptyActionProvider; readonly listEmptyColor = this.listPropertyProvider.listEmptyColor; readonly listEmptyCssClass = this.listPropertyProvider.listEmptyCssClass; readonly listEmptyForegroundColor = this.listPropertyProvider.listEmptyForegroundColor; readonly listEmptyForegroundMessageColor = this.listPropertyProvider.listEmptyForegroundMessageColor; readonly listEmptyForegroundRefreshButtonColor = this.listPropertyProvider.listEmptyForegroundRefreshButtonColor; readonly listEmptyHasRefresh = this.listPropertyProvider.listEmptyHasRefresh; readonly listEmptyMessage = this.listPropertyProvider.listEmptyMessage; readonly listEmptyMessageColor = this.listPropertyProvider.listEmptyMessageColor; readonly listEmptyRefresh = this.listPropertyProvider.listEmptyRefresh; readonly listEmptyRefreshButtonColor = this.listPropertyProvider.listEmptyRefreshButtonColor; readonly listEmptyRefreshIcon = this.listPropertyProvider.listEmptyRefreshIcon; //#endregion // //#region List Search ... readonly listSearchBarValue = this.listPropertyProvider.listSearchBarValue; readonly listSearchBarColor = this.listPropertyProvider.listSearchBarColor; readonly listSearchBarDebounce = this.listPropertyProvider.listSearchBarDebounce; readonly listSearchBarSearchInputColor = this.listPropertyProvider.listSearchBarSearchInputColor; readonly listSearchBarForegroundSearchInputColor = this.listPropertyProvider.listSearchBarForegroundSearchInputColor; readonly listSearchBarCancelButtonIcon = this.listPropertyProvider.listSearchBarCancelButtonIcon; readonly listSearchBarCancelButtonTitle = this.listPropertyProvider.listSearchBarCancelButtonTitle; readonly listSearchBarClearButtonIcon = this.listPropertyProvider.listSearchBarClearButtonIcon; readonly listSearchBarClearButtonIconColor = this.listPropertyProvider.listSearchBarClearButtonIconColor; readonly listSearchBarCssClass = this.listPropertyProvider.listSearchBarCssClass; readonly listSearchBarEnterKeyHint = this.listPropertyProvider.listSearchBarEnterKeyHint; readonly listSearchBarForegroundColor = this.listPropertyProvider.listSearchBarForegroundColor; readonly listSearchBarKeyboardType = this.listPropertyProvider.listSearchBarKeyboardType; readonly listActionBarActionFired = this.listPropertyProvider.listActionBarActionFired; readonly listSearchBarOnEvent = this.listPropertyProvider.listSearchBarOnEvent; readonly listSearchBarQueryChange = this.listPropertyProvider.listSearchBarQueryChange; readonly listSearchBarSearchButtonIcon = this.listPropertyProvider.listSearchBarSearchButtonIcon; readonly listSearchBarSearchButtonIconColor = this.listPropertyProvider.listSearchBarSearchButtonIconColor; readonly listSearchBarShowCancelButton = this.listPropertyProvider.listSearchBarShowCancelButton; readonly listSearchBarSpellcheck = this.listPropertyProvider.listSearchBarSpellcheck; readonly listSearchBarTitle = this.listPropertyProvider.listSearchBarTitle; readonly listShowSearchBar = this.listPropertyProvider.listShowSearchBar; //#endregion //#endregion // //#region File Upload ... readonly themeUploadColor = this.fileUploadPropertyProvider.color; readonly themeUploadCssClass = this.fileUploadPropertyProvider.cssClass; readonly themeUploadEmptyMessage = this.fileUploadPropertyProvider.emptyMessage; readonly themeUploadForegroundColor = this.fileUploadPropertyProvider.foregroundColor; readonly themeUploadFileDropAreaIcon = this.fileUploadPropertyProvider.fileDropAreaIcon; readonly themeUploadShowFileDropArea = this.fileUploadPropertyProvider.showFileDropArea; readonly themeUploadFileDropAreaColor = this.fileUploadPropertyProvider.fileDropAreaColor; readonly themeUploadFileDropAreaMessage = this.fileUploadPropertyProvider.fileDropAreaMessage; readonly themeUploadFileDropAreaCssClass = this.fileUploadPropertyProvider.fileDropAreaCssClass; readonly themeUploadFileDropAreaErrorColor = this.fileUploadPropertyProvider.fileDropAreaErrorColor; readonly themeUploadFileDropAreaAccentColor = this.fileUploadPropertyProvider.fileDropAreaAccentColor; readonly themeUploadFileDropAreaSuccessColor = this.fileUploadPropertyProvider.fileDropAreaSuccessColor; readonly themeUploadFileDropAreaForegroundColor = this.fileUploadPropertyProvider.fileDropAreaForegroundColor; readonly themeUploadEmptyForegroundMessageColor = this.fileUploadPropertyProvider.emptyForegroundMessageColor; readonly themeUploadFileDropAreaSupportsMultipleFiles = this.fileUploadPropertyProvider.fileDropAreaSupportsMultipleFiles; //#endregion // //#region File ... readonly maxAllowedSize = this.filePropertyProvider.maxAllowedSize; readonly minAllowedFileSize = this.filePropertyProvider.minAllowedFileSize; readonly maxAllowedFileSize = this.filePropertyProvider.maxAllowedFileSize; readonly maxAllowedFiles = this.filePropertyProvider.maxAllowedFiles; //#endregion //#endregion // //#region Constructor ... constructor( protected filePropertyProvider: XFileContainer, protected cardPropertyProvider: XCardContainer, protected listPropertyProvider: XComponentListContainer, protected fileUploadPropertyProvider: XFileUploadContainer, protected actionBarPropertyProvider: XComponentActionBarContainer ) { super(cardPropertyProvider); } //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XThemeManagerContainerComponent extends XComponentCardContainerComponent implements IXThemeManagerContainer { // //#region Props ... // //#region Self ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() color: XStandardType = this.propertyProvider.color; // @Output() themeChange: EventEmitter = new EventEmitter(); @Output() tabChange: EventEmitter> = new EventEmitter(); // @Input() restartAfterSetTheme: XStandardType = this.propertyProvider.restartAfterSetTheme; @Input() colorViewBorderWidth: XStandardType = this.propertyProvider.colorViewBorderWidth; @Input() colorViewBorderStyle: XStandardType = this.propertyProvider.colorViewBorderStyle; // @Input() propertyLabelColor: XStandardType = this.propertyProvider.propertyLabelColor; @Input() propertyValueColor: XStandardType = this.propertyProvider.propertyValueColor; @Input() colorViewBorderColor: XStandardType = this.propertyProvider.colorViewBorderColor; // @Input() propertyActionMenuIconColor: XStandardType = this.propertyProvider.propertyActionMenuIconColor; @Input() propertyActionMenuIcon: XStandardType = this.propertyProvider.propertyActionMenuIcon; @Input() propertyEditIconColor: XStandardType = this.propertyProvider.propertyEditIconColor; @Input() propertyEditIcon: XStandardType = this.propertyProvider.propertyEditIcon; @Input() propertyClearIconColor: XStandardType = this.propertyProvider.propertyClearIconColor; @Input() propertyClearIcon: XStandardType = this.propertyProvider.propertyClearIcon; @Input() emptyPropertyEditIconColor: XStandardType = this.propertyProvider.emptyPropertyEditIconColor; // @Input() presenterHeaderColor: XStandardType = this.propertyProvider.presenterHeaderColor; @Input() presenterContentColor: XStandardType = this.propertyProvider.presenterContentColor; @Input() presenterHeaderHighlightColor: XStandardType = this.propertyProvider.presenterHeaderHighlightColor; // @Input() saveColor: XStandardType = this.propertyProvider.saveColor; @Input() saveLabel: XStandardType = this.propertyProvider.saveLabel; // @Input() resetColor: XStandardType = this.propertyProvider.resetColor; @Input() resetLabel: XStandardType = this.propertyProvider.resetLabel; //#endregion // //#region ActionBar ... @Input() showActionBar: XStandardType = this.propertyProvider.showActionBar; @Input() actionBarColor: XStandardType = this.propertyProvider.actionBarColor; @Input() actionBarCssClass: XStandardType> = this.propertyProvider.actionBarCssClass; @Input() actionBarForegroundColor: XStandardType = this.propertyProvider.actionBarForegroundColor; //#endregion // //#region List ... @Input() listCssClass = this.propertyProvider.listCssClass; @Input() listShowDivider = this.propertyProvider.listShowDivider; // //#region List Empty ... @Input() listShowEmpty = this.propertyProvider.listShowEmpty; @Input() listEmptyActionProvider = this.propertyProvider.listEmptyActionProvider; @Input() listEmptyColor = this.propertyProvider.listEmptyColor; @Input() listEmptyCssClass = this.propertyProvider.listEmptyCssClass; @Input() listEmptyForegroundColor = this.propertyProvider.listEmptyForegroundColor; @Input() listEmptyForegroundMessageColor = this.propertyProvider.listEmptyForegroundMessageColor; @Input() listEmptyForegroundRefreshButtonColor = this.propertyProvider.listEmptyForegroundRefreshButtonColor; @Input() listEmptyHasRefresh = this.propertyProvider.listEmptyHasRefresh; @Input() listEmptyMessage = this.propertyProvider.listEmptyMessage; @Input() listEmptyMessageColor = this.propertyProvider.listEmptyMessageColor; @Output() listEmptyRefresh: EventEmitter = new EventEmitter(); @Input() listEmptyRefreshButtonColor = this.propertyProvider.listEmptyRefreshButtonColor; @Input() listEmptyRefreshIcon = this.propertyProvider.listEmptyRefreshIcon; //#endregion // //#region List Search ... @Input() listSearchBarValue = this.propertyProvider.listSearchBarValue; @Input() listSearchBarColor = this.propertyProvider.listSearchBarColor; @Input() listSearchBarDebounce = this.propertyProvider.listSearchBarDebounce; @Input() listSearchBarSearchInputColor = this.propertyProvider.listSearchBarSearchInputColor; @Input() listSearchBarForegroundSearchInputColor = this.propertyProvider.listSearchBarForegroundSearchInputColor; @Input() listSearchBarCancelButtonIcon = this.propertyProvider.listSearchBarCancelButtonIcon; @Input() listSearchBarCancelButtonTitle = this.propertyProvider.listSearchBarCancelButtonTitle; @Input() listSearchBarClearButtonIcon = this.propertyProvider.listSearchBarClearButtonIcon; @Input() listSearchBarClearButtonIconColor = this.propertyProvider.listSearchBarClearButtonIconColor; @Input() listSearchBarCssClass = this.propertyProvider.listSearchBarCssClass; @Input() listSearchBarEnterKeyHint = this.propertyProvider.listSearchBarEnterKeyHint; @Input() listSearchBarForegroundColor = this.propertyProvider.listSearchBarForegroundColor; @Input() listSearchBarKeyboardType = this.propertyProvider.listSearchBarKeyboardType; @Output() listActionBarActionFired: EventEmitter = new EventEmitter(); @Output() listSearchBarOnEvent: EventEmitter = new EventEmitter(); @Output() listSearchBarQueryChange: EventEmitter = new EventEmitter(); @Input() listSearchBarSearchButtonIcon = this.propertyProvider.listSearchBarSearchButtonIcon; @Input() listSearchBarSearchButtonIconColor = this.propertyProvider.listSearchBarSearchButtonIconColor; @Input() listSearchBarShowCancelButton = this.propertyProvider.listSearchBarShowCancelButton; @Input() listSearchBarSpellcheck = this.propertyProvider.listSearchBarSpellcheck; @Input() listSearchBarTitle = this.propertyProvider.listSearchBarTitle; @Input() listShowSearchBar = this.propertyProvider.listShowSearchBar; //#endregion //#endregion // //#region File Upload ... @Input() themeUploadColor = this.propertyProvider.themeUploadColor; @Input() themeUploadCssClass = this.propertyProvider.themeUploadCssClass; @Input() themeUploadEmptyMessage = this.propertyProvider.themeUploadEmptyMessage; @Input() themeUploadForegroundColor = this.propertyProvider.themeUploadForegroundColor; @Input() themeUploadFileDropAreaIcon = this.propertyProvider.themeUploadFileDropAreaIcon; @Input() themeUploadShowFileDropArea = this.propertyProvider.themeUploadShowFileDropArea; @Input() themeUploadFileDropAreaColor = this.propertyProvider.themeUploadFileDropAreaColor; @Input() themeUploadFileDropAreaMessage = this.propertyProvider.themeUploadFileDropAreaMessage; @Input() themeUploadFileDropAreaCssClass = this.propertyProvider.themeUploadFileDropAreaCssClass; @Input() themeUploadFileDropAreaErrorColor = this.propertyProvider.themeUploadFileDropAreaErrorColor; @Input() themeUploadFileDropAreaAccentColor = this.propertyProvider.themeUploadFileDropAreaAccentColor; @Input() themeUploadFileDropAreaSuccessColor = this.propertyProvider.themeUploadFileDropAreaSuccessColor; @Input() themeUploadFileDropAreaForegroundColor = this.propertyProvider.themeUploadFileDropAreaForegroundColor; @Input() themeUploadEmptyForegroundMessageColor = this.propertyProvider.themeUploadEmptyForegroundMessageColor; @Input() themeUploadFileDropAreaSupportsMultipleFiles = this.propertyProvider.themeUploadFileDropAreaSupportsMultipleFiles; //#endregion // //#region File ... @Input() maxAllowedSize = this.propertyProvider.maxAllowedSize; @Input() minAllowedFileSize = this.propertyProvider.minAllowedFileSize; @Input() maxAllowedFileSize = this.propertyProvider.maxAllowedFileSize; @Input() maxAllowedFiles = this.propertyProvider.maxAllowedFiles; //#endregion //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XThemeManagerContainer, public colorPickerDialogService: XColorPickerDialogService ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXThemeManagerContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getValue( container ? container.cssClass : this.cssClass ), // restartAfterSetTheme: this.getValue( container ? container.restartAfterSetTheme : this.restartAfterSetTheme ), colorViewBorderWidth: this.getValue( container ? container.colorViewBorderWidth : this.colorViewBorderWidth ), colorViewBorderStyle: this.getValue( container ? container.colorViewBorderStyle : this.colorViewBorderStyle ), // propertyLabelColor: this.getValue( container ? container.propertyLabelColor : this.propertyLabelColor ), propertyValueColor: this.getValue( container ? container.propertyValueColor : this.propertyValueColor ), colorViewBorderColor: this.getValue( container ? container.colorViewBorderColor : this.colorViewBorderColor ), color: this.getValue(container ? container.color : this.color), // propertyActionMenuIconColor: this.getValue( container ? container.propertyActionMenuIconColor : this.propertyActionMenuIconColor ), propertyActionMenuIcon: this.getValue( container ? container.propertyActionMenuIcon : this.propertyActionMenuIcon ), propertyEditIconColor: this.getValue( container ? container.propertyEditIconColor : this.propertyEditIconColor ), propertyEditIcon: this.getValue( container ? container.propertyEditIcon : this.propertyEditIcon ), propertyClearIconColor: this.getValue( container ? container.propertyClearIconColor : this.propertyClearIconColor ), propertyClearIcon: this.getValue( container ? container.propertyClearIcon : this.propertyClearIcon ), emptyPropertyEditIconColor: this.getValue( container ? container.emptyPropertyEditIconColor : this.emptyPropertyEditIconColor ), // presenterHeaderColor: this.getValue( container ? container.presenterHeaderColor : this.presenterHeaderColor ), presenterContentColor: this.getValue( container ? container.presenterContentColor : this.presenterContentColor ), presenterHeaderHighlightColor: this.getValue( container ? container.presenterHeaderHighlightColor : this.presenterHeaderHighlightColor ), // saveColor: this.getValue( container ? container.saveColor : this.saveColor ), saveLabel: this.getValue( container ? container.saveLabel : this.saveLabel ), // resetColor: this.getValue( container ? container.resetColor : this.resetColor ), resetLabel: this.getValue( container ? container.resetLabel : this.resetLabel ), // showActionBar: this.getValue( container ? container.showActionBar : this.showActionBar ), actionBarColor: this.getValue( container ? container.actionBarColor : this.actionBarColor ), actionBarCssClass: this.getValue( container ? container.actionBarCssClass : this.actionBarCssClass ), actionBarForegroundColor: this.getValue( container ? container.actionBarForegroundColor : this.actionBarForegroundColor ), // listCssClass: this.getValue( container ? container.listCssClass : this.listCssClass ), listShowDivider: this.getValue( container ? container.listShowDivider : this.listShowDivider ), // listShowEmpty: this.getValue( container ? container.listShowEmpty : this.listShowEmpty ), listEmptyColor: this.getValue( container ? container.listEmptyColor : this.listEmptyColor ), listEmptyCssClass: this.getValue( container ? container.listEmptyCssClass : this.listEmptyCssClass ), listEmptyForegroundColor: this.getValue( container ? container.listEmptyForegroundColor : this.listEmptyForegroundColor ), listEmptyForegroundMessageColor: this.getValue( container ? container.listEmptyForegroundMessageColor : this.listEmptyForegroundMessageColor ), listEmptyForegroundRefreshButtonColor: this.getValue( container ? container.listEmptyForegroundRefreshButtonColor : this.listEmptyForegroundRefreshButtonColor ), listEmptyHasRefresh: this.getValue( container ? container.listEmptyHasRefresh : this.listEmptyHasRefresh ), listEmptyMessage: this.getValue( container ? container.listEmptyMessage : this.listEmptyMessage ), listEmptyMessageColor: this.getValue( container ? container.listEmptyMessageColor : this.listEmptyMessageColor ), listEmptyRefreshButtonColor: this.getValue( container ? container.listEmptyRefreshButtonColor : this.listEmptyRefreshButtonColor ), listEmptyRefreshIcon: this.getValue( container ? container.listEmptyRefreshIcon : this.listEmptyRefreshIcon ), // listSearchBarValue: this.getValue( container ? container.listSearchBarValue : this.listSearchBarValue ), listSearchBarColor: this.getValue( container ? container.listSearchBarColor : this.listSearchBarColor ), listSearchBarDebounce: this.getValue( container ? container.listSearchBarDebounce : this.listSearchBarDebounce ), listSearchBarSearchInputColor: this.getValue( container ? container.listSearchBarSearchInputColor : this.listSearchBarSearchInputColor ), listSearchBarForegroundSearchInputColor: this.getValue( container ? container.listSearchBarForegroundSearchInputColor : this.listSearchBarForegroundSearchInputColor ), listSearchBarCancelButtonIcon: this.getValue( container ? container.listSearchBarCancelButtonIcon : this.listSearchBarCancelButtonIcon ), listSearchBarCancelButtonTitle: this.getValue( container ? container.listSearchBarCancelButtonTitle : this.listSearchBarCancelButtonTitle ), listSearchBarClearButtonIcon: this.getValue( container ? container.listSearchBarClearButtonIcon : this.listSearchBarClearButtonIcon ), listSearchBarClearButtonIconColor: this.getValue( container ? container.listSearchBarClearButtonIconColor : this.listSearchBarClearButtonIconColor ), listSearchBarCssClass: this.getValue( container ? container.listSearchBarCssClass : this.listSearchBarCssClass ), listSearchBarEnterKeyHint: this.getValue( container ? container.listSearchBarEnterKeyHint : this.listSearchBarEnterKeyHint ), listSearchBarForegroundColor: this.getValue( container ? container.listSearchBarForegroundColor : this.listSearchBarForegroundColor ), listSearchBarKeyboardType: this.getValue( container ? container.listSearchBarKeyboardType : this.listSearchBarKeyboardType ), listSearchBarSearchButtonIcon: this.getValue( container ? container.listSearchBarSearchButtonIcon : this.listSearchBarSearchButtonIcon ), listSearchBarSearchButtonIconColor: this.getValue( container ? container.listSearchBarSearchButtonIconColor : this.listSearchBarSearchButtonIconColor ), listSearchBarShowCancelButton: this.getValue( container ? container.listSearchBarShowCancelButton : this.listSearchBarShowCancelButton ), listSearchBarSpellcheck: this.getValue( container ? container.listSearchBarSpellcheck : this.listSearchBarSpellcheck ), listSearchBarTitle: this.getValue( container ? container.listSearchBarTitle : this.listSearchBarTitle ), listShowSearchBar: this.getValue( container ? container.listShowSearchBar : this.listShowSearchBar ), // themeUploadColor: this.getValue( container ? container.themeUploadColor : this.themeUploadColor ), themeUploadCssClass: this.getValue( container ? container.themeUploadCssClass : this.themeUploadCssClass ), themeUploadEmptyMessage: this.getValue( container ? container.themeUploadEmptyMessage : this.themeUploadEmptyMessage ), themeUploadForegroundColor: this.getValue( container ? container.themeUploadForegroundColor : this.themeUploadForegroundColor ), themeUploadFileDropAreaIcon: this.getValue( container ? container.themeUploadFileDropAreaIcon : this.themeUploadFileDropAreaIcon ), themeUploadShowFileDropArea: this.getValue( container ? container.themeUploadShowFileDropArea : this.themeUploadShowFileDropArea ), themeUploadFileDropAreaColor: this.getValue( container ? container.themeUploadFileDropAreaColor : this.themeUploadFileDropAreaColor ), themeUploadFileDropAreaMessage: this.getValue( container ? container.themeUploadFileDropAreaMessage : this.themeUploadFileDropAreaMessage ), themeUploadFileDropAreaCssClass: this.getValue( container ? container.themeUploadFileDropAreaCssClass : this.themeUploadFileDropAreaCssClass ), themeUploadFileDropAreaErrorColor: this.getValue( container ? container.themeUploadFileDropAreaErrorColor : this.themeUploadFileDropAreaErrorColor ), themeUploadFileDropAreaAccentColor: this.getValue( container ? container.themeUploadFileDropAreaAccentColor : this.themeUploadFileDropAreaAccentColor ), themeUploadFileDropAreaSuccessColor: this.getValue( container ? container.themeUploadFileDropAreaSuccessColor : this.themeUploadFileDropAreaSuccessColor ), themeUploadFileDropAreaForegroundColor: this.getValue( container ? container.themeUploadFileDropAreaForegroundColor : this.themeUploadFileDropAreaForegroundColor ), themeUploadEmptyForegroundMessageColor: this.getValue( container ? container.themeUploadEmptyForegroundMessageColor : this.themeUploadEmptyForegroundMessageColor ), themeUploadFileDropAreaSupportsMultipleFiles: this.getValue( container ? container.themeUploadFileDropAreaSupportsMultipleFiles : this.themeUploadFileDropAreaSupportsMultipleFiles ), // maxAllowedSize: this.getValue( container ? container.maxAllowedSize : this.maxAllowedSize ), minAllowedFileSize: this.getValue( container ? container.minAllowedFileSize : this.minAllowedFileSize ), maxAllowedFileSize: this.getValue( container ? container.maxAllowedFileSize : this.maxAllowedFileSize ), maxAllowedFiles: this.getValue( container ? container.maxAllowedFiles : this.maxAllowedFiles ), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // themeChange: this.themeChange, tabChange: this.tabChange, // listEmptyActionProvider: container ? container.listEmptyActionProvider : this.listEmptyActionProvider, // listEmptyRefresh: this.listEmptyRefresh, // listActionBarActionFired: this.listActionBarActionFired, listSearchBarOnEvent: this.listSearchBarOnEvent, listSearchBarQueryChange: this.listSearchBarQueryChange, }; }) ); } //#endregion } function XStandardType() { throw new Error('Function not implemented.'); } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.component.scss :host { --thumbnail-size: 32px; } x-icon { --size: var(--thumbnail-size, 32px); color: inherit; } .x-item, .x-wrapper, ion-thumbnail { // width: var(--thumbnail-size, 32px); min-width: var(--thumbnail-size, 32px); // height: var(--thumbnail-size, 32px); min-height: var(--thumbnail-size, 32px); // color: inherit; } ion-thumbnail.circular { --border-radius: 50%; } .x-thumbnail { // display: inline-block; position: relative; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.component.ts import { nameof, isString, XFileType, getFileType, XGeneralThumbnails, getGeneralThumbnail, } from 'x-framework-core'; import { XThumbnailType, XThumbnailAction, XThumbnailInputType, XThumbnailActionModel, XThumbnailContainerComponent, } from './x-thumbnail.typings'; import { Subject, Subscription } from 'rxjs'; import { XIconNames } from '../x-icon/x-icon.typings'; import { map, filter, concatMap } from 'rxjs/operators'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-thumbnail', templateUrl: './x-thumbnail.component.html', styleUrls: ['./x-thumbnail.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XThumbnailComponent extends XThumbnailContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; private PREPARED_IDENTIFIER: XThumbnailInputType; get preparedIdentifier() { return this.PREPARED_IDENTIFIER; } //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Identifier Changed ... const isIdentifierChanged = changeKeys.includes( nameof('identifier') ); if (isIdentifierChanged) { await this.prepareIdentifier(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Register Handlers ... //#endregion // //#region UI Providers ... // //#region Type Providers ... isTypeGeneral() { return this.getValue(this.type).pipe( map( (type) => type === XThumbnailType.GENERAL || type !== XThumbnailType.CUSTOM ) ); } isTypeCustom() { return this.getValue(this.type).pipe( map((type) => type === XThumbnailType.CUSTOM) ); } //#endregion isUrlIdentifier() { // // && isValidURL(identifier as string) return this.getIdentifier().pipe(map((identifier) => isString(identifier))); } isImageTypeIdentifier() { return this.isUrlIdentifier().pipe( filter((isUrl) => !isUrl), concatMap(() => this.getIdentifier()), map((identifier) => { // const type = getFileType(identifier); return [ XFileType.CoverImage, XFileType.Image, XFileType.ProfileImage, ].includes(type); }) ); } getGThumbnail(identifier: XThumbnailInputType) { return this.getValue(getGeneralThumbnail(identifier)).pipe( map((type) => { switch (type) { // case XGeneralThumbnails.IMAGE: return XIconNames.image; // case XGeneralThumbnails.AUDIO: return XIconNames.audio; // case XGeneralThumbnails.VIDEO: return XIconNames.video; // case XGeneralThumbnails.DOCUMENT: default: return XIconNames.document; } }) ); } //#endregion // //#region UI Handlers ... async handleClicked() { // if (this.uiDisabled || this.loading) { return; } // const isClickable = await this.getValueAsync(this.clickable); if (isClickable) { this.clicked.emit(); } } //#endregion // //#region Actions ... //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XThumbnailAction.Refresh: this.detectChanges(); break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion private getIdentifier() { return this.getValue(this.identifier); } private async prepareIdentifier() { // const identifier = await this.getValueAsync(this.identifier); this.PREPARED_IDENTIFIER = identifier; // this.detectChanges(); } //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XIconModule } from '../x-icon/x-icon.module'; import { XThumbnailComponent } from './x-thumbnail.component'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XThumbnailComponent], imports: [CommonModule, XIconModule, XBaseComponentModule], exports: [XIconModule, XBaseComponentModule, XThumbnailComponent], }) export class XThumbnailModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-thumbnail\x-thumbnail.typings.ts import { Input, Output, Inject, NgZone, Component, Renderer2, ElementRef, Injectable, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { map } from 'rxjs/operators'; import { XBaseContainer, IXBaseContainer, XBaseContainerComponent, } from '../classes/i-x-base.container'; import { Subject, forkJoin, Observable } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { XFileBlob, XOneOrManyType, XStandardType } from 'x-framework-core'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export enum XThumbnailType { GENERAL = 'general', CUSTOM = 'custom', } export type XThumbnailTypeIdentifier = XThumbnailType | string; export type XThumbnailInputType = File | Blob | XFileBlob | string; export enum XThumbnailAction { Refresh = 'refresh', } export type XThumbnailActionIdentifier = XThumbnailAction | string; export interface XThumbnailActionModel extends XBaseActionModel {} // //#region Container ... export interface IXThumbnailContainer extends IXBaseContainer { // actionProvider: Subject; cssClass: XStandardType>; // circular: XStandardType; clickable: XStandardType; selectable: XStandardType; type: XStandardType; identifier: XStandardType; // clicked: EventEmitter; } @Injectable({ providedIn: 'root', }) export class XThumbnailContainer extends XBaseContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject = new Subject(); readonly cssClass: XStandardType>; // readonly circular: XStandardType = false; readonly clickable: XStandardType = false; readonly selectable: XStandardType = false; readonly type: XStandardType = XThumbnailType.GENERAL; readonly identifier: XStandardType; // readonly clicked: EventEmitter = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XThumbnailContainerComponent extends XBaseContainerComponent implements IXThumbnailContainer { // //#region Props ... @Input() actionProvider: Subject = this.propertyProvider.actionProvider; @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; @Input() circular: XStandardType = this.propertyProvider.circular; @Input() clickable: XStandardType = this.propertyProvider.clickable; @Input() selectable: XStandardType = this.propertyProvider.selectable; @Input() type: XStandardType = this.propertyProvider.type; @Input() identifier: XStandardType = this.propertyProvider.identifier; @Output() clicked: EventEmitter = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XThumbnailContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector ); } //#endregion // //#region Abstract ... public extractProps( container?: IXThumbnailContainer ): Observable { return forkJoin({ cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), circular: this.getValue(container ? container.circular : this.circular), clickable: this.getValue( container ? container.clickable : this.clickable ), selectable: this.getValue( container ? container.selectable : this.selectable ), type: this.getValue(container ? container.type : this.type), identifier: this.getValue( container ? container.identifier : this.identifier ), }).pipe( map((data) => { return { // ...data, // actionProvider: container ? container.actionProvider : this.actionProvider, // clicked: this.clicked, }; }) ); } //#endregion } //#endregion ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.component.html
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.component.scss :host(::ng-deep.mat-tree) { background-color: unset !important; } :host(::ng-deep.mat-tree-node) { align-items: baseline !important; } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.component.ts import { XTreeNode, XTreeAction, XTreeFlatNode, XTreeActionModel, XTreeContainerComponent, } from './x-tree.typings'; import { nameof, toArray, isNullOrUndefined, isNullOrEmptyString, } from 'x-framework-core'; import { MatTreeFlattener, MatTreeFlatDataSource, } from '@angular/material/tree'; import { Subject, Subscription } from 'rxjs'; import { FlatTreeControl } from '@angular/cdk/tree'; import { Component, ChangeDetectionStrategy } from '@angular/core'; @Component({ // tslint:disable-next-line:component-selector selector: 'x-tree', templateUrl: './x-tree.component.html', styleUrls: ['./x-tree.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class XTreeComponent extends XTreeContainerComponent { // //#region Props ... // private ACTION_PROVIDER_SUBSCRIPTION: Subscription; // treeControl: FlatTreeControl = null; // treeFlattener: MatTreeFlattener< XTreeNode, XTreeFlatNode, XTreeFlatNode > = null; // dataSource: MatTreeFlatDataSource< XTreeNode, XTreeFlatNode, XTreeFlatNode > = null; //#endregion // //#region LifeCycles ... async onChange(changeKeys: string[]) { super.onChange(changeKeys); // //#region ActionProvider Changed ... const isActionProviderChanged = changeKeys.includes( nameof('actionProvider') ); if (isActionProviderChanged) { this.registerActionProvider(); } //#endregion // //#region Nodes Changes ... const isNodesChanged = changeKeys.includes(nameof('nodes')); if (isNodesChanged) { await this.prepareDataSource(); } //#endregion } onDestroy() { super.onDestroy(); // this.unregisterActionProvider(); } registerViewHandlers() { super.registerViewHandlers(); // this.registerActionProvider(); } //#endregion // //#region Register Handlers ... //#endregion // //#region UI Providers ... getNodeClassNames(node: XTreeFlatNode) { // const result = ['x-tree-node', `x-tree-node-level-${node.level}`]; // if (node.expandable) { result.push('x-tree-expandable-node'); } // if (!isNullOrEmptyString(node.id)) { result.push(`x-tree-node-id-${node.id}`); result.push(`x-tree-node-id-${node.id}-level-${node.level}`); } // return this.getArrayValue(result); } nodeHasChild = (_: number, node: XTreeFlatNode) => node.expandable; //#endregion // //#region UI Handlers ... handleTreeNodeToggle(id: string, isExpanded: boolean) { // if (isNullOrEmptyString(id)) { return; } // this.onNodeToggle.emit({ id, isExpanded, }); } //#endregion // //#region Actions ... //#endregion // //#region Private ... // //#region ActionProvider ... private registerActionProvider() { // this.unregisterActionProvider(); // if (!this.actionProvider) { this.actionProvider = new Subject(); } // // Handle Action Provider ... this.ACTION_PROVIDER_SUBSCRIPTION = this.actionProvider .asObservable() .subscribe(async (model) => { // if (!model) { return; } // switch (model.action) { // case XTreeAction.Refresh: this.detectChanges(); break; // case XTreeAction.Expand: // if (this.treeControl) { // // Get Tree Node ... if (model.payload) { // const id = model.payload.toString(); if (!isNullOrEmptyString(id)) { // const node = this.treeControl.dataNodes.find( (d) => d.id === id ); if (!isNullOrUndefined(node)) { this.treeControl.expand(node); } } } } break; // case XTreeAction.Collapse: // if (this.treeControl) { // // Get Tree Node ... if (model.payload) { // const id = model.payload.toString(); if (!isNullOrEmptyString(id)) { // const node = this.treeControl.dataNodes.find( (d) => d.id === id ); if (!isNullOrUndefined(node)) { this.treeControl.collapse(node); } } } } break; // case XTreeAction.ExpandAll: // if (this.treeControl) { this.treeControl.expandAll(); } break; // case XTreeAction.CollapseAll: // if (this.treeControl) { this.treeControl.collapseAll(); } break; } }); } private unregisterActionProvider() { // if (!this.ACTION_PROVIDER_SUBSCRIPTION) { return; } // this.ACTION_PROVIDER_SUBSCRIPTION.unsubscribe(); this.ACTION_PROVIDER_SUBSCRIPTION = null; } //#endregion // //#region Tree ... async prepareDataSource() { // this.treeControl = null; this.treeFlattener = null; this.dataSource = null; // const nodes = await this.getArrayValueAsync(this.nodes); if (!this.hasChild(nodes)) { this.detectChanges(); return; } // this.treeControl = new FlatTreeControl( (node) => node.level, (node) => node.expandable ); // this.treeFlattener = new MatTreeFlattener( (node: XTreeNode, level: number) => { return { id: node.id, level: level, data: node.data, tooltip: node.tooltip, expandable: this.hasChild(node.childs), } as XTreeFlatNode; }, (node) => node.level, (node) => node.expandable, (node) => toArray(node.childs) ); // this.dataSource = new MatTreeFlatDataSource( this.treeControl, this.treeFlattener ); this.dataSource.data = nodes; // this.detectChanges(); } //#endregion //#endregion } ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.module.ts import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { XTreeComponent } from './x-tree.component'; import { XCardModule } from '../x-card/x-card.module'; import { XIconModule } from '../x-icon/x-icon.module'; import { XBaseComponentModule } from '../modules/x-base-component.module'; @NgModule({ declarations: [XTreeComponent], imports: [CommonModule, XCardModule, XIconModule, XBaseComponentModule], exports: [XIconModule, XCardModule, XBaseComponentModule, XTreeComponent], }) export class XTreeModule {} ### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-tree\x-tree.typings.ts import { Input, Inject, Output, NgZone, Component, Renderer2, ElementRef, Injectable, TemplateRef, EventEmitter, ChangeDetectorRef, } from '@angular/core'; import { XStandardType, XOneOrManyType, XColorIdentifier, XResourceIdentifier, XColorWithBrightness, } from 'x-framework-core'; import { XComponentCardContainer, IXComponentCardContainer, XComponentCardContainerComponent, } from '../x-card/x-card.typings'; import { concatMap, map } from 'rxjs/operators'; import { Observable, Subject, forkJoin } from 'rxjs'; import { ViewportRuler } from '@angular/cdk/overlay'; import { XManagerService } from 'x-framework-services'; import { XBaseActionModel } from '../classes/x-base-action.model'; import { X_FRAMEWORK_COMPONENTS_CONFIG } from '../tokens/x-injectable-tokens'; import { XFrameworkComponentsConfig } from '../config/x-framework-components.config'; export interface XTreeNodeToggle { id: string; isExpanded: boolean; } export interface XTreeNode { id: string; data: T; childs?: XOneOrManyType>; tooltip?: XStandardType; } export interface XTreeFlatNode { id: string; level: number; data: XTreeNode; expandable: boolean; tooltip?: XStandardType; } export enum XTreeAction { // Refresh = 'refresh', // Expand = 'expand', Collapse = 'collapse', // ExpandAll = 'expand-all', CollapseAll = 'collapse-all', } export type XTreeActionIdentifier = XTreeAction | string; export interface XTreeActionModel extends XBaseActionModel {} // //#region Component Container Typings ... export interface IXTreeContainer extends IXComponentCardContainer { // //#region Props ... // actionProvider: Subject; cssClass: XStandardType>; // isForegroundToggleColor: XStandardType; toggleIconColor: XStandardType; // nodes: XStandardType>>; // nodeTemplate: TemplateRef; // onNodeToggle: EventEmitter; //#endregion } @Injectable({ providedIn: 'root', }) export class XTreeContainer extends XComponentCardContainer implements Readonly { // //#region Props ... // readonly actionProvider: Subject; readonly cssClass: XStandardType>; // readonly isForegroundToggleColor: XStandardType = true; readonly toggleIconColor: XStandardType = XColorWithBrightness.Dark; // readonly nodes: XStandardType>>; // readonly nodeTemplate: TemplateRef; // readonly onNodeToggle = new EventEmitter(); //#endregion } @Injectable() @Component({ template: ``, }) export abstract class XTreeContainerComponent extends XComponentCardContainerComponent implements IXTreeContainer { // //#region Props ... // @Input() actionProvider: Subject = this.propertyProvider.actionProvider; // @Input() cssClass: XStandardType> = this.propertyProvider.cssClass; // @Input() toggleIconColor: XStandardType = this.propertyProvider.toggleIconColor; // @Input() isForegroundToggleColor: XStandardType = this.propertyProvider.isForegroundToggleColor; // @Input() nodes: XStandardType>> = this.propertyProvider.nodes; // @Input() nodeTemplate: TemplateRef = this.propertyProvider.nodeTemplate; // @Output() onNodeToggle = new EventEmitter(); //#endregion // //#region Constructor ... public constructor( @Inject(X_FRAMEWORK_COMPONENTS_CONFIG) public config: XFrameworkComponentsConfig, public managerService: XManagerService, public element: ElementRef, public renderer: Renderer2, public ruler: ViewportRuler, public zone: NgZone, public changeDetector: ChangeDetectorRef, protected propertyProvider: XTreeContainer ) { super( config, managerService, element, renderer, ruler, zone, changeDetector, propertyProvider ); } //#endregion // //#region Abstract ... public extractProps( container?: IXTreeContainer ): Observable { return super .extractProps(container ? container : this) .pipe( concatMap((superData) => { return forkJoin({ // cssClass: this.getArrayValue( container ? container.cssClass : this.cssClass ), // toggleIconColor: this.getValue( container ? container.toggleIconColor : this.toggleIconColor ), // isForegroundToggleColor: this.getValue( container ? container.isForegroundToggleColor : this.isForegroundToggleColor ), // nodes: this.getArrayValue(container ? container.nodes : this.nodes), }).pipe( map((data) => { return { superData, data, }; }) ); }) ) .pipe( map((info) => { return { // ...info.superData, // ...info.data, // actionProvider: container ? container.actionProvider : this.actionProvider, // nodeTemplate: container ? container.nodeTemplate : this.nodeTemplate, // onNodeToggle: container.onNodeToggle ? container.onNodeToggle : this.onNodeToggle, }; }) ); } //#endregion } //#endregion