Files
xSaherelmWorkspace/Documents/GeneratedContext/xDashboard-xFrameworkComponentsHolder-20260821_041126.txt
T
2026-08-21 18:47:06 +03:30

99899 lines
2.6 MiB
Plaintext

### 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[];
<T>(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<XResourceIdentifier>;
}
### 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<any>;
//#endregion
//
//#region Props Actions ...
public async extractPropsAsync(container?: any): Promise<any> {
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<any>;
//#endregion
//
//#region Props Actions ...
public async extractPropsAsync(container?: any): Promise<any> {
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<boolean> =
this.cardPropertyProvider.isInPage;
readonly wrapWithCard: XStandardType<boolean> =
this.cardPropertyProvider.wrapWithCard;
readonly cardShowFooter: XStandardType<boolean> =
this.cardPropertyProvider.cardShowFooter;
readonly cardShowActions: XStandardType<boolean> =
this.cardPropertyProvider.cardShowActions;
readonly cardColor: XStandardType<XColorIdentifier> =
this.cardPropertyProvider.cardColor;
readonly cardForegroundColor: XStandardType<boolean> =
this.cardPropertyProvider.cardForegroundColor;
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardTitle;
readonly cardActionProvider: Subject<XCardActionModel> =
this.cardPropertyProvider.cardActionProvider;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardSubTitle;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
this.cardPropertyProvider.cardCssClass;
//#endregion
//
//#region XComponentEmpty ...
//
readonly showEmpty: XStandardType<boolean> = true;
readonly emptyHasRefresh: XStandardType<boolean> =
this.emptyPropertyProvider.hasRefresh;
//
readonly emptyActionProvider: Subject<XEmptyActionModel> =
this.emptyPropertyProvider.actionProvider;
readonly emptyCssClass: XStandardType<XOneOrManyType<string>> =
this.emptyPropertyProvider.cssClass;
readonly emptyColor: XStandardType<XColorIdentifier> =
this.emptyPropertyProvider.color;
readonly emptyForegroundColor: XStandardType<boolean> =
this.emptyPropertyProvider.foregroundColor;
readonly emptyMessageColor: XStandardType<XColorIdentifier> =
this.emptyPropertyProvider.messageColor;
readonly emptyForegroundMessageColor: XStandardType<boolean> =
this.emptyPropertyProvider.foregroundMessageColor;
readonly emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
this.emptyPropertyProvider.refreshButtonColor;
readonly emptyForegroundRefreshButtonColor: XStandardType<boolean> =
this.emptyPropertyProvider.foregroundRefreshButtonColor;
readonly emptyMessage: XStandardType<XResourceIdentifier> =
this.emptyPropertyProvider.message;
readonly emptyRefreshIcon: XStandardType<XIconIdentifier> =
this.emptyPropertyProvider.refreshIcon;
readonly emptyRefresh: EventEmitter<void> =
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<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
//#endregion
//
//#region XComponentEmpty ...
//
@Input()
showEmpty: XStandardType<boolean> = this.propertyProvider.showEmpty;
@Input()
emptyHasRefresh: XStandardType<boolean> =
this.propertyProvider.emptyHasRefresh;
@Input()
emptyActionProvider: Subject<XEmptyActionModel> =
this.propertyProvider.emptyActionProvider;
@Input()
emptyCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.emptyCssClass;
@Input()
emptyColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyColor;
@Input()
emptyForegroundColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundColor;
@Input()
emptyMessageColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyMessageColor;
@Input()
emptyForegroundMessageColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundMessageColor;
@Input()
emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyRefreshButtonColor;
@Input()
emptyForegroundRefreshButtonColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundRefreshButtonColor;
@Input()
emptyMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.emptyMessage;
@Input()
emptyRefreshIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.emptyRefreshIcon;
@Output()
emptyRefresh: EventEmitter<void> = 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<IXCardEmptyContainer> {
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<boolean> =
this.cardPropertyProvider.isInPage;
readonly wrapWithCard: XStandardType<boolean> =
this.cardPropertyProvider.wrapWithCard;
readonly cardActionProvider: Subject<XCardActionModel> =
this.cardPropertyProvider.cardActionProvider;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
this.cardPropertyProvider.cardCssClass;
readonly cardColor: XStandardType<XColorIdentifier> =
this.cardPropertyProvider.cardColor;
readonly cardForegroundColor: XStandardType<boolean> =
this.cardPropertyProvider.cardForegroundColor;
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardTitle;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardSubTitle;
readonly cardShowFooter: XStandardType<boolean> =
this.cardPropertyProvider.cardShowFooter;
readonly cardShowActions: XStandardType<boolean> =
this.cardPropertyProvider.cardShowActions;
//#endregion
//
//#region ComponentActionBar Props ...
readonly showActionBar: XStandardType<boolean> =
this.actionBarPropertyProvider.showActionBar;
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
this.actionBarPropertyProvider.actionBarActionProvider;
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.actionBarPropertyProvider.actionBarCssClass;
readonly actionBarColor: XStandardType<XColorIdentifier> =
this.actionBarPropertyProvider.actionBarColor;
readonly actionBarForegroundColor: XStandardType<boolean> =
this.actionBarPropertyProvider.actionBarForegroundColor;
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.actionBarPropertyProvider.actionBarActions;
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
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<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
//#endregion
//
//#region ComponentActionBar Props ...
@Input()
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
@Input()
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.actionBarCssClass;
@Input()
actionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.actionBarColor;
@Input()
actionBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.actionBarForegroundColor;
@Input()
actionBarActionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.actionBarActionProvider;
@Output()
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
this.propertyProvider.actionBarActionFired;
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
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<IXCardActionBarContainer> {
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<boolean> =
this.actionBarPropertyProvider.showActionBar;
//
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
this.actionBarPropertyProvider.actionBarActionProvider;
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.actionBarPropertyProvider.actionBarCssClass;
//
readonly actionBarColor: XStandardType<XColorIdentifier> =
this.actionBarPropertyProvider.actionBarColor;
readonly actionBarForegroundColor: XStandardType<boolean> =
this.actionBarPropertyProvider.actionBarForegroundColor;
//
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.actionBarPropertyProvider.actionBarActions;
//
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
this.actionBarPropertyProvider.actionBarActionFired;
//#endregion
//
//#region SearchBar ...
//
readonly showSearchBar: XStandardType<boolean> =
this.searchBarPropertyProvider.showSearchBar;
//
readonly searchBarActionProvider: Subject<XSearchBarActionModel> =
this.searchBarPropertyProvider.searchBarActionProvider;
readonly searchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.searchBarPropertyProvider.searchBarCssClass;
//
readonly searchBarColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarColor;
readonly searchBarForegroundColor: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarForegroundColor;
//
readonly searchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarSearchInputColor;
readonly searchBarForegroundSearchInputColor: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarForegroundSearchInputColor;
//
readonly searchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.searchBarPropertyProvider.searchBarType;
readonly searchBarTitle: XStandardType<XResourceIdentifier> =
this.searchBarPropertyProvider.searchBarTitle;
readonly searchBarValue: XStandardType<string> =
this.searchBarPropertyProvider.searchBarValue;
readonly searchBarEnterKeyHint: XStandardType<string> =
this.searchBarPropertyProvider.searchBarEnterKeyHint;
readonly searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.searchBarPropertyProvider.searchBarKeyboardType;
readonly searchBarSpellcheck: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarSpellcheck;
readonly searchBarDebounce: XStandardType<number> =
this.searchBarPropertyProvider.searchBarDebounce;
//
readonly searchBarShowCancelButton: XStandardType<string> =
this.searchBarPropertyProvider.searchBarShowCancelButton;
readonly searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonIcon;
readonly searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonTitle;
readonly searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonIconColor;
//
readonly searchBarShowClearButton: XStandardType<string> =
this.searchBarPropertyProvider.searchBarShowClearButton;
readonly searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarClearButtonIcon;
readonly searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarClearButtonIconColor;
//
readonly searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarSearchButtonIcon;
readonly searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarSearchButtonIconColor;
//
readonly searchBarQueryChange: EventEmitter<string> =
this.searchBarPropertyProvider.searchBarQueryChange;
readonly searchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> =
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<boolean> = this.propertyProvider.showActionBar;
//
@Input()
actionBarActionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.actionBarActionProvider;
@Input()
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.actionBarCssClass;
//
@Input()
actionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.actionBarColor;
@Input()
actionBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.actionBarForegroundColor;
//
@Input()
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.propertyProvider.actionBarActions;
//
@Output()
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
//#endregion
//
//#region SearchBar ...
//
@Input()
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
//
@Input()
searchBarActionProvider: Subject<XSearchBarActionModel> =
this.propertyProvider.searchBarActionProvider;
@Input()
searchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.searchBarCssClass;
//
@Input()
searchBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarColor;
@Input()
searchBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundColor;
//
@Input()
searchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchInputColor;
@Input()
searchBarForegroundSearchInputColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundSearchInputColor;
//
@Input()
searchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarType;
@Input()
searchBarTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarTitle;
@Input()
searchBarValue: XStandardType<string> = this.propertyProvider.searchBarValue;
@Input()
searchBarEnterKeyHint: XStandardType<string> =
this.propertyProvider.searchBarEnterKeyHint;
@Input()
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarKeyboardType;
@Input()
searchBarSpellcheck: XStandardType<boolean> =
this.propertyProvider.searchBarSpellcheck;
@Input()
searchBarDebounce: XStandardType<number> =
this.propertyProvider.searchBarDebounce;
//
@Input()
searchBarShowCancelButton: XStandardType<string> =
this.propertyProvider.searchBarShowCancelButton;
@Input()
searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarCancelButtonIcon;
@Input()
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarCancelButtonTitle;
@Input()
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarCancelButtonIconColor;
//
@Input()
searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarClearButtonIcon;
@Input()
searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarClearButtonIconColor;
//
@Input()
searchBarShowClearButton: XStandardType<string> =
this.propertyProvider.searchBarShowClearButton;
@Input()
searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarSearchButtonIcon;
@Input()
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchButtonIconColor;
//
@Output()
searchBarQueryChange: EventEmitter<string> = new EventEmitter();
@Output()
searchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> = 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<IXCardEmptyActionSearchBarContainer> {
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<number>;
maxAllowedFilesException: XStandardType<XExceptionIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XMaxAllowedFilesContainer
implements Readonly<IXMaxAllowedFilesContainer>
{
//
//#region Props ...
readonly maxAllowedFiles: XStandardType<number> = this.config.maxUploadFiles;
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
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<number>;
maxAllowedSizeException: XStandardType<XExceptionIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XMaxAllowedSizeContainer
implements Readonly<IXMaxAllowedSizeContainer>
{
//
//#region Props ...
readonly maxAllowedSize: XStandardType<number> = this.config.maxAllowedSize;
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
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<number>;
minAllowedFileSizeException: XStandardType<XExceptionIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XMinAllowedFileSizeContainer
implements Readonly<IXMinAllowedFileSizeContainer>
{
//
//#region Props ...
readonly minAllowedFileSize: XStandardType<number> =
this.config.minAllowedFileSize;
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
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<number>;
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XMaxAllowedFileSizeContainer
implements Readonly<IXMaxAllowedFileSizeContainer>
{
//
//#region Props ...
readonly maxAllowedFileSize: XStandardType<number> =
this.config.maxAllowedFileSize;
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.MaxFilesSizeExceeded;
//#endregion
//
//#region Constructor ...
constructor(
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
private config: XFrameworkComponentsConfig
) {}
//#endregion
}
//#endregion
//
//#region Regular File ...
export interface IXFileRegularContainer {
emptyFileException: XStandardType<XExceptionIdentifier>;
notAllowedFileException: XStandardType<XExceptionIdentifier>;
allowedExtensions: XStandardType<XOneOrManyType<string>>;
}
@Injectable({
providedIn: 'root',
})
export class XFileRegularContainer implements Readonly<IXFileRegularContainer> {
//
//#region Props ...
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.EmptyFile;
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.InavlidFile;
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> = [];
//#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<IXFileContainer> {
//
//#region Props ...
//
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.EmptyFile;
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.InavlidFile;
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> = [];
//
readonly maxAllowedFiles: XStandardType<number> = this.config.maxUploadFiles;
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.MaxAllowedFilesExceeded;
//
readonly maxAllowedSize: XStandardType<number> = this.config.maxAllowedSize;
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.MaxFilesSizeExceeded;
//
readonly minAllowedFileSize: XStandardType<number> =
this.config.minAllowedFileSize;
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.MinFilesSizeExceeded;
//
readonly maxAllowedFileSize: XStandardType<number> =
this.config.maxAllowedFileSize;
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
XExceptionIDs.MaxFilesSizeExceeded;
//#endregion
//
//#region Constructor ...
constructor(
@Inject(X_FRAMEWORK_COMPONENTS_CONFIG)
private config: XFrameworkComponentsConfig
) {}
//#endregion
}
//#endregion
//
//#region XFileContainerComponent ...
@Injectable({
providedIn: 'root',
})
@Component({
template: `
<!--
<ng-container *ngIf="extractProps() | async as props">
</ng-container>
-->
`,
})
export abstract class XFileContainerComponent
extends XBaseContainerComponent
implements IXFileContainer
{
//
//#region Props ...
//
@Input()
emptyFileException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.emptyFileException;
@Input()
notAllowedFileException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.notAllowedFileException;
@Input()
allowedExtensions: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.allowedExtensions;
//
@Input()
maxAllowedFiles: XStandardType<number> =
this.propertyProvider.maxAllowedFiles;
@Input()
maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedFilesException;
//
@Input()
maxAllowedSize: XStandardType<number> = this.propertyProvider.maxAllowedSize;
@Input()
maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedSizeException;
//
@Input()
minAllowedFileSize: XStandardType<number> =
this.propertyProvider.minAllowedFileSize;
@Input()
minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.minAllowedFileSizeException;
//
@Input()
maxAllowedFileSize: XStandardType<number> =
this.propertyProvider.maxAllowedFileSize;
@Input()
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
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<IXFileContainer> {
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<IXCardFileContainer>
{
//
//#region XComponentCard ...
readonly isInPage: XStandardType<boolean> =
this.cardPropertyProvider.isInPage;
readonly wrapWithCard: XStandardType<boolean> =
this.cardPropertyProvider.wrapWithCard;
readonly cardShowFooter: XStandardType<boolean> =
this.cardPropertyProvider.cardShowFooter;
readonly cardShowActions: XStandardType<boolean> =
this.cardPropertyProvider.cardShowActions;
readonly cardColor: XStandardType<XColorIdentifier> =
this.cardPropertyProvider.cardColor;
readonly cardForegroundColor: XStandardType<boolean> =
this.cardPropertyProvider.cardForegroundColor;
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardTitle;
readonly cardActionProvider: Subject<XCardActionModel> =
this.cardPropertyProvider.cardActionProvider;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardSubTitle;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
this.cardPropertyProvider.cardCssClass;
//#endregion
//
//#region XFile ...
//
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.emptyFileException;
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.notAllowedFileException;
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> =
this.filePropertyProvider.allowedExtensions;
//
readonly maxAllowedFiles: XStandardType<number> =
this.filePropertyProvider.maxAllowedFiles;
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.maxAllowedFilesException;
//
readonly maxAllowedSize: XStandardType<number> =
this.filePropertyProvider.maxAllowedSize;
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.maxAllowedSizeException;
//
readonly minAllowedFileSize: XStandardType<number> =
this.filePropertyProvider.minAllowedFileSize;
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.minAllowedFileSizeException;
//
readonly maxAllowedFileSize: XStandardType<number> =
this.filePropertyProvider.maxAllowedFileSize;
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
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<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
//#endregion
//
//#region File ...
//
@Input()
emptyFileException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.emptyFileException;
@Input()
notAllowedFileException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.notAllowedFileException;
@Input()
allowedExtensions: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.allowedExtensions;
//
@Input()
maxAllowedFiles: XStandardType<number> =
this.propertyProvider.maxAllowedFiles;
@Input()
maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedFilesException;
//
@Input()
maxAllowedSize: XStandardType<number> = this.propertyProvider.maxAllowedSize;
@Input()
maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedSizeException;
//
@Input()
minAllowedFileSize: XStandardType<number> =
this.propertyProvider.minAllowedFileSize;
@Input()
minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.minAllowedFileSizeException;
//
@Input()
maxAllowedFileSize: XStandardType<number> =
this.propertyProvider.maxAllowedFileSize;
@Input()
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
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<IXCardFileContainer> {
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<IXCardFileFileDropContainer>
{
//
//#region Props ...
//
//#region ComponentCard ...
readonly isInPage: XStandardType<boolean> =
this.cardPropertyProvider.isInPage;
readonly wrapWithCard: XStandardType<boolean> =
this.cardPropertyProvider.wrapWithCard;
readonly cardShowFooter: XStandardType<boolean> =
this.cardPropertyProvider.cardShowFooter;
readonly cardShowActions: XStandardType<boolean> =
this.cardPropertyProvider.cardShowActions;
readonly cardColor: XStandardType<XColorIdentifier> =
this.cardPropertyProvider.cardColor;
readonly cardForegroundColor: XStandardType<boolean> =
this.cardPropertyProvider.cardForegroundColor;
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardTitle;
readonly cardActionProvider: Subject<XCardActionModel> =
this.cardPropertyProvider.cardActionProvider;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardSubTitle;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
this.cardPropertyProvider.cardCssClass;
//#endregion
//
//#region File ...
//
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.emptyFileException;
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.notAllowedFileException;
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> =
this.filePropertyProvider.allowedExtensions;
//
readonly maxAllowedFiles: XStandardType<number> =
this.filePropertyProvider.maxAllowedFiles;
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.maxAllowedFilesException;
//
readonly maxAllowedSize: XStandardType<number> =
this.filePropertyProvider.maxAllowedSize;
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.maxAllowedSizeException;
//
readonly minAllowedFileSize: XStandardType<number> =
this.filePropertyProvider.minAllowedFileSize;
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.minAllowedFileSizeException;
//
readonly maxAllowedFileSize: XStandardType<number> =
this.filePropertyProvider.maxAllowedFileSize;
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.maxAllowedFileSizeException;
//#endregion
//
//#region File Drop ...
//
readonly showFileDropArea: XStandardType<boolean> =
this.fileDropPropertyProvider.showFileDropArea;
//
readonly fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
this.fileDropPropertyProvider.fileDropAreaActionProvider;
readonly fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
this.fileDropPropertyProvider.fileDropAreaCssClass;
//
readonly fileDropAreaColor: XStandardType<XColorIdentifier> =
this.fileDropPropertyProvider.fileDropAreaColor;
readonly fileDropAreaForegroundColor: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaForegroundColor;
//
readonly fileDropAreaIcon: XStandardType<XIconIdentifier> =
this.fileDropPropertyProvider.fileDropAreaIcon;
readonly fileDropAreaMessage: XStandardType<XResourceIdentifier> =
this.fileDropPropertyProvider.fileDropAreaMessage;
//
readonly fileDropAreaDisableFileCheck: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaDisableFileCheck;
//
readonly fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaSupportsMultipleFiles;
readonly fileDropAreaAllowedExtensions: XStandardType<
XOneOrManyType<string>
> = this.fileDropPropertyProvider.fileDropAreaAllowedExtensions;
//
readonly fileDropAreaDragDisabled: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaDragDisabled;
readonly fileDropAreaContentTemplate: TemplateRef<any> =
this.fileDropPropertyProvider.fileDropAreaContentTemplate;
readonly fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
this.fileDropPropertyProvider.fileDropAreaFilesChangeEmiter;
//
readonly fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
this.fileDropPropertyProvider.fileDropAreaSuccessColor;
readonly fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
this.fileDropPropertyProvider.fileDropAreaErrorColor;
readonly fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
this.fileDropPropertyProvider.fileDropAreaAccentColor;
//
//#region ComponentsCard ...
readonly fileDropAreaIsInPage: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaIsInPage;
readonly fileDropAreaWrapWithCard: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaWrapWithCard;
readonly fileDropAreaCardShowFooter: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaCardShowFooter;
readonly fileDropAreaCardShowActions: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaCardShowActions;
readonly fileDropAreaCardColor: XStandardType<XColorIdentifier> =
this.fileDropPropertyProvider.fileDropAreaCardColor;
readonly fileDropAreaCardForegroundColor: XStandardType<boolean> =
this.fileDropPropertyProvider.fileDropAreaCardForegroundColor;
readonly fileDropAreaCardTitle: XStandardType<XResourceIdentifier> =
this.fileDropPropertyProvider.fileDropAreaCardTitle;
readonly fileDropAreaCardActionProvider: Subject<XCardActionModel> =
this.fileDropPropertyProvider.fileDropAreaCardActionProvider;
readonly fileDropAreaCardSubTitle: XStandardType<XResourceIdentifier> =
this.fileDropPropertyProvider.fileDropAreaCardSubTitle;
readonly fileDropAreaCardCssClass: XStandardType<XOneOrManyType<string>> =
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<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
//#endregion
//
//#region File ...
//
@Input()
emptyFileException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.emptyFileException;
@Input()
notAllowedFileException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.notAllowedFileException;
@Input()
allowedExtensions: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.allowedExtensions;
//
@Input()
maxAllowedFiles: XStandardType<number> =
this.propertyProvider.maxAllowedFiles;
@Input()
maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedFilesException;
//
@Input()
maxAllowedSize: XStandardType<number> = this.propertyProvider.maxAllowedSize;
@Input()
maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedSizeException;
//
@Input()
minAllowedFileSize: XStandardType<number> =
this.propertyProvider.minAllowedFileSize;
@Input()
minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.minAllowedFileSizeException;
//
@Input()
maxAllowedFileSize: XStandardType<number> =
this.propertyProvider.maxAllowedFileSize;
@Input()
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedFileSizeException;
//#endregion
//
//#region FileDrop ...
//
@Input()
fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
this.propertyProvider.fileDropAreaActionProvider;
@Input()
fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.fileDropAreaCssClass;
//
@Input()
fileDropAreaColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaColor;
@Input()
fileDropAreaForegroundColor: XStandardType<boolean> =
this.propertyProvider.fileDropAreaForegroundColor;
//
@Input()
fileDropAreaIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.fileDropAreaIcon;
@Input()
fileDropAreaMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.fileDropAreaMessage;
//
@Input()
fileDropAreaDisableFileCheck: XStandardType<boolean> =
this.propertyProvider.fileDropAreaDisableFileCheck;
//
@Input()
fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
this.propertyProvider.fileDropAreaSupportsMultipleFiles;
@Input()
fileDropAreaAllowedExtensions: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.fileDropAreaAllowedExtensions;
//
@Input()
fileDropAreaDragDisabled: XStandardType<boolean> =
this.propertyProvider.fileDropAreaDragDisabled;
@Input()
fileDropAreaContentTemplate: TemplateRef<any> =
this.propertyProvider.fileDropAreaContentTemplate;
@Output()
fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
new EventEmitter();
//
@Input()
fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaSuccessColor;
@Input()
fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaErrorColor;
@Input()
fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaAccentColor;
//
@Input()
showFileDropArea: XStandardType<boolean> =
this.propertyProvider.showFileDropArea;
//
//#region ComponentsCard ...
@Input()
fileDropAreaIsInPage: XStandardType<boolean> =
this.propertyProvider.fileDropAreaIsInPage;
@Input()
fileDropAreaWrapWithCard: XStandardType<boolean> =
this.propertyProvider.fileDropAreaWrapWithCard;
@Input()
fileDropAreaCardShowFooter: XStandardType<boolean> =
this.propertyProvider.fileDropAreaCardShowFooter;
@Input()
fileDropAreaCardShowActions: XStandardType<boolean> =
this.propertyProvider.fileDropAreaCardShowActions;
@Input()
fileDropAreaCardColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaCardColor;
@Input()
fileDropAreaCardForegroundColor: XStandardType<boolean> =
this.propertyProvider.fileDropAreaCardForegroundColor;
@Input()
fileDropAreaCardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.fileDropAreaCardTitle;
@Input()
fileDropAreaCardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.fileDropAreaCardActionProvider;
@Input()
fileDropAreaCardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.fileDropAreaCardSubTitle;
@Input()
fileDropAreaCardCssClass: XStandardType<XOneOrManyType<string>> =
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<IXCardFileFileDropContainer> {
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<boolean>;
onNext: EventEmitter<string>;
}
export interface IXNextContainer extends IXBaseContainer {
//
//#region Next ...
hasNext: XStandardType<boolean>;
disableNext: XStandardType<boolean>;
nextConfirmer: () => XStandardType<boolean>;
nextPosition: XStandardType<XSlotNameIdentifier>;
nextCssClass: XStandardType<XOneOrManyType<string>>;
nextButton: XStandardType<Partial<IXButtonContainer>>;
//#endregion
}
export const defaultNextButton: Partial<IXButtonContainer> = {
title: XResourceIDs.next,
type: XButtonType.Raised,
color: XColorWithBrightness.Primary,
};
@Injectable({
providedIn: 'root',
})
export abstract class XNextContainer
extends XBaseContainer
implements Readonly<IXNextContainer>
{
//
//#region Next ...
readonly hasNext: XStandardType<boolean>;
readonly disableNext: XStandardType<boolean>;
readonly nextConfirmer: () => XStandardType<boolean>;
readonly nextPosition: XStandardType<XSlotNameIdentifier> = XSlotName.START;
readonly nextCssClass: XStandardType<XOneOrManyType<string>> =
'ion-text-start';
readonly nextButton: XStandardType<Partial<IXButtonContainer>> = {
...defaultNextButton,
};
//#endregion
}
//#endregion
//
//#region Prev ...
export interface IXPrevHost {
canPrev: XStandardType<boolean>;
onPrev: EventEmitter<string>;
}
export interface IXPrevContainer extends IXBaseContainer {
//
//#region Prev ...
hasPrev: XStandardType<boolean>;
disablePrev: XStandardType<boolean>;
prevConfirmer: () => XStandardType<boolean>;
prevPosition: XStandardType<XSlotNameIdentifier>;
prevCssClass: XStandardType<XOneOrManyType<string>>;
prevButton: XStandardType<Partial<IXButtonContainer>>;
//#endregion
}
export const defaultPrevButton: Partial<IXButtonContainer> = {
type: XButtonType.Raised,
title: XResourceIDs.previous,
color: XColorWithBrightness.Primary,
};
@Injectable({
providedIn: 'root',
})
export abstract class XPrevContainer
extends XBaseContainer
implements Readonly<IXPrevContainer>
{
//
//#region Prev ...
readonly hasPrev: XStandardType<boolean>;
readonly disablePrev: XStandardType<boolean>;
readonly prevConfirmer: () => XStandardType<boolean>;
readonly prevPosition: XStandardType<XSlotNameIdentifier> = XSlotName.END;
readonly prevCssClass: XStandardType<XOneOrManyType<string>> = 'ion-text-end';
readonly prevButton: XStandardType<Partial<IXButtonContainer>> = {
...defaultPrevButton,
};
//#endregion
}
//#endregion
//
//#region Reset ...
export interface IXResetHost {
canReset: XStandardType<boolean>;
onReset: EventEmitter<string>;
}
export interface IXResetContainer extends IXBaseContainer {
//
//#region Reset ...
hasReset: XStandardType<boolean>;
disableReset: XStandardType<boolean>;
resetConfirmer: () => XStandardType<boolean>;
resetPosition: XStandardType<XSlotNameIdentifier>;
resetCssClass: XStandardType<XOneOrManyType<string>>;
resetButton: XStandardType<Partial<IXButtonContainer>>;
//#endregion
}
export const defaultResetButton: Partial<IXButtonContainer> = {
type: XButtonType.Raised,
title: XResourceIDs.reset,
color: XColorWithBrightness.Warning,
};
@Injectable({
providedIn: 'root',
})
export abstract class XResetContainer
extends XBaseContainer
implements Readonly<IXResetContainer>
{
//
//#region Reset ...
readonly hasReset: XStandardType<boolean>;
readonly disableReset: XStandardType<boolean>;
readonly resetConfirmer: () => XStandardType<boolean>;
readonly resetPosition: XStandardType<XSlotNameIdentifier> = XSlotName.CENTER;
readonly resetCssClass: XStandardType<XOneOrManyType<string>> =
'ion-text-center';
readonly resetButton: XStandardType<Partial<IXButtonContainer>> = {
...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<IXNextPrevResetHostContainer>
{
//
//#region Props ...
//
//#region Next ...
readonly canNext: XStandardType<boolean> = true;
readonly onNext: EventEmitter<string> = new EventEmitter<string>();
//#endregion
//
//#region Prev ...
readonly canPrev: XStandardType<boolean> = true;
readonly onPrev: EventEmitter<string> = new EventEmitter<string>();
//#endregion
//
//#region Reset ...
readonly canReset: XStandardType<boolean> = true;
readonly onReset: EventEmitter<string> = new EventEmitter<string>();
//#endregion
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XNextPrevResetHostContainerComponent
extends XBaseContainerComponent
implements IXNextPrevResetHostContainer
{
//
//#region Props ...
//
//#region Next ...
@Input()
canNext: XStandardType<boolean> = this.propertyProvider.canNext;
@Output()
onNext: EventEmitter<string> = new EventEmitter();
//#endregion
//
//#region Prev ...
@Input()
canPrev: XStandardType<boolean> = this.propertyProvider.canPrev;
@Output()
onPrev: EventEmitter<string> = new EventEmitter();
//#endregion
//
//#region Reset ...
@Input()
canReset: XStandardType<boolean> = this.propertyProvider.canReset;
@Output()
onReset: EventEmitter<string> = 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<IXNextPrevResetHostContainer> {
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<boolean> =
this.cardPropertyProvider.isInPage;
readonly wrapWithCard: XStandardType<boolean> =
this.cardPropertyProvider.wrapWithCard;
readonly cardShowFooter: XStandardType<boolean> =
this.cardPropertyProvider.cardShowFooter;
readonly cardShowActions: XStandardType<boolean> =
this.cardPropertyProvider.cardShowActions;
readonly cardColor: XStandardType<XColorIdentifier> =
this.cardPropertyProvider.cardColor;
readonly cardForegroundColor: XStandardType<boolean> =
this.cardPropertyProvider.cardForegroundColor;
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardTitle;
readonly cardActionProvider: Subject<XCardActionModel> =
this.cardPropertyProvider.cardActionProvider;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardSubTitle;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
this.cardPropertyProvider.cardCssClass;
//#endregion
//
//#region XNextPrevResetHost ...
//
//#region Next ...
readonly canNext: XStandardType<boolean> =
this.nextPrevResetHostPropertyProvider.canNext;
readonly onNext: EventEmitter<string> =
this.nextPrevResetHostPropertyProvider.onNext;
//#endregion
//
//#region Prev ...
readonly canPrev: XStandardType<boolean> =
this.nextPrevResetHostPropertyProvider.canPrev;
readonly onPrev: EventEmitter<string> =
this.nextPrevResetHostPropertyProvider.onPrev;
//#endregion
//
//#region Reset ...
readonly canReset: XStandardType<boolean> =
this.nextPrevResetHostPropertyProvider.canReset;
readonly onReset: EventEmitter<string> =
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<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
//#endregion
//
//#region XNextPrevResetHost ...
//
//#region Next ...
@Input()
canNext: XStandardType<boolean> = this.propertyProvider.canNext;
@Output()
onNext: EventEmitter<string> = new EventEmitter();
//#endregion
//
//#region Prev ...
@Input()
canPrev: XStandardType<boolean> = this.propertyProvider.canPrev;
@Output()
onPrev: EventEmitter<string> = new EventEmitter();
//#endregion
//
//#region Reset ...
@Input()
canReset: XStandardType<boolean> = this.propertyProvider.canReset;
@Output()
onReset: EventEmitter<string> = 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<IXCardNextPrevResetHostContainer> {
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<IXNextPrevResetContainer>
{
//
//#region Props ...
//
//#region Next ...
hasNext: XStandardType<boolean> = this.nextPropertyProvider.hasNext;
disableNext: XStandardType<boolean> = this.nextPropertyProvider.disableNext;
nextConfirmer: () => XStandardType<boolean> =
this.nextPropertyProvider.nextConfirmer;
nextPosition: XStandardType<XSlotNameIdentifier> =
this.nextPropertyProvider.nextPosition;
nextCssClass: XStandardType<XOneOrManyType<string>> =
this.nextPropertyProvider.nextCssClass;
nextButton: XStandardType<Partial<IXButtonContainer>> =
this.nextPropertyProvider.nextButton;
//#endregion
//
//#region Prev ...
hasPrev: XStandardType<boolean> = this.prevPropertyProvider.hasPrev;
disablePrev: XStandardType<boolean> = this.prevPropertyProvider.disablePrev;
prevConfirmer: () => XStandardType<boolean> =
this.prevPropertyProvider.prevConfirmer;
prevPosition: XStandardType<XSlotNameIdentifier> =
this.prevPropertyProvider.prevPosition;
prevCssClass: XStandardType<XOneOrManyType<string>> =
this.prevPropertyProvider.prevCssClass;
prevButton: XStandardType<Partial<IXButtonContainer>> =
this.prevPropertyProvider.prevButton;
//#endregion
//
//#region Reset ...
hasReset: XStandardType<boolean> = this.resetpropertyProvider.hasReset;
disableReset: XStandardType<boolean> =
this.resetpropertyProvider.disableReset;
resetConfirmer: () => XStandardType<boolean> =
this.resetpropertyProvider.resetConfirmer;
resetPosition: XStandardType<XSlotNameIdentifier> =
this.resetpropertyProvider.resetPosition;
resetCssClass: XStandardType<XOneOrManyType<string>> =
this.resetpropertyProvider.resetCssClass;
resetButton: XStandardType<Partial<IXButtonContainer>> =
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<boolean> = this.propertyProvider.hasNext;
@Input()
disableNext: XStandardType<boolean> = this.propertyProvider.disableNext;
@Input()
nextConfirmer: () => XStandardType<boolean> =
this.propertyProvider.nextConfirmer;
@Input()
nextPosition: XStandardType<XSlotNameIdentifier> =
this.propertyProvider.nextPosition;
@Input()
nextCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.nextCssClass;
@Input()
nextButton: XStandardType<Partial<IXButtonContainer>> =
this.propertyProvider.nextButton;
//#endregion
//
//#region Prev ...
@Input()
hasPrev: XStandardType<boolean> = this.propertyProvider.hasPrev;
@Input()
disablePrev: XStandardType<boolean> = this.propertyProvider.disablePrev;
@Input()
prevConfirmer: () => XStandardType<boolean> =
this.propertyProvider.prevConfirmer;
@Input()
prevPosition: XStandardType<XSlotNameIdentifier> =
this.propertyProvider.prevPosition;
@Input()
prevCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.prevCssClass;
@Input()
prevButton: XStandardType<Partial<IXButtonContainer>> =
this.propertyProvider.prevButton;
//#endregion
//
//#region Reset ...
@Input()
hasReset: XStandardType<boolean> = this.propertyProvider.hasReset;
@Input()
disableReset: XStandardType<boolean> = this.propertyProvider.disableReset;
@Input()
resetConfirmer: () => XStandardType<boolean> =
this.propertyProvider.resetConfirmer;
@Input()
resetPosition: XStandardType<XSlotNameIdentifier> =
this.propertyProvider.resetPosition;
@Input()
resetCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.resetCssClass;
@Input()
resetButton: XStandardType<Partial<IXButtonContainer>> =
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<IXNextPrevResetContainer> {
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<IXNextPrevResetAndHostContainer>
{
//
//#region Props ...
//
//#region Inteface ...
//
//#region Next ...
hasNext: XStandardType<boolean> = this.nextPrevResetPropertyProvider.hasNext;
disableNext: XStandardType<boolean> =
this.nextPrevResetPropertyProvider.disableNext;
nextConfirmer: () => XStandardType<boolean> =
this.nextPrevResetPropertyProvider.nextConfirmer;
nextPosition: XStandardType<XSlotNameIdentifier> =
this.nextPrevResetPropertyProvider.nextPosition;
nextCssClass: XStandardType<XOneOrManyType<string>> =
this.nextPrevResetPropertyProvider.nextCssClass;
nextButton: XStandardType<Partial<IXButtonContainer>> =
this.nextPrevResetPropertyProvider.nextButton;
//#endregion
//
//#region Prev ...
hasPrev: XStandardType<boolean> = this.nextPrevResetPropertyProvider.hasPrev;
disablePrev: XStandardType<boolean> =
this.nextPrevResetPropertyProvider.disablePrev;
prevConfirmer: () => XStandardType<boolean> =
this.nextPrevResetPropertyProvider.prevConfirmer;
prevPosition: XStandardType<XSlotNameIdentifier> =
this.nextPrevResetPropertyProvider.prevPosition;
prevCssClass: XStandardType<XOneOrManyType<string>> =
this.nextPrevResetPropertyProvider.prevCssClass;
prevButton: XStandardType<Partial<IXButtonContainer>> =
this.nextPrevResetPropertyProvider.prevButton;
//#endregion
//
//#region Reset ...
hasReset: XStandardType<boolean> =
this.nextPrevResetPropertyProvider.hasReset;
disableReset: XStandardType<boolean> =
this.nextPrevResetPropertyProvider.disableReset;
resetConfirmer: () => XStandardType<boolean> =
this.nextPrevResetPropertyProvider.resetConfirmer;
resetPosition: XStandardType<XSlotNameIdentifier> =
this.nextPrevResetPropertyProvider.resetPosition;
resetCssClass: XStandardType<XOneOrManyType<string>> =
this.nextPrevResetPropertyProvider.resetCssClass;
resetButton: XStandardType<Partial<IXButtonContainer>> =
this.nextPrevResetPropertyProvider.resetButton;
//#endregion
//#endregion
//
//#region Host ...
//
//#region Next ...
readonly canNext: XStandardType<boolean> =
this.cardNextPrevResetPropertyProvider.canNext;
readonly onNext: EventEmitter<string> =
this.cardNextPrevResetPropertyProvider.onNext;
//#endregion
//
//#region Prev ...
readonly canPrev: XStandardType<boolean> =
this.cardNextPrevResetPropertyProvider.canPrev;
readonly onPrev: EventEmitter<string> =
this.cardNextPrevResetPropertyProvider.onPrev;
//#endregion
//
//#region Reset ...
readonly canReset: XStandardType<boolean> =
this.cardNextPrevResetPropertyProvider.canReset;
readonly onReset: EventEmitter<string> =
this.cardNextPrevResetPropertyProvider.onReset;
//#endregion
//#endregion
//
//#region XComponentCard ...
readonly isInPage: XStandardType<boolean> =
this.cardNextPrevResetPropertyProvider.isInPage;
readonly wrapWithCard: XStandardType<boolean> =
this.cardNextPrevResetPropertyProvider.wrapWithCard;
readonly cardShowFooter: XStandardType<boolean> =
this.cardNextPrevResetPropertyProvider.cardShowFooter;
readonly cardShowActions: XStandardType<boolean> =
this.cardNextPrevResetPropertyProvider.cardShowActions;
readonly cardColor: XStandardType<XColorIdentifier> =
this.cardNextPrevResetPropertyProvider.cardColor;
readonly cardForegroundColor: XStandardType<boolean> =
this.cardNextPrevResetPropertyProvider.cardForegroundColor;
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.cardNextPrevResetPropertyProvider.cardTitle;
readonly cardActionProvider: Subject<XCardActionModel> =
this.cardNextPrevResetPropertyProvider.cardActionProvider;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.cardNextPrevResetPropertyProvider.cardSubTitle;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
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<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
//#endregion
//
//#region XNextPrevResetHost ...
//
//#region Next ...
@Input()
canNext: XStandardType<boolean> = this.propertyProvider.canNext;
@Output()
onNext: EventEmitter<string> = new EventEmitter();
//#endregion
//
//#region Prev ...
@Input()
canPrev: XStandardType<boolean> = this.propertyProvider.canPrev;
@Output()
onPrev: EventEmitter<string> = new EventEmitter();
//#endregion
//
//#region Reset ...
@Input()
canReset: XStandardType<boolean> = this.propertyProvider.canReset;
@Output()
onReset: EventEmitter<string> = new EventEmitter();
//#endregion
//#endregion
//
//#region Props ...
//
//#region Next ...
@Input()
hasNext: XStandardType<boolean> = this.propertyProvider.hasNext;
@Input()
disableNext: XStandardType<boolean> = this.propertyProvider.disableNext;
@Input()
nextConfirmer: () => XStandardType<boolean> =
this.propertyProvider.nextConfirmer;
@Input()
nextPosition: XStandardType<XSlotNameIdentifier> =
this.propertyProvider.nextPosition;
@Input()
nextCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.nextCssClass;
@Input()
nextButton: XStandardType<Partial<IXButtonContainer>> =
this.propertyProvider.nextButton;
//#endregion
//
//#region Prev ...
@Input()
hasPrev: XStandardType<boolean> = this.propertyProvider.hasPrev;
@Input()
disablePrev: XStandardType<boolean> = this.propertyProvider.disablePrev;
@Input()
prevConfirmer: () => XStandardType<boolean> =
this.propertyProvider.prevConfirmer;
@Input()
prevPosition: XStandardType<XSlotNameIdentifier> =
this.propertyProvider.prevPosition;
@Input()
prevCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.prevCssClass;
@Input()
prevButton: XStandardType<Partial<IXButtonContainer>> =
this.propertyProvider.prevButton;
//#endregion
//
//#region Reset ...
@Input()
hasReset: XStandardType<boolean> = this.propertyProvider.hasReset;
@Input()
disableReset: XStandardType<boolean> = this.propertyProvider.disableReset;
@Input()
resetConfirmer: () => XStandardType<boolean> =
this.propertyProvider.resetConfirmer;
@Input()
resetPosition: XStandardType<XSlotNameIdentifier> =
this.propertyProvider.resetPosition;
@Input()
resetCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.resetCssClass;
@Input()
resetButton: XStandardType<Partial<IXButtonContainer>> =
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<IXNextPrevResetAndHostContainer> {
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<IXToolbarFooterContainer>
{
//
//#region Props ...
//
//#region Toolbar ...
//
readonly showToolbar: XStandardType<boolean> =
this.toolbarPropertyProvider.showToolbar;
//
readonly toolbarActionProvider: Subject<XToolbarActionModel> =
this.toolbarPropertyProvider.toolbarActionProvider;
readonly toolbarCssClass: XStandardType<XOneOrManyType<string>> =
this.toolbarPropertyProvider.toolbarCssClass;
//
readonly toolbarColor: XStandardType<XColorIdentifier> =
this.toolbarPropertyProvider.toolbarColor;
//
readonly toolbarShowProgressBar: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarShowProgressBar;
readonly toolbarProgressBarColor: XStandardType<XColorIdentifier> =
this.toolbarPropertyProvider.toolbarProgressBarColor;
//
readonly toolbarShowTitle: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarShowTitle;
readonly toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
this.toolbarPropertyProvider.toolbarTitleSlot;
readonly toolbarTitle: XStandardType<string> =
this.toolbarPropertyProvider.toolbarTitle;
//
readonly toolbarShowSubTitle: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarShowSubTitle;
readonly toolbarSubTitle: XStandardType<string> =
this.toolbarPropertyProvider.toolbarSubTitle;
//
readonly toolbarShowLogo: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarShowLogo;
readonly toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
this.toolbarPropertyProvider.toolbarLogoSlot;
readonly toolbarLogoUrl: XStandardType<string> =
this.toolbarPropertyProvider.toolbarLogoUrl;
//
readonly toolbarHasBack: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarHasBack;
readonly toolbarShowBack: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarShowBack;
readonly toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
this.toolbarPropertyProvider.toolbarBackSlot;
readonly toolbarBackHandler?: () => XStandardType<void> =
this.toolbarPropertyProvider.toolbarBackHandler;
readonly toolbarDefaultHref: string =
this.toolbarPropertyProvider.toolbarDefaultHref;
//
readonly toolbarHasMenu: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarHasMenu;
readonly toolbarShowMenu: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarShowMenu;
readonly toolbarAutoHideMenu: XStandardType<boolean> =
this.toolbarPropertyProvider.toolbarAutoHideMenu;
readonly toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
this.toolbarPropertyProvider.toolbarMenuSlot;
//
readonly toolbarStartSlotButtonsTemplate: TemplateRef<any> =
this.toolbarPropertyProvider.toolbarStartSlotButtonsTemplate;
readonly toolbarEndSlotButtonsTemplate: TemplateRef<any> =
this.toolbarPropertyProvider.toolbarEndSlotButtonsTemplate;
//
readonly toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
this.toolbarPropertyProvider.toolbarContentSlot;
readonly toolbarContentTemplate: TemplateRef<any> =
this.toolbarPropertyProvider.toolbarContentTemplate;
//#endregion
//
//#region Footer ...
//
readonly showFooter: XStandardType<boolean> =
this.footerPropertyProvider.showFooter;
//
readonly footerActionProvider: Subject<XFooterActionModel> =
this.footerPropertyProvider.footerActionProvider;
readonly footerCssClass: XStandardType<XOneOrManyType<string>> =
this.footerPropertyProvider.footerCssClass;
//
readonly footerColor: XStandardType<XColorIdentifier> =
this.footerPropertyProvider.footerColor;
readonly footerContentTemplate: TemplateRef<any> =
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<boolean> = this.propertyProvider.showToolbar;
//
@Input()
toolbarActionProvider: Subject<XToolbarActionModel> =
this.propertyProvider.toolbarActionProvider;
@Input()
toolbarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.toolbarCssClass;
//
@Input()
toolbarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.toolbarColor;
//
@Input()
toolbarShowProgressBar: XStandardType<boolean> =
this.propertyProvider.toolbarShowProgressBar;
@Input()
toolbarProgressBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.toolbarProgressBarColor;
//
@Input()
toolbarShowTitle: XStandardType<boolean> =
this.propertyProvider.toolbarShowTitle;
@Input()
toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
this.propertyProvider.toolbarTitleSlot;
@Input()
toolbarTitle: XStandardType<string> = this.propertyProvider.toolbarTitle;
//
@Input()
toolbarShowSubTitle: XStandardType<boolean> =
this.propertyProvider.toolbarShowSubTitle;
@Input()
toolbarSubTitle: XStandardType<string> =
this.propertyProvider.toolbarSubTitle;
//
@Input()
toolbarShowLogo: XStandardType<boolean> =
this.propertyProvider.toolbarShowLogo;
@Input()
toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
this.propertyProvider.toolbarLogoSlot;
@Input()
toolbarLogoUrl: XStandardType<string> = this.propertyProvider.toolbarLogoUrl;
//
@Input()
toolbarHasBack: XStandardType<boolean> = this.propertyProvider.toolbarHasBack;
@Input()
toolbarShowBack: XStandardType<boolean> =
this.propertyProvider.toolbarShowBack;
@Input()
toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
this.propertyProvider.toolbarBackSlot;
@Input()
toolbarBackHandler?: () => XStandardType<void> =
this.propertyProvider.toolbarBackHandler;
@Input()
toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref;
//
@Input()
toolbarHasMenu: XStandardType<boolean> = this.propertyProvider.toolbarHasMenu;
@Input()
toolbarShowMenu: XStandardType<boolean> =
this.propertyProvider.toolbarShowMenu;
@Input()
toolbarAutoHideMenu: XStandardType<boolean> =
this.propertyProvider.toolbarAutoHideMenu;
@Input()
toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
this.propertyProvider.toolbarMenuSlot;
//
@Input()
toolbarStartSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.toolbarStartSlotButtonsTemplate;
@Input()
toolbarEndSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.toolbarEndSlotButtonsTemplate;
//
@Input()
toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
this.propertyProvider.toolbarContentSlot;
@Input()
toolbarContentTemplate: TemplateRef<any> =
this.propertyProvider.toolbarContentTemplate;
//#endregion
//
//#region Footer ...
//
@Input()
showFooter: XStandardType<boolean> = this.propertyProvider.showFooter;
//
@Input()
footerActionProvider: Subject<XFooterActionModel> =
this.propertyProvider.footerActionProvider;
@Input()
footerCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.footerCssClass;
//
@Input()
footerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.footerColor;
@Input()
footerContentTemplate: TemplateRef<any> =
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<IXToolbarFooterContainer> {
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<T> {
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<any>[] = [];
public RunningTasks: XTask<any>[] = [];
//
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<XBaseComponent>('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<XBaseComponent>('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<XBaseComponent>('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<XBaseComponent>('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<T>(obj: T, name: XKey<T>): 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<any>) {}
/**
* notify an error on running task ...
*
* @param name task name
* @param task task object
*/
public onTaskFailed(name: string, task: XTask<any>) {}
/**
* notify a task finished successfully ...
*
* @param name task name
* @param task task object
*/
public onTaskFinished(name: string, task: XTask<any>) {}
//#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<string>;
//
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<T>(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<any>) {
//
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<any>) {
//
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<any>) {
//
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<any>) {
//
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<any>) {
//
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<any>) {
//
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<any>) {
return hasChild(items);
}
/**
* convert an standard UI Value to Observable for consuming ...
*
* @param value the standard UI Value
*/
public getValue<T>(value: XStandardType<T>) {
return toObservable<T>(value);
}
/**
* get stream Observble of specified standard value
*/
public getValueStream<T>(value: XStandardType<T>) {
return this.applyTakeUntilWrapper(this.getValue(value));
}
/**
* retrieve an standard type var in promise
*
* @param value an standard type var
*/
public async getValueAsync<T>(value: XStandardType<T>) {
//
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<T>(value: XStandardType<XOneOrManyType<T>>) {
return this.getValue(value).pipe(map((valueType) => toArray(valueType)));
}
/**
* convert to array ...
*
* @param value an standard type one or many arg ...
*/
public async getArrayValueAsync<T>(value: XStandardType<XOneOrManyType<T>>) {
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<T>(value: XStandardType<XOneOrManyType<T>>) {
//
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<T>(value: XStandardType<XOneOrManyType<T>>) {
//
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<T>(value: XStandardType<XOneOrManyType<T>>) {
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<T>(
value: XStandardType<XOneOrManyType<T>>
) {
//
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<XResourceIdentifier>) {
//
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<XResourceIdentifier>
) {
//
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<string | any>) {
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<string | any>) {
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<string | any>) {
return await this.toPromise(this.emptyValue(value));
}
/**
* apply not operator to a boolean ...
*/
public notValue(value: XStandardType<boolean>) {
return notValue(this.getValue(value));
}
/**
* apply not operator to a boolean ...
*/
public async notValueAsync(value: XStandardType<boolean>) {
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<any>[]) {
//
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<any>[]) {
//
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<any>[]) {
//
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<any>[]
) {
//
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<any>) {
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<any>) {
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<any>) {
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<any>) {
return await this.toPromise(this.nullOrUndefinedValue(value));
}
/**
* retrieve an optional value ...
*
* @param value the optional standard value ...
*/
public getOptionalValue<T>(value?: XStandardType<T>): Observable<T> {
//
if (value) {
return this.getValue(value);
}
//
return this.getValue(getDefaultValue(value));
}
/**
* retrieve an optional value ...
*
* @param value the optional standard value ...
*/
public async getOptionalValueAsync<T>(value?: XStandardType<T>) {
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<T>(values?: XOneOrManyType<XStandardType<T>>) {
//
interface ForkSourceType<T> {
[index: number]: XStandardType<T>;
}
//
return this.getArrayValue(values).pipe(
concatMap((values) => {
//
if (!hasChild(values)) {
return this.getValue([] as T[]);
} else {
//
const forkSource: ForkSourceType<T> = {};
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<T>(values?: XOneOrManyType<XStandardType<T>>) {
return await this.toPromise(this.getValues(values));
}
/**
* apply take until wrapper arround an observable ...
*
* @param task the observable object
*/
public applyTakeUntilWrapper<T>(task: Observable<T>): Observable<T> {
return task.pipe(takeUntil(this.unsubscriber));
}
/**
* apply inside component loading wrapper arround an observable ...
*
* @param task the observable object
*/
public applyLoadingWrapper<T>(task: Observable<T>): Observable<T> {
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<T>(task: Observable<T>): Observable<T> {
return task.pipe(first());
}
/**
* convert an observable to promise object ...
*
* @param task the observable object
*/
public toPromise<T>(task: Observable<T>): Promise<T> {
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<TActionProviderModel>,
TDialogCompnent extends XBaseDialogComponent<
TItem,
TActionProviderModel,
TConfig
>
> extends XBaseService {
//
//#region Props ...
private MOBILE_CLASS_NAME = 'mobile';
private DIALOG_REF: MatDialogRef<TDialogCompnent>;
//
isMobile$ = this.managerService.isMobileUi$;
// tslint:disable-next-line:no-output-on-prefix
@Output()
onResult = new EventEmitter<IXBaseDialogResult>();
//#endregion
//
//#region Abstract ...
abstract defaultTitleResourceIdentifier: XResourceIdentifier;
abstract openDialogAndReturnRef(
config: MatDialogConfig
): MatDialogRef<TDialogCompnent>;
//#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<XBehaviourEventType>();
//
//#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<boolean> | Promise<boolean> {
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<XBasePage>('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<void>,
cancelCb?: () => XStandardType<void>
) {
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
<div class="x-dialog-wrapper">
<!-- Toolbar -->
<ion-header class="x-dialog-header">
<!-- Title Toolbar -->
<ion-toolbar
class="v-toolbar"
[xColor]="'primary'"
*ngIf="showToolbar | async"
>
<!-- Slots -->
<div class="toolbar-area">
<x-slotter>
<!-- Start -->
<x-slot
[name]="SlotNames.START"
[cssClass]="['ion-text-start', 'ion-float-start']"
>
<div
matRipple
(click)="handleBack()"
class="toolbar-item toolbar-button center-vertical-flex"
>
<x-icon
[name]="backIcon"
[loading]="isLoading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
<ion-title class="toolbar-item center-vertical-flex">
<h3>
{{ title | async }}
</h3>
</ion-title>
</x-slot>
<!-- End -->
<x-slot
[name]="SlotNames.END"
[cssClass]="['ion-text-end', 'ion-float-end']"
>
<!-- Select -->
<div
matRipple
(click)="handleSelect()"
*ngIf="dialogCanSelect()"
class="toolbar-item toolbar-inline-item toolbar-button center-vertical-flex"
>
<x-icon
[name]="selectIcon"
[loading]="isLoading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
</x-slotter>
</div>
<!-- Progressbar for Loading -->
<ion-progress-bar
*ngIf="isLoading"
type="indeterminate"
[color]="progressBarColor | async"
></ion-progress-bar>
</ion-toolbar>
</ion-header>
<!-- Component -->
<ion-content
class="x-dialog-content-wrapper"
[ngClass]="cssDialogClass | async"
[class.has-toolbar]="showToolbar | async"
>
</ion-content>
</div>
<!-- Default Item Ref -->
<ng-template #vItemRef let-item>
{{ item.data | json }}
</ng-template>
### 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<XBaseDialogActionIdentifier> {}
export interface IXBaseDialogConfig<
TActionProviderModel extends IXBaseDialogActionModel
> {
//
showToolbar?: boolean;
//
title?: XResourceIdentifier;
cssClass?: XOneOrManyType<string>;
progressBarColor?: XColorIdentifier;
//
showSearchBar?: boolean;
searchBarColor?: XColorIdentifier;
searchBarInputColor?: XColorIdentifier;
//
actionProvider?: Subject<TActionProviderModel>;
//
canMultipleSelect?: boolean;
//
onItemSelect?: (item: XOneOrManyType<any>) => XStandardType<void>;
//
onTaskStart?: (name: string) => XStandardType<void>;
onTaskFinished?: (name: string) => XStandardType<void>;
onTaskFailed?: (name: string) => XStandardType<void>;
}
export interface IXBaseDialogResult {
payload?: any;
result: XDialogResult;
}
@Component({
template: '',
})
export abstract class XBaseDialogComponent<
TItem,
TActionProviderModel extends IXBaseDialogActionModel,
TConfig extends IXBaseDialogConfig<TActionProviderModel>
> 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<TItem>;
//
//#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<TActionProviderModel>();
//#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<TItem, TActionProviderModel, TConfig>
>
) {
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<any>) {
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<any>) {
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<any>) {
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<Array<string>>;
abstract deselectAllListItems(): Promise<void>;
abstract deselectItemInList(item: TItem): Promise<void>;
abstract handleSearchbarQuryChanged(query: string): Promise<void>;
//#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<any>) => boolean;
//#endregion
//
//#region Observables ...
getValue: <T>(value: XStandardType<T>) => Observable<T>;
getArrayValue: <T>(
value: XStandardType<XOneOrManyType<T>>
) => Observable<T[]>;
hasChildValue: <T>(
value: XStandardType<XOneOrManyType<T>>
) => Observable<boolean>;
countChildsValue: <T>(
value: XStandardType<XOneOrManyType<T>>
) => Observable<number>;
getResourceValue: (
value: XStandardType<XResourceIdentifier>
) => Observable<string>;
notEmptyValue: (value: XStandardType<string | any>) => Observable<boolean>;
emptyValue: (value: XStandardType<string | any>) => Observable<boolean>;
notValue: (value: XStandardType<boolean>) => Observable<boolean>;
mustBeValue: (
value: any,
...values: XStandardType<any>[]
) => Observable<boolean>;
atLeastHasOneValue: (
value: any,
...values: XStandardType<any>[]
) => Observable<boolean>;
notNullOrUndefinedValue: (value: XStandardType<any>) => Observable<boolean>;
nullOrUndefinedValue: (value: XStandardType<any>) => Observable<boolean>;
getOptionalValue: <T>(value?: XStandardType<T>) => Observable<T>;
getValues: <T>(values?: XOneOrManyType<XStandardType<T>>) => Observable<T[]>;
//#endregion
//
//#region Async of Observables ...
getValueAsync: <T>(value: XStandardType<T>) => Promise<T>;
getArrayValueAsync: <T>(
value: XStandardType<XOneOrManyType<T>>
) => Promise<T[]>;
hasChildValueAsync: <T>(
value: XStandardType<XOneOrManyType<T>>
) => Promise<boolean>;
countChildsValueAsync: <T>(
value: XStandardType<XOneOrManyType<T>>
) => Promise<number>;
getResourceValueAsync: (
value: XStandardType<XResourceIdentifier>
) => Promise<string>;
notEmptyValueAsync: (value: XStandardType<string | any>) => Promise<boolean>;
emptyValueAsync: (value: XStandardType<string | any>) => Promise<boolean>;
notValueAsync: (value: XStandardType<boolean>) => Promise<boolean>;
mustBeValueAsync: (
value: any,
...values: XStandardType<any>[]
) => Promise<boolean>;
atLeastHasOneValueAsync: (
value: any,
...values: XStandardType<any>[]
) => Promise<boolean>;
notNullOrUndefinedValueAsync: (value: XStandardType<any>) => Promise<boolean>;
nullOrUndefinedValueAsync: (value: XStandardType<any>) => Promise<boolean>;
getOptionalValueAsync: <T>(value?: XStandardType<T>) => Promise<T>;
getValuesAsync: <T>(
values?: XOneOrManyType<XStandardType<T>>
) => Promise<T[]>;
//#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<any>) {
return hasChild(items);
}
/**
* convert an standard UI Value to Observable for consuming ...
*
* @param value the standard UI Value
*/
public getValue<T>(value: XStandardType<T>) {
return toObservable<T>(value);
}
/**
* retrieve an standard type var in promise
*
* @param value an standard type var
*/
public async getValueAsync<T>(value: XStandardType<T>) {
//
if (!value) {
return null;
}
//
return await toPromise(this.getValue(value));
}
/**
* convert to array ...
*
* @param value an standard type one or many arg ...
*/
public getArrayValue<T>(value: XStandardType<XOneOrManyType<T>>) {
return this.getValue(value).pipe(map((valueType) => toArray(valueType)));
}
/**
* convert to array ...
*
* @param value an standard type one or many arg ...
*/
public async getArrayValueAsync<T>(value: XStandardType<XOneOrManyType<T>>) {
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<T>(value: XStandardType<XOneOrManyType<T>>) {
//
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<T>(value: XStandardType<XOneOrManyType<T>>) {
//
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<T>(value: XStandardType<XOneOrManyType<T>>) {
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<T>(
value: XStandardType<XOneOrManyType<T>>
) {
//
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<XResourceIdentifier>) {
//
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<XResourceIdentifier>
) {
//
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<string | any>) {
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<string | any>) {
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<string | any>) {
return await toPromise(this.emptyValue(value));
}
/**
* apply not operator to a boolean ...
*/
public notValue(value: XStandardType<boolean>) {
return notValue(this.getValue(value));
}
/**
* apply not operator to a boolean ...
*/
public async notValueAsync(value: XStandardType<boolean>) {
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<any>[]) {
//
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<any>[]) {
//
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<any>[]) {
//
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<any>[]
) {
//
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<any>) {
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<any>) {
return await toPromise(this.notNullOrUndefinedValue(value));
}
/**
* determines a given value content must empty
*
* @param value an Standard type of any
*/
public nullOrUndefinedValue(value: XStandardType<any>) {
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<any>) {
return await toPromise(this.nullOrUndefinedValue(value));
}
/**
* retrieve an optional value ...
*
* @param value the optional standard value ...
*/
public getOptionalValue<T>(value?: XStandardType<T>): Observable<T> {
//
if (value) {
return this.getValue(value);
}
//
return this.getValue(getDefaultValue(value));
}
/**
* retrieve an optional value ...
*
* @param value the optional standard value ...
*/
public async getOptionalValueAsync<T>(value?: XStandardType<T>) {
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<T>(values?: XOneOrManyType<XStandardType<T>>) {
//
interface ForkSourceType<T> {
[index: number]: XStandardType<T>;
}
//
return this.getArrayValue(values).pipe(
concatMap((values) => {
//
if (!hasChild(values)) {
return this.getValue([] as T[]);
} else {
//
const forkSource: ForkSourceType<T> = {};
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<T>(values?: XOneOrManyType<XStandardType<T>>) {
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-action-bar
[color]="props.color"
[actions]="props.actions"
[cssClass]="props.cssClass"
(actionFired)="(props.actionFired)"
[actionProvider]="props.actionProvider"
[foregroundColor]="props.foregroundColor"
>
</x-action-bar>
</ng-container>
`,
})
export class XActionBarTestComponent extends XActionBarContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<ng-container *ngIf="props.showActionBar">
<x-action-bar
[color]="props.actionBarColor"
[actions]="props.actionBarActions"
[cssClass]="props.actionBarCssClass"
(actionFired)="(props.actionBarActionFired)"
[actionProvider]="props.actionBarActionProvider"
[foregroundColor]="props.actionBarForegroundColor"
></x-action-bar>
</ng-container>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-avatar-upload
[color]="props.color"
[actions]="props.actions"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[cardSubTitle]="props.cardSubTitle"
[cardCssClass]="props.cardCssClass"
[wrapWithCard]="props.wrapWithCard"
(avatarChange)="(props.avatarChange)"
[cardShowFooter]="props.cardShowFooter"
[actionProvider]="props.actionProvider"
[maxAllowedSize]="props.maxAllowedSize"
[fileDropAreaCardForegroundColor]="
props.fileDropAreaCardForegroundColor
"
[foregroundColor]="props.foregroundColor"
[maxAllowedFiles]="props.maxAllowedFiles"
[fileDropAreaSupportsMultipleFiles]="
props.fileDropAreaSupportsMultipleFiles
"
[showFileDropArea]="props.showFileDropArea"
[fileDropAreaIcon]="props.fileDropAreaIcon"
[fileDropAreaColor]="props.fileDropAreaColor"
[placeHolderAvatar]="props.placeHolderAvatar"
[allowedExtensions]="props.allowedExtensions"
[minAllowedFileSize]="props.minAllowedFileSize"
[maxAllowedFileSize]="props.maxAllowedFileSize"
[cardActionProvider]="props.cardActionProvider"
[emptyFileException]="props.emptyFileException"
[fileDropAreaMessage]="props.fileDropAreaMessage"
[cardForegroundColor]="props.cardForegroundColor"
[fileDropAreaIsInPage]="props.fileDropAreaIsInPage"
[fileDropAreaCssClass]="props.fileDropAreaCssClass"
[fileDropAreaCardColor]="props.fileDropAreaCardColor"
[fileDropAreaCardTitle]="props.fileDropAreaCardTitle"
[fileDropAreaErrorColor]="props.fileDropAreaErrorColor"
[fileDropAreaAccentColor]="props.fileDropAreaAccentColor"
[maxAllowedSizeException]="props.maxAllowedSizeException"
[notAllowedFileException]="props.notAllowedFileException"
[fileDropAreaSuccessColor]="props.fileDropAreaSuccessColor"
[fileDropAreaWrapWithCard]="props.fileDropAreaWrapWithCard"
[maxAllowedFilesException]="props.maxAllowedFilesException"
[fileDropAreaDragDisabled]="props.fileDropAreaDragDisabled"
[fileDropAreaCardSubTitle]="props.fileDropAreaCardSubTitle"
[fileDropAreaCardCssClass]="props.fileDropAreaCardCssClass"
[fileDropAreaCardShowFooter]="props.fileDropAreaCardShowFooter"
[fileDropAreaActionProvider]="props.fileDropAreaActionProvider"
[fileDropAreaContentTemplate]="props.fileDropAreaContentTemplate"
[minAllowedFileSizeException]="props.minAllowedFileSizeException"
[maxAllowedFileSizeException]="props.maxAllowedFileSizeException"
[fileDropAreaForegroundColor]="props.fileDropAreaForegroundColor"
[fileDropAreaDisableFileCheck]="props.fileDropAreaDisableFileCheck"
[fileDropAreaAllowedExtensions]="props.fileDropAreaAllowedExtensions"
(fileDropAreaFilesChangeEmiter)="(props.fileDropAreaFilesChangeEmiter)"
[fileDropAreaCardActionProvider]="props.fileDropAreaCardActionProvider"
>
</x-avatar-upload>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-button
[type]="props.type"
[icon]="props.icon"
[title]="props.title"
[color]="props.color"
(clicked)="(props.clicked)"
[cssClass]="props.cssClass"
[iconColor]="props.iconColor"
[iconPosition]="props.iconPosition"
[actionProvider]="props.actionProvider"
[foregroundColor]="props.foregroundColor"
>
</x-button>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-card
[title]="props.title"
[color]="props.color"
[isInPage]="props.isInPage"
[cssClass]="props.cssClass"
[imageUrl]="props.imageUrl"
[subTitle]="props.subTitle"
[avatarUrl]="props.avatarUrl"
[showHeader]="props.showHeader"
[showFooter]="props.showFooter"
[showContent]="props.showContent"
[showActions]="props.showActions"
[actionProvider]="props.actionProvider"
[foregroundColor]="props.foregroundColor"
[imageDescription]="props.imageDescription"
>
</x-card>
</ng-container>
`,
})
export class XCardTestComponent extends XCardContainerComponent {}
@Component({
template: `
<!-- Standalone Template -->
<ng-container *ngIf="extractProps() | async as props">
<ng-container *ngIf="props.wrapWithCard">
<x-card
[title]="props.cardTitle"
[color]="props.cardColor"
[isInPage]="props.isInPage"
[cssClass]="props.cardCssClass"
[subTitle]="props.cardSubTitle"
[showFooter]="props.cardShowFooter"
[actionProvider]="props.cardActionProvider"
[foregroundColor]="props.cardForegroundColor"
>
</x-card>
</ng-container>
</ng-container>
<!-- Component Present Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<ng-container *ngIf="extractProps() | async as props">
<x-card
class="x-card"
[showActions]="true"
[color]="props.cardColor"
[ngClass]="props.cardCssClass"
[isInPage]="props.isInPage"
[showHeader]="
(notEmptyValue(props.cardTitle) | async) ||
(notEmptyValue(props.cardSubTitle) | async)
"
[subTitle]="getResourceValue(props.cardSubTitle)"
[title]="getResourceValue(props.cardTitle) | async"
[showFooter]="getValue(props.cardShowFooter) | async"
[foregroundColor]="getValue(props.cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="props.cardCssClass" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="props.cardShowFooter">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef> </ng-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: `
<ng-container *ngIf="extractProps() | async as props">
<x-chart
[series]="props.series"
[options]="props.options"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[autoUpdate]="props.autoUpdate"
(zoomed)="props.zoomed($event)"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[cardSubTitle]="props.cardSubTitle"
[cardShowFooter]="props.cardShowFooter"
[actionProvider]="props.actionProvider"
[cardShowActions]="props.cardShowActions"
(chartRendered)="props.chartRendered($event)"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
(dataPointSelected)="props.dataPointSelected($event)"
>
</x-chart>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-color-picker
[color]="props.color"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardTitle]="props.cardTitle"
[cardColor]="props.cardColor"
[cursorColor]="props.cursorColor"
[wrapWithCard]="props.wrapWithCard"
[cardSubTitle]="props.cardSubTitle"
[presetColors]="props.presetColors"
[outputFormat]="props.outputFormat"
[selectedColor]="props.selectedColor"
[colorTextColor]="props.colorTextColor"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
(colorSelected)="(props.colorSelected)"
[showColorInput]="props.showColorInput"
[showHueChannel]="props.showHueChannel"
[showColorValue]="props.showColorValue"
[foregroundColor]="props.foregroundColor"
[showAlphaChannel]="props.showAlphaChannel"
[showPresetColors]="props.showPresetColors"
[presetColorsLable]="props.presetColorsLable"
[showPaletteChannel]="props.showPaletteChannel"
[cardForegroundColor]="props.cardForegroundColor"
[colorInputIconColor]="props.colorInputIconColor"
[clearColorIconColor]="props.clearColorIconColor"
[colorInputIconLabel]="props.colorInputIconLabel"
[clearColorIconLabel]="props.clearColorIconLabel"
[showCopyToClipboard]="props.showCopyToClipboard"
[representColorFormats]="props.representColorFormats"
[presetColorsLableColor]="props.presetColorsLableColor"
[copyToClipboardIconLabel]="props.copyToClipboardIconLabel"
[showSelectedColorPreview]="props.showSelectedColorPreview"
[copyToClipboardIconColor]="props.copyToClipboardIconColor"
>
</x-color-picker>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-color
[size]="props.size"
[value]="props.value"
[cssClass]="props.cssClass"
[showLabel]="props.showLabel"
[labelColor]="props.labelColor"
[borderWidth]="props.borderWidth"
[borderStyle]="props.borderStyle"
[borderColor]="props.borderColor"
[actionProvider]="props.actionProvider"
>
</x-color>
</ng-container>
`
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-counter
[type]="props.type"
[delay]="props.delay"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardTitle]="props.cardTitle"
[stopValue]="props.stopValue"
[cardColor]="props.cardColor"
[startValue]="props.startValue"
[currentValue]="props.currentValue"
(counterStop)="(props.counterStop)"
[wrapWithCard]="props.wrapWithCard"
[cardSubTitle]="props.cardSubTitle"
(counterStart)="(props.counterStart)"
(counterTtick)="(props.counterTtick)"
[displayPattern]="props.displayPattern"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
[cardForegroundColor]="props.cardForegroundColor"
>
</x-counter>
</ng-container>
`
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-data-pager
[type]="props.type"
[task]="props.task"
[query]="props.query"
[result]="props.result"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardTitle]="props.cardTitle"
[cardColor]="props.cardColor"
[emptyColor]="props.emptyColor"
(taskReady)="(props.taskReady)"
(pageChanged)="(props.pageChanged)"
(queryChange)="(props.queryChange)"
[itemTemplate]="props.itemTemplate"
[cardCssClass]="props.cardCssClass"
[wrapWithCard]="props.wrapWithCard"
[cardSubTitle]="props.cardSubTitle"
[emptyMessage]="props.emptyMessage"
[emptyCssClass]="props.emptyCssClass"
[showPaginator]="props.showPaginator"
(emptyRefresh)="(props.emptyRefresh)"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
[paginatorColor]="props.paginatorColor"
[emptyForegroundRefreshButtonColor]="
props.emptyForegroundRefreshButtonColor
"
[emptyHasRefresh]="props.emptyHasRefresh"
[emptyRefreshIcon]="props.emptyRefreshIcon"
[paginatorOptions]="props.paginatorOptions"
[emptyListTemplate]="props.emptyListTemplate"
[paginatorPosition]="props.paginatorPosition"
[emptyMessageColor]="props.emptyMessageColor"
[cardActionProvider]="props.cardActionProvider"
[emptyActionProvider]="props.emptyActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
[emptyForegroundColor]="props.emptyForegroundColor"
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
>
</x-data-pager>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-data-scroller
[task]="props.task"
[query]="props.query"
[result]="props.result"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardTitle]="props.cardTitle"
[cardColor]="props.cardColor"
[emptyColor]="props.emptyColor"
(taskReady)="(props.taskReady)"
[cardCssClass]="props.cardCssClass"
[wrapWithCard]="props.wrapWithCard"
[cardSubTitle]="props.cardSubTitle"
[emptyMessage]="props.emptyMessage"
(emptyRefresh)="(props.emptyRefresh)"
[emptyCssClass]="props.emptyCssClass"
(queryChange)="(props.queryChange)"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
[emptyForegroundRefreshButtonColor]="
props.emptyForegroundRefreshButtonColor
"
[emptyHasRefresh]="props.emptyHasRefresh"
[emptyRefreshIcon]="props.emptyRefreshIcon"
[emptyListTemplate]="props.emptyListTemplate"
[emptyMessageColor]="props.emptyMessageColor"
[cardActionProvider]="props.cardActionProvider"
[emptyActionProvider]="props.emptyActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
[emptyForegroundColor]="props.emptyForegroundColor"
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
>
</x-data-scroller>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-description-list
[color]="props.color"
[model]="props.model"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[isLegacy]="props.isLegacy"
[cardTitle]="props.cardTitle"
[cardColor]="props.cardColor"
[showLabels]="props.showLabels"
[labelColor]="props.labelColor"
[valueColor]="props.valueColor"
[cardCssClass]="props.cardCssClass"
[wrapWithCard]="props.wrapWithCard"
[cardSubTitle]="props.cardSubTitle"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
(onModelChanged)="(props.onModelChanged)"
[foregroundColor]="props.foregroundColor"
[hiddenModelKeys]="props.hiddenModelKeys"
[modelKeyProvider]="props.modelKeyProvider"
[modelValueProvider]="props.modelValueProvider"
[hideOptionalValues]="props.hideOptionalValues"
[availableModelKeys]="props.availableModelKeys"
[sortOrderModelKeys]="props.sortOrderModelKeys"
[cardForegroundColor]="props.cardForegroundColor"
[hiddenLabelModelKeys]="props.hiddenLabelModelKeys"
[propertyActionTemplate]="props.propertyActionTemplate"
>
</x-description-list>
</ng-container>
`,
})
export class XDescriptionListTestComponent extends XDescriptionListContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<x-description-list-item
[name]="props.name"
[value]="props.value"
[cssClass]="props.cssClass"
[actionProvider]="props.actionProvider"
>
</x-description-list-item>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-empty
[color]="props.color"
[message]="props.message"
(refresh)="(props.refresh)"
[cssClass]="props.cssClass"
[hasRefresh]="props.hasRefresh"
[refreshIcon]="props.refreshIcon"
[messageColor]="props.messageColor"
[actionProvider]="props.actionProvider"
[foregroundColor]="props.foregroundColor"
[refreshButtonColor]="props.refreshButtonColor"
[foregroundMessageColor]="props.foregroundMessageColor"
[foregroundRefreshButtonColor]="props.foregroundRefreshButtonColor"
>
</x-empty>
</ng-container>
`,
})
export class XEmptyTestComponent extends XEmptyContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<ng-container *ngIf="props.showEmpty">
<x-empty
[color]="props.emptyColor"
[message]="props.emptyMessage"
(refresh)="(props.emptyRefresh)"
[cssClass]="props.emptyCssClass"
[hasRefresh]="props.emptyHasRefresh"
[refreshIcon]="props.emptyRefreshIcon"
[messageColor]="props.emptyMessageColor"
[actionProvider]="props.emptyActionProvider"
[foregroundColor]="props.emptyForegroundColor"
[refreshButtonColor]="props.emptyRefreshButtonColor"
[foregroundMessageColor]="props.emptyForegroundMessageColor"
[foregroundRefreshButtonColor]="
props.emptyForegroundRefreshButtonColor
"
>
</x-empty>
</ng-container>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-expandable-list
[items]="props.items"
[isInPage]="props.isInPage"
[cssClass]="props.cssClass"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[childColor]="props.childColor"
[parentColor]="props.parentColor"
[dividerColor]="props.dividerColor"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[cardSubTitle]="props.cardSubTitle"
[itemCssClass]="props.itemCssClass"
[startupState]="props.startupState"
(itemSelected)="(props.itemSelected)"
[closeSiblings]="props.closeSiblings"
[childTemplate]="props.childTemplate"
[highlightColor]="props.highlightColor"
[cardShowFooter]="props.cardShowFooter"
[actionProvider]="props.actionProvider"
[supportRouting]="props.supportRouting"
[parentTemplate]="props.parentTemplate"
[childActiveColor]="props.childActiveColor"
[parentActiveColor]="props.parentActiveColor"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
[showChildDetailIcon]="props.showChildDetailIcon"
[disableParentRouting]="props.disableParentRouting"
[showParentDetailIcon]="props.showParentDetailIcon"
>
</x-expandable-list>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-expandable-panel
[canNext]="props.canNext"
(onNext)="(props.onNext)"
[canPrev]="props.canPrev"
(onPrev)="(props.onPrev)"
[cssClass]="props.cssClass"
[selected]="props.selected"
[isInPage]="props.isInPage"
[canReset]="props.canReset"
(onReset)="(props.onReset)"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[isAccordion]="props.isAccordion"
[applyColors]="props.applyColors"
[headerColor]="props.headerColor"
[startupState]="props.startupState"
[cardSubTitle]="props.cardSubTitle"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[multiExpanded]="props.multiExpanded"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
[resetConfirmer]="props.resetConfirmer"
(selectedChange)="(props.selectedChange)"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
[headerHighlightColor]="props.headerHighlightColor"
[hideDescriptionOnSmallScreens]="props.hideDescriptionOnSmallScreens"
>
</x-expandable-panel>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-fab
[item]="props.item"
[cssClass]="props.cssClass"
[actionProvider]="props.actionProvider"
[childsCssClass]="props.childsCssClass"
>
</x-fab>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-file-drop-area
[icon]="props.icon"
[color]="props.color"
[message]="props.message"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardTitle]="props.cardTitle"
[cardColor]="props.cardColor"
[errorColor]="props.errorColor"
[accentColor]="props.accentColor"
[dragDisabled]="props.dragDisabled"
[successColor]="props.successColor"
[cardCssClass]="props.cardCssClass"
[wrapWithCard]="props.wrapWithCard"
[cardSubTitle]="props.cardSubTitle"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
[foregroundColor]="props.foregroundColor"
[contentTemplate]="props.contentTemplate"
[foregroundColor]="props.foregroundColor"
[disableFileCheck]="props.disableFileCheck"
[allowedExtensions]="props.allowedExtensions"
(filesChangeEmiter)="(props.filesChangeEmiter)"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
[supportsMultipleFiles]="props.supportsMultipleFiles"
></x-file-drop-area>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-file-upload
[color]="props.color"
[isInPage]="props.isInPage"
[showList]="props.showList"
[cssClass]="props.cssClass"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[showEmpty]="props.showEmpty"
[emptyColor]="props.emptyColor"
(fileChange)="(props.fileChange)"
[emptyMessage]="props.emptyMessage"
[wrapWithCard]="props.wrapWithCard"
[cardSubTitle]="props.cardSubTitle"
[cardCssClass]="props.cardCssClass"
[listCssClass]="props.listCssClass"
(emptyRefresh)="(props.emptyRefresh)"
[emptyCssClass]="props.emptyCssClass"
[searchBarType]="props.searchBarType"
[showActionBar]="props.showActionBar"
[showSearchBar]="props.showSearchBar"
[searchBarTitle]="props.searchBarTitle"
[searchBarValue]="props.searchBarValue"
[emptyForegroundRefreshButtonColor]="
props.emptyForegroundRefreshButtonColor
"
[maxAllowedSize]="props.maxAllowedSize"
[cardShowFooter]="props.cardShowFooter"
[actionBarColor]="props.actionBarColor"
[searchBarColor]="props.searchBarColor"
[actionProvider]="props.actionProvider"
[maxAllowedFiles]="props.maxAllowedFiles"
[emptyHasRefresh]="props.emptyHasRefresh"
[listShowToolbar]="props.listShowToolbar"
[listShowDivider]="props.listShowDivider"
[foregroundColor]="props.foregroundColor"
[fileDropAreaSupportsMultipleFiles]="
props.fileDropAreaSupportsMultipleFiles
"
[actionBarActions]="props.actionBarActions"
[showFileDropArea]="props.showFileDropArea"
[fileDropAreaIcon]="props.fileDropAreaIcon"
[emptyRefreshIcon]="props.emptyRefreshIcon"
[searchBarForegroundSearchInputColor]="
props.searchBarForegroundSearchInputColor
"
[allowedExtensions]="props.allowedExtensions"
[emptyMessageColor]="props.emptyMessageColor"
[searchBarDebounce]="props.searchBarDebounce"
(searchBarOnEvent)="(props.searchBarOnEvent)"
[listConfirmRemove]="props.listConfirmRemove"
[listStickyToolbar]="props.listStickyToolbar"
[actionBarCssClass]="props.actionBarCssClass"
[searchBarCssClass]="props.searchBarCssClass"
[fileDropAreaColor]="props.fileDropAreaColor"
[emptyFileException]="props.emptyFileException"
[minAllowedFileSize]="props.minAllowedFileSize"
[maxAllowedFileSize]="props.maxAllowedFileSize"
[searchBarClearIcon]="props.searchBarClearIcon"
[cardActionProvider]="props.cardActionProvider"
[listActionProvider]="props.listActionProvider"
[emptyActionProvider]="props.emptyActionProvider"
[searchBarSearchIcon]="props.searchBarSearchIcon"
[searchBarSpellcheck]="props.searchBarSpellcheck"
[cardForegroundColor]="props.cardForegroundColor"
[fileDropAreaMessage]="props.fileDropAreaMessage"
[emptyForegroundColor]="props.emptyForegroundColor"
[listEnableReordering]="props.listEnableReordering"
[listFilteringHandler]="props.listFilteringHandler"
[fileDropAreaCssClass]="props.fileDropAreaCssClass"
(searchBarQueryChange)="(props.searchBarQueryChange)"
[searchBarEnterKeyHint]="props.searchBarEnterKeyHint"
[searchBarKeyboardType]="props.searchBarKeyboardType"
(actionBarActionFired)="(props.actionBarActionFired)"
[fileDropAreaErrorColor]="props.fileDropAreaErrorColor"
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
[notAllowedFileException]="props.notAllowedFileException"
[maxAllowedSizeException]="props.maxAllowedSizeException"
[searchBarClearIconColor]="props.searchBarClearIconColor"
[actionBarActionProvider]="props.actionBarActionProvider"
[searchBarActionProvider]="props.searchBarActionProvider"
[fileDropAreaAccentColor]="props.fileDropAreaAccentColor"
[maxAllowedFilesException]="props.maxAllowedFilesException"
[searchBarSearchIconColor]="props.searchBarSearchIconColor"
[actionBarForegroundColor]="props.actionBarForegroundColor"
[searchBarForegroundColor]="props.searchBarForegroundColor"
[fileDropAreaDragDisabled]="props.fileDropAreaDragDisabled"
[fileDropAreaSuccessColor]="props.fileDropAreaSuccessColor"
[searchBarShowCancelButton]="props.searchBarShowCancelButton"
[searchBarCancelButtonIcon]="props.searchBarCancelButtonIcon"
[searchBarSearchInputColor]="props.searchBarSearchInputColor"
[searchBarCancelButtonTitle]="props.searchBarCancelButtonTitle"
[fileDropAreaActionProvider]="props.fileDropAreaActionProvider"
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
[minAllowedFileSizeException]="props.minAllowedFileSizeException"
[maxAllowedFileSizeException]="props.maxAllowedFileSizeException"
[fileDropAreaForegroundColor]="props.fileDropAreaForegroundColor"
[fileDropAreaContentTemplate]="props.fileDropAreaContentTemplate"
[fileDropAreaDisableFileCheck]="props.fileDropAreaDisableFileCheck"
[fileDropAreaAllowedExtensions]="props.fileDropAreaAllowedExtensions"
(fileDropAreaFilesChangeEmiter)="(props.fileDropAreaFilesChangeEmiter)"
>
</x-file-upload>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-footer
[color]="props.color"
[cssClass]="props.cssClass"
[actionProvider]="props.actionProvider"
[contentTemplate]="props.contentTemplate"
>
</x-footer>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-form
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[hintColor]="props.hintColor"
[fillColor]="props.fillColor"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[formConfig]="props.formConfig"
[validColor]="props.validColor"
[accentColor]="props.accentColor"
[activeColor]="props.activeColor"
[regularColor]="props.regularColor"
[invalidColor]="props.invalidColor"
[pendingColor]="props.pendingColor"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[cardSubTitle]="props.cardSubTitle"
[disabledColor]="props.disabledColor"
(valueChanged)="(props.valueChanged)"
[cardShowFooter]="props.cardShowFooter"
[actionProvider]="props.actionProvider"
(statusChanged)="(props.statusChanged)"
(controlBlured)="(props.controlBlured)"
(controlFocused)="(props.controlFocused)"
[disabledFillColor]="props.disabledFillColor"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
(controlValueChanged)="(props.controlValueChanged)"
[applyStatusOnControls]="props.applyStatusOnControls"
(controlStatusChanged)="(props.controlStatusChanged)"
>
</x-form>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-grid
[gap]="props.gap"
[cols]="props.cols"
[type]="props.type"
[align]="props.align"
[items]="props.items"
[layout]="props.layout"
[options]="props.options"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[showEmpty]="props.showEmpty"
[emptyColor]="props.emptyColor"
[itemTemplate]="props.itemTemplate"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[cardSubTitle]="props.cardSubTitle"
[emptyMessage]="props.emptyMessage"
(itemSelected)="(props.itemSelected)"
(emptyRefresh)="(props.emptyRefresh)"
[emptyCssClass]="props.emptyCssClass"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
[emptyHasRefresh]="props.emptyHasRefresh"
[selectableItems]="props.selectableItems"
[emptyForegroundRefreshButtonColor]="
props.emptyForegroundRefreshButtonColor
"
[emptyRefreshIcon]="props.emptyRefreshIcon"
[emptyMessageColor]="props.emptyMessageColor"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
[emptyActionProvider]="props.emptyActionProvider"
[emptyForegroundColor]="props.emptyForegroundColor"
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
></x-grid>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-icon
[slot]="props.slot"
[name]="props.name"
[color]="props.color"
(clicked)="(props.clicked)"
[cssClass]="props.cssClass"
[clickable]="props.clickable"
[selectable]="props.selectable"
[actionProvider]="props.actionProvider"
[applyDirection]="props.applyDirection"
[foregroundColor]="props.foregroundColor"
>
</x-icon>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-ide
[mode]="props.mode"
[theme]="props.theme"
[content]="props.content"
[cssClass]="props.cssClass"
[minLines]="props.minLines"
[maxLines]="props.maxLines"
[fontSize]="props.fontSize"
[readonly]="props.readonly"
[isInPage]="props.isInPage"
[alignTabs]="props.alignTabs"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[cardSubTitle]="props.cardSubTitle"
[wordWrapping]="props.wordWrapping"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[showActionBar]="props.showActionBar"
[actionBarColor]="props.actionBarColor"
[cardShowFooter]="props.cardShowFooter"
[defaultTabName]="props.defaultTabName"
[actionProvider]="props.actionProvider"
[tabHeaderColor]="props.tabHeaderColor"
[activeTabColor]="props.activeTabColor"
[cardShowActions]="props.cardShowActions"
[showLineNumbers]="props.showLineNumbers"
[showPrintMargin]="props.showPrintMargin"
[showFoldWidgets]="props.showFoldWidgets"
[actionBarActions]="props.actionBarActions"
[actionBarCssClass]="props.actionBarCssClass"
(contentChange)="props.contentChange($event)"
[cardActionProvider]="props.cardActionProvider"
[highlightActiveLine]="props.highlightActiveLine"
[cardForegroundColor]="props.cardForegroundColor"
[basicAutocompletion]="props.basicAutocompletion"
[hasCloseOnDefaultTab]="props.hasCloseOnDefaultTab"
[availableActionBarItems]="props.availableActionBarItems"
[actionBarActionProvider]="props.actionBarActionProvider"
(actionBarActionFired)="props.actionBarActionFired($event)"
[actionBarForegroundColor]="props.actionBarForegroundColor"
[defaultActionBarItemColor]="props.defaultActionBarItemColor"
>
</x-ide>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-image-cropper
[format]="props.format"
[cropper]="props.cropper"
[autoCrop]="props.autoCrop"
[cssClass]="props.cssClass"
[alignImage]="props.alignImage"
[outputType]="props.outputType"
[imageBase64]="props.imageBase64"
[aspectRatio]="props.aspectRatio"
[imageQuality]="props.imageQuality"
[roundCropper]="props.roundCropper"
(imageLoaded)="(props.imageLoaded)"
[onlyScaleDown]="props.onlyScaleDown"
[resizeToWidth]="props.resizeToWidth"
(imageCropped)="(props.imageCropped)"
(cropperReady)="(props.cropperReady)"
[actionProvider]="props.actionProvider"
[cropperMinWidth]="props.cropperMinWidth"
(startCropImage)="(props.startCropImage)"
(loadImageFailed)="(props.loadImageFailed)"
[imageFileChanged]="props.imageFileChanged"
[cropperMinHeight]="props.cropperMinHeight"
(imageCroppedFile)="(props.imageCroppedFile)"
[imageChangedEvent]="props.imageChangedEvent"
[maintainAspectRatio]="props.maintainAspectRatio"
(imageCroppedBase64)="(props.imageCroppedBase64)"
>
</x-image-cropper>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-list
[items]="props.items"
[color]="props.color"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[showEmpty]="props.showEmpty"
[emptyColor]="props.emptyColor"
[showToolbar]="props.showToolbar"
[showDivider]="props.showDivider"
[cardCssClass]="props.cardCssClass"
[cardSubTitle]="props.cardSubTitle"
[wrapWithCard]="props.wrapWithCard"
(removeItems)="(props.removeItems)"
[itemTemplate]="props.itemTemplate"
[emptyMessage]="props.emptyMessage"
(itemsChanged)="(props.itemsChanged)"
(orderChanged)="(props.orderChanged)"
[emptyCssClass]="props.emptyCssClass"
(itemSelected)="(props.itemSelected)"
[confirmRemove]="props.confirmRemove"
[stickyToolbar]="props.stickyToolbar"
(emptyRefresh)="(props.emptyRefresh)"
[showActionBar]="props.showActionBar"
[showSearchBar]="props.showSearchBar"
[searchBarType]="props.searchBarType"
[searchBarTitle]="props.searchBarTitle"
[searchBarValue]="props.searchBarValue"
[actionProvider]="props.actionProvider"
[clickableItems]="props.clickableItems"
[cardShowFooter]="props.cardShowFooter"
[actionBarColor]="props.actionBarColor"
[searchBarColor]="props.searchBarColor"
[emptyForegroundRefreshButtonColor]="
props.emptyForegroundRefreshButtonColor
"
(optionSelected)="(props.optionSelected)"
[showItemOptions]="props.showItemOptions"
[emptyHasRefresh]="props.emptyHasRefresh"
[selectableItems]="props.selectableItems"
[foregroundColor]="props.foregroundColor"
[searchBarForegroundSearchInputColor]="
props.searchBarForegroundSearchInputColor
"
[filteringHandler]="props.filteringHandler"
[enableReordering]="props.enableReordering"
[actionBarActions]="props.actionBarActions"
[emptyRefreshIcon]="props.emptyRefreshIcon"
[showOptionsAsMenuWhenSlidingAvailable]="
props.showOptionsAsMenuWhenSlidingAvailable
"
[searchBarDebounce]="props.searchBarDebounce"
(searchBarOnEvent)="(props.searchBarOnEvent)"
(selectionChanged)="(props.selectionChanged)"
[emptyMessageColor]="props.emptyMessageColor"
[actionBarCssClass]="props.actionBarCssClass"
[searchBarCssClass]="props.searchBarCssClass"
[searchBarClearIcon]="props.searchBarClearIcon"
[showOptionsAsSlide]="props.showOptionsAsSlide"
[cardActionProvider]="props.cardActionProvider"
[searchBarSearchIcon]="props.searchBarSearchIcon"
[searchBarSpellcheck]="props.searchBarSpellcheck"
[cardForegroundColor]="props.cardForegroundColor"
[emptyActionProvider]="props.emptyActionProvider"
[emptyForegroundColor]="props.emptyForegroundColor"
[searchBarEnterKeyHint]="props.searchBarEnterKeyHint"
[searchBarKeyboardType]="props.searchBarKeyboardType"
(searchBarQueryChange)="(props.searchBarQueryChange)"
[slidingOptionTemplate]="props.slidingOptionTemplate"
(actionBarActionFired)="(props.actionBarActionFired)"
[searchBarClearIconColor]="props.searchBarClearIconColor"
[closeOptionsAfterSelect]="props.closeOptionsAfterSelect"
[actionBarActionProvider]="props.actionBarActionProvider"
[searchBarActionProvider]="props.searchBarActionProvider"
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
[searchBarSearchIconColor]="props.searchBarSearchIconColor"
[nonSlidingOptionTemplate]="props.nonSlidingOptionTemplate"
[actionBarForegroundColor]="props.actionBarForegroundColor"
[searchBarForegroundColor]="props.searchBarForegroundColor"
[searchBarShowCancelButton]="props.searchBarShowCancelButton"
[searchBarCancelButtonIcon]="props.searchBarCancelButtonIcon"
[searchBarSearchInputColor]="props.searchBarSearchInputColor"
[searchBarCancelButtonTitle]="props.searchBarCancelButtonTitle"
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
>
</x-list>
</ng-container>
`,
})
export class XListTestComponent extends XListContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<ng-container *ngIf="props.showList">
<x-list
[items]="props.listItems"
[color]="props.listColor"
[cssClass]="props.listCssClass"
[isInPage]="props.listIsInPage"
[cardColor]="props.listCardColor"
[cardTitle]="props.listCardTitle"
[showEmpty]="props.listShowEmpty"
[emptyColor]="props.listEmptyColor"
[showToolbar]="props.listShowToolbar"
[showDivider]="props.listShowDivider"
[cardCssClass]="props.listCardCssClass"
[cardSubTitle]="props.listCardSubTitle"
[wrapWithCard]="props.listWrapWithCard"
(removeItems)="(props.listRemoveItems)"
[itemTemplate]="props.listItemTemplate"
[emptyMessage]="props.listEmptyMessage"
(itemsChanged)="(props.listItemsChanged)"
(orderChanged)="(props.listOrderChanged)"
[emptyCssClass]="props.listEmptyCssClass"
(itemSelected)="(props.listItemSelected)"
[confirmRemove]="props.listConfirmRemove"
[stickyToolbar]="props.listStickyToolbar"
(emptyRefresh)="(props.listEmptyRefresh)"
[showActionBar]="props.listShowActionBar"
[showSearchBar]="props.listShowSearchBar"
[searchBarType]="props.listSearchBarType"
[searchBarTitle]="props.listSearchBarTitle"
[searchBarValue]="props.listSearchBarValue"
[actionProvider]="props.listActionProvider"
[clickableItems]="props.listClickableItems"
[cardShowFooter]="props.listCardShowFooter"
[actionBarColor]="props.listActionBarColor"
[searchBarColor]="props.listSearchBarColor"
[emptyForegroundRefreshButtonColor]="
props.listEmptyForegroundRefreshButtonColor
"
(optionSelected)="(props.listOptionSelected)"
[showItemOptions]="props.listShowItemOptions"
[emptyHasRefresh]="props.listEmptyHasRefresh"
[selectableItems]="props.listSelectableItems"
[foregroundColor]="props.listForegroundColor"
[searchBarForegroundSearchInputColor]="
props.listSearchBarForegroundSearchInputColor
"
[filteringHandler]="props.listFilteringHandler"
[enableReordering]="props.listEnableReordering"
[actionBarActions]="props.listActionBarActions"
[emptyRefreshIcon]="props.listEmptyRefreshIcon"
[showOptionsAsMenuWhenSlidingAvailable]="
props.listShowOptionsAsMenuWhenSlidingAvailable
"
[searchBarDebounce]="props.listSearchBarDebounce"
(searchBarOnEvent)="(props.listSearchBarOnEvent)"
(selectionChanged)="(props.listSelectionChanged)"
[emptyMessageColor]="props.listEmptyMessageColor"
[actionBarCssClass]="props.listActionBarCssClass"
[searchBarCssClass]="props.listSearchBarCssClass"
[searchBarClearIcon]="props.listSearchBarClearIcon"
[showOptionsAsSlide]="props.listShowOptionsAsSlide"
[cardActionProvider]="props.listCardActionProvider"
[searchBarSearchIcon]="props.listSearchBarSearchIcon"
[searchBarSpellcheck]="props.listSearchBarSpellcheck"
[cardForegroundColor]="props.listCardForegroundColor"
[emptyActionProvider]="props.listEmptyActionProvider"
[emptyForegroundColor]="props.listEmptyForegroundColor"
[searchBarEnterKeyHint]="props.listSearchBarEnterKeyHint"
[searchBarKeyboardType]="props.listSearchBarKeyboardType"
(searchBarQueryChange)="(props.listSearchBarQueryChange)"
[slidingOptionTemplate]="props.listSlidingOptionTemplate"
(actionBarActionFired)="(props.listActionBarActionFired)"
[searchBarClearIconColor]="props.listSearchBarClearIconColor"
[closeOptionsAfterSelect]="props.listCloseOptionsAfterSelect"
[actionBarActionProvider]="props.listActionBarActionProvider"
[searchBarActionProvider]="props.listSearchBarActionProvider"
[emptyRefreshButtonColor]="props.listEmptyRefreshButtonColor"
[searchBarSearchIconColor]="props.listSearchBarSearchIconColor"
[nonSlidingOptionTemplate]="props.listNonSlidingOptionTemplate"
[actionBarForegroundColor]="props.listActionBarForegroundColor"
[searchBarForegroundColor]="props.listSearchBarForegroundColor"
[searchBarShowCancelButton]="props.listSearchBarShowCancelButton"
[searchBarCancelButtonIcon]="props.listSearchBarCancelButtonIcon"
[searchBarSearchInputColor]="props.listSearchBarSearchInputColor"
[searchBarCancelButtonTitle]="props.listSearchBarCancelButtonTitle"
[emptyForegroundMessageColor]="props.listEmptyForegroundMessageColor"
>
</x-list>
</ng-container>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-map
[zoom]="props.zoom"
[cssClass]="props.cssClass"
(isReady)="(props.isReady)"
[latitude]="props.latitude"
[showZoom]="props.showZoom"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[longitude]="props.longitude"
[canSelect]="props.canSelect"
[showRotate]="props.showRotate"
[showLocator]="props.showLocator"
[markerStyle]="props.markerStyle"
[wrapWithCard]="props.wrapWithCard"
[cardSubTitle]="props.cardSubTitle"
[cardCssClass]="props.cardCssClass"
(viewChanged)="(props.viewChanged)"
[searchBarType]="props.searchBarType"
[showSearchBar]="props.showSearchBar"
[searchBarTitle]="props.searchBarTitle"
[searchBarValue]="props.searchBarValue"
[cardShowFooter]="props.cardShowFooter"
[showZoomSlider]="props.showZoomSlider"
[searchBarColor]="props.searchBarColor"
[actionProvider]="props.actionProvider"
[showProgressBar]="props.showProgressBar"
[showClearMarker]="props.showClearMarker"
[locatorPosition]="props.locatorPosition"
[progressBarColor]="props.progressBarColor"
[searchBarPosition]="props.searchBarPosition"
[searchBarCssClass]="props.searchBarCssClass"
[searchBarDebounce]="props.searchBarDebounce"
(searchBarOnEvent)="(props.searchBarOnEvent)"
(locationSelected)="(props.locationSelected)"
[showGoMarkedPlace]="props.showGoMarkedPlace"
[cardActionProvider]="props.cardActionProvider"
[searchBarClearIcon]="props.searchBarClearIcon"
[searchPlaceProvider]="props.searchPlaceProvider"
[searchBarSearchIcon]="props.searchBarSearchIcon"
[cardForegroundColor]="props.cardForegroundColor"
[searchBarSpellcheck]="props.searchBarSpellcheck"
[clearMarkerPosition]="props.clearMarkerPosition"
[progressBarPosition]="props.progressBarPosition"
[showSelectedLocation]="props.showSelectedLocation"
[searchResultListColor]="props.searchResultListColor"
(searchBarQueryChange)="(props.searchBarQueryChange)"
[searchBarEnterKeyHint]="props.searchBarEnterKeyHint"
[searchBarKeyboardType]="props.searchBarKeyboardType"
[goMarkedPlacePosition]="props.goMarkedPlacePosition"
[searchBarActionProvider]="props.searchBarActionProvider"
[searchBarClearIconColor]="props.searchBarClearIconColor"
[searchBarForegroundColor]="props.searchBarForegroundColor"
[searchBarSearchIconColor]="props.searchBarSearchIconColor"
[selectedLocationPosition]="props.selectedLocationPosition"
[searchBarSearchInputColor]="props.searchBarSearchInputColor"
[searchBarShowCancelButton]="props.searchBarShowCancelButton"
[searchBarCancelButtonIcon]="props.searchBarCancelButtonIcon"
[searchBarCancelButtonTitle]="props.searchBarCancelButtonTitle"
[addMarkerOnSelectedLocation]="props.addMarkerOnSelectedLocation"
[searchBarForegroundSearchInputColor]="
props.searchBarForegroundSearchInputColor
"
>
</x-map>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-markdown
[mode]="props.mode"
[content]="props.content"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[hasToolbar]="props.hasToolbar"
[toolbarColor]="props.toolbarColor"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[cardSubTitle]="props.cardSubTitle"
[toolbarConfig]="props.toolbarConfig"
[cardShowFooter]="props.cardShowFooter"
[actionProvider]="props.actionProvider"
(contentChange)="(props.contentChange)"
[editorBoxColor]="props.editorBoxColor"
[toolbarCssClass]="props.toolbarCssClass"
[previewBoxColor]="props.previewBoxColor"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
[toolbarForegroundColor]="props.toolbarForegroundColor"
></x-markdown>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-model-presenter
[color]="props.color"
[model]="props.model"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[labelColor]="props.labelColor"
[valueColor]="props.valueColor"
[showLabels]="props.showLabels"
[headerColor]="props.headerColor"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[cardSubTitle]="props.cardSubTitle"
[contentColor]="props.contentColor"
[startupState]="props.startupState"
[panelCssClass]="props.panelCssClass"
[cardShowFooter]="props.cardShowFooter"
[actionProvider]="props.actionProvider"
[foregroundColor]="props.foregroundColor"
[hiddenModelKeys]="props.hiddenModelKeys"
(onModelChanged)="(props.onModelChanged)"
[modelKeyProvider]="props.modelKeyProvider"
[sortOrderModelKeys]="props.sortOrderModelKeys"
[modelValueProvider]="props.modelValueProvider"
[hideOptionalValues]="props.hideOptionalValues"
[availableModelKeys]="props.availableModelKeys"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
[panelActionProvider]="props.panelActionProvider"
[hiddenLabelModelKeys]="props.hiddenLabelModelKeys"
[headerHighlightColor]="props.headerHighlightColor"
[propertyActionTemplate]="props.propertyActionTemplate"
>
</x-model-presenter>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-navigator
[items]="props.items"
[cssClass]="props.cssClass"
[iconSlot]="props.iconSlot"
[childColor]="props.childColor"
[parentColor]="props.parentColor"
[dividerColor]="props.dividerColor"
[startupState]="props.startupState"
[itemCssClass]="props.itemCssClass"
(itemSelected)="(props.itemSelected)"
[closeSiblings]="props.closeSiblings"
[showChildIcon]="props.showChildIcon"
[actionProvider]="props.actionProvider"
[showParentIcon]="props.showParentIcon"
[highlightColor]="props.highlightColor"
[childActiveColor]="props.childActiveColor"
[parentActiveColor]="props.parentActiveColor"
[showChildDetailIcon]="props.showChildDetailIcon"
[disableParentRouting]="props.disableParentRouting"
[showParentDetailIcon]="props.showParentDetailIcon"
>
</x-navigator>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-page
[color]="props.color"
[hasSide]="props.hasSide"
[actions]="props.actions"
[cssClass]="props.cssClass"
[sideSlot]="props.sideSlot"
[sideType]="props.sideType"
[sideColor]="props.sideColor"
(loadMore)="(props.loadMore)"
[showFooter]="props.showFooter"
[showToolbar]="props.showToolbar"
[footerColor]="props.footerColor"
[toolbarTitle]="props.toolbarTitle"
(refreshPage)="(props.refreshPage)"
[toolbarColor]="props.toolbarColor"
[sideMenuWidth]="props.sideMenuWidth"
[toolbarLogoUrl]="props.toolbarLogoUrl"
[toolbarHasBack]="props.toolbarHasBack"
[toolbarHasMenu]="props.toolbarHasMenu"
[footerCssClass]="props.footerCssClass"
[refreshingText]="props.refreshingText"
(scrolledEvent)="(props.scrolledEvent)"
[toggleMenuWhen]="props.toggleMenuWhen"
(imageCaptured)="(props.imageCaptured)"
[toolbarStartSlotButtonsTemplate]="
props.toolbarStartSlotButtonsTemplate
"
[toolbarShowBack]="props.toolbarShowBack"
[toolbarBackSlot]="props.toolbarBackSlot"
[toolbarSubTitle]="props.toolbarSubTitle"
[toolbarShowLogo]="props.toolbarShowLogo"
[toolbarLogoSlot]="props.toolbarLogoSlot"
[toolbarShowTitle]="props.toolbarShowTitle"
[toolbarTitleSlot]="props.toolbarTitleSlot"
[toolbarShowMenu]="props.toolbarShowMenu"
[toolbarMenuSlot]="props.toolbarMenuSlot"
[toolbarCssClass]="props.toolbarCssClass"
[scrollBehaviour]="props.scrollBehaviour"
[sideMenuMaxWidth]="props.sideMenuMaxWidth"
[scrollingClasses]="props.scrollingClasses"
[sideMenuMinWidth]="props.sideMenuMinWidth"
[scrollEndClasses]="props.scrollEndClasses"
[captureTopOffset]="props.captureTopOffset"
[showPageRefresher]="props.showPageRefresher"
[refreshingSpinner]="props.refreshingSpinner"
[enableCaptureMode]="props.enableCaptureMode"
[toolbarBackHandler]="props.toolbarBackHandler"
[toolbarDefaultHref]="props.toolbarDefaultHref"
[refreshPullingText]="props.refreshPullingText"
[refreshPullingIcon]="props.refreshPullingIcon"
[toolbarContentSlot]="props.toolbarContentSlot"
[scrollStartClasses]="props.scrollStartClasses"
[toolbarShowSubTitle]="props.toolbarShowSubTitle"
[captureBottomOffset]="props.captureBottomOffset"
[provideScrollEvents]="props.provideScrollEvents"
[footerActionProvider]="props.footerActionProvider"
[footerContentTemplate]="props.footerContentTemplate"
[downloadCapturedImage]="props.downloadCapturedImage"
[actionsActionProvider]="props.actionsActionProvider"
[toolbarActionProvider]="props.toolbarActionProvider"
[toolbarContentTemplate]="props.toolbarContentTemplate"
[infinityScrollDisabled]="props.infinityScrollDisabled"
[toolbarShowProgressBar]="props.toolbarShowProgressBar"
[toolbarProgressBarColor]="props.toolbarProgressBarColor"
[infinityScrollThreshold]="props.infinityScrollThreshold"
[showPageInfinityScroller]="props.showPageInfinityScroller"
[scrollEventActionProvider]="props.scrollEventActionProvider"
[infinityScrollerLoadingText]="props.infinityScrollerLoadingText"
[toolbarEndSlotButtonsTemplate]="props.toolbarEndSlotButtonsTemplate"
[infinityScrollerLoadingSpinner]="props.infinityScrollerLoadingSpinner"
>
</x-page>
</ng-container>
`
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-screen-capture
[enable]="props.enable"
[topOffset]="props.topOffset"
[bottomOffset]="props.bottomOffset"
(imageCaptured)="(props.imageCaptured)"
[downloadCapturedImage]="props.downloadCapturedImage"
>
</x-screen-capture>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-search-bar
[type]="props.type"
[color]="props.color"
[title]="props.title"
[value]="props.value"
[cssClass]="props.cssClass"
(onEvent)="(props.onEvent)"
[debounce]="props.debounce"
[clearIcon]="props.clearIcon"
[spellcheck]="props.spellcheck"
[searchIcon]="props.searchIcon"
[enterKeyHint]="props.enterKeyHint"
[keyboardType]="props.keyboardType"
(queryChange)="(props.queryChange)"
[clearIconColor]="props.clearIconColor"
[actionProvider]="props.actionProvider"
[searchIconColor]="props.searchIconColor"
[foregroundColor]="props.foregroundColor"
[showCancelButton]="props.showCancelButton"
[cancelButtonIcon]="props.cancelButtonIcon"
[searchInputColor]="props.searchInputColor"
[cancelButtonTitle]="props.cancelButtonTitle"
[foregroundSearchInputColor]="props.foregroundSearchInputColor"
>
</x-search-bar>
</ng-container>
`,
})
export class XSearchBarTestComponent extends XSearchBarContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<ng-container *ngIf="props.showSearchBar">
<x-search-bar
[color]="props.searchBarColor"
[title]="props.searchBarTitle"
[value]="props.searchBarValue"
[cssClass]="props.searchBarCssClass"
[debounce]="props.searchBarDebounce"
(onEvent)="(props.searchBarOnEvent)"
[clearIcon]="props.searchBarClearIcon"
[spellcheck]="props.searchBarSpellcheck"
[searchIcon]="props.searchBarSearchIcon"
[foregroundSearchInputColor]="
props.searchBarForegroundSearchInputColor
"
[type]="props.searchBarType"
[enterKeyHint]="props.searchBarEnterKeyHint"
[keyboardType]="props.searchBarKeyboardType"
(queryChange)="(props.searchBarQueryChange)"
[actionProvider]="props.searchBarActionProvider"
[clearIconColor]="props.searchBarClearIconColor"
[searchIconColor]="props.searchBarSearchIconColor"
[foregroundColor]="props.searchBarForegroundColor"
[searchInputColor]="props.searchBarSearchInputColor"
[showCancelButton]="props.searchBarShowCancelButton"
[cancelButtonIcon]="props.searchBarCancelButtonIcon"
[cancelButtonTitle]="props.searchBarCancelButtonTitle"
>
</x-search-bar>
</ng-container>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-slider
[options]="props.options"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[animation]="props.animation"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[cardSubTitle]="props.cardSubTitle"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[cardShowFooter]="props.cardShowFooter"
[actionProvider]="props.actionProvider"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
>
</x-slider>
</ng-container>
`,
})
export class XSliderTestComponent extends XSliderContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<x-slide [actionProvider]="props.actionProvider"></x-slide>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-slotter
[layout]="props.layout"
[cssClass]="props.cssClass"
[hasCenterSlot]="props.hasCenterSlot"
[actionProvider]="props.actionProvider"
[hasStartOrTopSlot]="props.hasStartOrTopSlot"
[centerSlotCssClass]="props.centerSlotCssClass"
[hasEndOrBottomSlot]="props.hasEndOrBottomSlot"
[startTopSlotCssClass]="props.startTopSlotCssClass"
[endBottomSlotCssClass]="props.endBottomSlotCssClass"
>
</x-slotter>
</ng-container>
`,
})
export class XSlotterTestComponent extends XSlotterContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<x-slot
[name]="props.name"
[cssClass]="props.cssClass"
[actionProvider]="props.actionProvider"
>
</x-slot>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-spinner
[name]="props.name"
[color]="props.color"
[paused]="props.paused"
[cssClass]="props.cssClass"
[duration]="props.duration"
[actionProvider]="props.actionProvider"
>
</x-spinner>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-stepper
[type]="props.type"
[hasNext]="props.hasNext"
[hasPrev]="props.hasPrev"
[canNext]="props.canNext"
(onNext)="(props.onNext)"
[canPrev]="props.canPrev"
(onPrev)="(props.onPrev)"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[canReset]="props.canReset"
(onReset)="(props.onReset)"
[hasReset]="props.hasReset"
[cardColor]="props.cardColor"
[showLabel]="props.showLabel"
[cardTitle]="props.cardTitle"
[nextButton]="props.nextButton"
[prevButton]="props.prevButton"
[disablePrev]="props.disablePrev"
[resetButton]="props.resetButton"
[disableNext]="props.disableNext"
[prevPosition]="props.prevPosition"
[prevCssClass]="props.prevCssClass"
[disableReset]="props.disableReset"
[cardSubTitle]="props.cardSubTitle"
[cardCssClass]="props.cardCssClass"
[wrapWithCard]="props.wrapWithCard"
[nextPosition]="props.nextPosition"
[nextCssClass]="props.nextCssClass"
[nextConfirmer]="props.nextConfirmer"
[labelPosition]="props.labelPosition"
[selectedIndex]="props.selectedIndex"
[prevConfirmer]="props.prevConfirmer"
[resetPosition]="props.resetPosition"
[resetCssClass]="props.resetCssClass"
[actionProvider]="props.actionProvider"
[cardShowFooter]="props.cardShowFooter"
[resetConfirmer]="props.resetConfirmer"
(selectedChange)="(props.selectedChange)"
[cardActionProvider]="props.cardActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
>
</x-stepper>
</ng-container>
`,
})
export class XStepperTestComponent extends XStepperContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<x-step
[id]="props.id"
[hasNext]="props.hasNext"
[hasPrev]="props.hasPrev"
[hasReset]="props.hasReset"
[nextButton]="props.nextButton"
[prevButton]="props.prevButton"
[disableNext]="props.disableNext"
[disablePrev]="props.disablePrev"
[resetButton]="props.resetButton"
[nextCssClass]="props.nextCssClass"
[prevPosition]="props.prevPosition"
[prevCssClass]="props.prevCssClass"
[disableReset]="props.disableReset"
[nextPosition]="props.nextPosition"
[prevConfirmer]="props.prevConfirmer"
[resetPosition]="props.resetPosition"
[nextConfirmer]="props.nextConfirmer"
[resetCssClass]="props.resetCssClass"
[resetConfirmer]="props.resetConfirmer"
[actionProvider]="props.actionProvider"
[hasCustomActions]="props.hasCustomActions"
>
</x-step>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-tab-navigator
[items]="props.items"
[color]="props.color"
[cssClass]="props.cssClass"
[iconColor]="props.iconColor"
[badgeColor]="props.badgeColor"
[navigatorSlot]="props.navigatorSlot"
[selectedColor]="props.selectedColor"
[actionProvider]="props.actionProvider"
[highlightColor]="props.highlightColor"
[foregroundColor]="props.foregroundColor"
[hideTabLabelsOnSmallScreens]="props.hideTabLabelsOnSmallScreens"
>
</x-tab-navigator>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-table
[color]="props.color"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[showEmpty]="props.showEmpty"
[emptyColor]="props.emptyColor"
[properties]="props.properties"
[showHeader]="props.showHeader"
(rowClicked)="(props.rowClicked)"
[headerColor]="props.headerColor"
[searchTitle]="props.searchTitle"
(rowSelected)="(props.rowSelected)"
[canClearSort]="props.canClearSort"
[cellCssClass]="props.cellCssClass"
[stickyHeader]="props.stickyHeader"
[cellTemplate]="props.cellTemplate"
(pageChanged)="(props.pageChanged)"
[cardSubTitle]="props.cardSubTitle"
(removeItems)="(props.removeItems)"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
[emptyMessage]="props.emptyMessage"
(emptyRefresh)="(props.emptyRefresh)"
[clickableRows]="props.clickableRows"
[showSearchBar]="props.showSearchBar"
[showActionBar]="props.showActionBar"
[showPaginator]="props.showPaginator"
[actionOptions]="props.actionOptions"
[emptyCssClass]="props.emptyCssClass"
[searchBarColor]="props.searchBarColor"
[cardShowFooter]="props.cardShowFooter"
[paginatorColor]="props.paginatorColor"
[actionBarColor]="props.actionBarColor"
[selectableRows]="props.selectableRows"
[actionProvider]="props.actionProvider"
[emptyHasRefresh]="props.emptyHasRefresh"
[foregroundColor]="props.foregroundColor"
[emptyForegroundRefreshButtonColor]="
props.emptyForegroundRefreshButtonColor
"
[emptyRefreshIcon]="props.emptyRefreshIcon"
[paginatorOptions]="props.paginatorOptions"
[allowMultiSelect]="props.allowMultiSelect"
[searchBarPosition]="props.searchBarPosition"
[paginatorPosition]="props.paginatorPosition"
[actionBarPosition]="props.actionBarPosition"
[emptyMessageColor]="props.emptyMessageColor"
[cardActionProvider]="props.cardActionProvider"
[headerCellCssClass]="props.headerCellCssClass"
[customCellTemplate]="props.customCellTemplate"
[emptyActionProvider]="props.emptyActionProvider"
[cardForegroundColor]="props.cardForegroundColor"
(rowSelectionChanged)="(props.rowSelectionChanged)"
[emptyForegroundColor]="props.emptyForegroundColor"
[headerForegroundColor]="props.headerForegroundColor"
[initialSelectedValues]="props.initialSelectedValues"
[emptyRefreshButtonColor]="props.emptyRefreshButtonColor"
[emptyForegroundMessageColor]="props.emptyForegroundMessageColor"
>
</x-table>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-tabs
[lock]="props.lock"
[color]="props.color"
[cssClass]="props.cssClass"
[loopTabs]="props.loopTabs"
[swipable]="props.swipable"
[alignTabs]="props.alignTabs"
[showHeader]="props.showHeader"
[headerColor]="props.headerColor"
[selectedIndex]="props.selectedIndex"
[dynamicHeight]="props.dynamicHeight"
[disableRipple]="props.disableRipple"
[activeTabColor]="props.activeTabColor"
[headerPosition]="props.headerPosition"
[actionProvider]="props.actionProvider"
(animationDone)="(props.animationDone)"
[disablePagination]="props.disablePagination"
[animationDuration]="props.animationDuration"
[tabIndicatorColor]="props.tabIndicatorColor"
[tabPaginatorColor]="props.tabPaginatorColor"
(selectedTabChange)="(props.selectedTabChange)"
(selectedIndexChange)="(props.selectedIndexChange)"
>
</x-tabs>
</ng-container>
`,
})
export class XTabsTestComponent extends XTabsContainerComponent {}
@Component({
template: `
<ng-container *ngIf="extractProps() | async as props">
<x-tab [actionProvider]="props.actionProvider"></x-tab>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-theme-manager
[color]="props.color"
[cssClass]="props.cssClass"
[isInPage]="props.isInPage"
[cardColor]="props.cardColor"
[cardTitle]="props.cardTitle"
[saveColor]="props.saveColor"
[saveLabel]="props.saveLabel"
[resetColor]="props.resetColor"
[resetLabel]="props.resetLabel"
(tabChange)="(props.tabChange)"
[cardSubTitle]="props.cardSubTitle"
[wrapWithCard]="props.wrapWithCard"
[cardCssClass]="props.cardCssClass"
(themeChange)="(props.themeChange)"
[listCssClass]="props.listCssClass"
[listShowEmpty]="props.listShowEmpty"
[showActionBar]="props.showActionBar"
[themeUploadFileDropAreaCssClass]="
props.themeUploadFileDropAreaCssClass
"
[listEmptyForegroundMessageColor]="
props.listEmptyForegroundMessageColor
"
[cardShowFooter]="props.cardShowFooter"
[maxAllowedSize]="props.maxAllowedSize"
[listEmptyColor]="props.listEmptyColor"
[actionBarColor]="props.actionBarColor"
[actionProvider]="props.actionProvider"
[themeUploadFileDropAreaErrorColor]="
props.themeUploadFileDropAreaErrorColor
"
[maxAllowedFiles]="props.maxAllowedFiles"
[listShowDivider]="props.listShowDivider"
[themeUploadFileDropAreaAccentColor]="
props.themeUploadFileDropAreaAccentColor
"
[themeUploadFileDropAreaSuccessColor]="
props.themeUploadFileDropAreaSuccessColor
"
[propertyEditIcon]="props.propertyEditIcon"
[listEmptyMessage]="props.listEmptyMessage"
[themeUploadColor]="props.themeUploadColor"
[listEmptyForegroundRefreshButtonColor]="
props.listEmptyForegroundRefreshButtonColor
"
[listShowSearchBar]="props.listShowSearchBar"
(listEmptyRefresh)="(props.listEmptyRefresh)"
[listEmptyCssClass]="props.listEmptyCssClass"
[actionBarCssClass]="props.actionBarCssClass"
[propertyClearIcon]="props.propertyClearIcon"
[themeUploadFileDropAreaForegroundColor]="
props.themeUploadFileDropAreaForegroundColor
"
[themeUploadEmptyForegroundMessageColor]="
props.themeUploadEmptyForegroundMessageColor
"
[listSearchBarForegroundSearchInputColor]="
props.listSearchBarForegroundSearchInputColor
"
[minAllowedFileSize]="props.minAllowedFileSize"
[maxAllowedFileSize]="props.maxAllowedFileSize"
[cardActionProvider]="props.cardActionProvider"
[listSearchBarTitle]="props.listSearchBarTitle"
[listSearchBarValue]="props.listSearchBarValue"
[listSearchBarColor]="props.listSearchBarColor"
[propertyLabelColor]="props.propertyLabelColor"
[propertyValueColor]="props.propertyValueColor"
[cardForegroundColor]="props.cardForegroundColor"
[listEmptyHasRefresh]="props.listEmptyHasRefresh"
[themeUploadCssClass]="props.themeUploadCssClass"
[listEmptyRefreshIcon]="props.listEmptyRefreshIcon"
[colorViewBorderColor]="props.colorViewBorderColor"
[restartAfterSetTheme]="props.restartAfterSetTheme"
[colorViewBorderWidth]="props.colorViewBorderWidth"
[colorViewBorderStyle]="props.colorViewBorderStyle"
[presenterHeaderColor]="props.presenterHeaderColor"
[themeUploadFileDropAreaSupportsMultipleFiles]="
props.themeUploadFileDropAreaSupportsMultipleFiles
"
[listSearchBarCssClass]="props.listSearchBarCssClass"
(listSearchBarOnEvent)="(props.listSearchBarOnEvent)"
[listEmptyMessageColor]="props.listEmptyMessageColor"
[listSearchBarDebounce]="props.listSearchBarDebounce"
[presenterContentColor]="props.presenterContentColor"
[propertyEditIconColor]="props.propertyEditIconColor"
[listSearchBarClearIcon]="props.listSearchBarClearIcon"
[propertyActionMenuIcon]="props.propertyActionMenuIcon"
[propertyClearIconColor]="props.propertyClearIconColor"
[themeUploadEmptyMessage]="props.themeUploadEmptyMessage"
[listSearchBarSpellcheck]="props.listSearchBarSpellcheck"
[listSearchBarSearchIcon]="props.listSearchBarSearchIcon"
[listEmptyActionProvider]="props.listEmptyActionProvider"
[listEmptyForegroundColor]="props.listEmptyForegroundColor"
[actionBarForegroundColor]="props.actionBarForegroundColor"
[listSearchBarEnterKeyHint]="props.listSearchBarEnterKeyHint"
[listSearchBarKeyboardType]="props.listSearchBarKeyboardType"
(listActionBarActionFired)="(props.listActionBarActionFired)"
(listSearchBarQueryChange)="(props.listSearchBarQueryChange)"
[themeUploadForegroundColor]="props.themeUploadForegroundColor"
[emptyPropertyEditIconColor]="props.emptyPropertyEditIconColor"
[themeUploadFileDropAreaIcon]="props.themeUploadFileDropAreaIcon"
[themeUploadShowFileDropArea]="props.themeUploadShowFileDropArea"
[listSearchBarClearIconColor]="props.listSearchBarClearIconColor"
[listEmptyRefreshButtonColor]="props.listEmptyRefreshButtonColor"
[propertyActionMenuIconColor]="props.propertyActionMenuIconColor"
[themeUploadFileDropAreaColor]="props.themeUploadFileDropAreaColor"
[listSearchBarSearchIconColor]="props.listSearchBarSearchIconColor"
[listSearchBarForegroundColor]="props.listSearchBarForegroundColor"
[listSearchBarShowCancelButton]="props.listSearchBarShowCancelButton"
[listSearchBarCancelButtonIcon]="props.listSearchBarCancelButtonIcon"
[listSearchBarSearchInputColor]="props.listSearchBarSearchInputColor"
[presenterHeaderHighlightColor]="props.presenterHeaderHighlightColor"
[themeUploadFileDropAreaMessage]="props.themeUploadFileDropAreaMessage"
[listSearchBarCancelButtonTitle]="props.listSearchBarCancelButtonTitle"
></x-theme-manager>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-thumbnail
[type]="props.type"
(clicked)="(props.clicked)"
[cssClass]="props.cssClass"
[circular]="props.circular"
[clickable]="props.clickable"
[selectable]="props.selectable"
[identifier]="props.identifier"
[actionProvider]="props.actionProvider"
>
</x-thumbnail>
</ng-container>
`,
})
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: `
<ng-container *ngIf="extractProps() | async as props">
<x-toolbar
[color]="props.color"
[title]="props.title"
[logoUrl]="props.logoUrl"
[hasBack]="props.hasBack"
[hasMenu]="props.hasMenu"
[subTitle]="props.subTitle"
[showLogo]="props.showLogo"
[logoSlot]="props.logoSlot"
[showBack]="props.showBack"
[backSlot]="props.backSlot"
[showMenu]="props.showMenu"
[menuSlot]="props.menuSlot"
[cssClass]="props.cssClass"
[showTitle]="props.showTitle"
[titleSlot]="props.titleSlot"
[backHandler]="props.backHandler"
[defaultHref]="props.defaultHref"
[contentSlot]="props.contentSlot"
[showSubTitle]="props.showSubTitle"
[actionProvider]="props.actionProvider"
[contentTemplate]="props.contentTemplate"
[showProgressBar]="props.showProgressBar"
[progressBarColor]="props.progressBarColor"
[endSlotButtonsTemplate]="props.endSlotButtonsTemplate"
[startSlotButtonsTemplate]="props.startSlotButtonsTemplate"
>
</x-toolbar>
</ng-container>
`,
})
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
<section
#xBaseDialogContainer
class="x-base-dialog"
[isForeground]="false"
[xColor]="getBackgroundColor() | async"
[ngClass]="getDialogContainerClasses() | async"
>
<!-- Title Toolbar -->
<section #xBaseDialogToolbar>
<!-- Toolbar -->
<ion-toolbar
[xColor]="getToolbarColor() | async"
[ngClass]="getDialogToolbarClasses() | async"
>
<!-- Slots -->
<div class="x-base-dialog-toolbar-area">
<x-slotter>
<!-- Start -->
<x-slot
[name]="SlotNames.START"
[cssClass]="['ion-text-start', 'ion-float-start']"
>
<div
matRipple
(click)="handleClosePopup()"
class="x-base-dialog-toolbar-item x-base-dialog-toolbar-button center-vertical-flex"
>
<x-icon
[name]="backIcon"
[loading]="isLoading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
<ion-title class="x-base-dialog-toolbar-item center-vertical-flex">
<h3>
{{ getTitle() | async }}
</h3>
</ion-title>
</x-slot>
<!-- End -->
<x-slot
[name]="SlotNames.END"
[cssClass]="['ion-text-end', 'ion-float-end']"
>
<div
matRipple
*ngIf="canSelect() | async"
(click)="handleSelect(selectedValue)"
[matRippleDisabled]="!(hasSelectedValue() | async)"
class="x-base-dialog-toolbar-item x-base-dialog-toolbar-button center-vertical-flex"
>
<x-icon
[name]="selectIcon"
[loading]="isLoading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
</x-slotter>
</div>
</ion-toolbar>
<!-- Progressbar -->
<ion-progress-bar
type="indeterminate"
*ngIf="canShowProgressBar() | async"
[color]="getProgressBarColor() | async"
></ion-progress-bar>
</section>
<!-- Components -->
<section class="x-base-dialog-content">
<!-- Content -->
</section>
</section>
### 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<XDialogConfig>;
//#endregion
//
//#region ViewChilds ...
@ViewChild('xBaseDialogToolbar')
dialogToolbar: ElementRef<any>;
//#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<XDialogConfig> = {
//
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
<mat-card class="x-card mobile x-popover-wrapper">
<ion-list #list class="ion-no-padding">
<!-- Options -->
<ng-container
*ngIf="
(hasChildValue(options) | async) && !(hasChildValue(items) | async)
"
>
<ng-container *ngFor="let item of getArrayValue(options) | async">
<ng-container
*ngTemplateOutlet="
listItemRef;
context: { $implicit: item, isItem: false }
"
></ng-container>
</ng-container>
</ng-container>
<!-- Items -->
<ng-container
*ngIf="
!(hasChildValue(options) | async) && (hasChildValue(items) | async)
"
>
<ng-container *ngFor="let item of getArrayValue(items) | async">
<ng-container
*ngTemplateOutlet="
listItemRef;
context: { $implicit: item, isItem: true }
"
></ng-container>
</ng-container>
</ng-container>
</ion-list>
</mat-card>
<!-- -->
<!-- Templates -->
<!-- -->
<!-- List Item Template -->
<ng-template #listItemRef let-item let-isItem="isItem">
<ion-item
button
lines="full"
[isForeground]="true"
[xColor]="getValue(item.color) | async"
(click)="handleMenuSelected(isItem, item, $event)"
[matTooltip]="getResourceValue(item.title) | async"
[matTooltipDisabled]="!(getValue(item.onlyIcon) | async)"
[detail]="
(getValue(item.showDetailedIcon) | async) &&
(hasChildValue(item.options) | async)
"
[disabled]="!(getValue(item) | async) || (getValue(item.disabled) | async)"
>
<ng-container
*ngTemplateOutlet="
listItemContentRef;
context: {
icon: item.icon,
title: item.title,
onlyIcon: item.onlyIcon,
iconSlot: item.slot || item.iconSlot,
iconColor: item.color || item.iconColor
}
"
></ng-container>
</ion-item>
</ng-template>
<!-- List Item Content Template -->
<ng-template
#listItemContentRef
let-icon="icon"
let-title="title"
let-iconSlot="iconSlot"
let-onlyIcon="onlyIcon"
let-iconColor="iconColor"
>
<x-slotter
class="full-with"
[cssClass]="'full-with'"
[layout]="SlotLayouts.HORIZONTAL"
[startTopSlotCssClass]="'dynamic-slot'"
[endBottomSlotCssClass]="'dynamic-slot'"
[centerSlotCssClass]="
'align-self-center ion-text-start ion-margin-horizontal'
"
[hasEndOrBottomSlot]="
(notEmptyValue(icon) | async) && (getValue(iconSlot) | async) === 'end'
"
[hasStartOrTopSlot]="
(notEmptyValue(icon) | async) && (getValue(iconSlot) | async) === 'start'
"
[hasCenterSlot]="notEmptyValue(title) && !(getValue(onlyIcon) | async)"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Icon -->
<ng-container
*ngTemplateOutlet="iconRef; context: { icon: icon, color: iconColor }"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<ng-container
*ngTemplateOutlet="labelRef; context: { $implicit: title }"
></ng-container>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Icon -->
<ng-container
*ngTemplateOutlet="iconRef; context: { icon: icon, color: iconColor }"
></ng-container>
</x-slot>
</x-slotter>
</ng-template>
<!-- Icon Template -->
<ng-template #iconRef let-icon="icon" let-color="color">
<x-icon
[foregroundColor]="true"
*ngIf="notEmptyValue(icon)"
[name]="getValue(icon) | async"
[color]="
(notEmptyValue(color) | async)
? (getValue(color) | async)
: ColorNames.Tertiary
"
></x-icon>
</ng-template>
<!-- Label Template -->
<ng-template #labelRef let-title>
<ion-label *ngIf="notEmptyValue(title)">{{
getResourceValue(title) | async
}}</ion-label>
</ng-template>
### 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<XPopoverItem>;
options: XOneOrManyType<XPopoverOption>;
//
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<XPopoverComponent>('options')
) as XPopoverOption[];
this.options = options;
//
// Items ...
const items = this.navParams.get(
nameof<XPopoverComponent>('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<XPopoverComponent>('height'));
if (!isNullOrEmptyString(this.height)) {
this.applyHeight();
}
//
// DividerColor ...
this.dividerColor = this.navParams.get(
nameof<XPopoverComponent>('dividerColor')
);
if (!isNullOrEmptyString(this.dividerColor)) {
this.applyDividerColor();
}
//
// BackgroundColor ...
this.backgroundColor = this.navParams.get(
nameof<XPopoverComponent>('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<XPopoverOption>,
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<XPopoverItem>,
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<XPopoverItem>
) => string = (items) => {
//
const itemIds = toArray(items)
.map((i) => i.id)
.join('|');
const result = toMd5(itemIds);
//
return result;
};
export const toPopoverOptions: (
item: XListItem<any>
) => XOneOrManyType<XPopoverOption> = (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<any>;
}
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<any>;
}
export interface XPopoverResult {
//
item?: XPopoverItem;
itemResult?: any;
//
option?: XPopoverOption;
optionResult?: any;
}
type SelectedKeysOfXpopoverComponent = Pick<
Partial<XPopoverComponent>,
'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<XPopoverItem>;
options?: XOneOrManyType<XPopoverOption>;
}
export type XPopoverPresentOptions = Pick<
Partial<XPopoverComponentProps>,
'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
<div class="x-dialog-wrapper">
<!-- Toolbar -->
<ion-header class="x-dialog-header">
<!-- Title Toolbar -->
<ion-toolbar
class="v-toolbar"
[xColor]="'primary'"
*ngIf="showToolbar | async"
>
<!-- Slots -->
<div class="toolbar-area">
<x-slotter>
<!-- Start -->
<x-slot
[name]="SlotNames.START"
[cssClass]="['ion-text-start', 'ion-float-start']"
>
<div
matRipple
(click)="handleBack()"
class="toolbar-item toolbar-button center-vertical-flex"
>
<x-icon
[name]="backIcon"
[loading]="loading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
<ion-title class="toolbar-item center-vertical-flex">
<h3>
{{ title | async }}
</h3>
</ion-title>
</x-slot>
<!-- End -->
<x-slot
[name]="SlotNames.END"
[cssClass]="['ion-text-end', 'ion-float-end']"
>
<!-- De Select -->
<div
matRipple
(click)="handleDeselect()"
*ngIf="dialogCanSelect()"
class="
toolbar-item toolbar-inline-item toolbar-button
center-vertical-flex
"
>
<x-icon
[name]="cancelIcon"
[loading]="loading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
<!-- Select -->
<div
matRipple
(click)="handleSelect()"
*ngIf="dialogCanSelect()"
class="
toolbar-item toolbar-inline-item toolbar-button
center-vertical-flex
"
>
<x-icon
[name]="selectIcon"
[loading]="loading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
</x-slotter>
</div>
<!-- Progressbar for Loading -->
<ion-progress-bar
*ngIf="loading"
type="indeterminate"
[color]="progressBarColor | async"
></ion-progress-bar>
</ion-toolbar>
</ion-header>
<!-- Component -->
<ion-content
[ngClass]="cssClass | async"
class="x-dialog-content-wrapper"
[class.has-toolbar]="showToolbar | async"
>
<!-- Search -->
<x-search-bar
class="x-selector-search"
[color]="searchBarColor | async"
[value]="dataPagerQuery.filter"
[searchInputColor]="searchBarInputColor | async"
(queryChange)="handleSearchbarQuryChanged($event)"
*ngIf="(showSearchBar | async) && (getValue(canSearch) | async)"
></x-search-bar>
<!-- Data Pager -->
<x-data-pager
[loading]="loading"
[itemTemplate]="listRef"
[query]="dataPagerQuery"
[uiDisabled]="uiDisabled"
[result]="dataPagerResult"
[task]="queryFetcher | async"
clas="x-selector-data-pager"
[type]="DataPagerPresentTypes.Page"
[paginatorColor]="paginatorColor | async"
[actionProvider]="actionProvider | async"
(emptyRefresh)="handleResetDataPagerQuery()"
(taskReady)="handleDataPagerTaskReady($event)"
[paginatorPosition]="paginatorPosition | async"
(queryChange)="handleDataPagerQueryChanged($event)"
[showPaginator]="(showPaginator | async) && showDataPagerPaginator"
></x-data-pager>
</ion-content>
</div>
<!-- List Template -->
<ng-template #listRef>
<ng-container *ngIf="hasChildValue(dataPagerResultListItems) | async">
<x-list
[showEmpty]="true"
[showDivider]="true"
class="x-selector-list"
[emptyHasRefresh]="true"
[items]="dataPagerResultListItems"
[actionProvider]="pageListActionProvider"
(emptyRefresh)="handleResetDataPagerQuery()"
[selectableItems]="canMultipleSelect | async"
[clickableItems]="!(canMultipleSelect | async)"
(itemSelected)="handleListItemSelected($event)"
[itemTemplate]="
(notNullOrUndefinedValue(itemTemplate) | async)
? (itemTemplate | async)
: vItemRef
"
(selectionChanged)="handleListItemsSelected($event)"
>
</x-list>
</ng-container>
</ng-template>
<ng-template #vItemRef let-item>
{{ item.data | json }}
</ng-template>
### 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<any>[] = [];
dataPagerResult: XBaseDataPagerQueryResult<any>;
dataPagerActionProvider = new Subject<XDataPagerActionModel>();
//
pageListActionProvider = new Subject<XListActionModel>();
//
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<XSelectorDialogComponent>
) {
super(
zone,
element,
renderer,
ruler,
managerService,
changeDetector,
config,
data,
dialogRef
);
}
//#endregion
//
//#region Task Handlers ...
async onTaskFinished(name: string, task: XTask<any>) {
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<any>>
) {
//
// XBaseDataPagerQueryResult<any> ...
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<any>) {
//
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<XListItem<any>>) {
//
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<any>[]) {
//
const canSelectMultipleItems = await this.getValueAsync(
this.canMultipleSelect
);
//
if (!this.hasChild(event) || !canSelectMultipleItems) {
return;
}
//
await this.handleSelectedItems(event);
}
//#endregion
//
//#region Abstracts ...
async getTaskNames(): Promise<string[]> {
return [await this.getValueAsync(this.taskName)];
}
async deselectAllListItems(): Promise<void> {
//
if (!this.hasChild(this.dataPagerResultListItems)) {
return;
}
//
this.dataPagerResultListItems.forEach((i) => {
i.disabled = false;
});
//
this.dataPagerResultListItems = [...this.dataPagerResultListItems];
//
this.detectChanges();
}
async deselectItemInList(item: any): Promise<void> {
//
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<void> {
//
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<XBaseDataPagerQueryResult<any>>
) {
//
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<any>
) {
//
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<any>;
});
}
//#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<any>
): MatDialogRef<XSelectorDialogComponent, any> {
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<XDataPagerActionModel> {
//
showPaginator?: XStandardType<boolean>;
paginatorColor?: XStandardType<XColorIdentifier>;
paginatorPosition?: XStandardType<XDataPagerPaginatorPositionIdentifier>;
//
queryFetcher?: (
query: XBaseDataPagerQuery
) => Observable<XBaseDataPagerQueryResult<any>>;
onQueryChanged?: (query: XBaseDataPagerQuery) => XStandardType<void>;
onPageLoad?: (result: XBaseDataPagerQueryResult<any>) => XStandardType<void>;
itemTemplate?: XStandardType<TemplateRef<any>>;
//
taskName?: XStandardType<string>;
}
### 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);
// }
// }
//
// <div id="external-card" class="mat-elevation-z2"><p>Some content</p></div>
//
// 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;
// <input> 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
<ion-toolbar
class="x-actions-bar x-wrapper"
[class.mobile]="isMobileUi$ | async"
*ngIf="hasChild(preparedActions)"
[xColor]="getValue(color) | async"
[ngClass]="getValue(cssClass) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- Start Slot Actions -->
<ion-buttons slot="start">
<ng-container *ngFor="let item of getStartSoltItems() | async">
<ng-container
*ngTemplateOutlet="actionRef; context: { $implicit: item }"
></ng-container>
</ng-container>
</ion-buttons>
<!-- End Slot Actions -->
<ion-buttons slot="end">
<ng-container *ngFor="let item of getEndSoltItems() | async">
<ng-container
*ngTemplateOutlet="actionRef; context: { $implicit: item }"
></ng-container>
</ng-container>
</ion-buttons>
</ion-toolbar>
<!-- Action Template -->
<ng-template #actionRef let-action>
<ng-container *ngIf="action && !(isHidedAction(action) | async)">
<ng-container
*ngTemplateOutlet="
(isOnlyIcon(action) | async) ? iconRef : buttonRef;
context: {
$implicit: action,
clickable: true,
color:
(isOnlyIcon(action) | async)
? (getValue(action.iconColor) | async)
: (getValue(action.color) | async)
}
"
></ng-container>
</ng-container>
</ng-template>
<!-- Button Template -->
<ng-template #buttonRef let-action>
<x-button
[loading]="loading"
class="x-action-bar-item"
[type]="ButtonTypes.Raised"
[color]="getValue(action.color) | async"
[ngClass]="getValue(action.cssClass) | async"
(clicked)="handleActionClicked(action, $event)"
*ngIf="!(getOptionalValue(action.hidden) | async)"
[uiDisabled]="
uiDisabled ||
(isDisabledAction(action) | async) ||
(getOptionalValue(action.disabled) | async)
"
[class.disabled]="
uiDisabled ||
(isDisabledAction(action) | async) ||
(getOptionalValue(action.disabled) | async)
"
>
<div class="x-action-bar-item-inner">
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
$implicit: action,
clickable: false,
color: getValue(action.iconColor) | async
}
"
></ng-container>
<span
[isForeground]="true"
[xColor]="getValue(action.titleColor) | async"
*ngIf="action.title && (notEmptyValue(action.title) | async)"
>{{ getResourceValue(action.title) | async }}</span
>
</div>
</x-button>
</ng-template>
<!-- Icon Template -->
<ng-template #iconRef let-action let-color="color" let-clickable="clickable">
<x-icon
[color]="color"
[loading]="loading"
class="x-action-bar-item"
[clickable]="
clickable &&
!loading &&
!uiDisabled &&
!(getValue(action.disabled) | async)
"
[name]="getValue(action.icon) | async"
(clicked)="handleActionClicked(action, $event)"
[matTooltip]="getResourceValue(action.title) | async"
[uiDisabled]="
uiDisabled ||
(isDisabledAction(action) | async) ||
(getOptionalValue(action.disabled) | async)
"
[class.disabled]="
uiDisabled ||
(isDisabledAction(action) | async) ||
(getOptionalValue(action.disabled) | async)
"
></x-icon>
</ng-template>
### 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<XActionBarActionIdentifier, boolean> = new Map();
private ACTIONS_DISABLED: Map<XActionBarActionIdentifier, boolean> =
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<XActionBarComponent>('actions')
);
if (isActionsChanged) {
await this.prepareActions();
}
//#endregion
//
//#region Action Provider Changed ...
//
const isActionProviderChaged = changeKeys.includes(
nameof<XActionBarComponent>('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<XActionBarActionModel>();
}
//
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<string>;
hidden?: XStandardType<boolean>;
onlyIcon?: XStandardType<boolean>;
disabled?: XStandardType<boolean>;
icon: XStandardType<XIconIdentifier>;
color?: XStandardType<XColorIdentifier>;
title?: XStandardType<XResourceIdentifier>;
iconColor?: XStandardType<XColorIdentifier>;
titleColor?: XStandardType<XColorIdentifier>;
cssClass?: XStandardType<XOneOrManyType<string>>;
slot: XStandardType<XActionBarItemSlotIdentifier>;
handler?: (model?: XActionBarActionFiredModel) => XStandardType<any>;
}
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<XActionBarActionIdentifier> {
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<XActionBarActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
actions: XStandardType<XOneOrManyType<XActionBarItem>>;
//
actionFired: EventEmitter<XActionBarActionFiredModel>;
}
@Injectable({
providedIn: 'root',
})
export class XActionBarContainer
extends XBaseContainer
implements Readonly<IXActionBarContainer>
{
//
//#region Props ...
//
readonly actionProvider = new Subject<XActionBarActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly actions: XStandardType<XOneOrManyType<XActionBarItem>>;
//
readonly actionFired = new EventEmitter<XActionBarActionFiredModel>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XActionBarContainerComponent
extends XBaseContainerComponent
implements IXActionBarContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Input()
actions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.propertyProvider.actions;
//
@Output()
actionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
//#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<IXActionBarContainer> {
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<boolean>;
actionBarColor: XStandardType<XColorIdentifier>;
actionBarForegroundColor: XStandardType<boolean>;
actionBarActionProvider: Subject<XActionBarActionModel>;
actionBarCssClass: XStandardType<XOneOrManyType<string>>;
actionBarActionFired: EventEmitter<XActionBarActionFiredModel>;
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>>;
}
@Injectable({
providedIn: 'root',
})
export class XComponentActionBarContainer
extends XBaseComponentContainer
implements Readonly<IXComponentActionBarContainer>
{
//
//#region Props ...
//
readonly showActionBar: XStandardType<boolean> = true;
//
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.actionProvider;
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly actionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
readonly actionBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.propertyProvider.actions;
//
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
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<boolean> = this.propertyProvider.showActionBar;
//
@Input()
actionBarActionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.actionBarActionProvider;
@Input()
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.actionBarCssClass;
//
@Input()
actionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.actionBarColor;
@Input()
actionBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.actionBarForegroundColor;
//
@Input()
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.propertyProvider.actionBarActions;
//
@Output()
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
//#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<IXComponentActionBarContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<!-- Avatar Container -->
<div
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
class="x-avatar-container x-wrapper"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- File Upload Input -->
<input
hidden
#fileInput
type="file"
multiple="false"
(change)="handleFilesSelected()"
[disabled]="loading || uiDisabled"
/>
<!-- File Drop -->
<ng-container *ngIf="getValue(showFileDropArea) | async">
<ng-container *ngTemplateOutlet="fileDragAreaRef"></ng-container>
</ng-container>
<!-- Wrapper of Thumbnail -->
<div class="thumbnail-wrapper">
<x-slotter
[hasCenterSlot]="false"
[layout]="SlotLayout.HORIZONTAL"
[startTopSlotCssClass]="'ion-text-start'"
[endBottomSlotCssClass]="['ion-text-center']"
>
<x-slot [name]="SlotNames.START" [cssClass]="">
<!-- Thumbnail -->
<x-thumbnail
class="x-thumb"
[circular]="true"
[loading]="loading"
[cssClass]="'thumbnail'"
[uiDisabled]="uiDisabled"
[type]="ThumbnailTypes.CUSTOM"
[identifier]="avatar || (getValue(placeHolderAvatar) | async)"
>
</x-thumbnail>
</x-slot>
<x-slot [name]="SlotNames.END" cssClass="ion-text-end">
<div
class="avatar-actions ion-text-end"
*ngIf="hasChildValue(actions) | async"
>
<!-- Action Buttons -->
<ng-container *ngFor="let action of getActions() | async">
<!-- Crop -->
<ng-container *ngIf="action.name === ActionButtonNames.Crop">
<ng-container
*ngTemplateOutlet="
actionButtonRef;
context: {
$implicit: action,
showCondition: isCroppableImage()
}
"
></ng-container>
</ng-container>
<!-- Clear -->
<ng-container *ngIf="action.name === ActionButtonNames.Clear">
<ng-container
*ngTemplateOutlet="
actionButtonRef;
context: {
$implicit: action,
showCondition: avatar
}
"
></ng-container>
</ng-container>
<!-- Select -->
<ng-container *ngIf="action.name === ActionButtonNames.Select">
<ng-container
*ngTemplateOutlet="
actionButtonRef;
context: {
$implicit: action,
showCondition: !avatar
}
"
></ng-container>
</ng-container>
</ng-container>
</div>
</x-slot>
</x-slotter>
</div>
</div>
</ng-template>
<!-- File Drop Area Template -->
<ng-template #fileDragAreaRef>
<div class="x-file-drag-drop-wrapper">
<x-file-drop-area
[loading]="loading"
[uiDisabled]="uiDisabled"
[supportsMultipleFiles]="false"
[icon]="getValue(fileDropAreaIcon) | async"
[actionProvider]="fileDropAreaActionProvider"
[color]="getValue(fileDropAreaColor) | async"
(filesChangeEmiter)="handleFileDropped($event)"
[cssClass]="getValue(fileDropAreaCssClass) | async"
[isInPage]="getValue(fileDropAreaIsInPage) | async"
[cardColor]="getValue(fileDropAreaCardColor) | async"
[errorColor]="getValue(fileDropAreaErrorColor) | async"
[accentColor]="getValue(fileDropAreaAccentColor) | async"
[message]="getResourceValue(fileDropAreaMessage) | async"
[wrapWithCard]="getValue(fileDropAreaWrapWithCard) | async"
[successColor]="getValue(fileDropAreaSuccessColor) | async"
[dragDisabled]="getValue(fileDropAreaDragDisabled) | async"
[cardTitle]="getResourceValue(fileDropAreaCardTitle) | async"
[allowedExtensions]="getArrayValue(allowedExtensions) | async"
[cardShowFooter]="getValue(fileDropAreaCardShowFooter) | async"
[foregroundColor]="getValue(fileDropAreaForegroundColor) | async"
[contentTemplate]="getValue(fileDropAreaContentTemplate) | async"
[cardSubTitle]="getResourceValue(fileDropAreaCardSubTitle) | async"
[disableFileCheck]="getValue(fileDropAreaDisableFileCheck) | async"
[cardForegroundColor]="getValue(fileDropAreaCardForegroundColor) | async"
></x-file-drop-area>
</div>
</ng-template>
<!-- Action Button Template -->
<ng-template #actionButtonRef let-descriptor let-showCondition="showCondition">
<x-button
*ngIf="showCondition"
[loading]="loading"
[uiDisabled]="uiDisabled"
[type]="ButtonTypes.Icon"
[color]="getValue(descriptor.color) | async"
(clicked)="handleActionButtonClicked(descriptor.name)"
[matTooltip]="getResourceValue(descriptor.tooltip) | async"
>
<ng-container
*ngTemplateOutlet="iconRef; context: { $implicit: descriptor }"
></ng-container>
</x-button>
</ng-template>
<!-- Icon Template -->
<ng-template #iconRef let-descriptor>
<x-icon
[name]="getValue(descriptor.icon) | async"
[color]="getValue(descriptor.color) | async"
[foregroundColor]="getValue(foregroundColor) | async"
></x-icon>
</ng-template>
### 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<XAvatarUploadComponent>('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<File>(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<XAvatarUploadActionModel>();
}
//
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<XAvatarUploadActionIdentifier> {}
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<XIconIdentifier>;
color?: XStandardType<XColorIdentifier>;
tooltip?: XStandardType<XResourceIdentifier>;
}
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<XAvatarUploadActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
placeHolderAvatar: XStandardType<string>;
//
actions: XStandardType<XOneOrManyType<XAvatarUploadActionButton>>;
//
avatarChange: EventEmitter<File>;
}
@Injectable({
providedIn: 'root',
})
export class XAvatarUploadContainer
extends XCardFileFileDropContainer
implements Readonly<IXAvatarUploadContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XAvatarUploadActionModel> =
new Subject<XAvatarUploadActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly placeHolderAvatar: XStandardType<string>;
//
readonly actions: XStandardType<XOneOrManyType<XAvatarUploadActionButton>> =
defaultAvatarUploadActionButtons;
//
readonly avatarChange: EventEmitter<File> = new EventEmitter<File>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XAvatarUploadContainerComponent
extends XCardFileFileDropContainerComponent
implements IXAvatarUploadContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XAvatarUploadActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Input()
placeHolderAvatar: XStandardType<string> =
this.propertyProvider.placeHolderAvatar;
//
@Input()
actions: XStandardType<XOneOrManyType<XAvatarUploadActionButton>> =
this.propertyProvider.actions;
//
@Output()
avatarChange: EventEmitter<File> = 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<IXAvatarUploadContainer> {
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
<ng-container
*ngTemplateOutlet="
buttonRef;
context: { $implicit: getValue(this.type) | async }
"
></ng-container>
<ng-template #buttonRef let-type>
<!-- Raised -->
<button
mat-raised-button
class="x-button x-wrapper"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
*ngIf="type === XButtonTypes.Raised"
[disabled]="uiDisabled || loading"
(click)="handleButtonClicked($event)"
[ngClass]="getValue(cssClass) | async"
[disableRipple]="uiDisabled || loading"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- Has Icon -->
<ng-container *ngIf="hasIcon() | async">
<ng-container *ngTemplateOutlet="bothRef"></ng-container>
</ng-container>
<!-- Hasn't Icon -->
<ng-container *ngIf="!(hasIcon() | async)">
<ng-container
*ngTemplateOutlet="contentRef; context: { $implicit: true }"
></ng-container>
</ng-container>
</button>
<!-- Icon -->
<button
mat-icon-button
class="x-button x-wrapper"
(click)="handleButtonClicked()"
*ngIf="type === XButtonTypes.Icon"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
[disabled]="uiDisabled || loading"
[ngClass]="getValue(cssClass) | async"
[disableRipple]="uiDisabled || loading"
[matTooltip]="getResourceValue(title) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<ng-container
*ngTemplateOutlet="contentRef; context: { $implicit: false }"
></ng-container>
</button>
</ng-template>
<ng-template #bothRef>
<x-slotter
[hasCenterSlot]="false"
[startTopSlotCssClass]="'ion-text-center'"
[endBottomSlotCssClass]="'ion-text-center'"
[layout]="
(isVerticalLayout() | async)
? XSlotLayouts.VERTICAL
: XSlotLayouts.HORIZONTAL
"
>
<!-- icon slot -->
<x-slot
[name]="iconSlotName() | async"
[cssClass]="'x-button-icon-wrapper'"
>
<ng-container
*ngTemplateOutlet="contentRef; context: { $implicit: false }"
></ng-container>
</x-slot>
<!-- title slot -->
<x-slot [name]="titleSlotName() | async">
<ng-container
*ngTemplateOutlet="contentRef; context: { $implicit: true }"
></ng-container>
</x-slot>
</x-slotter>
</ng-template>
<ng-template #contentRef let-showTitle>
<!-- if Title Not Provided -->
<ng-container *ngIf="!showTitle || !title || !(getValue(title) | async)">
<!-- Has Icon -->
<ng-container *ngIf="hasIcon() | async">
<x-icon
[name]="getValue(icon) | async"
[color]="getValue(iconColor) | async"
[foregroundColor]="getValue(foregroundColor) | async"
></x-icon>
</ng-container>
<!-- Hasn't Icon -->
<ng-container *ngIf="!(hasIcon() | async)">
<ng-content></ng-content>
</ng-container>
</ng-container>
<!-- if Title Provided -->
<ng-container *ngIf="showTitle && title && (getValue(title) | async)">
{{ getResourceValue(title) | async }}
</ng-container>
</ng-template>
### 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<XButtonComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region is IconPositionChanged ...
const isIconPositionChanged = changeKeys.includes(
nameof<XButtonComponent>('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<XSlotName> {
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<XSlotName> {
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<XButtonActionModel>();
}
//
// 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<XButtonActionIdentifier> {}
//
//#region Container ...
export interface IXButtonContainer extends IXBaseContainer {
//
actionProvider: Subject<XButtonActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
type: XStandardType<XButtonTypeIdentifier>;
title: XStandardType<XResourceIdentifier>;
icon: XStandardType<XIconIdentifier>;
iconPosition: XStandardType<XButtonIconPositionIdentifier>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
iconColor: XStandardType<XColorIdentifier>;
//
clicked: EventEmitter<Event>;
}
@Injectable({
providedIn: 'root',
})
export class XButtonContainer
extends XBaseContainer
implements Readonly<IXButtonContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XButtonActionModel> =
new Subject<XButtonActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly type: XStandardType<XButtonTypeIdentifier> = XButtonType.Raised;
readonly title: XStandardType<XResourceIdentifier>;
readonly icon: XStandardType<XIconIdentifier>;
readonly iconPosition: XStandardType<XButtonIconPositionIdentifier> =
XButtonIconPosition.Start;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
readonly iconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
//
readonly clicked: EventEmitter<Event> = new EventEmitter<Event>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XButtonContainerComponent
extends XBaseContainerComponent
implements IXButtonContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XButtonActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
type: XStandardType<XButtonTypeIdentifier> = this.propertyProvider.type;
@Input()
title: XStandardType<XResourceIdentifier> = this.propertyProvider.title;
@Input()
icon: XStandardType<XIconIdentifier> = this.propertyProvider.icon;
@Input()
iconPosition: XStandardType<XButtonIconPositionIdentifier> =
this.propertyProvider.iconPosition;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
@Input()
iconColor: XStandardType<XColorIdentifier> = this.propertyProvider.iconColor;
//
@Output()
clicked: EventEmitter<Event> = new EventEmitter<Event>();
//#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<IXButtonContainer> {
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
<mat-card
class="x-card x-wrapper"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[class.no-text]="isNoTextCard() | async"
[class.page-card]="getValue(isInPage) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- Card Header -->
<mat-card-header class="x-header" *ngIf="getValue(showHeader) | async">
<!-- Avatar Image -->
<section
*ngIf="notEmptyValue(avatarUrl) | async"
mat-card-avatar
class="x-avatar"
>
<img
mat-card-avatar
class="x-avatar"
[src]="getValue(avatarUrl) | async"
*ngIf="
(notEmptyValue(avatarUrl) | async) &&
!(notNullOrUndefinedValue(avatarTemplate) | async)
"
/>
<ng-container *ngIf="notNullOrUndefinedValue(avatarTemplate) | async">
<ng-container
*ngTemplateOutlet="
avatarTemplate;
context: {
avatarUrl: getValue(avatarUrl) | async
}
"
></ng-container>
</ng-container>
</section>
<!-- Card Title -->
<mat-card-title class="x-title" *ngIf="notEmptyValue(title) | async">
{{ getResourceValue(title) | async }}
</mat-card-title>
<!-- Card Sub Title -->
<mat-card-subtitle
class="x-sub-title"
*ngIf="notEmptyValue(subTitle) | async"
>
{{ getResourceValue(subTitle) | async }}</mat-card-subtitle
>
<!-- Header Content -->
<ng-content select="[header]"></ng-content>
</mat-card-header>
<!-- Card Image -->
<img
mat-card-image
class="x-image"
[src]="getValue(imageUrl) | async"
*ngIf="notEmptyValue(imageUrl) | async"
[alt]="getResourceValue(imageDescription) | async"
/>
<!-- Card Content -->
<mat-card-content class="x-content" *ngIf="getValue(showContent) | async">
<ng-content></ng-content>
</mat-card-content>
<!-- Card Actions -->
<mat-card-actions class="x-actions" *ngIf="getValue(showActions) | async">
<ng-content select="[actions]"></ng-content>
</mat-card-actions>
<!-- Card Footer -->
<mat-card-footer
#footer
class="x-footer"
*ngIf="getValue(showFooter) | async"
>
<ng-content select="[footer]"></ng-content>
</mat-card-footer>
</mat-card>
### 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<XCardComponent>('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<XCardActionModel>();
}
//
// 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<XCardActionIdentifier> {}
//
//#region Container ...
export interface IXCardContainer extends IXBaseContainer {
//
actionProvider: Subject<XCardActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
showHeader: XStandardType<boolean>;
title: XStandardType<XResourceIdentifier>;
subTitle: XStandardType<XResourceIdentifier>;
avatarUrl: XStandardType<string>;
avatarTemplate: TemplateRef<any>;
//
imageUrl: XStandardType<string>;
imageDescription: XStandardType<XResourceIdentifier>;
//
isInPage: XStandardType<boolean>;
//
showContent: XStandardType<boolean>;
showActions: XStandardType<boolean>;
showFooter: XStandardType<boolean>;
}
@Injectable({
providedIn: 'root',
})
export class XCardContainer
extends XBaseContainer
implements Readonly<IXCardContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XCardActionModel> =
new Subject<XCardActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly showHeader: XStandardType<boolean> = false;
readonly title: XStandardType<XResourceIdentifier>;
readonly subTitle: XStandardType<XResourceIdentifier>;
readonly avatarUrl: XStandardType<string>;
readonly avatarTemplate: TemplateRef<any>;
//
readonly imageUrl: XStandardType<string>;
readonly imageDescription: XStandardType<XResourceIdentifier>;
//
readonly isInPage: XStandardType<boolean> = false;
//
readonly showContent: XStandardType<boolean> = true;
readonly showActions: XStandardType<boolean> = false;
readonly showFooter: XStandardType<boolean> = false;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XCardContainerComponent
extends XBaseContainerComponent
implements IXCardContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XCardActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Input()
showHeader: XStandardType<boolean> = this.propertyProvider.showHeader;
@Input()
title: XStandardType<XResourceIdentifier> = this.propertyProvider.title;
@Input()
subTitle: XStandardType<XResourceIdentifier> = this.propertyProvider.subTitle;
@Input()
avatarUrl: XStandardType<string> = this.propertyProvider.avatarUrl;
@Input()
avatarTemplate: TemplateRef<any> = this.propertyProvider.avatarTemplate;
//
@Input()
imageUrl: XStandardType<string> = this.propertyProvider.imageUrl;
@Input()
imageDescription: XStandardType<XResourceIdentifier> =
this.propertyProvider.imageDescription;
//
@Input()
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
//
@Input()
showContent: XStandardType<boolean> = this.propertyProvider.showContent;
@Input()
showActions: XStandardType<boolean> = this.propertyProvider.showActions;
@Input()
showFooter: XStandardType<boolean> = 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<IXCardContainer> {
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<string & TKey>}`]: IXCardContainer[TKey];
};
export interface IXComponentCardContainer
extends TXComponentCardContainer,
IXBaseComponentContainer {
isInPage: XStandardType<boolean>;
wrapWithCard: XStandardType<boolean>;
}
@Injectable({
providedIn: 'root',
})
export class XComponentCardContainer
extends XBaseComponentContainer
implements Readonly<IXComponentCardContainer>
{
//
//#region Props ...
//
readonly isInPage: XStandardType<boolean> = false;
readonly wrapWithCard: XStandardType<boolean> = false;
//
readonly cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.actionProvider;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly cardColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
readonly cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.title;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.subTitle;
//
readonly cardShowFooter: XStandardType<boolean> =
this.propertyProvider.showFooter;
readonly cardShowActions: XStandardType<boolean> =
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<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
//
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
//
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
//
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
//
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
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<IXComponentCardContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<!-- Component Box ... -->
<div
class="x-chart x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<div #chartContainer class="x-chart-container"></div>
</div>
</ng-template>
### 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<XChartComponent>('autoUpdate'),
);
if (isAutoUpdateChanged) {
//
if (isNullOrUndefined(this.autoUpdate)) {
this.autoUpdate = this.propertyProvider.autoUpdate;
}
}
//
// Action Provider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XChartComponent>('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<XChartComponent>('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<XChartComponent>('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<string, any>`.
| XChartHierarchyNode[]
| Record<string, any>[];
}[];
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
* `"<seriesIndex>:<dataPointIndex>"`.
*/
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: '<id>'` 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 `"#<dataPointIndex+1> of <count>"`.
*/
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<string | number> | Array<Array<string | number>>;
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<XChart, 'type' | 'stacked' | 'stackType'>;
plotOptions?: XChartPlotOptions;
xaxis?: XChartXAxis;
yaxis?: XChartYAxis | XChartYAxis[];
colors?: Array<string | ((opts: XChartColorFormatterOpts) => 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<XChartDrilldownSeries>;
/**
* 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<string, any>;
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 | ((opts: XChartColorFormatterOpts) => 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<string, any>;
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<XChartActionIdentifier> {}
export type XChartSeriesType = XChartAxisChartSeries | XChartNonAxisChartSeries;
export interface IXChartContainer extends IXComponentCardContainer {
//
// Commons ...
actionProvider: Subject<XChartActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
// Chart Props ...
autoUpdate: XStandardType<boolean>;
options: XStandardType<XChartOptions>;
series: XStandardType<XChartSeriesType>;
//
// Events ...
chartRendered: EventEmitter<void>;
dataPointSelected: EventEmitter<any>;
zoomed: EventEmitter<any>;
}
@Injectable({
providedIn: 'root',
})
export class XChartContainer
extends XComponentCardContainer
implements Readonly<IXChartContainer>
{
//
readonly chartId: XStandardType<string>;
readonly options: XStandardType<XChartOptions>;
readonly autoUpdate: XStandardType<boolean> = true;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
readonly actionProvider = new Subject<XChartActionModel>();
readonly series: XStandardType<XChartSeriesType>;
//
readonly zoomed = new EventEmitter<any>();
readonly chartRendered = new EventEmitter<void>();
readonly dataPointSelected = new EventEmitter<any>();
}
@Injectable()
@Component({ template: `` })
export abstract class XChartContainerComponent
extends XComponentCardContainerComponent
implements IXChartContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XChartActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
options: XStandardType<XChartOptions> = this.propertyProvider.options;
@Input()
series: XStandardType<XChartSeriesType> =
this.propertyProvider.series;
@Input()
autoUpdate: XStandardType<boolean> = this.propertyProvider.autoUpdate;
//
// Events ...
@Output()
chartRendered: EventEmitter<void> = new EventEmitter();
@Output()
dataPointSelected: EventEmitter<any> = new EventEmitter();
@Output()
zoomed: EventEmitter<any> = new EventEmitter();
//
//#region ComponentCard Props ...
@Input()
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardActionProvider: Subject<XCardActionModel> =
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<IXChartContainer> {
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
<div
class="x-color x-wrapper"
[class.mobile]="isMobileUi$ | async"
*ngIf="getValue(value) | async as item"
>
<!-- Color Title -->
<div
class="x-color-title text-truncate"
*ngIf="item.key && (getValue(showLabel) | async)"
>
<span [xColor]="getValue(labelColor) | async" [isForeground]="true">{{
item.key
}}</span>
</div>
<!-- Spacer -->
<div class="x-spacer"></div>
<!-- Color Value -->
<button
*ngIf="item.value"
[matTooltip]="item.value"
class="x-color-value-button"
(click)="handleCopyToClipboard(item.value)"
>
<div class="x-color-value" [style.backgroundColor]="item.value"></div>
</button>
</div>
### 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<XColorComponent>('size'));
if (isSizeChanged) {
await this.applySize();
}
//#endregion
//
//#region borderWidth Changed ...
const isBorderWidthChanged = changeKeys.includes(
nameof<XColorComponent>('borderWidth')
);
if (isBorderWidthChanged) {
await this.applyBorderWith();
}
//#endregion
//
//#region borderStyle Changed ...
const isBorderStyleChanged = changeKeys.includes(
nameof<XColorComponent>('borderStyle')
);
if (isBorderStyleChanged) {
await this.applyBorderStyle();
}
//#endregion
//
//#region borderColor Changed ...
const isBorderColorChanged = changeKeys.includes(
nameof<XColorComponent>('borderColor')
);
if (isBorderColorChanged) {
await this.applyBorderColor();
}
//#endregion
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XColorComponent>('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<XColorActionModel>();
}
//
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<XColorActionIdentifier> {}
export enum XColorCssVars {
Size = 'size',
BorderWidth = 'border-width',
BorderColor = 'border-color',
BorderStyle = 'border-style',
}
//
//#region Container ...
export interface IXColorContainer extends IXBaseContainer {
//
actionProvider: Subject<XColorActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
showLabel: XStandardType<boolean>;
labelColor: XStandardType<XColorIdentifier>;
//
size: XStandardType<number>;
value: XStandardType<XColorKeyValue>;
//
borderWidth: XStandardType<number>;
borderStyle: XStandardType<XBorderStyleIdentifier>;
borderColor: XStandardType<XColorIdentifier>;
}
@Injectable({
providedIn: 'root'
})
export class XColorContainer
extends XBaseContainer
implements Readonly<IXColorContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XColorActionModel> =
new Subject<XColorActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly showLabel: XStandardType<boolean> = true;
readonly labelColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
//
readonly size: XStandardType<number> = 32;
//
readonly value: XStandardType<XColorKeyValue>;
//
readonly borderWidth: XStandardType<number> = 1;
readonly borderStyle: XStandardType<XBorderStyleIdentifier> =
XBorderStyle.Solid;
readonly borderColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.LightShade;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XColorContainerComponent
extends XBaseContainerComponent
implements IXColorContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XColorActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
showLabel: XStandardType<boolean> = this.propertyProvider.showLabel;
@Input()
labelColor: XStandardType<XColorIdentifier> =
this.propertyProvider.labelColor;
//
@Input()
size: XStandardType<number> = this.propertyProvider.size;
@Input()
value: XStandardType<XColorKeyValue> = this.propertyProvider.value;
//
@Input()
borderWidth: XStandardType<number> = this.propertyProvider.borderWidth;
@Input()
borderStyle: XStandardType<XBorderStyleIdentifier> =
this.propertyProvider.borderStyle;
@Input()
borderColor: XStandardType<XColorIdentifier> =
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<IXColorContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<!-- Color Palette/Slider Box ... -->
<div
#colorPicker
class="x-color-picker x-wrapper"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- Force LTR Direction -->
<div class="x-force-ltr">
<!-- Color Pallete -->
<div
xSlider
[rgX]="1"
[rgY]="1"
#paletteSlider
class="x-color-palette"
[style.background-color]="hueSliderColor"
*ngIf="getValue(showPaletteChannel) | async"
(newValue)="setSaturationAndBrightness($event)"
>
<!-- Cursor -->
<div
*ngIf="slider"
class="x-cursor"
[style.top.px]="slider.v"
[style.left.px]="slider.s"
></div>
</div>
<!-- Color Sliders -->
<div class="x-info-box">
<!-- Start -->
<div class="x-start" *ngIf="getValue(showSelectedColorPreview) | async">
<!-- Background -->
<div class="x-selected-color-background"></div>
<!-- Selected Color -->
<div
class="x-selected-color"
[style.background-color]="selectedColor"
></div>
</div>
<!-- Margin -->
<div class="x-margin"></div>
<!-- End -->
<div class="x-end">
<!-- Hue Slider -->
<div
xSlider
[rgX]="1"
#hueSlider
class="x-color-hue"
(newValue)="setHue($event)"
*ngIf="getValue(showHueChannel) | async"
>
<!-- Cursor -->
<div
*ngIf="slider"
class="x-cursor"
[style.left.px]="slider.h"
></div>
</div>
<!-- Alpha Slider -->
<div
xSlider
[rgX]="1"
#alphaSlider
class="x-color-alpha"
(newValue)="setAlpha($event)"
*ngIf="getValue(showAlphaChannel) | async"
[style.background-color]="alphaSliderColor"
>
<!-- Cursor -->
<div
*ngIf="slider"
class="x-cursor"
[style.left.px]="slider.a"
></div>
</div>
</div>
</div>
<!-- Color Value -->
<div
class="x-color-value"
*ngIf="
atLeastHasOneValue(true, showColorValue, showCopyToClipboard) | async
"
>
<ng-container
*ngIf="getArrayValue(representColorFormats) | async as outputFormats;"
>
<!-- Hex Value -->
<div class="x-hex" *ngIf="outputFormats.includes(ColorFormats.XHEX)">
<!-- Color Text -->
<span
class="x-color-text"
*ngIf="getValue(showColorValue) | async"
>{{ hexValue }}</span
>
<!-- Clipboard Icon ... -->
<div class="x-icon-wrapper">
<ng-container
*ngTemplateOutlet="
iconActionsRef;
context: { $implicit: hexValue }
"
></ng-container>
</div>
</div>
<!-- RGBA Value -->
<div
class="x-rgba"
*ngIf="outputFormats.includes(ColorFormats.XRGBA)"
>
<!-- Color Text -->
<span
class="x-color-text"
*ngIf="getValue(showColorValue) | async"
>{{ rgbaValue }}</span
>
<!-- Clipboard Icon ... -->
<div class="x-icon-wrapper">
<ng-container
*ngTemplateOutlet="
iconActionsRef;
context: { $implicit: rgbaValue }
"
></ng-container>
</div>
</div>
<!-- HSLA Value -->
<div
class="x-hsla"
*ngIf="outputFormats.includes(ColorFormats.XHSLA)"
>
<!-- Color Text -->
<span
class="x-color-text"
*ngIf="getValue(showColorValue) | async"
>{{ hslaValue }}</span
>
<!-- Clipboard Icon ... -->
<div class="x-icon-wrapper">
<ng-container
*ngTemplateOutlet="
iconActionsRef;
context: { $implicit: hslaValue }
"
></ng-container>
</div>
</div>
</ng-container>
</div>
</div>
<!-- Color Input -->
<div class="x-color-input-box" *ngIf="getValue(showColorInput) | async">
<div fxLayout="row" fxLayoutAlign="none">
<!-- Input Icon -->
<div>
<x-icon
name="input"
[clickable]="true"
(clicked)="handleInputColor()"
[color]="getValue(colorInputIconColor) | async"
[matTooltip]="getResourceValue(colorInputIconLabel) | async"
></x-icon>
</div>
<!-- Input Box -->
<div fxFlex>
<input
class="x-color-input"
[isForeground]="true"
[(ngModel)]="inputColor"
(xOnEnter)="handleInputColor($event)"
[xColor]="getValue(colorTextColor) | async"
[placeholder]="
getResourceValue(ResourceIDs.input_color_description) | async
"
/>
</div>
</div>
</div>
<!-- Preset Colors -->
<div
class="x-preset-colors-wrapper"
*ngIf="
(getValue(showPresetColors) | async) &&
(hasChildValue(presetColors) | async)
"
>
<hr class="x-hr" />
<!-- Lable -->
<span
class="x-preset-label"
*ngIf="notEmptyValue(presetColorsLable) | async"
>{{ getResourceValue(presetColorsLable) | async }}</span
>
<!-- Preset Colors Boxes -->
<div
class="x-preset-colors-box"
*ngIf="getArrayValue(presetColors) | async as pColors;"
>
<div
class="x-preset-color"
(click)="setHexColor(color)"
*ngFor="let color of pColors"
[style.backgroundColor]="color"
></div>
</div>
</div>
</div>
</ng-template>
<!-- Icon Action Template -->
<ng-template #iconActionsRef let-value>
<!-- Copy To Clipboard -->
<x-icon
name="clipboard"
[clickable]="true"
*ngIf="getValue(showCopyToClipboard) | async"
[color]="getValue(copyToClipboardIconColor) | async"
(clicked)="handleSaveSelectedColorInClipboard(value)"
[matTooltip]="getResourceValue(copyToClipboardIconLabel) | async"
></x-icon>
<!-- Clear Color -->
<x-icon
name="clear"
[clickable]="true"
(clicked)="handleClearSelectedColor()"
*ngIf="notEmptyValue(selectedColor) | async"
[color]="getValue(clearColorIconColor) | async"
[matTooltip]="getResourceValue(clearColorIconLabel) | async"
></x-icon>
</ng-template>
### 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<any>;
@ViewChild('colorPicker', { static: false })
set colorPicker(v: ElementRef<any>) {
//
this.COLOR_PICKER = v;
this.initializeComponent();
}
get colorPicker() {
return this.COLOR_PICKER;
}
//#endregion
//
//#region PaletteSlider ViewChild ...
private PALETTE_SLIDER: ElementRef<any>;
@ViewChild('paletteSlider', { static: false })
set paletteSlider(v: ElementRef<any>) {
//
this.PALETTE_SLIDER = v;
this.initializeComponent();
}
get paletteSlider() {
return this.PALETTE_SLIDER;
}
//#endregion
//
//#region HueSlider ViewChild ...
private HUE_SLIDER: ElementRef<any>;
@ViewChild('hueSlider', { static: false })
set hueSlider(v: ElementRef<any>) {
//
this.HUE_SLIDER = v;
this.initializeComponent();
}
get hueSlider() {
return this.HUE_SLIDER;
}
//#endregion
//
//#region AlphaSlider ViewChild ...
private ALPHA_SLIDER: ElementRef<any>;
@ViewChild('alphaSlider', { static: false })
set alphaSlider(v: ElementRef<any>) {
//
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<XColorPickerComponent>('cursorColor')
);
if (isCursorColorChanged) {
await this.applyColors();
}
//#endregion
//
//#region SelectedColor Changed ...
const isSelectedColorChanged = changeKeys.includes(
nameof<XColorPickerComponent>('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<XColorPickerComponent>('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<XColorPickerActionModel>();
}
//
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<XColorPickerActionIdentifier> {}
export interface XSliderPosition extends Required<XHSVAColor> {}
export interface XSliderDimension extends Required<XHSVAColor> {}
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<XColorPickerActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
colorSelected: EventEmitter<string>;
//
//#region Colors ...
selectedColor: XStandardType<string>;
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
copyToClipboardIconColor: XStandardType<XColorIdentifier>;
colorInputIconColor: XStandardType<XColorIdentifier>;
clearColorIconColor: XStandardType<XColorIdentifier>;
colorTextColor: XStandardType<XColorIdentifier>;
presetColorsLableColor: XStandardType<XColorIdentifier>;
cursorColor: XStandardType<XColorIdentifier>;
//#endregion
//
//#region Labels ...
colorInputIconLabel: XStandardType<XResourceIdentifier>;
copyToClipboardIconLabel: XStandardType<XResourceIdentifier>;
clearColorIconLabel: XStandardType<XResourceIdentifier>;
//#endregion
//
//#region PresetColors ...
presetColorsLable: XStandardType<XResourceIdentifier>;
presetColors: XStandardType<XOneOrManyType<string>>;
//#endregion
//
//#region Represent Color Value ...
representColorFormats: XStandardType<
XOneOrManyType<XColorPickerOutputFormatIdentifier>
>;
outputFormat: XStandardType<XColorPickerOutputFormatIdentifier>;
//#endregion
//
//#region Show Parts Props ...
showColorInput: XStandardType<boolean>;
showCopyToClipboard: XStandardType<boolean>;
showSelectedColorPreview: XStandardType<boolean>;
showPaletteChannel: XStandardType<boolean>;
showHueChannel: XStandardType<boolean>;
showAlphaChannel: XStandardType<boolean>;
showColorValue: XStandardType<boolean>;
showPresetColors: XStandardType<boolean>;
//#endregion
}
@Injectable({
providedIn: 'root',
})
export class XColorPickerContainer
extends XComponentCardContainer
implements Readonly<IXColorPickerContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XColorPickerActionModel> =
new Subject<XColorPickerActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly colorSelected: EventEmitter<string> = new EventEmitter();
//
//#region Colors ...
readonly selectedColor: XStandardType<string> = DEFAULT_COLOR_PICKER_COLOR;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly copyToClipboardIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.TertiaryShade;
readonly colorInputIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.SecondaryShade;
readonly clearColorIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Danger;
readonly colorTextColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly presetColorsLableColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly cursorColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
//#endregion
//
//#region Labels ...
readonly colorInputIconLabel: XStandardType<XResourceIdentifier> =
XResourceIDs.input;
readonly copyToClipboardIconLabel: XStandardType<XResourceIdentifier> =
XResourceIDs.copy_to_clipboard;
readonly clearColorIconLabel: XStandardType<XResourceIdentifier> =
XResourceIDs.clear;
//#endregion
//
//#region PresetColors ...
readonly presetColorsLable: XStandardType<XResourceIdentifier>;
readonly presetColors: XStandardType<XOneOrManyType<string>>;
//#endregion
//
//#region Represent Color Value ...
readonly representColorFormats: XStandardType<
XOneOrManyType<XColorPickerOutputFormatIdentifier>
> = [XColorPickerOutputFormat.XHEX];
readonly outputFormat: XStandardType<XColorPickerOutputFormatIdentifier> =
XColorPickerOutputFormat.XHEX;
//#endregion
//
//#region Show Parts Props ...
readonly showColorInput: XStandardType<boolean> = true;
readonly showCopyToClipboard: XStandardType<boolean> = false;
readonly showSelectedColorPreview: XStandardType<boolean> = true;
readonly showPaletteChannel: XStandardType<boolean> = true;
readonly showHueChannel: XStandardType<boolean> = true;
readonly showAlphaChannel: XStandardType<boolean> = true;
readonly showColorValue: XStandardType<boolean> = true;
readonly showPresetColors: XStandardType<boolean> = true;
//#endregion
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XColorPickerContainerComponent
extends XComponentCardContainerComponent
implements IXColorPickerContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XColorPickerActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Output()
colorSelected: EventEmitter<string> = new EventEmitter();
//
//#region Colors ...
@Input()
selectedColor: XStandardType<string> = this.propertyProvider.selectedColor;
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
@Input()
copyToClipboardIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.copyToClipboardIconColor;
@Input()
colorInputIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.colorInputIconColor;
@Input()
clearColorIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.clearColorIconColor;
@Input()
colorTextColor: XStandardType<XColorIdentifier> =
this.propertyProvider.colorTextColor;
@Input()
presetColorsLableColor: XStandardType<XColorIdentifier> =
this.propertyProvider.presetColorsLableColor;
@Input()
cursorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.cursorColor;
//#endregion
//
//#region Labels ...
@Input()
colorInputIconLabel: XStandardType<XResourceIdentifier> =
this.propertyProvider.colorInputIconLabel;
@Input()
copyToClipboardIconLabel: XStandardType<XResourceIdentifier> =
this.propertyProvider.copyToClipboardIconLabel;
@Input()
clearColorIconLabel: XStandardType<XResourceIdentifier> =
this.propertyProvider.clearColorIconLabel;
//#endregion
//
//#region PresetColors ...
@Input()
presetColorsLable: XStandardType<XResourceIdentifier> =
this.propertyProvider.presetColorsLable;
@Input()
presetColors: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.presetColors;
//#endregion
//
//#region Represent Color Value ...
@Input()
representColorFormats: XStandardType<
XOneOrManyType<XColorPickerOutputFormatIdentifier>
> = this.propertyProvider.representColorFormats;
@Input()
outputFormat: XStandardType<XColorPickerOutputFormatIdentifier> =
this.propertyProvider.outputFormat;
//#endregion
//
//#region Show Parts Props ...
@Input()
showColorInput: XStandardType<boolean> = this.propertyProvider.showColorInput;
@Input()
showCopyToClipboard: XStandardType<boolean> =
this.propertyProvider.showCopyToClipboard;
@Input()
showSelectedColorPreview: XStandardType<boolean> =
this.propertyProvider.showSelectedColorPreview;
@Input()
showPaletteChannel: XStandardType<boolean> =
this.propertyProvider.showPaletteChannel;
@Input()
showHueChannel: XStandardType<boolean> = this.propertyProvider.showHueChannel;
@Input()
showAlphaChannel: XStandardType<boolean> =
this.propertyProvider.showAlphaChannel;
@Input()
showColorValue: XStandardType<boolean> = this.propertyProvider.showColorValue;
@Input()
showPresetColors: XStandardType<boolean> =
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<IXColorPickerContainer> {
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<any>();
//
@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
<!-- Title Toolbar -->
<ion-toolbar class="v-toolbar" [xColor]="'primary'">
<!-- Slots -->
<div class="toolbar-area">
<x-slotter>
<!-- Start -->
<x-slot
[name]="SlotNames.START"
[cssClass]="['ion-text-start', 'ion-float-start']"
>
<div
matRipple
(click)="handleBack()"
class="toolbar-item toolbar-button center-vertical-flex"
>
<x-icon
[name]="backIcon"
[loading]="loading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
<ion-title class="toolbar-item center-vertical-flex">
<h3>
{{ getTitle() | async }}
</h3>
</ion-title>
</x-slot>
<!-- End -->
<x-slot
[name]="SlotNames.END"
[cssClass]="['ion-text-end', 'ion-float-end']"
>
<div
matRipple
*ngIf="canSelect()"
(click)="handleSelect()"
class="toolbar-item toolbar-button center-vertical-flex"
>
<x-icon
[name]="selectIcon"
[loading]="loading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
</x-slotter>
</div>
</ion-toolbar>
<!-- ColorPicker Component -->
<x-color-picker
[isInPage]="true"
[wrapWithCard]="true"
[uiDisabled]="uiDisabled"
[color]="getColor() | async"
[actionProvider]="actionProvider"
[cssClass]="getCssClass() | async"
[cardColor]="getCardColor() | async"
[cardTitle]="getCardTitle() | async"
[cursorColor]="getCursorColor() | async"
[cardSubTitle]="getCardSubTitle() | async"
[presetColors]="getPresetColors() | async"
[outputFormat]="getOutputFormat() | async"
[showHueChannel]="showHueChannel() | async"
[showColorValue]="showColorValue() | async"
[showColorInput]="showColorInput() | async"
[selectedColor]="getSelectedColor() | async"
(colorSelected)="handleColorSelected($event)"
[colorTextColor]="getColorTextColor() | async"
[foregroundColor]="isForegroundColor() | async"
[showPresetColors]="showPresetColors() | async"
[showAlphaChannel]="showAlphaChannel() | async"
[showPaletteChannel]="showPaletteChannel() | async"
[presetColorsLable]="getPresetColorsLable() | async"
[showCopyToClipboard]="showCopyToClipboard() | async"
[cardForegroundColor]="isCardForegroundColor() | async"
[clearColorIconColor]="getClearColorIconColor() | async"
[clearColorIconLabel]="getClearColorIconLabel() | async"
[representColorFormats]="getRepresentColorFormats() | async"
[presetColorsLableColor]="getPresetColorsLableColor() | async"
[colorInputIconColor]="getColorInputIconColor() | async"
[colorInputIconLabel]="getColorInputIconLabel() | async"
[showSelectedColorPreview]="showSelectedColorPreview() | async"
[copyToClipboardIconColor]="getCopyToClipboardIconColor() | async"
[copyToClipboardIconLabel]="getCopyToClipboardIconLabel() | async"
>
</x-color-picker>
### 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<XColorPickerActionModel>();
//
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<XColorPickerDialogComponent>
) {
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<XColorPickerDialogComponent>;
//
isMobile$ = this.managerService.isMobileUi$;
// tslint:disable-next-line:no-output-on-prefix
@Output()
onResult = new EventEmitter<XColorPickerDialogResult>();
//#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<IXColorPickerContainer> {}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-counter\x-counter.component.html
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<h4
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
class="
x-wrapper x-counter
display-message-container
ion-no-padding ion-no-margin
"
>
{{ displayMessage }}
</h4>
</ng-template>
### 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<XCounterComponent>('stopValue')
);
const isStartValueChanged = changeKeys.includes(
nameof<XCounterComponent>('startValue')
);
const isCurrentValueChanged = changeKeys.includes(
nameof<XCounterComponent>('currentValue')
);
if (isStopValueChanged || isStartValueChanged || isCurrentValueChanged) {
this.setBoundaries(this.startValue, this.stopValue, this.currentValue);
}
//#endregion
//
//#region Handle Type Changed ...
const isTypeChanged = changeKeys.includes(
nameof<XCounterComponent>('type')
);
if (isTypeChanged) {
await this.prepareType();
}
//#endregion
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XCounterComponent>('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<XCounterActionModel>();
}
//
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<boolean>((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<XCounterActionIdentifier> {}
//
//#region Container ...
export interface IXCounterContainer extends IXComponentCardContainer {
//
actionProvider: Subject<XCounterActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
type: XStandardType<XCounterTypeIdentifier>;
autoStart: XStandardType<boolean>;
stopValue: number;
startValue: number;
currentValue: number;
delay: number;
//
displayPattern: (min: number, max: number, current: number) => string;
//
counterStart: EventEmitter<XCounterTick>;
counterTtick: EventEmitter<XCounterTick>;
counterStop: EventEmitter<XCounterTick>;
}
@Injectable({
providedIn: 'root',
})
export class XCounterContainer
extends XComponentCardContainer
implements Readonly<IXCounterContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XCounterActionModel> =
new Subject<XCounterActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly type: XStandardType<XCounterTypeIdentifier> = XCounterType.CountDown;
readonly autoStart: XStandardType<boolean> = 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<XCounterTick> =
new EventEmitter<XCounterTick>();
readonly counterTtick: EventEmitter<XCounterTick> =
new EventEmitter<XCounterTick>();
readonly counterStop: EventEmitter<XCounterTick> =
new EventEmitter<XCounterTick>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XCounterContainerComponent
extends XComponentCardContainerComponent
implements IXCounterContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XCounterActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
type: XStandardType<XCounterTypeIdentifier> = this.propertyProvider.type;
@Input()
autoStart: XStandardType<boolean> = 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<XCounterTick> = new EventEmitter();
@Output()
counterTtick: EventEmitter<XCounterTick> = new EventEmitter();
@Output()
counterStop: EventEmitter<XCounterTick> = 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<IXCounterContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<div
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
class="x-wrapper x-data-pager ion-no-padding"
>
<!-- Above Pager -->
<ng-container
*ngIf="
(getValue(paginatorPosition) | async) ===
DataPagerPaginatorPositions.Above &&
result &&
hasChildValue(result.items)
"
>
<ng-container *ngTemplateOutlet="paginatorRef"></ng-container>
</ng-container>
<!-- Custom Contet -->
<ng-content select="[content]"> </ng-content>
<!-- Items or Empty -->
<ng-container
*ngTemplateOutlet="
result && (hasChildValue(result.items) | async)
? itemsRef
: emptyListTemplate
? emptyListTemplate
: defaultEmptyListRef
"
>
</ng-container>
<!-- Below Pager -->
<ng-container
*ngIf="
(getValue(paginatorPosition) | async) ===
DataPagerPaginatorPositions.Below &&
result &&
hasChildValue(result.items)
"
>
<ng-container *ngTemplateOutlet="paginatorRef"></ng-container>
</ng-container>
</div>
</ng-template>
<!-- Items Presenting -->
<ng-template #itemsRef>
<ng-container *ngIf="itemTemplate">
<!-- Item Type Handler -->
<ng-container
*ngIf="(getValue(type) | async) === DataPagerPresetTypes.Item"
>
<ng-container *ngFor="let item of result.items">
<ng-container
*ngTemplateOutlet="itemTemplate; context: { $implicit: item }"
></ng-container>
</ng-container>
</ng-container>
<!-- Page Type Handler -->
<ng-container
*ngIf="(getValue(type) | async) === DataPagerPresetTypes.Page"
>
<ng-container
*ngTemplateOutlet="itemTemplate; context: { $implicit: result.items }"
></ng-container>
</ng-container>
</ng-container>
</ng-template>
<ng-template #paginatorRef>
<ion-toolbar
class="x-paginator-bar"
*ngIf="
(getValue(showPaginator) | async) &&
(notNullOrUndefinedValue(preparedPaginatorOptions) | async)
"
[xColor]="getValue(paginatorColor) | async"
>
<!-- Mat Paginator Component -->
<mat-paginator
#matPaginator
[hidden]="true"
[disabled]="loading || uiDisabled"
[pageSize]="getValue(preparedPaginatorOptions.pageSize) | async"
></mat-paginator>
<!-- Start Slot Contents -->
<ion-buttons slot="start" *ngIf="preparedPaginatorOptions">
<!-- First -->
<ion-button
#first
(click)="firstPage()"
*ngIf="preparedPaginatorOptions.first"
[hidden]="getValue(preparedPaginatorOptions.first.hidden) | async"
[disabled]="
loading ||
uiDisabled ||
(getValue(preparedPaginatorOptions.first.disabled) | async)
"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(preparedPaginatorOptions.first.icon) | async,
tooltip:
getResourceValue(preparedPaginatorOptions.first.title) | async,
color: getValue(preparedPaginatorOptions.first.color) | async,
applyDirection: true
}
"
></ng-container>
</ion-button>
<!-- Previous -->
<ion-button
#previous
(click)="previousPage()"
*ngIf="preparedPaginatorOptions.prev"
[hidden]="getValue(preparedPaginatorOptions.prev.hidden) | async"
[disabled]="
loading ||
uiDisabled ||
(getValue(preparedPaginatorOptions.prev.disabled) | async)
"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(preparedPaginatorOptions.prev.icon) | async,
tooltip:
getResourceValue(preparedPaginatorOptions.prev.title) | async,
color: getValue(preparedPaginatorOptions.prev.color) | async,
applyDirection: true
}
"
></ng-container>
</ion-button>
</ion-buttons>
<!-- Pagination Info -->
<div class="x-paginator-wrapper">
<div fxLayout="row" fxLayoutAlign="center stretch">
<!-- Current Page -->
<div fxFlex="auto">
<ion-button
fill="clear"
expand="full"
class="cb-inherit"
*ngIf="!showPageNumberInput"
(click)="showPageNumberInput = true"
[disabled]="loading || uiDisabled"
>
{{
preparedPaginatorOptions.pageInfoProvider(
managerService.currentLocale,
currentPage,
pageSize,
totalPages,
totalItems
)
}}
</ion-button>
<!-- Change Current Page -->
<ion-input
step="1"
[min]="1"
type="number"
debounce="500"
required="true"
autofocus="true"
[max]="totalPages"
class="cb-inherit"
inputmode="numeric"
[value]="currentPage"
*ngIf="showPageNumberInput"
(ionBlur)="showPageNumberInput = false"
[disabled]="loading || uiDisabled"
(ionChange)="handlePageChange($event)"
></ion-input>
</div>
<!-- Page Size -->
<div fxFlex="auto">
<ion-button
fill="clear"
expand="full"
*ngIf="pageSize"
class="cb-inherit"
[disabled]="loading || uiDisabled"
(click)="handlePageSizeChange($event)"
>
{{ applyLocale(pageSize) }}
</ion-button>
</div>
</div>
</div>
<!-- End Slot Content -->
<ion-buttons slot="end">
<!-- Noxt -->
<ion-button
#next
(click)="nextPage()"
*ngIf="preparedPaginatorOptions.next"
[hidden]="getValue(preparedPaginatorOptions.next.hidden) | async"
[disabled]="
loading ||
uiDisabled ||
(getValue(preparedPaginatorOptions.next.disabled) | async)
"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(preparedPaginatorOptions.next.icon) | async,
tooltip:
getResourceValue(preparedPaginatorOptions.next.title) | async,
color: getValue(preparedPaginatorOptions.next.color) | async,
applyDirection: true
}
"
></ng-container>
</ion-button>
<!-- Last -->
<ion-button
#last
(click)="lastPage()"
*ngIf="preparedPaginatorOptions.last"
[hidden]="getValue(preparedPaginatorOptions.last.hidden) | async"
[disabled]="
loading ||
uiDisabled ||
(getValue(preparedPaginatorOptions.last.disabled) | async)
"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(preparedPaginatorOptions.last.icon) | async,
tooltip:
getResourceValue(preparedPaginatorOptions.last.title) | async,
color: getValue(preparedPaginatorOptions.prev.color) | async,
applyDirection: true
}
"
></ng-container>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ng-template>
<!-- Default Empty Content -->
<ng-template #defaultEmptyListRef>
<!-- Empty Handler -->
<ng-container
*ngIf="
(getValue(showEmpty) | async) &&
(!result || !(hasChildValue(result.items) | async))
"
>
<x-empty
(refresh)="emptyRefresh.emit($event)"
[color]="getValue(emptyColor) | async"
[message]="getResourceValue(emptyMessage) | async"
[refreshIcon]="getValue(emptyRefreshIcon) | async"
[messageColor]="getValue(emptyMessageColor) | async"
[hasRefresh]="getValue(emptyHasRefresh) | async"
[foregroundRefreshButtonColor]="
getValue(emptyForegroundRefreshButtonColor) | async
"
[foregroundColor]="getValue(emptyForegroundColor) | async"
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
></x-empty> </ng-container
></ng-template>
<!-- Icon Template Ref -->
<ng-template
#iconRef
let-name="name"
let-tooltip="tooltip"
let-color="color"
let-applyDirection="applyDirection"
>
<x-icon
[name]="name"
[color]="color"
[loading]="loading"
[matTooltip]="tooltip"
[foregroundColor]="true"
[uiDisabled]="uiDisabled"
[applyDirection]="applyDirection"
[cssClass]="!color ? 'cb-inherit' : null"
></x-icon>
</ng-template>
### 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<XDataPagerComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region PaginatorOptionChanged ...
const isPaginatorOptionsChanged = changeKeys.includes(
nameof<XDataPagerComponent>('paginatorOptions')
);
if (isPaginatorOptionsChanged) {
await this.preparePaginatorOptions();
}
//#endregion
//
//#region Query Changed ...
const isTaskChanged = changeKeys.includes(
nameof<XDataPagerComponent>('task')
);
const isQueryChanged = changeKeys.includes(
nameof<XDataPagerComponent>('query')
);
if (isQueryChanged || isTaskChanged) {
await this.handleQueryChanged();
}
//#endregion
//
//#region Result Changed ...
const isResultChanged = changeKeys.includes(
nameof<XDataPagerComponent>('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<XDataPagerActionModel>();
}
//
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<XDataPagerActionIdentifier> {}
//
//#region Inside Card/Empty Container ...
export interface IXDataPagerContainer extends IXCardEmptyContainer {
//
actionProvider: Subject<XDataPagerActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
pageChanged: EventEmitter<number>;
type: XStandardType<XDataPagerPresentTypeIdentifier>;
itemTemplate: TemplateRef<any>;
//
result: XBaseDataPagerQueryResult<any>;
task: (
query: XBaseDataPagerQuery
) => Observable<XBaseDataPagerQueryResult<any>>;
taskReady: EventEmitter<Observable<XBaseDataPagerQueryResult<any>>>;
query: XBaseDataPagerQuery;
queryChange: EventEmitter<XBaseDataPagerQuery>;
//
showPaginator: XStandardType<boolean>;
paginatorPosition: XStandardType<XDataPagerPaginatorPositionIdentifier>;
paginatorColor: XStandardType<XColorIdentifier>;
paginatorOptions: XStandardType<XDataPagerPaginatorOptions>;
//
emptyListTemplate: TemplateRef<any>;
}
@Injectable({
providedIn: 'root',
})
export class XDataPagerContainer
extends XCardEmptyContainer
implements Readonly<IXDataPagerContainer>
{
//
//#region Props ...
//
readonly actionProvider = new Subject<XDataPagerActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly pageChanged: EventEmitter<number> = new EventEmitter<number>();
readonly type: XStandardType<XDataPagerPresentTypeIdentifier> =
XDataPagerPresentType.Item;
readonly itemTemplate: TemplateRef<any>;
//
readonly result: XBaseDataPagerQueryResult<any>;
readonly task: (
query: XBaseDataPagerQuery
) => Observable<XBaseDataPagerQueryResult<any>>;
readonly taskReady: EventEmitter<Observable<XBaseDataPagerQueryResult<any>>> =
new EventEmitter<Observable<XBaseDataPagerQueryResult<any>>>();
readonly query: XBaseDataPagerQuery;
readonly queryChange: EventEmitter<XBaseDataPagerQuery> =
new EventEmitter<XBaseDataPagerQuery>();
//
readonly showPaginator: XStandardType<boolean>;
readonly paginatorPosition: XStandardType<XDataPagerPaginatorPositionIdentifier> =
XDataPagerPaginatorPosition.Below;
readonly paginatorColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly paginatorOptions: XStandardType<XDataPagerPaginatorOptions>;
//
readonly emptyListTemplate: TemplateRef<any>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XDataPagerContainerComponent
extends XCardEmptyContainerComponent
implements IXDataPagerContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XDataPagerActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Output()
pageChanged: EventEmitter<number> = new EventEmitter();
@Input()
type: XStandardType<XDataPagerPresentTypeIdentifier> =
this.propertyProvider.type;
@Input()
itemTemplate: TemplateRef<any> = this.propertyProvider.itemTemplate;
//
@Input()
result: XBaseDataPagerQueryResult<any> = this.propertyProvider.result;
@Input()
task: (
query: XBaseDataPagerQuery
) => Observable<XBaseDataPagerQueryResult<any>> = this.propertyProvider.task;
@Output()
taskReady: EventEmitter<Observable<XBaseDataPagerQueryResult<any>>> =
new EventEmitter();
@Input()
query: XBaseDataPagerQuery = this.propertyProvider.query;
@Output()
queryChange: EventEmitter<XBaseDataPagerQuery> = new EventEmitter();
//
@Input()
showPaginator: XStandardType<boolean> = this.propertyProvider.showPaginator;
@Input()
paginatorPosition: XStandardType<XDataPagerPaginatorPositionIdentifier> =
this.propertyProvider.paginatorPosition;
@Input()
paginatorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.paginatorColor;
@Input()
paginatorOptions: XStandardType<XDataPagerPaginatorOptions> =
this.propertyProvider.paginatorOptions;
//
@Input()
emptyListTemplate: TemplateRef<any> = 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<IXDataPagerContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<div
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
class="x-data-scroller x-wrapper ion-no-padding"
>
<!-- Items or Empty -->
<ng-container
*ngTemplateOutlet="
items && (hasChildValue(items) | async)
? contentsRef
: emptyListTemplate
? emptyListTemplate
: defaultEmptyListRef
"
>
</ng-container>
</div>
</ng-template>
<!-- Default Empty Content -->
<ng-template #defaultEmptyListRef>
<!-- Empty Handler -->
<ng-container
*ngIf="
(getValue(showEmpty) | async) &&
(!result || !(hasChildValue(result.items) | async))
"
>
<x-empty
(refresh)="emptyRefresh.emit($event)"
[color]="getValue(emptyColor) | async"
[hasRefresh]="getValue(emptyHasRefresh) | async"
[message]="getResourceValue(emptyMessage) | async"
[refreshIcon]="getValue(emptyRefreshIcon) | async"
[messageColor]="getValue(emptyMessageColor) | async"
[foregroundRefreshButtonColor]="
getValue(emptyForegroundRefreshButtonColor) | async
"
[foregroundColor]="getValue(emptyForegroundColor) | async"
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
></x-empty> </ng-container
></ng-template>
<!-- Contents Template -->
<ng-template #contentsRef>
<ng-content></ng-content>
</ng-template>
### 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<XDataScrollerComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Query Changed ...
const isTaskChanged = changeKeys.includes(
nameof<XDataScrollerComponent>('task')
);
const isQueryChanged = changeKeys.includes(
nameof<XDataScrollerComponent>('query')
);
if (isQueryChanged || isTaskChanged) {
await this.handleQueryChanged();
}
//#endregion
//
//#region Result Changed ...
const isResultChanged = changeKeys.includes(
nameof<XDataScrollerComponent>('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<XDataScrollerActionModel>();
}
//
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<XDataScrollerActionIdentifier> {}
//
//#region Inside Card/Empty Container ...
export interface IXDataScrollerContainer extends IXCardEmptyContainer {
//
actionProvider: Subject<XDataScrollerActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
result: XBaseDataPagerQueryResult<any>;
task: (query: XBaseDataPagerQuery) => Observable<any>;
taskReady: EventEmitter<Observable<any>>;
query: XBaseDataPagerQuery;
queryChange: EventEmitter<XBaseDataPagerQuery>;
//
emptyListTemplate: TemplateRef<any>;
}
@Injectable({
providedIn: 'root',
})
export class XDataScrollerContainer
extends XCardEmptyContainer
implements Readonly<IXDataScrollerContainer>
{
//
//#region Props ...
//
readonly actionProvider = new Subject<XDataScrollerActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly result: XBaseDataPagerQueryResult<any>;
readonly task: (query: XBaseDataPagerQuery) => Observable<any>;
readonly taskReady = new EventEmitter<Observable<any>>();
readonly query: XBaseDataPagerQuery;
readonly queryChange = new EventEmitter<XBaseDataPagerQuery>();
//
readonly emptyListTemplate: TemplateRef<any>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XDataScrollerContainerComponent
extends XCardEmptyContainerComponent
implements IXDataScrollerContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XDataScrollerActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
result: XBaseDataPagerQueryResult<any> = this.propertyProvider.result;
@Input()
task: (query: XBaseDataPagerQuery) => Observable<any> =
this.propertyProvider.task;
@Output()
taskReady: EventEmitter<Observable<any>> = new EventEmitter();
@Input()
query: XBaseDataPagerQuery = this.propertyProvider.query;
@Output()
queryChange: EventEmitter<XBaseDataPagerQuery> = new EventEmitter();
//
@Input()
emptyListTemplate: TemplateRef<any>;
//#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<IXDataScrollerContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<!-- Check Prepared Model Exists -->
<div
class="x-wrapper x-description-list"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[class.isLegacy]="getValue(isLegacy) | async"
[class.isNotLegacy]="!(getValue(isLegacy) | async)"
*ngIf="notNullOrUndefinedValue(preparedModel) | async"
>
<!-- New -->
<ng-container *ngIf="!(getValue(isLegacy) | async)">
<dl
class="x-description-list-innner"
[xColor]="getValue(color) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- Loop of Model Keys -->
<ng-container *ngFor="let key of keys(preparedModel)">
<!-- Check Can Show Key -->
<section
class="x-description-list-item-container"
*ngIf="canShowKey(key) | async as canShowTheKey"
>
<!-- Title (Key) -->
<dt
[isForeground]="true"
class="x-description-list-title"
*ngIf="
canShowTheKey &&
(getValue(showLabels) | async) &&
(canShowLabelKey(key) | async)
"
[xColor]="getValue(labelColor) | async"
[ngClass]="getDescriptionTitleClasses(key)"
>
<span class="x-title-span text-truncate">
{{ getTitle(key) | async }}
</span>
</dt>
<!-- Content (Value) -->
<!-- if Has Not ContentItem and Descibeable -->
<dd
[isForeground]="true"
class="x-description-list-description"
[xColor]="getValue(valueColor) | async"
[ngClass]="getDescriptionContentClasses(key)"
*ngIf="
!(hasContentItem(key) | async) &&
(canDescribe(key, preparedModel[key]) | async)
"
>
<x-slotter
[hasCenterSlot]="false"
[layout]="SlotLayouts.HORIZONTAL"
[hasEndOrBottomSlot]="
notNullOrUndefinedValue(propertyActionTemplate) | async
"
>
<!-- Start -->
<x-slot
[name]="SlotNames.START"
style="overflow: hidden"
[cssClass]="[
'ion-text-start',
'text-truncate',
'x-decription-span'
]"
>
{{ getContent(key, preparedModel[key]) | async }}
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END" [cssClass]="'ion-text-end'">
<!-- propertyActionTemplate -->
<ng-container
*ngIf="
notNullOrUndefinedValue(propertyActionTemplate) | async
"
>
<ng-container
*ngTemplateOutlet="
propertyActionTemplate;
context: {
key: key,
prefix: prefix,
value: preparedModel[key]
}
"
>
</ng-container>
</ng-container>
</x-slot>
</x-slotter>
</dd>
<!-- if Has not ContentItem && not Describeable -->
<dd
[isForeground]="true"
class="x-description-list-description"
[xColor]="getValue(valueColor) | async"
[ngClass]="getDescriptionContentClasses(key)"
*ngIf="
!(hasContentItem(key) | async) &&
!(canDescribe(key, preparedModel[key]) | async)
"
>
<section class="nested-container ion-margin-start">
<ng-container
*ngTemplateOutlet="
nestedRef;
context: {
key: key,
value: preparedModel[key],
prefix: getKeyPrefix(key),
hiddenModelKeys: (getHiddenModelKeys(key) | async),
availableModelKeys: (getAvailableModelKeys(key) | async),
sortOrderModelKeys: (getSortOrderModelKeys(key) | async),
hiddenLabelModelKeys:
(getHiddenLabelModelKeys(key) | async)
}
"
>
</ng-container>
</section>
</dd>
<!-- if Has ContentItem -->
<dd
[isForeground]="true"
*ngIf="hasContentItem(key) | async"
class="x-description-list-description"
[xColor]="getValue(valueColor) | async"
[ngClass]="getDescriptionContentClasses(key)"
>
<ng-container
*ngTemplateOutlet="
(getContentItem(key, preparedModel[key]) | async).content
"
></ng-container>
</dd>
</section>
</ng-container>
</dl>
</ng-container>
<!-- Legacy -->
<ng-container *ngIf="getValue(isLegacy) | async">
<dl
class="x-description-list"
[xColor]="getValue(color) | async"
[class.inline]="isNotMobileUi$ | async"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- Loop of Model Keys -->
<ng-container *ngFor="let key of keys(preparedModel)">
<!-- Check Can Show Key -->
<ng-container *ngIf="canShowKey(key) | async">
<!-- Title -->
<dt
[isForeground]="true"
class="x-description-list-title"
[xColor]="getValue(labelColor) | async"
[ngClass]="getDescriptionTitleClasses(key)"
*ngIf="
(getValue(showLabels) | async) && (canShowLabelKey(key) | async)
"
>
{{ getTitle(key) | async }}
</dt>
<!-- Description -->
<dd
[isForeground]="true"
class="x-description-list-description"
[xColor]="getValue(valueColor) | async"
[ngClass]="getDescriptionContentClasses(key)"
[class.full-width]="hasContentItem(key) | async"
>
<ng-container
*ngTemplateOutlet="
(hasContentItem(key) | async) ? contentItemRef : contentRef;
context: {
$implicit: key,
value: getContent(key, preparedModel[key]) | async
}
"
>
</ng-container>
</dd>
</ng-container>
</ng-container>
</dl>
</ng-container>
</div>
</ng-template>
<!-- NestedRef -->
<ng-template
#nestedRef
let-key="key"
let-value="value"
let-prefix="prefix"
let-hiddenModelKeys="hiddenModelKeys"
let-availableModelKeys="availableModelKeys"
let-sortOrderModelKeys="sortOrderModelKeys"
let-hiddenLabelModelKeys="hiddenLabelModelKeys"
>
<x-description-list
[model]="value"
[attr.keyPrefix]="prefix"
[actionProvider]="actionProvider"
[color]="getValue(color) | async"
[hiddenModelKeys]="hiddenModelKeys"
[modelKeyProvider]="modelKeyProvider"
[availableModelKeys]="availableModelKeys"
[sortOrderModelKeys]="sortOrderModelKeys"
[modelValueProvider]="modelValueProvider"
[showLabels]="getValue(showLabels) | async"
[labelColor]="getValue(labelColor) | async"
[valueColor]="getValue(valueColor) | async"
[cssClass]="getArrayValue(cssClass) | async"
[hiddenLabelModelKeys]="hiddenLabelModelKeys"
(onModelChanged)="onModelChanged.emit($event)"
[propertyActionTemplate]="propertyActionTemplate"
[foregroundColor]="getValue(foregroundColor) | async"
[hideOptionalValues]="getValue(hideOptionalValues) | async"
*ngIf="
(notEmptyValue(key) | async) && (notNullOrUndefinedValue(value) | async)
"
>
</x-description-list>
</ng-template>
<!-- XDescriptionListItemContent Template -->
<ng-template #contentItemRef let-key let-value="value">
<ng-container
*ngTemplateOutlet="(getContentItem(key, value) | async).content"
></ng-container>
</ng-template>
<!-- XDescriptionList Default Content Template -->
<ng-template #contentRef let-key let-value="value">
{{ value }}
</ng-template>
### 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<T> {
//
//#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<XDescriptionListItemComponent>;
//#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<XDescriptionListComponent>('model')
);
//
if (isModelChanged) {
await this.prepareModel();
}
//#endregion
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XDescriptionListComponent>('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<string> {
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<XDescriptionListItemComponent> {
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<string> {
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<XDescriptionListActionModel>();
}
//
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<string>
) {
//
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<XDescriptionListActionIdentifier> {}
//
//#region Inside Card Container ...
export interface IXDescriptionListContainer<T = any>
extends IXComponentCardContainer {
//
actionProvider: Subject<XDescriptionListActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
isLegacy: XStandardType<boolean>;
showLabels: XStandardType<boolean>;
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
labelColor: XStandardType<XColorIdentifier>;
valueColor: XStandardType<XColorIdentifier>;
propertyActionTemplate: TemplateRef<any>;
onModelChanged: EventEmitter<T>;
//
model: XStandardType<T>;
//
//#region Model Providers ...
hideOptionalValues: XStandardType<boolean>;
availableModelKeys: XModelFieldsType<T>;
hiddenModelKeys: XModelFieldsType<T>;
hiddenLabelModelKeys: XModelFieldsType<T>;
sortOrderModelKeys: XModelFieldsType<T>;
modelKeyProvider: XModelKeyProvider<T>;
modelValueProvider: XModelValueProvider<T>;
//#endregion
}
@Injectable({
providedIn: 'root',
})
export class XDescriptionListContainer<T = any>
extends XComponentCardContainer
implements Readonly<IXDescriptionListContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XDescriptionListActionModel> =
new Subject<XDescriptionListActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly isLegacy: XStandardType<boolean> = true;
readonly showLabels: XStandardType<boolean> = false;
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
readonly labelColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.TertiaryShade;
readonly valueColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly propertyActionTemplate: TemplateRef<any>;
//
readonly onModelChanged: EventEmitter<T>;
//
readonly model: XStandardType<T>;
//
//#region Model Providers ...
readonly hideOptionalValues: XStandardType<boolean>;
readonly availableModelKeys: XModelFieldsType<T>;
readonly hiddenModelKeys: XModelFieldsType<T>;
readonly hiddenLabelModelKeys: XModelFieldsType<T>;
readonly sortOrderModelKeys: XModelFieldsType<T>;
readonly modelKeyProvider: XModelKeyProvider<T>;
readonly modelValueProvider: XModelValueProvider<T>;
//#endregion
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XDescriptionListContainerComponent<T = any>
extends XComponentCardContainerComponent
implements IXDescriptionListContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XDescriptionListActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
isLegacy: XStandardType<boolean> = this.propertyProvider.isLegacy;
@Input()
showLabels: XStandardType<boolean> = this.propertyProvider.showLabels;
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
@Input()
labelColor: XStandardType<XColorIdentifier> =
this.propertyProvider.labelColor;
@Input()
valueColor: XStandardType<XColorIdentifier> =
this.propertyProvider.valueColor;
@Input()
propertyActionTemplate: TemplateRef<any> =
this.propertyProvider.propertyActionTemplate;
@Output()
onModelChanged: EventEmitter<T> = new EventEmitter();
//
@Input()
model: XStandardType<T> = this.propertyProvider.model;
//
//#region Model Providers ...
@Input()
hideOptionalValues: XStandardType<boolean> =
this.propertyProvider.hideOptionalValues;
@Input()
availableModelKeys: XModelFieldsType<T> =
this.propertyProvider.availableModelKeys;
@Input()
hiddenModelKeys: XModelFieldsType<T> = this.propertyProvider.hiddenModelKeys;
@Input()
hiddenLabelModelKeys: XModelFieldsType<T> =
this.propertyProvider.hiddenLabelModelKeys;
@Input()
sortOrderModelKeys: XModelFieldsType<T> =
this.propertyProvider.sortOrderModelKeys;
@Input()
modelKeyProvider: XModelKeyProvider<T> =
this.propertyProvider.modelKeyProvider;
@Input()
modelValueProvider: XModelValueProvider<T> =
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<IXDescriptionListContainer> {
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
<ng-template #content>
<ng-content></ng-content>
</ng-template>
### 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<any>;
//#endregion
//
//#region LifeCycles ...
onChange(changeKeys: string[]) {
super.onChange(changeKeys);
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XDescriptionListItemComponent>('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<XDescriptionListItemActionModel>();
}
//
// 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<XDescriptionListItemActionIdentifier> {}
//
//#region Container ...
export interface IXDescriptionListItemContainer extends IXBaseContainer {
//
actionProvider: Subject<XDescriptionListItemActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
name: XStandardType<string>;
value: XStandardType<any>;
}
@Injectable({
providedIn: 'root'
})
export class XDescriptionListItemContainer
extends XBaseContainer
implements Readonly<IXDescriptionListItemContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XDescriptionListItemActionModel> =
new Subject<XDescriptionListItemActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly name: XStandardType<string>;
readonly value: XStandardType<any>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XDescriptionListItemContainerComponent
extends XBaseContainerComponent
implements IXDescriptionListItemContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XDescriptionListItemActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
name: XStandardType<string> = this.propertyProvider.name;
@Input()
value: XStandardType<any> = 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<IXDescriptionListItemContainer> {
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
<div
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
class="x-empty x-wrapper ion-text-center"
[ngClass]="getArrayValue(cssClass) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<h3
class="x-empty-title"
[xColor]="getValue(messageColor) | async"
[isForeground]="getValue(foregroundMessageColor) | async"
>
{{ getResourceValue(message) | async }}
</h3>
<x-button
class="x-refresh"
(clicked)="refresh.emit()"
[type]="ButtonTypes.Icon"
*ngIf="getValue(hasRefresh) | async"
[color]="getValue(refreshButtonColor) | async"
[foregroundColor]="getValue(foregroundRefreshButtonColor) | async"
>
<x-icon
[foregroundColor]="true"
[name]="getValue(refreshIcon) | async"
[color]="getValue(refreshButtonColor) | async"
></x-icon>
</x-button>
</div>
### 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<XEmptyComponent>('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<XEmptyActionModel>();
}
//
// 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<XEmptyActionIdentifier> {}
//
//#region Container ...
export interface IXEmptyContainer extends IXBaseContainer {
//
actionProvider: Subject<XEmptyActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
message: XStandardType<XResourceIdentifier>;
messageColor: XStandardType<XColorIdentifier>;
foregroundMessageColor: XStandardType<boolean>;
//
hasRefresh: XStandardType<boolean>;
//
refreshButtonColor: XStandardType<XColorIdentifier>;
foregroundRefreshButtonColor: XStandardType<boolean>;
//
refreshIcon: XStandardType<XIconIdentifier>;
//
refresh: EventEmitter<void>;
}
@Injectable({
providedIn: 'root',
})
export class XEmptyContainer
extends XBaseContainer
implements Readonly<IXEmptyContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XEmptyActionModel> =
new Subject<XEmptyActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly messageColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly foregroundMessageColor: XStandardType<boolean> = true;
//
readonly hasRefresh: XStandardType<boolean> = true;
//
readonly refreshButtonColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly foregroundRefreshButtonColor: XStandardType<boolean> = true;
readonly message: XStandardType<XResourceIdentifier> = XResourceIDs.no_item;
//
readonly refreshIcon: XStandardType<XIconIdentifier> = XIconNames.refresh;
//
readonly refresh: EventEmitter<void> = new EventEmitter<void>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XEmptyContainerComponent
extends XBaseContainerComponent
implements IXEmptyContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XEmptyActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Input()
message: XStandardType<XResourceIdentifier> = this.propertyProvider.message;
@Input()
messageColor: XStandardType<XColorIdentifier> =
this.propertyProvider.messageColor;
@Input()
foregroundMessageColor: XStandardType<boolean> =
this.propertyProvider.foregroundMessageColor;
//
@Input()
hasRefresh: XStandardType<boolean> = this.propertyProvider.hasRefresh;
//
@Input()
refreshButtonColor: XStandardType<XColorIdentifier> =
this.propertyProvider.refreshButtonColor;
@Input()
foregroundRefreshButtonColor: XStandardType<boolean> =
this.propertyProvider.foregroundRefreshButtonColor;
//
@Input()
refreshIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.refreshIcon;
@Output()
refresh: EventEmitter<void> = 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<IXEmptyContainer> {
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<boolean>;
}
@Injectable({
providedIn: 'root',
})
export class XComponentEmptyContainer
extends XBaseComponentContainer
implements Readonly<IXComponentEmptyContainer>
{
//
//#region Props ...
//
readonly showEmpty: XStandardType<boolean> = false;
//
readonly emptyActionProvider: Subject<XEmptyActionModel> =
this.propertyProvider.actionProvider;
readonly emptyCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly emptyColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
readonly emptyForegroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
readonly emptyMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.message;
readonly emptyMessageColor: XStandardType<XColorIdentifier> =
this.propertyProvider.messageColor;
readonly emptyForegroundMessageColor: XStandardType<boolean> =
this.propertyProvider.foregroundMessageColor;
//
readonly emptyHasRefresh: XStandardType<boolean> =
this.propertyProvider.hasRefresh;
//
readonly emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
this.propertyProvider.refreshButtonColor;
readonly emptyForegroundRefreshButtonColor: XStandardType<boolean> =
this.propertyProvider.foregroundRefreshButtonColor;
//
readonly emptyRefreshIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.refreshIcon;
//
readonly emptyRefresh: EventEmitter<void> = 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<boolean> = this.propertyProvider.showEmpty;
//
@Input()
emptyActionProvider: Subject<XEmptyActionModel> =
this.propertyProvider.emptyActionProvider;
@Input()
emptyCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.emptyCssClass;
//
@Input()
emptyColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyColor;
@Input()
emptyForegroundColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundColor;
//
@Input()
emptyMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.emptyMessage;
@Input()
emptyMessageColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyMessageColor;
@Input()
emptyForegroundMessageColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundMessageColor;
//
@Input()
emptyHasRefresh: XStandardType<boolean> =
this.propertyProvider.emptyHasRefresh;
//
@Input()
emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyRefreshButtonColor;
@Input()
emptyForegroundRefreshButtonColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundRefreshButtonColor;
//
@Input()
emptyRefreshIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.emptyRefreshIcon;
//
@Output()
emptyRefresh: EventEmitter<void> = 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<IXComponentEmptyContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else listRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="listRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- List Ref -->
<ng-template #listRef>
<ion-list
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
class="x-expandable-list x-wrapper ion-no-padding"
>
<ng-container *ngFor="let item of getArrayValue(items) | async">
<ng-container
*ngTemplateOutlet="
parentPresenterRef;
context: { $implicit: item, siblings: getArrayValue(items) | async }
"
>
</ng-container>
</ng-container>
</ion-list>
</ng-template>
<!-- Parent Ref -->
<ng-template #parentPresenterRef let-item let-siblings="siblings">
<ion-item-group
button="true"
xStopClickPropagation
class="expandable-item-parent"
[ngClass]="{ active: isExpanded(item) | async }"
>
<ion-item-divider
(click)="toggle(item, siblings)"
class="item-parent ion-activatable"
[class.active-parent]="isParentActivated(item) | async"
[matTooltip]="getResourceValue(item.description) | async"
>
<ion-ripple-effect></ion-ripple-effect>
<ng-container
*ngTemplateOutlet="
parentTemplate ? parentTemplate : defaultParentRef;
context: { $implicit: item }
"
></ng-container>
<x-icon
slot="end"
[color]="'cb-inherit'"
[name]="getIconName(item) | async"
[class.invisible]="
!(getValue(showParentDetailIcon) | async) ||
!(hasChildItems(item) | async)
"
></x-icon>
</ion-item-divider>
<!-- Childs -->
<ng-container
*ngTemplateOutlet="childsPresenterRef; context: { $implicit: item }"
>
</ng-container>
</ion-item-group>
</ng-template>
<!-- Children Ref -->
<ng-template #childsPresenterRef let-item>
<ng-container *ngFor="let child of getValue(item.childs) | async">
<ng-container *ngIf="!(hasChildItems(child) | async)">
<ion-item
button="true"
class="item-child"
xStopClickPropagation
[class.ion-hide]="isHidden(child) | async"
[ngClass]="getValue(itemCssClass) | async"
(click)="handleItemSelectedAction(child, item)"
[class.collapsed]="!(isExpanded(item) | async)"
[detail]="getValue(showChildDetailIcon) | async"
[class.active-child]="isChildActivated(child) | async"
[matTooltip]="getResourceValue(child.description) | async"
[disabled]="loading || uiDisabled || (isDisabled(child) | async)"
>
<ng-container
*ngTemplateOutlet="
childTemplate ? childTemplate : defaultChildRef;
context: { $implicit: child }
"
>
</ng-container>
</ion-item>
</ng-container>
<ng-container *ngIf="hasChildItems(child) | async">
<ion-item
[class.ion-hide]="isHidden(child) | async"
[class.collapsed]="!(isExpanded(item) | async)"
class="item-child ion-no-padding ion-no-margin"
>
<ng-container
*ngTemplateOutlet="
parentPresenterRef;
context: {
$implicit: child,
siblings: getValue(item.childs) | async
}
"
>
</ng-container>
</ion-item>
</ng-container>
</ng-container>
</ng-template>
<!-- Default Parent Item -->
<ng-template #defaultParentRef let-item>
<h4>{{ getResourceValue(item.title) | async }}</h4>
</ng-template>
<!-- Default Child Item -->
<ng-template #defaultChildRef let-item>
<h5>{{ getResourceValue(item.title) | async }}</h5>
</ng-template>
### 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<any>;
private ACTIVATED_PARENTS: XExpandableListItem<any>[];
//
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
//#endregion
//
//#region LifeCycle ...
async onChange(changeKeys: string[]) {
super.onChange(changeKeys);
//
//#region Item Changed ...
const isItemsChanged = changeKeys.includes(
nameof<XExpandableListComponent>('items')
);
if (isItemsChanged) {
await this.handleStartupState();
}
//#endregion
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XExpandableListComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Color Change Detectors ...
const isChildColorChanged = changeKeys.includes(
nameof<XExpandableListComponent>('childColor')
);
if (isChildColorChanged) {
await this.applyChildColor();
}
const isChildActiveColorChanged = changeKeys.includes(
nameof<XExpandableListComponent>('childActiveColor')
);
if (isChildActiveColorChanged) {
await this.applyChildActiveColor();
}
const isParentColorChanged = changeKeys.includes(
nameof<XExpandableListComponent>('parentColor')
);
if (isParentColorChanged) {
await this.applyParentColor();
}
const isParentActiveColorChanged = changeKeys.includes(
nameof<XExpandableListComponent>('parentActiveColor')
);
if (isParentActiveColorChanged) {
await this.applyParentActiveColor();
}
const isHighlightColorChanged = changeKeys.includes(
nameof<XExpandableListComponent>('highlightColor')
);
if (isHighlightColorChanged) {
await this.applyHighlightColor();
}
const isDividerColorChanged = changeKeys.includes(
nameof<XExpandableListComponent>('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<any>) {
//
if (!item || !item.childs) {
return of(false);
}
return this.getValue(item.childs).pipe(map((childs) => hasChild(childs)));
}
getIconName(item: XExpandableListItem<any>) {
return this.isExpanded(item).pipe(
map((isExpanded) =>
isExpanded
? XIconNames.arrow_dropup.toString()
: XIconNames.arrow_dropdown.toString()
)
);
}
isParentActivated(item: XExpandableListItem<any>) {
//
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<any>) {
//
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<any>) {
return !item || !item.hidden ? of(false) : this.getValue(item.hidden);
}
isDisabled(item: XExpandableListItem<any>) {
return !item || !item.disabled ? of(false) : this.getValue(item.disabled);
}
isExpanded(item: XExpandableListItem<any>) {
return !item || !item.opened ? of(false) : this.getValue(item.opened);
}
//#endregion
//
//#region UI Handlers ...
async handleItemSelectedAction(
item: XExpandableListItem<any>,
parent: XExpandableListItem<any>
) {
//
// 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<any>,
siblings: XExpandableListItem<any>[]
) {
//
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<any>) {
item.opened = true;
}
async expandAll() {
//
const items = await this.getArrayValueAsync(this.items);
await this.handleChangeState(items, true);
}
async collapse(item: XExpandableListItem<any>) {
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<XExpandableListActionModel>();
}
//
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<any>,
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<any>,
siblings: XOneOrManyType<XExpandableListItem<any>>
) {
//
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<XExpandableListItem<any>>,
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<any>[];
//
await this.applyStartupState(items);
await this.handleApplyCurrentItems();
}
private async setActivatedParent(v: XExpandableListItem<any>) {
//
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<any>) {
//
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<XExpandableListItem<any>>
) {
//
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<XOneOrManyType<XExpandableListItem<any>>>
) {
//
const result: XExpandableListItem<any>[] = [];
//
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<XOneOrManyType<XExpandableListItem<any>>>,
route: XStandardType<XOneOrManyType<string>>
) {
//
let result: XExpandableListItem<any> = 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<XOneOrManyType<XExpandableListItem<any>>>,
route: XStandardType<XOneOrManyType<string>>
) {
//
const result: XExpandableListItem<any>[] = [];
//
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<XOneOrManyType<XExpandableListItem<any>>>,
route: XStandardType<XOneOrManyType<string>>
) {
//
let result: XExpandableListItem<any>[] = [];
//
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<XOneOrManyType<XExpandableListItem<any>>>,
id: XStandardType<string>
) {
//
let result: XExpandableListItem<any> = 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<XOneOrManyType<XExpandableListItem<any>>>,
id: XStandardType<string>
) {
//
const result: XExpandableListItem<any>[] = [];
//
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<XOneOrManyType<XExpandableListItem<any>>>,
id: XStandardType<string>
) {
//
let result: XExpandableListItem<any>[] = [];
//
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<T> {
id: string;
data: XStandardType<T>;
opened?: XStandardType<boolean>;
hidden?: XStandardType<boolean>;
disabled?: XStandardType<boolean>;
replaceUrl?: XStandardType<boolean>;
title: XStandardType<XResourceIdentifier>;
href?: XStandardType<XOneOrManyType<string>>;
description?: XStandardType<XResourceIdentifier>;
childs?: XStandardType<XOneOrManyType<XExpandableListItem<T>>>;
}
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<XExpandableListActionIdentifier> {}
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<XExpandableListActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
itemCssClass: XStandardType<XOneOrManyType<string>>;
//
supportRouting: XStandardType<boolean>;
disableParentRouting: XStandardType<boolean>;
showParentDetailIcon: XStandardType<boolean>;
showChildDetailIcon: XStandardType<boolean>;
closeSiblings: XStandardType<boolean>;
startupState: XStandardType<XExpandableListStartupStateIdentifier>;
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>;
parentTemplate: TemplateRef<any>;
childTemplate: TemplateRef<any>;
//
childColor: XStandardType<XColorIdentifier>;
childActiveColor: XStandardType<XColorIdentifier>;
parentColor: XStandardType<XColorIdentifier>;
parentActiveColor: XStandardType<XColorIdentifier>;
highlightColor: XStandardType<XColorIdentifier>;
dividerColor: XStandardType<XColorIdentifier>;
//
itemSelected: EventEmitter<XExpandableListItem<any>>;
}
@Injectable({
providedIn: 'root',
})
export class XExpandableListContainer
extends XComponentCardContainer
implements Readonly<IXExpandableListContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XExpandableListActionModel>;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly itemCssClass: XStandardType<XOneOrManyType<string>>;
//
readonly supportRouting: XStandardType<boolean> = false;
readonly disableParentRouting: XStandardType<boolean> = true;
readonly showParentDetailIcon: XStandardType<boolean> = true;
readonly showChildDetailIcon: XStandardType<boolean> = true;
readonly closeSiblings: XStandardType<boolean> = false;
readonly startupState: XStandardType<XExpandableListStartupStateIdentifier> =
XExpandableListStartupState.CollapseAll;
readonly items: XStandardType<XOneOrManyType<XExpandableListItem<any>>>;
readonly parentTemplate: TemplateRef<any>;
readonly childTemplate: TemplateRef<any>;
//
readonly childColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.PrimaryShade;
readonly childActiveColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly parentColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.TertiaryTint;
readonly parentActiveColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly highlightColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Warning;
readonly dividerColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
//
readonly itemSelected: EventEmitter<XExpandableListItem<any>> =
new EventEmitter<XExpandableListItem<any>>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XExpandableListContainerComponent
extends XComponentCardContainerComponent
implements IXExpandableListContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XExpandableListActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
itemCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.itemCssClass;
//
@Input()
supportRouting: XStandardType<boolean> = this.propertyProvider.supportRouting;
@Input()
disableParentRouting: XStandardType<boolean> =
this.propertyProvider.disableParentRouting;
@Input()
showParentDetailIcon: XStandardType<boolean> =
this.propertyProvider.showParentDetailIcon;
@Input()
showChildDetailIcon: XStandardType<boolean> =
this.propertyProvider.showChildDetailIcon;
@Input()
closeSiblings: XStandardType<boolean> = this.propertyProvider.closeSiblings;
@Input()
startupState: XStandardType<XExpandableListStartupStateIdentifier> =
this.propertyProvider.startupState;
@Input()
items: XStandardType<XOneOrManyType<XExpandableListItem<any>>> =
this.propertyProvider.items;
@Input()
parentTemplate: TemplateRef<any> = this.propertyProvider.parentTemplate;
@Input()
childTemplate: TemplateRef<any> = this.propertyProvider.childTemplate;
//
@Input()
childColor: XStandardType<XColorIdentifier> =
this.propertyProvider.childColor;
@Input()
childActiveColor: XStandardType<XColorIdentifier> =
this.propertyProvider.childActiveColor;
@Input()
parentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.parentColor;
@Input()
parentActiveColor: XStandardType<XColorIdentifier> =
this.propertyProvider.parentActiveColor;
@Input()
highlightColor: XStandardType<XColorIdentifier> =
this.propertyProvider.highlightColor;
@Input()
dividerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.dividerColor;
//
@Output()
itemSelected: EventEmitter<XExpandableListItem<any>> = 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<IXExpandableListContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else wrapperRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="wrapperRef"></ng-container>
<!-- Actions -->
<div class="x-card-actions" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Components itSelf Template -->
<ng-template #wrapperRef>
<!-- Wrapper Element -->
<div
class="x-expandable-panel x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[class.applyColors]="getValue(applyColors) | async"
>
<ng-container
*ngTemplateOutlet="getIsAccordion() ? accordionRef : panelRef"
></ng-container>
</div>
</ng-template>
<!-- Accordion Template -->
<ng-template #accordionRef>
<mat-accordion
class="x-expandable-accordion"
[multi]="getValue(multiExpanded) | async"
>
<ng-container *ngTemplateOutlet="panelRef"> </ng-container>
</mat-accordion>
</ng-template>
<!-- Non Accordion Template -->
<ng-template #panelRef>
<!-- Check Panels Exists -->
<ng-container *ngIf="hasPanels()">
<ng-container *ngFor="let panel of panels">
<!-- Panel -->
<mat-expansion-panel
[disabled]="panel.uiDisabled"
(opened)="handlePanelOpened(panel)"
[expanded]="getExpanded(panel) | async"
[ngClass]="getValue(panel.cssClass) | async"
[hideToggle]="getValue(panel.hideToggle) | async"
>
<!-- Header -->
<mat-expansion-panel-header
class="x-expandable-panel-header"
[class.mobile]="isMobileUi$ | async"
>
<!-- Title -->
<mat-panel-title
*ngIf="panel.title"
class="x-expandable-panel-header-title"
>
<ng-container *ngTemplateOutlet="panel.title"></ng-container>
</mat-panel-title>
<!-- Description -->
<mat-panel-description
class="x-expandable-panel-header-description"
*ngIf="
panel.description &&
(!(getValue(hideDescriptionOnSmallScreens) | async) ||
((getValue(hideDescriptionOnSmallScreens) | async) &&
(isNotMobileUi$ | async)))
"
>
<ng-container *ngTemplateOutlet="panel.description"></ng-container>
</mat-panel-description>
</mat-expansion-panel-header>
<!-- Conent -->
<ng-template matExpansionPanelContent>
<div class="x-expandable-panel-content">
<ng-container *ngTemplateOutlet="panel.content"></ng-container>
</div>
</ng-template>
<!-- Actions -->
<mat-action-row
class="x-expandable-panel-actions"
*ngIf="
(hasActions(panel) | async) ||
(getValue(panel.hasCustomActions) | async)
"
>
<ng-container
*ngTemplateOutlet="panelActionsRef; context: { $implicit: panel }"
></ng-container>
</mat-action-row>
</mat-expansion-panel>
</ng-container>
</ng-container>
</ng-template>
<!-- Panel Actions Template -->
<ng-template #panelActionsRef let-panel>
<!-- Step Buttons -->
<div class="x-panel-actions">
<!-- Defined Actions -->
<x-slotter *ngIf="hasActions(panel) | async">
<!-- Next -->
<x-slot
[name]="getValue(panel.nextPosition) | async"
[cssClass]="getValue(panel.nextCssClass) | async"
>
<ng-container *ngIf="hasStepAction(panel, NPRButtonTypes.Next) | async">
<ng-container
*ngTemplateOutlet="
buttonRef;
context: {
panel: panel,
type: NPRButtonTypes.Next
}
"
></ng-container>
</ng-container>
</x-slot>
<!-- Reset -->
<x-slot
[name]="getValue(panel.resetPosition) | async"
[cssClass]="getValue(panel.resetCssClass) | async"
>
<ng-container
*ngIf="hasStepAction(panel, NPRButtonTypes.Reset) | async"
>
<ng-container
*ngTemplateOutlet="
buttonRef;
context: {
panel: panel,
type: NPRButtonTypes.Reset
}
"
></ng-container>
</ng-container>
</x-slot>
<!-- Prev -->
<x-slot
[name]="getValue(panel.prevPosition) | async"
[cssClass]="getValue(panel.prevCssClass) | async"
>
<ng-container *ngIf="hasStepAction(panel, NPRButtonTypes.Prev) | async">
<ng-container
*ngTemplateOutlet="
buttonRef;
context: {
panel: panel,
type: NPRButtonTypes.Prev
}
"
></ng-container>
</ng-container>
</x-slot>
</x-slotter>
<!-- Specified Actions -->
<div
class="x-panel-custom-actions-wrapper"
*ngIf="getValue(panel.hasCustomActions) | async"
>
<ng-container *ngTemplateOutlet="panel.actions"></ng-container>
</div>
</div>
</ng-template>
<!-- Button Template -->
<ng-template #buttonRef let-panel="panel" let-type="type">
<x-button
(clicked)="handleNPRStep(panel, type)"
[icon]="getButtonIcon(panel, type) | async"
[type]="getButtonType(panel, type) | async"
[title]="getButtonTitle(panel, type) | async"
[color]="getButtonColor(panel, type) | async"
[cssClass]="getButtonCssClass(panel, type) | async"
[uiDisabled]="getButtonDisabled(panel, type) | async"
[class.disabled]="getButtonDisabled(panel, type) | async"
[iconPosition]="getButtonIconPosition(panel, type) | async"
[foregroundColor]="getButtonForegroundColor(panel, type) | async"
></x-button>
</ng-template>
### 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<XPanelComponent>;
//
@ContentChildren(XPanelComponent)
set panels(p: QueryList<XPanelComponent>) {
//
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<XExpandablePanelComponent>('isAccordion')
);
if (isAccordionChanged) {
this.IS_ACCORDION = await this.getValueAsync(this.isAccordion);
}
//
const isHeaderColorChanged = changeKeys.includes(
nameof<XExpandablePanelComponent>('headerColor')
);
if (isHeaderColorChanged) {
await this.applyHeaderColor();
}
//
const isHeaderHighlighColorChanged = changeKeys.includes(
nameof<XExpandablePanelComponent>('headerHighlightColor')
);
if (isHeaderHighlighColorChanged) {
await this.applyHeaderHighlightColor();
}
//
const isActionProviderChanged = changeKeys.includes(
nameof<XExpandablePanelComponent>('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<string>, 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<boolean>((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<XExpandablePanelActionModel>();
}
//
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<XExpandablePanelActionIdentifier> {
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<XExpandablePanelActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
startupState: XStandardType<XExpandablePanelStartupStateIdentifier>;
isAccordion: XStandardType<boolean>;
multiExpanded: XStandardType<boolean>;
hideDescriptionOnSmallScreens: XStandardType<boolean>;
//
applyColors: XStandardType<boolean>;
headerColor: XStandardType<XColorIdentifier>;
headerHighlightColor: XStandardType<XColorIdentifier>;
//
resetConfirmer: () => XStandardType<boolean>;
selected: string;
//
selectedChange: EventEmitter<string>;
}
@Injectable({
providedIn: 'root',
})
export class XExpandablePandelContainer
extends XCardNextPrevResetHostContainer
implements Readonly<IXExpandablePandelContainer>
{
//
//#region Props ...
//
readonly actionProvider = new Subject<XExpandablePanelActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly startupState: XStandardType<XExpandablePanelStartupStateIdentifier> =
XExpandablePanelStartupState.ExpandAll;
readonly isAccordion: XStandardType<boolean>;
readonly multiExpanded: XStandardType<boolean>;
readonly hideDescriptionOnSmallScreens: XStandardType<boolean>;
//
readonly applyColors: XStandardType<boolean> = true;
readonly headerColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Primary;
readonly headerHighlightColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Warning;
//
readonly resetConfirmer: () => XStandardType<boolean> = () => {
return new Promise<boolean>((resolver) => {
//
this.managerService.dialogService.presentAreYouSureYesNoDialog(
() => resolver(true),
XModalButtonRole.Destructive,
() => resolver(false)
);
});
};
readonly selected: string;
//
readonly selectedChange: EventEmitter<string>;
//#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<XExpandablePanelActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
startupState: XStandardType<XExpandablePanelStartupStateIdentifier> =
this.propertyProvider.startupState;
@Input()
isAccordion: XStandardType<boolean> = this.propertyProvider.isAccordion;
@Input()
multiExpanded: XStandardType<boolean> = this.propertyProvider.multiExpanded;
@Input()
hideDescriptionOnSmallScreens: XStandardType<boolean> =
this.propertyProvider.hideDescriptionOnSmallScreens;
//
@Input()
applyColors: XStandardType<boolean> = this.propertyProvider.applyColors;
@Input()
headerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.headerColor;
@Input()
headerHighlightColor: XStandardType<XColorIdentifier> =
this.propertyProvider.headerHighlightColor;
//
@Input()
resetConfirmer: () => XStandardType<boolean> =
this.propertyProvider.resetConfirmer;
@Input()
selected: string = this.propertyProvider.selected;
//
@Output()
selectedChange: EventEmitter<string> = 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<IXExpandablePandelContainer> {
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
<!-- Title -->
<ng-template #title>
<ng-content select="[x-panel-title]"></ng-content>
</ng-template>
<!-- Description -->
<ng-template #description>
<ng-content select="[x-panel-description]"></ng-content>
</ng-template>
<!-- Content -->
<ng-template #content>
<ng-content></ng-content>
</ng-template>
<!-- Actions -->
<ng-template #actions>
<ng-content select="[x-panel-actions]"></ng-content>
</ng-template>
### 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<any>;
@ViewChild('description', { static: false })
description!: TemplateRef<any>;
@ViewChild('content', { static: false })
content!: TemplateRef<any>;
@ViewChild('actions', { static: false })
actions!: TemplateRef<any>;
//#endregion
//#endregion
//
//#region LifeCycle ...
onChange(changeKeys: string[]) {
super.onChange(changeKeys);
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XPanelComponent>('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<XPanelActionModel>();
}
//
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<XPanelActionIdentifier> {}
//
//#region Inside Card Container ...
export interface IXPanelContainer extends IXNextPrevResetContainer {
//
actionProvider: Subject<XPanelActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
id: XStandardType<string>;
//
hideToggle: XStandardType<boolean>;
expanded: XStandardType<boolean>;
hasCustomActions: XStandardType<boolean>;
}
@Injectable({
providedIn: 'root'
})
export class XPanelContainer
extends XNextPrevResetContainer
implements Readonly<IXPanelContainer>
{
//
//#region Props ...
readonly actionProvider = new Subject<XPanelActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly id: XStandardType<string> = generateUuid('XPanelComponent');
//
readonly hideToggle: XStandardType<boolean> = false;
readonly expanded: XStandardType<boolean>;
readonly hasCustomActions: XStandardType<boolean>;
//#endregion
}
@Injectable({
providedIn: 'root'
})
@Component({
template: `
<!--
<ng-container *ngIf="extractProps() | async as props">
<x-panel
[id]="props.id"
[hasNext]="props.hasNext"
[hasPrev]="props.hasPrev"
[cssClass]="props.cssClass"
[expanded]="props.expanded"
[hasReset]="props.hasReset"
[hideToggle]="props.hideToggle"
[nextButton]="props.nextButton"
[prevButton]="props.prevButton"
[disablePrev]="props.disablePrev"
[disableNext]="props.disableNext"
[resetButton]="props.resetButton"
[nextPosition]="props.nextPosition"
[nextCssClass]="props.nextCssClass"
[prevPosition]="props.prevPosition"
[prevCssClass]="props.prevCssClass"
[disableReset]="props.disableReset"
[prevConfirmer]="props.prevConfirmer"
[nextConfirmer]="props.nextConfirmer"
[resetPosition]="props.resetPosition"
[resetCssClass]="props.resetCssClass"
[actionProvider]="props.actionProvider"
[resetConfirmer]="props.resetConfirmer"
[hasCustomActions]="props.hasCustomActions"
>
</x-panel>
</ng-container>
-->
`,
})
export abstract class XPanelContainerComponent
extends XNextPrevResetContainerComponent
implements IXPanelContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XPanelActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
id: XStandardType<string> = this.propertyProvider.id;
@Input()
hideToggle: XStandardType<boolean> = this.propertyProvider.hideToggle;
@Input()
expanded: XStandardType<boolean> = this.propertyProvider.expanded;
@Input()
hasCustomActions: XStandardType<boolean> =
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<IXPanelContainer> {
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
<section
class="x-fab x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
*ngIf="parsedItem && (notNullOrUndefinedValue(item) | async)"
>
<!-- Fab Main Button -->
<ion-fab
#fab
[slot]="getFixedValue(parsedItem) | async"
[edge]="getOptionalValue(parsedItem.edged) | async"
[vertical]="getValue(parsedItem.vertical) | async"
[horizontal]="getValue(parsedItem.horizontal) | async"
[activated]="getOptionalValue(parsedItem.activated) | async"
>
<!-- Fab Main Button -->
<ng-container
*ngTemplateOutlet="fabButtonRef; context: { $implicit: parsedItem }"
></ng-container>
<!-- Fab List Buttons -->
<section
class="x-fab-childs-container"
[ngClass]="getValue(childsCssClass) | async"
>
<ng-container *ngTemplateOutlet="fabChildsRef"></ng-container>
</section>
</ion-fab>
</section>
<!-- Fab Childs -->
<ng-template #fabChildsRef>
<!-- Fab Lists -->
<ng-container *ngIf="hasChildValue(parsedChilds) | async">
<!-- Top Side -->
<ion-fab-list side="top" *ngIf="hasTopSideChilds">
<ng-container *ngFor="let child of parsedChilds">
<ng-container *ngIf="isTopSideFab(child) | async">
<ng-container
*ngTemplateOutlet="fabButtonRef; context: { $implicit: child }"
></ng-container>
</ng-container>
</ng-container>
</ion-fab-list>
<!-- End Side -->
<ion-fab-list side="end" *ngIf="hasEndSideChilds">
<ng-container *ngFor="let child of parsedChilds">
<ng-container *ngIf="isEndSideFab(child) | async">
<ng-container
*ngTemplateOutlet="fabButtonRef; context: { $implicit: child }"
></ng-container>
</ng-container>
</ng-container>
</ion-fab-list>
<!-- Start Side -->
<ion-fab-list side="start" *ngIf="hasStartSideChilds">
<ng-container *ngFor="let child of parsedChilds">
<ng-container *ngIf="isStartSideFab(child) | async">
<ng-container
*ngTemplateOutlet="fabButtonRef; context: { $implicit: child }"
></ng-container>
</ng-container>
</ng-container>
</ion-fab-list>
<!-- Bottom Side -->
<ion-fab-list side="bottom" *ngIf="hasBottomSideChilds">
<ng-container *ngFor="let child of parsedChilds">
<ng-container *ngIf="isBottomSideFab(child) | async">
<ng-container
*ngTemplateOutlet="fabButtonRef; context: { $implicit: child }"
></ng-container>
</ng-container>
</ng-container>
</ion-fab-list>
</ng-container>
</ng-template>
<!-- Represent Single Fab -->
<ng-template #fabButtonRef let-item>
<ion-fab-button
[color]="getValue(item.color) | async"
(click)="handleFabButtonClicked(item)"
[size]="getOptionalValue(item.size) | async"
[href]="getOptionalValue(item.href) | async"
[hidden]="getOptionalValue(item.hidden) | async"
[download]="getOptionalValue(item.download) | async"
[matTooltip]="getResourceValue(item.tooltip) | async"
[target]="getOptionalValue(item.routerTarget) | async"
[routerDirection]="getOptionalValue(item.routerDirection) | async"
[disabled]="
uiDisabled ||
loading ||
(applyTakeUntilWrapper(getOptionalValue(item.disabled)) | async)
"
>
<x-icon
[foregroundColor]="false"
[name]="getValue(item.icon) | async"
[color]="getValue(item.color) | async"
></x-icon>
</ion-fab-button>
</ng-template>
### 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<XFabComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Items Changes ...
//
const isItemsChanged = changeKeys.includes(nameof<XFabComponent>('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<boolean>;
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<XFabActionModel>();
}
//
// 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<XIconIdentifier>;
side: XStandardType<XFabButtonSideIdentifier>;
size?: XStandardType<XFabButtonSizeIdentifier>;
//
disabled?: XStandardType<boolean>;
hidden?: XStandardType<boolean>;
//
color: XStandardType<XColorIdentifier>;
//
tooltip?: XStandardType<XResourceIdentifier>;
//
href?: XStandardType<string>;
download?: XStandardType<string>;
routerDirection?: XStandardType<XRouterDirection>;
routerTarget?: XStandardType<XRouterTargetIdentifier>;
//
handler?: (id?: string) => XStandardType<void>;
}
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<XFabVerticalSlotIdentifier>;
horizontal: XStandardType<XFabHorizontalSlotIdentifier>;
//
fixed?: XStandardType<boolean>;
edged?: XStandardType<boolean>;
//
activated?: XStandardType<boolean>;
//
childs?: XStandardType<XFabButton[]>;
}
export enum XFabAction {
CLOSE = 'close',
//
Refresh = 'refresh',
}
export type XFabActionIdentifier = XFabAction | string;
export interface XFabActionModel
extends XBaseActionModel<XFabActionIdentifier> {}
//
//#region Container ...
export interface IXFabContainer extends IXBaseContainer {
//
actionProvider: Subject<XFabActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
childsCssClass: XStandardType<XOneOrManyType<string>>;
item: XStandardType<XFabItem>;
}
@Injectable({
providedIn: 'root'
})
export class XFabContainer
extends XBaseContainer
implements Readonly<IXFabContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XFabActionModel> =
new Subject<XFabActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly childsCssClass: XStandardType<XOneOrManyType<string>>;
readonly item: XStandardType<XFabItem> = null;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XFabContainerComponent
extends XBaseContainerComponent
implements IXFabContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XFabActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
childsCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.childsCssClass;
@Input()
item: XStandardType<XFabItem> = 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<IXFabContainer> {
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
<!-- Card Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component Template -->
<ng-template #componentRef>
<div
class="x-file-drop-area x-wrapper"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[isForeground]="getValue(foregroundColor) | async"
[class.no-drag]="
uiDisabled || loading || (getValue(dragDisabled) | async)
"
>
<section
xDroppable
class="x-droppable-container"
[errorColor]="getValue(errorColor) | async"
[accentColor]="getValue(accentColor) | async"
[successColor]="getValue(successColor) | async"
[error]="notNullOrUndefinedValue(error) | async"
(filesChangeEmiter)="filesChangeEmiter.emit($event)"
[disableFileCheck]="getValue(disableFileCheck) | async"
[allowedExtensions]="getValue(allowedExtensions) | async"
[dragDisabled]="
uiDisabled || loading || (getValue(dragDisabled) | async)
"
[supportsMultipleFiles]="getValue(supportsMultipleFiles) | async"
>
<ng-container
*ngTemplateOutlet="
contentTemplate ? contentTemplate : defaultContentTemplateRef
"
></ng-container>
</section>
</div>
</ng-template>
<!-- Default Content Template -->
<ng-template #defaultContentTemplateRef>
<div class="x-drop-area">
<div class="x-icon">
<x-icon
[foregroundColor]="false"
[cssClass]="'transparent'"
[name]="getValue(icon) | async"
[color]="getValue(color) | async"
></x-icon>
</div>
<ion-text class="x-drag-drop-title">
{{ getResourceValue(message) | async }}
</ion-text>
</div>
</ng-template>
### 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<XFileDropAreaComponent>('color')
);
if (isColorChanged) {
await this.applyColor();
}
//#endregion
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XFileDropAreaComponent>('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<XFileDropAreaActionModel>();
}
//
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<XFileDropAreaActionIdentifier> {}
export enum XFileDropAreaCssVars {
LabelColor = 'label-color',
}
//
//#region Container ...
export interface IXFileDropAreaContainer extends IXComponentCardContainer {
//
actionProvider: Subject<XFileDropAreaActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
icon: XStandardType<XIconIdentifier>;
message: XStandardType<XResourceIdentifier>;
//
disableFileCheck: XStandardType<boolean>;
//
supportsMultipleFiles: XStandardType<boolean>;
allowedExtensions: XStandardType<XOneOrManyType<string>>;
//
dragDisabled: XStandardType<boolean>;
contentTemplate: TemplateRef<any>;
filesChangeEmiter: EventEmitter<XOneOrManyType<File>>;
//
successColor: XStandardType<XColorIdentifier>;
errorColor: XStandardType<XColorIdentifier>;
accentColor: XStandardType<XColorIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XFileDropAreaContainer
extends XComponentCardContainer
implements Readonly<IXFileDropAreaContainer>
{
//
//#region Props ...
//
readonly actionProvider = new Subject<XFileDropAreaActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
readonly icon: XStandardType<XIconIdentifier> = XIconNames.arrow_down;
readonly message: XStandardType<XResourceIdentifier> =
XResourceIDs.drag_drop_here;
//
readonly disableFileCheck: XStandardType<boolean> = false;
//
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> = [];
readonly supportsMultipleFiles: XStandardType<boolean> = true;
//
readonly dragDisabled: XStandardType<boolean> = false;
readonly contentTemplate: TemplateRef<any>;
readonly filesChangeEmiter = new EventEmitter<XOneOrManyType<File>>();
//
readonly successColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Success;
readonly errorColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Danger;
readonly accentColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Secondary;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XFileDropAreaContainerComponent
extends XComponentCardContainerComponent
implements IXFileDropAreaContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XFileDropAreaActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Input()
icon: XStandardType<XIconIdentifier> = this.propertyProvider.icon;
@Input()
message: XStandardType<XResourceIdentifier> = this.propertyProvider.message;
//
@Input()
disableFileCheck: XStandardType<boolean> =
this.propertyProvider.disableFileCheck;
//
@Input()
supportsMultipleFiles: XStandardType<boolean> =
this.propertyProvider.supportsMultipleFiles;
@Input()
allowedExtensions: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.allowedExtensions;
//
@Input()
dragDisabled: XStandardType<boolean> = this.propertyProvider.dragDisabled;
@Input()
contentTemplate: TemplateRef<any> = this.propertyProvider.contentTemplate;
@Output()
filesChangeEmiter: EventEmitter<XOneOrManyType<File>> = new EventEmitter();
//
@Input()
successColor: XStandardType<XColorIdentifier> =
this.propertyProvider.successColor;
@Input()
errorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.errorColor;
@Input()
accentColor: XStandardType<XColorIdentifier> =
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<IXFileDropAreaContainer> {
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<boolean>;
}
@Injectable({
providedIn: 'root',
})
export class XComponentFileDropAreaContainer
extends XBaseComponentContainer
implements Readonly<IXComponentFileDropAreaContainer>
{
//
//#region Props ...
//
readonly showFileDropArea: XStandardType<boolean> = true;
//
readonly fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
this.propertyProvider.actionProvider;
readonly fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly fileDropAreaColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
readonly fileDropAreaForegroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
readonly fileDropAreaIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.icon;
readonly fileDropAreaMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.message;
//
readonly fileDropAreaDisableFileCheck: XStandardType<boolean> =
this.propertyProvider.disableFileCheck;
//
readonly fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
this.propertyProvider.supportsMultipleFiles;
readonly fileDropAreaAllowedExtensions: XStandardType<
XOneOrManyType<string>
> = this.propertyProvider.allowedExtensions;
//
readonly fileDropAreaDragDisabled: XStandardType<boolean> =
this.propertyProvider.dragDisabled;
readonly fileDropAreaContentTemplate: TemplateRef<any> =
this.propertyProvider.contentTemplate;
readonly fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
this.propertyProvider.filesChangeEmiter;
//
readonly fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
this.propertyProvider.successColor;
readonly fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.errorColor;
readonly fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.accentColor;
//
//#region ComponentsCard ...
readonly fileDropAreaIsInPage: XStandardType<boolean> = false;
readonly fileDropAreaWrapWithCard: XStandardType<boolean> = false;
readonly fileDropAreaCardShowFooter: XStandardType<boolean> = false;
readonly fileDropAreaCardShowActions: XStandardType<boolean> = false;
readonly fileDropAreaCardColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly fileDropAreaCardForegroundColor: XStandardType<boolean> = false;
readonly fileDropAreaCardTitle: XStandardType<XResourceIdentifier>;
readonly fileDropAreaCardActionProvider: Subject<XCardActionModel> =
new Subject<XCardActionModel>();
readonly fileDropAreaCardSubTitle: XStandardType<XResourceIdentifier>;
readonly fileDropAreaCardCssClass: XStandardType<XOneOrManyType<string>>;
//#endregion
//#endregion
//
//#region Constructor ...
constructor(protected propertyProvider: XFileDropAreaContainer) {
super();
}
//#endregion
}
@Injectable({
providedIn: 'root',
})
@Component({
template: `
<!--
<ng-container *ngIf="extractProps() | async as props">
<ng-container *ngIf="props.showFileDropArea">
<x-file-drop-area
[icon]="props.fileDropAreaIcon"
[color]="props.fileDropAreaColor"
[message]="props.fileDropAreaMessage"
[cssClass]="props.fileDropAreaCssClass"
[isInPage]="props.fileDropAreaIsInPage"
[cardTitle]="props.fileDropAreaCardTitle"
[cardColor]="props.fileDropAreaCardColor"
[errorColor]="props.fileDropAreaErrorColor"
[accentColor]="props.fileDropAreaAccentColor"
[dragDisabled]="props.fileDropAreaDragDisabled"
[successColor]="props.fileDropAreaSuccessColor"
[cardCssClass]="props.fileDropAreaCardCssClass"
[wrapWithCard]="props.fileDropAreaWrapWithCard"
[cardSubTitle]="props.fileDropAreaCardSubTitle"
[actionProvider]="props.fileDropAreaActionProvider"
[cardShowFooter]="props.fileDropAreaCardShowFooter"
[foregroundColor]="props.fileDropAreaForegroundColor"
[contentTemplate]="props.fileDropAreaContentTemplate"
[foregroundColor]="props.fileDropAreaForegroundColor"
[disableFileCheck]="props.fileDropAreaDisableFileCheck"
[allowedExtensions]="props.fileDropAreaAllowedExtensions"
(filesChangeEmiter)="(props.fileDropAreaFilesChangeEmiter)"
[cardActionProvider]="props.fileDropAreaCardActionProvider"
[cardForegroundColor]="props.fileDropAreaCardForegroundColor"
[supportsMultipleFiles]="props.fileDropAreaSupportsMultipleFiles"
></x-file-drop-area>
</ng-container>
</ng-container>
-->
`,
})
export abstract class XComponentFileDropAreaContainerComponent
extends XBaseComponentContainerComponent
implements IXComponentFileDropAreaContainer
{
//
//#region Props ...
//
@Input()
fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
this.propertyProvider.fileDropAreaActionProvider;
@Input()
fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.fileDropAreaCssClass;
//
@Input()
fileDropAreaColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaColor;
@Input()
fileDropAreaForegroundColor: XStandardType<boolean> =
this.propertyProvider.fileDropAreaForegroundColor;
//
@Input()
fileDropAreaIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.fileDropAreaIcon;
@Input()
fileDropAreaMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.fileDropAreaMessage;
//
@Input()
fileDropAreaDisableFileCheck: XStandardType<boolean> =
this.propertyProvider.fileDropAreaDisableFileCheck;
//
@Input()
fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
this.propertyProvider.fileDropAreaSupportsMultipleFiles;
@Input()
fileDropAreaAllowedExtensions: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.fileDropAreaAllowedExtensions;
//
@Input()
fileDropAreaDragDisabled: XStandardType<boolean> =
this.propertyProvider.fileDropAreaDragDisabled;
@Input()
fileDropAreaContentTemplate: TemplateRef<any> =
this.propertyProvider.fileDropAreaContentTemplate;
@Output()
fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
new EventEmitter();
//
@Input()
fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaSuccessColor;
@Input()
fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaErrorColor;
@Input()
fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaAccentColor;
//
@Input()
showFileDropArea: XStandardType<boolean> =
this.propertyProvider.showFileDropArea;
//
//#region ComponentsCard ...
@Input()
fileDropAreaIsInPage: XStandardType<boolean> =
this.propertyProvider.fileDropAreaIsInPage;
@Input()
fileDropAreaWrapWithCard: XStandardType<boolean> =
this.propertyProvider.fileDropAreaWrapWithCard;
@Input()
fileDropAreaCardShowFooter: XStandardType<boolean> =
this.propertyProvider.fileDropAreaCardShowFooter;
@Input()
fileDropAreaCardShowActions: XStandardType<boolean> =
this.propertyProvider.fileDropAreaCardShowActions;
@Input()
fileDropAreaCardColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaCardColor;
@Input()
fileDropAreaCardForegroundColor: XStandardType<boolean> =
this.propertyProvider.fileDropAreaCardForegroundColor;
@Input()
fileDropAreaCardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.fileDropAreaCardTitle;
@Input()
fileDropAreaCardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.fileDropAreaCardActionProvider;
@Input()
fileDropAreaCardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.fileDropAreaCardSubTitle;
@Input()
fileDropAreaCardCssClass: XStandardType<XOneOrManyType<string>> =
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<IXComponentFileDropAreaContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component Template -->
<ng-template #componentRef>
<div
class="x-file-upload x-wrapper"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- File Upload Input -->
<input
hidden
#fileInput
type="file"
multiple="true"
(change)="handleFilesSelected()"
/>
<!-- File Drop -->
<ng-container *ngIf="getValue(showFileDropArea) | async">
<ng-container *ngTemplateOutlet="fileDragAreaRef"></ng-container>
</ng-container>
<!-- File List -->
<ng-container *ngIf="getValue(showList) | async">
<ng-container *ngTemplateOutlet="filesListRef"></ng-container>
</ng-container>
</div>
</ng-template>
<!-- File Drop Area Template -->
<ng-template #fileDragAreaRef>
<div class="x-file-upload-file-drag-drop-wrapper">
<x-file-drop-area
[cardTitle]=""
[cardSubTitle]=""
[isInPage]="false"
[loading]="loading"
[wrapWithCard]="false"
[cardShowFooter]="false"
[uiDisabled]="uiDisabled"
[cardForegroundColor]="false"
[supportsMultipleFiles]="true"
[icon]="getValue(fileDropAreaIcon) | async"
[color]="getValue(fileDropAreaColor) | async"
[actionProvider]="fileDropAreaActionProvider"
(filesChangeEmiter)="handleFileDropped($event)"
[cssClass]="getValue(fileDropAreaCssClass) | async"
[cardColor]="getValue(cardColor) | async"
[errorColor]="getValue(fileDropAreaErrorColor) | async"
[accentColor]="getValue(fileDropAreaAccentColor) | async"
[message]="getResourceValue(fileDropAreaMessage) | async"
[successColor]="getValue(fileDropAreaSuccessColor) | async"
[dragDisabled]="getValue(fileDropAreaDragDisabled) | async"
[allowedExtensions]="getArrayValue(allowedExtensions) | async"
[foregroundColor]="getValue(fileDropAreaForegroundColor) | async"
[contentTemplate]="getValue(fileDropAreaContentTemplate) | async"
[disableFileCheck]="getValue(fileDropAreaDisableFileCheck) | async"
></x-file-drop-area>
</div>
</ng-template>
<!-- Files List Template -->
<ng-template #filesListRef>
<x-list
#listPresenter
[loading]="loading"
[selectableItems]="true"
[foregroundColor]="false"
[uiDisabled]="uiDisabled"
[itemTemplate]="fileItemRef"
[color]="getValue(color) | async"
[actionProvider]="listActionProvider"
[showEmpty]="getValue(showEmpty) | async"
[filteringHandler]="listFilteringHandler"
(orderChanged)="handleListOrderChanged()"
(removeItems)="handleRemoveItems($event)"
(emptyRefresh)="emptyRefresh.emit($event)"
[emptyColor]="getValue(emptyColor) | async"
[cssClass]="getValue(listCssClass) | async"
[emptyForegroundMessageColor]="
getValue(emptyForegroundMessageColor) | async
"
[showSearchBar]="
(getValue(showSearchBar) | async) &&
(countChildsValue(fileListItems) | async) > 1
"
[emptyMessage]="getValue(emptyMessage) | async"
[showToolbar]="getValue(listShowToolbar) | async"
[showDivider]="getValue(listShowDivider) | async"
[showActionBar]="getValue(showActionBar) | async"
[searchBarColor]="getValue(searchBarColor) | async"
[actionBarColor]="getValue(actionBarColor) | async"
[confirmRemove]="getValue(listConfirmRemove) | async"
[items]="fileListItemsSubject.asObservable() | async"
[emptyForegroundRefreshButtonColor]="
getValue(emptyForegroundRefreshButtonColor) | async
"
[stickyToolbar]="getValue(listStickyToolbar) | async"
[emptyHasRefresh]="getValue(emptyHasRefresh) | async"
[actionBarActions]="getValue(actionBarActions) | async"
[emptyRefreshIcon]="getValue(emptyRefreshIcon) | async"
(selectionChanged)="handleFilesSelectionChanged($event)"
[actionBarCssClass]="getValue(actionBarCssClass) | async"
[searchBarCssClass]="getValue(searchBarCssClass) | async"
[emptyMessageColor]="getValue(emptyMessageColor) | async"
(actionBarActionFired)="actionBarActionFired.emit($event)"
[enableReordering]="getValue(listEnableReordering) | async"
[emptyForegroundColor]="getValue(emptyForegroundColor) | async"
[actionBarHideActions]="getArrayValue(actionBarHideActions) | async"
[emptyRefreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
[searchBarSearchInputColor]="getValue(searchBarSearchInputColor) | async"
>
</x-list>
</ng-template>
<!-- File Item Template -->
<ng-template #fileItemRef let-item="item" let-index="index">
<div fxLayout="row" class="x-file-item" [matTooltip]="item.data.name">
<x-thumbnail
fxFlex="nogrow"
[loading]="loading"
class="x-file-thumbnail"
[uiDisabled]="uiDisabled"
[type]="getThumbnailType(item.data) | async"
[identifier]="getThumbnailIdentifier(item.data) | async"
></x-thumbnail>
<div class="x-file-title text-truncate">
{{ item.data.name }}
</div>
</div>
</ng-template>
### 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<boolean>(false);
private uploadDisablerSubject = new BehaviorSubject<boolean>(true);
private removeDisablerSubject = new BehaviorSubject<boolean>(true);
private selectAllDisablerSubject = new BehaviorSubject<boolean>(true);
private deSelectAllDisablerSubject = new BehaviorSubject<boolean>(true);
private inverseSelectionDisablerSubject = new BehaviorSubject<boolean>(true);
//
@ViewChild('fileInput', { static: false })
private fileInputRef!: ElementRef;
//
private inputFiles: File[] = [];
fileListItems: XListItem<File>[] = [];
fileListItemsSubject: BehaviorSubject<XListItem<File>[]> =
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<XFileUploadComponent>('color')
);
if (isColorChanged) {
await this.applyColor();
}
//
//#region ActionBar Actions ...
const isActionBarActionsChanged = changeKeys.includes(
nameof<XFileUploadComponent>('actionBarActions')
);
const isActionBarHideActionsChanged = changeKeys.includes(
nameof<XFileUploadComponent>('actionBarHideActions')
);
if (isActionBarActionsChanged || isActionBarHideActionsChanged) {
await this.prepareActionBarActions();
}
//#endregion
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XFileUploadComponent>('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<File>) {
//
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<File>[]) {
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<File>(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<File>) {
//
// 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<XActionBarItem> = [];
//
// 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<File>[]) {
//
// 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<XFileUploadActionModel>();
}
//
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<any> = {
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<any>) {
this.fileListItems.push(item);
}
private changeDataSourceItem(item: XListItem<any>) {
//
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<File>) {
//
if (!items) {
return;
}
//
const extractedItems: File[] = !items
? []
: isArray(items)
? (items as File[])
: [items as File];
const removeRequest: XBaseRangeRequestDto<File> = {
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<XFileUploadActionIdentifier> {}
export const defaultFileUploadListFilteringHandler: XListFilteringHandler = (
query: string,
items: XListItem<File>[]
) => {
//
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<IXComponentFileDropAreaContainer> &
Partial<IXComponentListContainer> &
IXComponentActionBarContainer &
IXComponentSearchBarContainer &
IXComponentEmptyContainer &
IXFileContainer;
export interface IXFileUploadContainer
extends IXBaseContainer,
TXFileUploadContainer {
//
actionProvider: Subject<XFileUploadActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
fileChange: EventEmitter<XOneOrManyType<File | XFileBlob | any>>;
//
actionBarHideActions: XStandardType<
XOneOrManyType<XActionBarActionIdentifier>
>;
}
@Injectable({
providedIn: 'root',
})
export class XFileUploadContainer
extends XBaseContainer
implements Readonly<IXFileUploadContainer>
{
//
//#region Props ...
//
//#region Self ...
//
readonly actionProvider: Subject<XFileUploadActionModel> =
new Subject<XFileUploadActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly fileChange: EventEmitter<XOneOrManyType<File | XFileBlob | any>> = new EventEmitter<
XOneOrManyType<File | XFileBlob>
>();
readonly actionBarHideActions: XStandardType<
XOneOrManyType<XActionBarActionIdentifier>
>;
//#endregion
//
//#region File Drop Props ...
//
readonly showFileDropArea: XStandardType<boolean> =
this.fileDropAreaPropertyProvider.showFileDropArea;
//
readonly fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
this.fileDropAreaPropertyProvider.fileDropAreaActionProvider;
readonly fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
this.fileDropAreaPropertyProvider.fileDropAreaCssClass;
//
readonly fileDropAreaColor: XStandardType<XColorIdentifier> =
this.fileDropAreaPropertyProvider.fileDropAreaColor;
readonly fileDropAreaForegroundColor: XStandardType<boolean> =
this.fileDropAreaPropertyProvider.fileDropAreaForegroundColor;
//
readonly fileDropAreaIcon: XStandardType<XIconIdentifier> =
this.fileDropAreaPropertyProvider.fileDropAreaIcon;
readonly fileDropAreaMessage: XStandardType<XResourceIdentifier> =
this.fileDropAreaPropertyProvider.fileDropAreaMessage;
//
readonly fileDropAreaDisableFileCheck: XStandardType<boolean> =
this.fileDropAreaPropertyProvider.fileDropAreaDisableFileCheck;
//
readonly fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
this.fileDropAreaPropertyProvider.fileDropAreaSupportsMultipleFiles;
readonly fileDropAreaAllowedExtensions: XStandardType<
XOneOrManyType<string>
> = this.fileDropAreaPropertyProvider.fileDropAreaAllowedExtensions;
//
readonly fileDropAreaDragDisabled: XStandardType<boolean> =
this.fileDropAreaPropertyProvider.fileDropAreaDragDisabled;
readonly fileDropAreaContentTemplate: TemplateRef<any> =
this.fileDropAreaPropertyProvider.fileDropAreaContentTemplate;
readonly fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
this.fileDropAreaPropertyProvider.fileDropAreaFilesChangeEmiter;
//
readonly fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
this.fileDropAreaPropertyProvider.fileDropAreaSuccessColor;
readonly fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
this.fileDropAreaPropertyProvider.fileDropAreaErrorColor;
readonly fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
this.fileDropAreaPropertyProvider.fileDropAreaAccentColor;
//#endregion
//
//#region Card Props ...
readonly isInPage: XStandardType<boolean> =
this.cardPropertyProvider.isInPage;
readonly wrapWithCard: XStandardType<boolean> =
this.cardPropertyProvider.wrapWithCard;
readonly cardActionProvider: Subject<XCardActionModel> =
this.cardPropertyProvider.cardActionProvider;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
this.cardPropertyProvider.cardCssClass;
readonly cardColor: XStandardType<XColorIdentifier> =
this.cardPropertyProvider.cardColor;
readonly cardForegroundColor: XStandardType<boolean> =
this.cardPropertyProvider.cardForegroundColor;
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardTitle;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardSubTitle;
readonly cardShowFooter: XStandardType<boolean> =
this.cardPropertyProvider.cardShowFooter;
readonly cardShowActions: XStandardType<boolean> =
this.cardPropertyProvider.cardShowActions;
//#endregion
//
//#region List Props ...
readonly showList: XStandardType<boolean> =
this.listPropertyProvider.showList;
readonly listConfirmRemove: XStandardType<boolean> =
this.listPropertyProvider.listConfirmRemove;
readonly listActionProvider = this.listPropertyProvider.listActionProvider;
readonly listCssClass: XStandardType<XOneOrManyType<string>> =
this.listPropertyProvider.listCssClass;
readonly listShowToolbar: XStandardType<boolean> = true;
readonly listStickyToolbar: XStandardType<boolean> =
this.listPropertyProvider.listStickyToolbar;
readonly listEnableReordering: XStandardType<boolean> =
this.listPropertyProvider.listEnableReordering;
readonly listShowDivider: XStandardType<boolean> =
this.listPropertyProvider.listShowDivider;
readonly listFilteringHandler: XListFilteringHandler =
this.listPropertyProvider.listFilteringHandler;
//#endregion
//
//#region ActionBar ...
//
readonly showActionBar: XStandardType<boolean> = true;
//
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
this.actionBarPropertyProvider.actionBarActionProvider;
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.actionBarPropertyProvider.actionBarCssClass;
//
readonly actionBarColor: XStandardType<XColorIdentifier> =
this.actionBarPropertyProvider.actionBarColor;
readonly actionBarForegroundColor: XStandardType<boolean> =
this.actionBarPropertyProvider.actionBarForegroundColor;
//
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.actionBarPropertyProvider.actionBarActions;
//
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
this.actionBarPropertyProvider.actionBarActionFired;
//#endregion
//
//#region SearchBar ...
//
readonly showSearchBar: XStandardType<boolean> =
this.searchBarPropertyProvider.showSearchBar;
//
readonly searchBarActionProvider: Subject<XSearchBarActionModel> =
this.searchBarPropertyProvider.searchBarActionProvider;
readonly searchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.searchBarPropertyProvider.searchBarCssClass;
//
readonly searchBarColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarColor;
readonly searchBarForegroundColor: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarForegroundColor;
//
readonly searchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarSearchInputColor;
readonly searchBarForegroundSearchInputColor: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarForegroundSearchInputColor;
//
readonly searchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.searchBarPropertyProvider.searchBarType;
readonly searchBarTitle: XStandardType<XResourceIdentifier> =
this.searchBarPropertyProvider.searchBarTitle;
readonly searchBarValue: XStandardType<string> =
this.searchBarPropertyProvider.searchBarValue;
readonly searchBarEnterKeyHint: XStandardType<string> =
this.searchBarPropertyProvider.searchBarEnterKeyHint;
readonly searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.searchBarPropertyProvider.searchBarKeyboardType;
readonly searchBarSpellcheck: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarSpellcheck;
readonly searchBarDebounce: XStandardType<number> =
this.searchBarPropertyProvider.searchBarDebounce;
//
readonly searchBarShowCancelButton: XStandardType<string> =
this.searchBarPropertyProvider.searchBarShowCancelButton;
readonly searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonIcon;
readonly searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonTitle;
readonly searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonIconColor;
//
readonly searchBarShowClearButton: XStandardType<string> =
this.searchBarPropertyProvider.searchBarShowClearButton;
readonly searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarClearButtonIcon;
readonly searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarClearButtonIconColor;
//
readonly searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarSearchButtonIcon;
readonly searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarSearchButtonIconColor;
//
readonly searchBarQueryChange: EventEmitter<string> =
this.searchBarPropertyProvider.searchBarQueryChange;
readonly searchBarOnEvent: EventEmitter<string> =
this.searchBarPropertyProvider.searchBarOnEvent;
//#endregion
//
//#region Empty Props ...
readonly showEmpty: XStandardType<boolean> =
this.emptyPropertyProvider.showEmpty;
readonly emptyActionProvider: Subject<XEmptyActionModel> =
this.emptyPropertyProvider.emptyActionProvider;
readonly emptyCssClass: XStandardType<XOneOrManyType<string>> =
this.emptyPropertyProvider.emptyCssClass;
readonly emptyColor: XStandardType<XColorIdentifier> =
this.emptyPropertyProvider.emptyColor;
readonly emptyForegroundColor: XStandardType<boolean> =
this.emptyPropertyProvider.emptyForegroundColor;
readonly emptyMessage: XStandardType<XResourceIdentifier> =
this.emptyPropertyProvider.emptyMessage;
readonly emptyMessageColor: XStandardType<XColorIdentifier> =
this.emptyPropertyProvider.emptyMessageColor;
readonly emptyForegroundMessageColor: XStandardType<boolean> =
this.emptyPropertyProvider.emptyForegroundMessageColor;
readonly emptyHasRefresh: XStandardType<boolean> =
this.emptyPropertyProvider.emptyHasRefresh;
readonly emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
this.emptyPropertyProvider.emptyRefreshButtonColor;
readonly emptyForegroundRefreshButtonColor: XStandardType<boolean> =
this.emptyPropertyProvider.emptyForegroundRefreshButtonColor;
readonly emptyRefreshIcon: XStandardType<XIconIdentifier> =
this.emptyPropertyProvider.emptyRefreshIcon;
readonly emptyRefresh: EventEmitter<void> =
this.emptyPropertyProvider.emptyRefresh;
//#endregion
//
//#region File Props ...
readonly emptyFileException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.emptyFileException;
readonly notAllowedFileException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.notAllowedFileException;
readonly allowedExtensions: XStandardType<XOneOrManyType<string>> =
this.filePropertyProvider.allowedExtensions;
readonly maxAllowedFiles: XStandardType<number> =
this.filePropertyProvider.maxAllowedFiles;
readonly maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.maxAllowedFilesException;
readonly maxAllowedSize: XStandardType<number> =
this.filePropertyProvider.maxAllowedSize;
readonly maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.maxAllowedSizeException;
readonly minAllowedFileSize: XStandardType<number> =
this.filePropertyProvider.minAllowedFileSize;
readonly minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.filePropertyProvider.minAllowedFileSizeException;
readonly maxAllowedFileSize: XStandardType<number> =
this.filePropertyProvider.maxAllowedFileSize;
readonly maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
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<XFileUploadActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Output()
fileChange: EventEmitter<XOneOrManyType<File | XFileBlob | any>> = new EventEmitter();
@Input()
actionBarHideActions: XStandardType<
XOneOrManyType<XActionBarActionIdentifier>
> = this.propertyProvider.actionBarHideActions;
//#endregion
//
//#region File Drop Props ...
//
@Input()
showFileDropArea: XStandardType<boolean> =
this.propertyProvider.showFileDropArea;
//
@Input()
fileDropAreaActionProvider: Subject<XFileDropAreaActionModel> =
this.propertyProvider.fileDropAreaActionProvider;
@Input()
fileDropAreaCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.fileDropAreaCssClass;
//
@Input()
fileDropAreaColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaColor;
@Input()
fileDropAreaForegroundColor: XStandardType<boolean> =
this.propertyProvider.fileDropAreaForegroundColor;
//
@Input()
fileDropAreaIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.fileDropAreaIcon;
@Input()
fileDropAreaMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.fileDropAreaMessage;
//
@Input()
fileDropAreaDisableFileCheck: XStandardType<boolean> =
this.propertyProvider.fileDropAreaDisableFileCheck;
//
@Input()
fileDropAreaSupportsMultipleFiles: XStandardType<boolean> =
this.propertyProvider.fileDropAreaSupportsMultipleFiles;
@Input()
fileDropAreaAllowedExtensions: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.fileDropAreaAllowedExtensions;
//
@Input()
fileDropAreaDragDisabled: XStandardType<boolean> =
this.propertyProvider.fileDropAreaDragDisabled;
@Input()
fileDropAreaContentTemplate: TemplateRef<any> =
this.propertyProvider.fileDropAreaContentTemplate;
@Output()
fileDropAreaFilesChangeEmiter: EventEmitter<XOneOrManyType<File>> =
new EventEmitter();
//
@Input()
fileDropAreaSuccessColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaSuccessColor;
@Input()
fileDropAreaErrorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaErrorColor;
@Input()
fileDropAreaAccentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.fileDropAreaAccentColor;
//#endregion
//
//#region Card Props ...
@Input()
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
//#endregion
//
//#region List Props ...
@Input()
showList: XStandardType<boolean> = this.propertyProvider.showList;
@Input()
listConfirmRemove: XStandardType<boolean> =
this.propertyProvider.listConfirmRemove;
@Input()
listActionProvider = this.propertyProvider.listActionProvider;
@Input()
listCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.listCssClass;
@Input()
listShowToolbar: XStandardType<boolean> =
this.propertyProvider.listShowToolbar;
@Input()
listStickyToolbar: XStandardType<boolean> =
this.propertyProvider.listStickyToolbar;
@Input()
listEnableReordering: XStandardType<boolean> =
this.propertyProvider.listEnableReordering;
@Input()
listShowDivider: XStandardType<boolean> =
this.propertyProvider.listShowDivider;
@Input()
listFilteringHandler: XListFilteringHandler =
this.propertyProvider.listFilteringHandler;
//#endregion
//
//#region ActionBar ...
//
@Input()
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
//
@Input()
actionBarActionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.actionBarActionProvider;
@Input()
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.actionBarCssClass;
//
@Input()
actionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.actionBarColor;
@Input()
actionBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.actionBarForegroundColor;
//
@Input()
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.propertyProvider.actionBarActions;
//
@Output()
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
//#endregion
//
//#region SearchBar ...
//
@Input()
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
//
@Input()
searchBarActionProvider: Subject<XSearchBarActionModel> =
this.propertyProvider.searchBarActionProvider;
@Input()
searchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.searchBarCssClass;
//
@Input()
searchBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarColor;
@Input()
searchBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundColor;
//
@Input()
searchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchInputColor;
@Input()
searchBarForegroundSearchInputColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundSearchInputColor;
//
@Input()
searchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarType;
@Input()
searchBarTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarTitle;
@Input()
searchBarValue: XStandardType<string> = this.propertyProvider.searchBarValue;
@Input()
searchBarEnterKeyHint: XStandardType<string> =
this.propertyProvider.searchBarEnterKeyHint;
@Input()
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarKeyboardType;
@Input()
searchBarSpellcheck: XStandardType<boolean> =
this.propertyProvider.searchBarSpellcheck;
@Input()
searchBarDebounce: XStandardType<number> =
this.propertyProvider.searchBarDebounce;
//
@Input()
searchBarShowCancelButton: XStandardType<string> =
this.propertyProvider.searchBarShowCancelButton;
@Input()
searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarCancelButtonIcon;
@Input()
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarCancelButtonTitle;
@Input()
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarCancelButtonIconColor;
//
@Input()
searchBarShowClearButton: XStandardType<string> =
this.propertyProvider.searchBarShowClearButton;
@Input()
searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarClearButtonIcon;
@Input()
searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarClearButtonIconColor;
//
@Input()
searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarSearchButtonIcon;
@Input()
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchButtonIconColor;
//
@Output()
searchBarQueryChange: EventEmitter<string> = new EventEmitter();
@Output()
searchBarOnEvent: EventEmitter<string> = new EventEmitter();
//#endregion
//
//#region Empty Props ...
@Input()
showEmpty: XStandardType<boolean> = this.propertyProvider.showEmpty;
@Input()
emptyActionProvider: Subject<XEmptyActionModel> =
this.propertyProvider.emptyActionProvider;
@Input()
emptyCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.emptyCssClass;
@Input()
emptyColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyColor;
@Input()
emptyForegroundColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundColor;
@Input()
emptyMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.emptyMessage;
@Input()
emptyMessageColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyMessageColor;
@Input()
emptyForegroundMessageColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundMessageColor;
@Input()
emptyHasRefresh: XStandardType<boolean> =
this.propertyProvider.emptyHasRefresh;
@Input()
emptyRefreshButtonColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyRefreshButtonColor;
@Input()
emptyForegroundRefreshButtonColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundRefreshButtonColor;
@Input()
emptyRefreshIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.emptyRefreshIcon;
@Output()
emptyRefresh: EventEmitter<void> = new EventEmitter();
//#endregion
//
//#region File Props ...
@Input()
emptyFileException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.emptyFileException;
@Input()
notAllowedFileException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.notAllowedFileException;
@Input()
allowedExtensions: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.allowedExtensions;
@Input()
maxAllowedFiles: XStandardType<number> =
this.propertyProvider.maxAllowedFiles;
@Input()
maxAllowedFilesException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedFilesException;
@Input()
maxAllowedSize: XStandardType<number> = this.propertyProvider.maxAllowedSize;
@Input()
maxAllowedSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.maxAllowedSizeException;
@Input()
minAllowedFileSize: XStandardType<number> =
this.propertyProvider.minAllowedFileSize;
@Input()
minAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
this.propertyProvider.minAllowedFileSizeException;
@Input()
maxAllowedFileSize: XStandardType<number> =
this.propertyProvider.maxAllowedFileSize;
@Input()
maxAllowedFileSizeException: XStandardType<XExceptionIdentifier> =
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<IXFileUploadContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else formRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="formRef"></ng-container>
<!-- Actions -->
<div [ngClass]="getFormCardActionsCssClass() | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div
footer
*ngIf="getValue(cardShowFooter) | async"
[ngClass]="getFormCardFooterCssClass() | async"
>
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Form itSelf Template -->
<ng-template #formRef>
<!-- Form Wrapper -->
<div
*ngIf="form"
class="x-form x-wrapper"
[class.mobile]="isMobileUi$ | async"
>
<!-- Form Element -->
<form
*ngIf="form"
[formGroup]="form"
[ngClass]="getFormCssClass() | async"
style="width: 100%"
>
<ng-container *ngIf="hasChildValue(getFormControls()) | async">
<!-- Presenting Props -->
<ng-container
*ngFor="
let control of getFormControls() | async;
index as controlIndex
"
>
<!-- Check Control Exists -->
<ng-container *ngIf="control">
<ng-container
*ngIf="getControlType(control) | async as controlType"
>
<!-- 1- Input Type (Text/Number/Password/Email/Url/Color/Tel) Type -->
<ng-container
*ngIf="
controlType === ControlTypes.Text ||
controlType === ControlTypes.Number ||
controlType === ControlTypes.Password ||
controlType === ControlTypes.Color ||
controlType === ControlTypes.Email ||
controlType === ControlTypes.Url ||
controlType === ControlTypes.Tel
"
>
<!-- Auto Complete Wrapper -->
<div
class="x-auto-complete-wrapper"
(xOnOutsideClicked)="
handleAutoCompleteOutsideClicked(control)
"
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- Form Control Wrapper -->
<div>
<!-- Not None Appearance -->
<ng-container
*ngIf="
(getControlAppearanceObject(control) | async) !==
FormControlAppearances.None
"
>
<!-- Mat Form Field -->
<mat-form-field
class="x-mat-form-field"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
[appearance]="getControlAppearance(control) | async"
>
<!-- label -->
<mat-label
class="x-field-label"
*ngIf="
notEmptyValue(getControlLabel(control)) | async
"
>{{ getControlLabel(control) | async }}</mat-label
>
<!-- Has Formatter Input Control -->
<ng-container
*ngIf="controlHasFormatter(control) | async"
>
<input
matInput
autocomplete="off"
xFromInputFormatter
[inputFormatterType]="
getFormatterType(control) | async
"
[formControlName]="control.propName.toString()"
[enabledInputFormatter]="
controlHasFormatter(control) | async
"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
[placeholder]="
getControlPlaceHolder(control) | async
"
[stringInputFormatterType]="
getFormatterInputType(control) | async
"
[currencyLable]="
getFormatterCurrencyLabel(control) | async
"
(blur)="handleControlBlured(control.propName.toString())"
[locale]="getFormatterLocale(control) | async"
[stringFormatter]="
getFormatterStringFormatter(control) | async
"
(xOnEscape)="handleAutoCompleteEscaped(control)"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[readonly]="isInputControlReadOnly(control) | async"
[seperator]="getFormatterSeperator(control) | async"
/>
</ng-container>
<!-- Has not Formatter Input Control -->
<ng-container
*ngIf="!(controlHasFormatter(control) | async)"
>
<input
matInput
autocomplete="off"
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
[placeholder]="
getControlPlaceHolder(control) | async
"
(blur)="handleControlBlured(control.propName.toString())"
(xOnEscape)="handleAutoCompleteEscaped(control)"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[readonly]="isInputControlReadOnly(control) | async"
/>
</ng-container>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
<!-- Prefix Icon -->
<span
matPrefix
*ngIf="controlHasPrefixIcon(control) | async"
>
<ng-container
*ngTemplateOutlet="
prefixIconRef;
context: { $implicit: control }
"
></ng-container>
</span>
<!-- Suffix Icon -->
<span
matSuffix
*ngIf="controlHasSuffixIcon(control) | async"
>
<ng-container
*ngTemplateOutlet="
suffixIconRef;
context: { $implicit: control }
"
></ng-container>
</span>
</mat-form-field>
</ng-container>
<!-- None Appearance -->
<ng-container
*ngIf="
(getControlAppearanceObject(control) | async) ===
FormControlAppearances.None
"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
>
<!-- Label -->
<ng-container
*ngTemplateOutlet="
byIconLabelRef;
context: { $implicit: control }
"
></ng-container>
<!-- Has Formatter Input Control -->
<ng-container
*ngIf="controlHasFormatter(control) | async"
>
<input
autocomplete="off"
xFromInputFormatter
[inputFormatterType]="
getFormatterType(control) | async
"
[formControlName]="control.propName.toString()"
[enabledInputFormatter]="
controlHasFormatter(control) | async
"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
[stringInputFormatterType]="
getFormatterInputType(control) | async
"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisabled(control) | async) ||
(isInputControlReadOnly(control) | async)
"
[currencyLable]="
getFormatterCurrencyLabel(control) | async
"
(blur)="handleControlBlured(control.propName.toString())"
[locale]="getFormatterLocale(control) | async"
[stringFormatter]="
getFormatterStringFormatter(control) | async
"
(focus)="handleControlFocused(control.propName.toString())"
[ngClass]="
getControlInputElementClasses(control) | async
"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[seperator]="getFormatterSeperator(control) | async"
/>
</ng-container>
<!-- Has not Formatter Input Control -->
<ng-container
*ngIf="!(controlHasFormatter(control) | async)"
>
<input
autocomplete="off"
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisabled(control) | async) ||
(isInputControlReadOnly(control) | async)
"
(blur)="handleControlBlured(control.propName.toString())"
(focus)="handleControlFocused(control.propName.toString())"
[ngClass]="
getControlInputElementClasses(control) | async
"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
/>
</ng-container>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="
hintRef;
context: { $implicit: control }
"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
<!-- Auto Complete -->
<div
[id]="getAutoCompleteId(control)"
[ngClass]="getAutoCompleteCssClass(control) | async"
[class.open]="getAutoCompleteOpened(control) | async"
*ngIf="
(controlHasAutoComplete(control) | async) &&
(hasChildValue(getAutoCompleteItems(control)) | async)
"
>
<ng-container
*ngIf="
getControlAutoCompleteConfig(control)
| async as autoComplete
"
>
<ng-container
*ngIf="getAutoCompleteItems(control) as items"
>
<x-list
[items]="items"
[showEmpty]="false"
[showToolbar]="false"
[wrapWithCard]="false"
[clickableItems]="true"
[uiDisabled]="uiDisabled"
[color]="getAutoCompleteColor(control) | async"
(itemSelected)="
handleAutoCompleteResultSelected(
control,
autoComplete,
$event
)
"
[itemTemplate]="
getAutoCompleteItemTemplate(control) | async
"
></x-list>
</ng-container>
</ng-container>
</div>
</div>
</div>
</ng-container>
<!-- 2- Select -->
<ng-container
*ngIf="
(hasSelectConfig(control) | async) &&
controlType === ControlTypes.Select
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[matTooltip]="getControlTooltip(control) | async"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- Not None Appearance -->
<ng-container
*ngIf="
(getControlAppearanceObject(control) | async) !==
FormControlAppearances.None
"
>
<!-- Mat Form Field -->
<mat-form-field
class="x-mat-form-field"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
[appearance]="getControlAppearance(control) | async"
>
<!-- label -->
<mat-label
class="x-field-label"
*ngIf="notEmptyValue(getControlLabel(control)) | async"
>{{ getControlLabel(control) | async }}</mat-label
>
<!-- Select -->
<mat-select
[formControlName]="control.propName.toString()"
[multiple]="getSelectMultiple(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[class.multiple]="getSelectMultiple(control) | async"
[panelClass]="getSelectPanelClasses(control) | async"
[placeholder]="getControlPlaceHolder(control) | async"
>
<mat-option
[value]="getValue(option.value) | async"
[ngClass]="getOptionClassName(option) | async"
*ngFor="
let option of getSelectOptions(control) | async
"
>
{{ getResourceValue(option.viewValue) | async }}
</mat-option>
</mat-select>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
<!-- Prefix Icon -->
<span
matPrefix
*ngIf="controlHasPrefixIcon(control) | async"
>
<ng-container
*ngTemplateOutlet="
prefixIconRef;
context: { $implicit: control }
"
></ng-container>
</span>
<!-- Suffix Icon -->
<span
matSuffix
*ngIf="controlHasSuffixIcon(control) | async"
>
<ng-container
*ngTemplateOutlet="
suffixIconRef;
context: { $implicit: control }
"
></ng-container>
</span>
</mat-form-field>
</ng-container>
<!-- None Appearance -->
<ng-container
*ngIf="
(getControlAppearanceObject(control) | async) ===
FormControlAppearances.None
"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
>
<!-- Label -->
<ng-container
*ngTemplateOutlet="
byIconLabelRef;
context: { $implicit: control }
"
></ng-container>
<!-- Select -->
<mat-select
[formControlName]="control.propName.toString()"
[multiple]="getSelectMultiple(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[class.multiple]="getSelectMultiple(control) | async"
[panelClass]="getSelectPanelClasses(control) | async"
[placeholder]="getControlPlaceHolder(control) | async"
>
<mat-option
[value]="getValue(option.value) | async"
[ngClass]="getOptionClassName(option) | async"
*ngFor="
let option of getSelectOptions(control) | async
"
>
{{ getResourceValue(option.viewValue) | async }}
</mat-option>
</mat-select>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- 3- Radio Type -->
<ng-container
*ngIf="
(hasRadioConfig(control) | async) &&
controlType === ControlTypes.Radio
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
[matTooltip]="getControlTooltip(control) | async"
>
<!-- Label -->
<ng-container
*ngTemplateOutlet="
byIconLabelRef;
context: { $implicit: control }
"
></ng-container>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
<!-- Content -->
<mat-radio-group
[formControlName]="control.propName.toString()"
*ngIf="notNullOrUndefinedValue(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[labelPosition]="getRadioLabelPosition(control) | async"
>
<mat-radio-button
#radioButton
class="x-radio-button"
[class.active]="radioButton.checked"
[value]="getValue(option.value) | async"
[ngClass]="getOptionClassName(option) | async"
*ngFor="let option of getRadioOptions(control) | async"
>
{{ getResourceValue(option.viewValue) | async }}
</mat-radio-button>
</mat-radio-group>
</div>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- 4- Checkbox Type -->
<ng-container *ngIf="controlType === ControlTypes.CheckBox">
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
[matTooltip]="getControlTooltip(control) | async"
>
<!-- Content -->
<x-slotter
[layout]="SlotLayouts.HORIZONTAL"
[hasStartOrTopSlot]="
(controlHasIcons(control) | async) &&
(controlHasPrefixIcon(control) | async)
"
[hasEndOrBottomSlot]="
(controlHasIcons(control) | async) &&
(controlHasSuffixIcon(control) | async)
"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Prefix Icon -->
<ng-container
*ngTemplateOutlet="
prefixIconRef;
context: { $implicit: control }
"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<mat-checkbox
[formControlName]="control.propName.toString()"
[labelPosition]="
getCheckboxLabelPosition(control) | async
"
*ngIf="notNullOrUndefinedValue(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[class.has-icon]="controlHasIcons(control) | async"
(change)="
handleCheckboxCheckedChange(control, $event.checked)
"
>
<!-- label -->
<ng-container
*ngTemplateOutlet="
defaultFieldLabelRef;
context: { $implicit: control }
"
></ng-container>
</mat-checkbox>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Suffix Icon -->
<ng-container
*ngTemplateOutlet="
suffixIconRef;
context: { $implicit: control }
"
></ng-container>
</x-slot>
</x-slotter>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
</div>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- 5- Toggle Type -->
<ng-container *ngIf="controlType === ControlTypes.Toggle">
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
[matTooltip]="getControlTooltip(control) | async"
>
<!-- Content -->
<x-slotter
[layout]="SlotLayouts.HORIZONTAL"
[hasStartOrTopSlot]="
(controlHasIcons(control) | async) &&
(controlHasPrefixIcon(control) | async)
"
[hasEndOrBottomSlot]="
(controlHasIcons(control) | async) &&
(controlHasSuffixIcon(control) | async)
"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Prefix Icon -->
<ng-container
*ngTemplateOutlet="
prefixIconRef;
context: { $implicit: control }
"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<!-- Content -->
<mat-slide-toggle
[formControlName]="control.propName.toString()"
[labelPosition]="
getToggleLabelPosition(control) | async
"
*ngIf="notNullOrUndefinedValue(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[class.has-icon]="controlHasIcons(control) | async"
>
<!-- label -->
<mat-label
class="x-field-label"
*ngIf="
notEmptyValue(getControlLabel(control)) | async
"
>
{{ getControlLabel(control) | async }}
</mat-label>
</mat-slide-toggle>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Suffix Icon -->
<ng-container
*ngTemplateOutlet="
suffixIconRef;
context: { $implicit: control }
"
></ng-container>
</x-slot>
</x-slotter>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
</div>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- 6- Slider Type -->
<ng-container
*ngIf="
(hasSliderConfig(control) | async) &&
controlType === ControlTypes.Slider
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
[matTooltip]="getControlTooltip(control) | async"
>
<!-- Label -->
<ng-container
*ngTemplateOutlet="
byIconLabelRef;
context: { $implicit: control }
"
></ng-container>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
<!-- Content -->
<!-- [disabled]="getControlDisabled(control) | async" -->
<mat-slider
[formControlName]="control.propName.toString()"
[min]="getSliderMin(control) | async"
[max]="getSliderMax(control) | async"
[step]="getSliderStep(control) | async"
[invert]="getSliderInvert(control) | async"
[vertical]="isSliderVertical(control) | async"
*ngIf="notNullOrUndefinedValue(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[displayWith]="getSliderFormatter(control) | async"
[thumbLabel]="showSliderThumbLabel(control) | async"
[class.vertical]="isSliderVertical(control) | async"
>
</mat-slider>
</div>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- 7- Date Type -->
<ng-container
*ngIf="
(hasDateConfig(control) | async) &&
controlType === ControlTypes.Date
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- Not None Appearance -->
<ng-container
*ngIf="
(getControlAppearanceObject(control) | async) !==
FormControlAppearances.None
"
>
<!-- Form Field -->
<mat-form-field
class="x-mat-form-field"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
[appearance]="getControlAppearance(control) | async"
>
<!-- label -->
<mat-label
class="x-field-label"
*ngIf="notEmptyValue(getControlLabel(control)) | async"
>{{ getControlLabel(control) | async }}</mat-label
>
<!-- Date Input -->
<input
matInput
autocomplete="off"
[matDatepicker]="dp"
[formControlName]="control.propName.toString()"
[readonly]="
(getControlDisabled(control) | async) ||
(isDatePickerInputDisabled(control) | async)
"
(blur)="handleControlBlured(control.propName.toString())"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[matDatepickerFilter]="getDateFilter(control) | async"
[placeholder]="getControlPlaceHolder(control) | async"
(dateInput)="
handleDatePickerDateInput(control.propName.toString(), $event)
"
(dateChange)="
handleDatePickerDateChange(control.propName.toString(), $event)
"
/>
<!-- Date Toggler Icon -->
<!-- Prefix -->
<mat-datepicker-toggle
[for]="dp"
matPrefix
[disabled]="
(getControlDisabled(control) | async) ||
(isDatePickerToggleDisabled(control) | async)
"
*ngIf="isDatePickerHasPrefixIcon(control) | async"
>
<x-icon
[selectable]="true"
matDatepickerToggleIcon
class="x-date-picker-icon"
[name]="getDatePickerIcon(control) | async"
[color]="getDatePickerIconColor(control) | async"
[matTooltip]="
getDatePickerIconTooltip(control) | async
"
[class.x-status-handler]="
getDatePickerIconApplyStateColor(control) | async
"
>
</x-icon>
</mat-datepicker-toggle>
<!-- Suffix -->
<mat-datepicker-toggle
[for]="dp"
matSuffix
[disabled]="
(getControlDisabled(control) | async) ||
(isDatePickerToggleDisabled(control) | async)
"
*ngIf="isDatePickerHasSuffixIcon(control) | async"
>
<x-icon
[selectable]="true"
[color]="'cb-inherit'"
matDatepickerToggleIcon
class="x-date-picker-icon"
[name]="getDatePickerIcon(control) | async"
[color]="getDatePickerIconColor(control) | async"
[matTooltip]="
getDatePickerIconTooltip(control) | async
"
[class.x-status-handler]="
getDatePickerIconApplyStateColor(control) | async
"
>
</x-icon>
</mat-datepicker-toggle>
<!-- Date Picker Component -->
<mat-datepicker
#dp
[touchUi]="isMobileUi$ | async"
[startAt]="getDateStartAt(control) | async"
[disabled]="getControlDisabled(control) | async"
[ngClass]="getDatePickerClasses(control) | async"
[panelClass]="getDatePickerClasses(control) | async"
></mat-datepicker>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
</mat-form-field>
</ng-container>
<!-- None Appearance -->
<ng-container
*ngIf="
(getControlAppearanceObject(control) | async) ===
FormControlAppearances.None
"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
>
<!-- Label -->
<ng-container
*ngTemplateOutlet="
byIconLabelRef;
context: { $implicit: control }
"
></ng-container>
<!-- Content -->
<x-slotter
[layout]="SlotLayouts.HORIZONTAL"
[centerSlotCssClass]="'full-heigh'"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
[hasStartOrTopSlot]="
isDatePickerHasPrefixIcon(control) | async
"
[hasEndOrBottomSlot]="
isDatePickerHasSuffixIcon(control) | async
"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Date Toggler Icon -->
<!-- Prefix -->
<mat-datepicker-toggle
[for]="dp"
matPrefix
[disabled]="
(getControlDisabled(control) | async) ||
(isDatePickerToggleDisabled(control) | async)
"
*ngIf="isDatePickerHasPrefixIcon(control) | async"
>
<x-icon
[selectable]="true"
matDatepickerToggleIcon
class="x-date-picker-icon"
[name]="getDatePickerIcon(control) | async"
[color]="getDatePickerIconColor(control) | async"
[matTooltip]="
getDatePickerIconTooltip(control) | async
"
[class.x-status-handler]="
getDatePickerIconApplyStateColor(control)
| async
"
>
</x-icon>
</mat-datepicker-toggle>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<!-- Date Input -->
<input
matInput
autocomplete="off"
[matDatepicker]="dp"
(dateInput)="
handleDatePickerDateInput(
control.propName.toString(),
$event
)
"
(dateChange)="
handleDatePickerDateChange(
control.propName.toString(),
$event
)
"
[matDatepickerFilter]="
getDateFilter(control) | async
"
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisabled(control) | async) ||
(isDatePickerInputDisabled(control) | async)
"
(blur)="handleControlBlured(control.propName.toString())"
(focus)="handleControlFocused(control.propName.toString())"
[ngClass]="
getControlInputElementClasses(control) | async
"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
/>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Date Toggler Icon -->
<!-- Suffix -->
<mat-datepicker-toggle
[for]="dp"
matSuffix
[disabled]="
(getControlDisabled(control) | async) ||
(isDatePickerToggleDisabled(control) | async)
"
*ngIf="isDatePickerHasSuffixIcon(control) | async"
>
<x-icon
[selectable]="true"
[color]="'cb-inherit'"
matDatepickerToggleIcon
class="x-date-picker-icon"
[name]="getDatePickerIcon(control) | async"
[color]="getDatePickerIconColor(control) | async"
[matTooltip]="
getDatePickerIconTooltip(control) | async
"
[class.x-status-handler]="
getDatePickerIconApplyStateColor(control)
| async
"
>
</x-icon>
</mat-datepicker-toggle>
</x-slot>
</x-slotter>
<!-- Date Picker Component -->
<mat-datepicker
#dp
[touchUi]="isMobileUi$ | async"
[startAt]="getDateStartAt(control) | async"
[disabled]="getControlDisabled(control) | async"
[ngClass]="getDatePickerClasses(control) | async"
[panelClass]="getDatePickerClasses(control) | async"
></mat-datepicker>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- 8- Hidden Type -->
<ng-container *ngIf="controlType === ControlTypes.Hidden">
<input
type="hidden"
autocomplete="off"
[formControlName]="control.propName.toString()"
/>
</ng-container>
<!-- 9- Markdown Type -->
<ng-container
*ngIf="
(hasMarkdownConfig(control) | async) &&
controlType === ControlTypes.MarkDown
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<ng-container
*ngTemplateOutlet="
markdownRef;
context: {
$implicit: control,
controlIndex: controlIndex
}
"
></ng-container>
</div>
</ng-container>
<!-- 10- Avatar Upload -->
<ng-container
*ngIf="
(hasAvatarConfig(control) | async) &&
controlType === ControlTypes.AvatarUpload
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<ng-container
*ngTemplateOutlet="
avatarRef;
context: {
$implicit: control,
controlIndex: controlIndex
}
"
></ng-container>
</div>
</ng-container>
<!-- 11- Map Type -->
<ng-container
*ngIf="
(hasMapConfig(control) | async) &&
controlType === ControlTypes.Map
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
>
<!-- Label -->
<ng-container
*ngTemplateOutlet="
defaultFieldLabelRef;
context: { $implicit: control }
"
></ng-container>
<!-- Control Input Element -->
<x-slotter
[hasStartOrTopSlot]="true"
[hasEndOrBottomSlot]="true"
[layout]="SlotLayouts.HORIZONTAL"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
*ngIf="notNullOrUndefinedValue(control) | async"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Prefix Icon -->
<ng-container
*ngTemplateOutlet="
prefixIconRef;
context: { $implicit: control }
"
></ng-container>
<!-- Action Prefix Icons -->
<ng-container
*ngTemplateOutlet="
actionIconsRef;
context: {
$implicit: control,
position: ControlIconPositions.Prefix
}
"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<!-- Has Formatter Input Control -->
<ng-container
*ngIf="controlHasFormatter(control) | async"
>
<input
class="x-input"
autocomplete="off"
xFromInputFormatter
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
(blur)="handleControlBlured(control.propName.toString())"
[locale]="getFormatterLocale(control) | async"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[seperator]="getFormatterSeperator(control) | async"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisableInput(control) | async) ||
(getControlDisabled(control) | async)
"
[inputFormatterType]="
getFormatterType(control) | async
"
[ngClass]="
getControlInputElementClasses(control) | async
"
[currencyLable]="
getFormatterCurrencyLabel(control) | async
"
[enabledInputFormatter]="
controlHasFormatter(control) | async
"
[stringFormatter]="
getFormatterStringFormatter(control) | async
"
[stringInputFormatterType]="
getFormatterInputType(control) | async
"
/>
</ng-container>
<!-- Has not Formatter Input Control -->
<ng-container
*ngIf="!(controlHasFormatter(control) | async)"
>
<input
class="x-input"
autocomplete="off"
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
(blur)="handleControlBlured(control.propName.toString())"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisableInput(control) | async) ||
(getControlDisabled(control) | async)
"
[ngClass]="
getControlInputElementClasses(control) | async
"
/>
</ng-container>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Suffix Icon -->
<ng-container
*ngTemplateOutlet="
suffixIconRef;
context: { $implicit: control }
"
></ng-container>
<!-- Action Suffix Icons -->
<ng-container
*ngTemplateOutlet="
actionIconsRef;
context: {
$implicit: control,
position: ControlIconPositions.Suffix
}
"
></ng-container>
</x-slot>
</x-slotter>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
<!-- Content -->
<ng-container
*ngIf="!(isMapPresentWithDialog(control) | async)"
>
<ng-container
*ngTemplateOutlet="
mapContentRef;
context: { $implicit: control }
"
>
</ng-container>
</ng-container>
</div>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- 12- ColorPicker Type -->
<ng-container
*ngIf="
(hasColorPickerConfig(control) | async) &&
controlType === ControlTypes.ColorPicker
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
>
<!-- Label -->
<ng-container
*ngTemplateOutlet="
defaultFieldLabelRef;
context: { $implicit: control }
"
></ng-container>
<!-- Control Input Element -->
<x-slotter
[hasStartOrTopSlot]="true"
[hasEndOrBottomSlot]="true"
[layout]="SlotLayouts.HORIZONTAL"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
*ngIf="notNullOrUndefinedValue(control) | async"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Prefix Icon -->
<ng-container
*ngTemplateOutlet="
prefixIconRef;
context: { $implicit: control }
"
></ng-container>
<!-- Action Prefix Icons -->
<ng-container
*ngTemplateOutlet="
actionIconsRef;
context: {
$implicit: control,
position: ControlIconPositions.Prefix
}
"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<div fxLayout="row" fxLayoutAlign="none">
<!-- Input Box -->
<div fxFlex>
<!-- Has Formatter Input Control -->
<ng-container
*ngIf="controlHasFormatter(control) | async"
>
<input
class="x-input"
autocomplete="off"
xFromInputFormatter
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
(blur)="handleControlBlured(control.propName.toString())"
[locale]="getFormatterLocale(control) | async"
(focus)="handleControlFocused(control.propName.toString())"
[xFocus]="
getControlFocusHandler(control) | async
"
[matTooltip]="
getControlTooltip(control) | async
"
[seperator]="
getFormatterSeperator(control) | async
"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisableInput(control) | async) ||
(getControlDisabled(control) | async)
"
[inputFormatterType]="
getFormatterType(control) | async
"
[ngClass]="
getControlInputElementClasses(control) | async
"
[currencyLable]="
getFormatterCurrencyLabel(control) | async
"
[enabledInputFormatter]="
controlHasFormatter(control) | async
"
[stringFormatter]="
getFormatterStringFormatter(control) | async
"
[readonly]="
(getControlDisabled(control) | async) ||
(getControlDisableInput(control) | async) ||
(isInputControlReadOnly(control) | async)
"
[stringInputFormatterType]="
getFormatterInputType(control) | async
"
/>
</ng-container>
<!-- Has not Formatter Input Control -->
<ng-container
*ngIf="!(controlHasFormatter(control) | async)"
>
<input
class="x-input"
autocomplete="off"
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
(blur)="handleControlBlured(control.propName.toString())"
(focus)="handleControlFocused(control.propName.toString())"
[xFocus]="
getControlFocusHandler(control) | async
"
[matTooltip]="
getControlTooltip(control) | async
"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisableInput(control) | async) ||
(getControlDisabled(control) | async) ||
(isInputControlReadOnly(control) | async)
"
[ngClass]="
getControlInputElementClasses(control) | async
"
/>
</ng-container>
</div>
<!-- Color Preview -->
<div
*ngIf="
isColorPickerPresentWithDialog(control) | async
"
>
<x-color
[size]="22"
[showLabel]="false"
[value]="{
key: 'color',
value: getControl(control.propName.toString()).value
}"
[borderWidth]="
getColorPickerColorViewBorderWidth(control)
| async
"
[borderStyle]="
getColorPickerColorViewBorderStyle(control)
| async
"
[borderColor]="
getColorPickerColorViewBorderColor(control)
| async
"
></x-color>
</div>
</div>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Suffix Icon -->
<ng-container
*ngTemplateOutlet="
suffixIconRef;
context: { $implicit: control }
"
></ng-container>
<!-- Action Suffix Icons -->
<ng-container
*ngTemplateOutlet="
actionIconsRef;
context: {
$implicit: control,
position: ControlIconPositions.Suffix
}
"
></ng-container>
</x-slot>
</x-slotter>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
<!-- Content -->
<ng-container
*ngIf="!(isColorPickerPresentWithDialog(control) | async)"
>
<ng-container
*ngTemplateOutlet="
colorPickerContentRef;
context: { $implicit: control }
"
>
</ng-container>
</ng-container>
</div>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
<!-- 13- Selector Type -->
<ng-container
*ngIf="
(hasSelectorConfig(control) | async) &&
controlType === ControlTypes.Selector
"
>
<!-- Form Control Wrapper -->
<div
[hidden]="getControlHidden(control) | async"
[class.show]="!(getControlHidden(control) | async)"
[ngClass]="getFormControlWrapperClasses(control) | async"
[class.readonly]="isInputControlReadOnly(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[enableHandler]="
!uiDisabled &&
!loading &&
!(getControlDisabled(control) | async)
"
[class.apply-status]="
getValue(applyStatusOnControls) | async
"
[ngClass]="getFormFieldClasses(control) | async"
>
<!-- Label -->
<ng-container
*ngTemplateOutlet="
defaultFieldLabelRef;
context: { $implicit: control }
"
></ng-container>
<!-- Control Input Element -->
<x-slotter
[hasStartOrTopSlot]="true"
[hasEndOrBottomSlot]="true"
[layout]="SlotLayouts.HORIZONTAL"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
*ngIf="notNullOrUndefinedValue(control) | async"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Prefix Icon -->
<ng-container
*ngTemplateOutlet="
prefixIconRef;
context: { $implicit: control }
"
></ng-container>
<!-- Action Prefix Icons -->
<ng-container
*ngTemplateOutlet="
actionIconsRef;
context: {
$implicit: control,
position: ControlIconPositions.Prefix
}
"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<!-- Has Formatter Input Control -->
<ng-container
*ngIf="controlHasFormatter(control) | async"
>
<input
class="x-input"
autocomplete="off"
xFromInputFormatter
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
(blur)="handleControlBlured(control.propName.toString())"
[locale]="getFormatterLocale(control) | async"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[seperator]="getFormatterSeperator(control) | async"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisabled(control) | async) ||
(getControlDisableInput(control) | async) ||
(isInputControlReadOnly(control) | async)
"
[inputFormatterType]="
getFormatterType(control) | async
"
[ngClass]="
getControlInputElementClasses(control) | async
"
[currencyLable]="
getFormatterCurrencyLabel(control) | async
"
[enabledInputFormatter]="
controlHasFormatter(control) | async
"
[stringFormatter]="
getFormatterStringFormatter(control) | async
"
[stringInputFormatterType]="
getFormatterInputType(control) | async
"
/>
</ng-container>
<!-- Has not Formatter Input Control -->
<ng-container
*ngIf="!(controlHasFormatter(control) | async)"
>
<input
class="x-input"
autocomplete="off"
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
(blur)="handleControlBlured(control.propName.toString())"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[placeholder]="
getControlPlaceHolder(control) | async
"
[readonly]="
(getControlDisabled(control) | async) ||
(getControlDisableInput(control) | async) ||
(isInputControlReadOnly(control) | async)
"
[ngClass]="
getControlInputElementClasses(control) | async
"
/>
</ng-container>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Suffix Icon -->
<ng-container
*ngTemplateOutlet="
suffixIconRef;
context: { $implicit: control }
"
></ng-container>
<!-- Action Suffix Icons -->
<ng-container
*ngTemplateOutlet="
actionIconsRef;
context: {
$implicit: control,
position: ControlIconPositions.Suffix
}
"
></ng-container>
</x-slot>
</x-slotter>
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="
loadingRef;
context: { $implicit: control }
"
></ng-container>
</div>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="
errorsRef;
context: { $implicit: control }
"
></ng-container>
</div>
</ng-container>
</ng-container>
</ng-container>
</ng-container>
</ng-container>
</form>
<!-- Custom Content -->
<ng-content select="[contents]"></ng-content>
<!-- Form Error Handlers -->
<div
[ngClass]="getFormErrorsClasses() | async"
*ngIf="errors && (formHasErrorHandlers() | async)"
>
<!-- Errors -->
<ng-container *ngIf="getFormErrorHandlers() | async as errorHandlers">
<mat-error
*ngFor="let handler of errorHandlers"
[class.show]="formHasError(handler) | async"
[ngClass]="getFormErrorClasses(handler) | async"
>
<span class="x-error-message">
{{ getErrorHandlerErrorMessage(handler) | async }}
</span>
</mat-error>
</ng-container>
</div>
</div>
</ng-template>
<!-- 9- MarkDown Template -->
<ng-template #markdownRef let-control let-controlIndex="controlIndex">
<ng-container
*ngTemplateOutlet="
xFormFieldRef;
context: {
$implicit: control,
controlIndex: controlIndex,
fieldLabelRef: byIconLabelRef,
fieldContentRef: markdownContentRef
}
"
>
</ng-container>
</ng-template>
<!-- 10 -Avatar Template -->
<ng-template #avatarRef let-control let-controlIndex="controlIndex">
<ng-container
*ngTemplateOutlet="
xFormFieldRef;
context: {
$implicit: control,
controlIndex: controlIndex,
fieldLabelRef: defaultFieldLabelRef,
fieldContentRef: avatarContentRef
}
"
>
</ng-container>
</ng-template>
<!-- //#region Templates -->
<!-- MarkDown Content Template -->
<ng-template #markdownContentRef let-control>
<!-- Markdown Component -->
<x-markdown
[mode]="getMarkdownMode(control) | async"
[isInPage]="isMarkdownInPage(control) | async"
[content]="getMarkDownContent(control) | async"
*ngIf="notNullOrUndefinedValue(control) | async"
[cssClass]="getMarkdownCssClass(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[cardTitle]="getMarkdownCardTitle(control) | async"
[cardColor]="getMarkdownCardColor(control) | async"
[toolbarForegroundColor]="
getMarkDownToolbarForegroundColor(control) | async
"
[hasToolbar]="getMarkDownHasToolbar(control) | async"
[wrapWithCard]="isMarkdownWrapWithCard(control) | async"
[cardSubTitle]="getMarkdownCardSubTitle(control) | async"
[toolbarColor]="getMarkDownToolbarColor(control) | async"
[toolbarConfig]="getMarkdownToolbarConfig(control) | async"
[actionProvider]="getMarkdownActionProvider(control) | async"
[editorBoxColor]="getMarkdownEditorBoxColor(control) | async"
[previewBoxColor]="getMarkdownPreviewBoxColor(control) | async"
[toolbarCssClass]="getMarkdownToolbarCssClass(control) | async"
[uiDisabled]="uiDisabled || (getControlDisabled(control) | async)"
[cardForegroundColor]="getMarkdownCardForegroundColor(control) | async"
(contentChange)="handleMarkDownContentChanged(control.propName.toString(), $event)"
></x-markdown>
</ng-template>
<!-- Avatar Content Template -->
<ng-template #avatarContentRef let-control>
<!-- Avatar Upload -->
<x-avatar-upload
[color]="getAvatarColor(control) | async"
[isInPage]="isAvatarInPage(control) | async"
[actions]="getAvatarActions(control) | async"
[cssClass]="getAvatarCssClass(control) | async"
[cardColor]="getAvatarCardColor(control) | async"
[cardTitle]="getAvatarCardTitle(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[fileDropAreaForegroundColor]="
isAvatarDropAreaForegroundColor(control) | async
"
[xFocus]="getControlFocusHandler(control) | async"
[fileDropAreaActionProvider]="
getAvatarDropAreaActionProvider(control) | async
"
[fileDropAreaDisableFileCheck]="
isAvatarDropAreaDisableFileCheck(control) | async
"
[fileDropAreaContentTemplate]="
getAvatarDropAreaContentTemplate(control) | async
"
[notAllowedFileException]="
getAvatarNotAllowedFileException(control) | async
"
[fileDropAreaAllowedExtensions]="
getAvatarDropAreaAllowedExtensions(control) | async
"
[wrapWithCard]="isAvatarWrapWithCard(control) | async"
[fileDropAreaCardForegroundColor]="
isAvatarDropAreaCardForegroundColor(control) | async
"
[cardSubTitle]="getAvatarCardSubTitle(control) | async"
[minAllowedFileSizeException]="
getAvatarMinAllowedFileSizeException(control) | async
"
[cardShowFooter]="avatarCardShowFooter(control) | async"
[maxAllowedFileSizeException]="
getAvatarMaxAllowedFileSizeException(control) | async
"
[fileDropAreaSupportsMultipleFiles]="
isAvatarDropAreaSupportsMultipleFiles(control) | async
"
(avatarChange)="handleAvatarAvatarChange(control, $event)"
[actionProvider]="getAvatarActionProvider(control) | async"
[fileDropAreaIcon]="getAvatarDropAreaIcon(control) | async"
[foregroundColor]="isAvatarForegroundColor(control) | async"
(fileDropAreaFilesChangeEmiter)="
handleAvatarFileDropAreaFilesChangeEmitter(control, $event)
"
[fileDropAreaColor]="getAvatarDropAreaColor(control) | async"
[fileDropAreaIsInPage]="isAvatarDropAreaInPage(control) | async"
[fileDropAreaMessage]="getAvatarDropAreaMessage(control) | async"
[allowedExtensions]="getAvatarAllowedExtensions(control) | async"
[placeHolderAvatar]="getAvatarPlaceHolderAvatar(control) | async"
[uiDisabled]="uiDisabled || (getControlDisabled(control) | async)"
[fileDropAreaCssClass]="getAvatarDropAreaCssClass(control) | async"
[emptyFileException]="getAvatarEmptyFileException(control) | async"
[minAllowedFileSize]="getAvatarMinAllowedFileSize(control) | async"
[maxAllowedFileSize]="getAvatarMaxAllowedFileSize(control) | async"
[cardForegroundColor]="isAvatarCardForegroundColor(control) | async"
[fileDropAreaCardColor]="getAvatarDropAreaCardColor(control) | async"
[fileDropAreaCardTitle]="getAvatarDropAreaCardTitle(control) | async"
[fileDropAreaErrorColor]="getAvatarDropAreaErrorColor(control) | async"
[fileDropAreaWrapWithCard]="isAvatarDropAreaWrapWithCard(control) | async"
[fileDropAreaDragDisabled]="isAvatarDropAreaDragDisabled(control) | async"
[fileDropAreaAccentColor]="getAvatarDropAreaAccesntColor(control) | async"
[fileDropAreaSuccessColor]="getAvatarDropAreaSuccessColor(control) | async"
[fileDropAreaCardSubTitle]="getAvatarDropAreaCardSubTitle(control) | async"
[fileDropAreaCardShowFooter]="avatarDropAreaCardShowFooter(control) | async"
[showFileDropArea]="
!(isMobileUi$ | async) && (avatarCanDrop(control) | async)
"
>
</x-avatar-upload>
</ng-template>
<!-- Map Content Template -->
<ng-template #mapContentRef let-control>
<!-- Map Component -->
<x-map
[zoom]="getMapZoom(control) | async"
[loading]="getValue(loading) | async"
(isReady)="handleMapIsReady(control)"
[isInPage]="isMapInPage(control) | async"
[showZoom]="mapShowZoom(control) | async"
[canSelect]="mapCanSelect(control) | async"
[cssClass]="getMapCssClass(control) | async"
[latitude]="getMapLatitude(control) | async"
[showRotate]="mapShowRotate(control) | async"
[showLocator]="mapShowLocator(control) | async"
[cardTitle]="getMapCardTitle(control) | async"
[longitude]="getMapLongitude(control) | async"
[cardColor]="getMapCardColor(control) | async"
[searchBarCancelButtonIcon]="
getMapSearchBarCancelButtonIcon(control) | async
"
*ngIf="!(isMapPresentWithDialog(control) | async)"
[ngClass]="getFormControlClasses(control) | async"
[markerStyle]="getMapMarkerStyle(control) | async"
[wrapWithCard]="isMapWrapWithCard(control) | async"
[showSearchBar]="mapShowSearchBar(control) | async"
[searchBarCancelButtonTitle]="
getMapSearchBarCancelButtonTitle(control) | async
"
[cardSubTitle]="getMapCardSubTitle(control) | async"
[cardShowFooter]="mapCardShowFooter(control) | async"
[showZoomSlider]="mapShowZoomSlider(control) | async"
[searchBarType]="getMapSearchBarType(control) | async"
[showClearMarker]="mapShowClearMarker(control) | async"
[showProgressBar]="mapShowProgressBar(control) | async"
[actionProvider]="getMapActionProvider(control) | async"
[searchBarColor]="getMapSearchBarColor(control) | async"
[searchBarValue]="getMapSearchBarValue(control) | async"
[searchBarTitle]="getMapSearchBarTitle(control) | async"
[locatorPosition]="getMapLocatorPosition(control) | async"
[showGoMarkedPlace]="mapShowGoMarkedPlace(control) | async"
[progressBarColor]="getMapProgressBarColor(control) | async"
[searchBarForegroundSearchInputColor]="
getMapSearchBarForegroundSearchInputColor(control) | async
"
[searchBarDebounce]="getMapSearchBarDebounce(control) | async"
[searchBarCssClass]="getMapSearchBarCssClass(control) | async"
[searchBarPosition]="getMapSearchBarPosition(control) | async"
(locationSelected)="handleMapLocationSelected(control, $event)"
[cardForegroundColor]="isMapCardForegroundColor(control) | async"
[showSelectedLocation]="mapShowSelectedLocation(control) | async"
[searchPlaceProvider]="getMapSearchPlaceProvider(control) | async"
[uiDisabled]="uiDisabled || (getControlDisabled(control) | async)"
[clearMarkerPosition]="getMapClearMarkerPosition(control) | async"
[searchPlaceProvider]="getMapSearchPlaceProvider(control) | async"
[searchBarSpellcheck]="getMapSearchBarSpellcheck(control) | async"
[searchBarSearchInputColor]="
getMapSearchBarSearchInputColor(control) | async
"
[progressBarPosition]="getMapProgressBarPosition(control) | async"
[searchResultListColor]="getMapSearchResultListColor(control) | async"
(searchBarQueryChange)="handleMapSearchBarQueryChange(control, $event)"
[searchBarActionProvider]="getMapSearchBarActionProvider(control) | async"
[searchBarShowCancelButton]="mapShowSearchBarCancelButton(control) | async"
[searchBarClearButtonIcon]="getMapSearchBarClearButtonIcon(control) | async"
[searchBarForegroundColor]="getMapSearchBarForegroundColor(control) | async"
[selectedLocationPosition]="getMapSelectedLocationPosition(control) | async"
[searchBarClearButtonIconColor]="
getMapSearchBarClearButtonIconColor(control) | async
"
[searchBarSearchButtonIconColor]="
getMapSearchBarSearchButtonIconColor(control) | async
"
>
</x-map>
<!-- (zoomChanged)="handleMapZoomChanged(control, $event)" -->
</ng-template>
<!-- ColorPicker Content Template -->
<ng-template #colorPickerContentRef let-control>
<!-- ColorPicker Component -->
<x-color-picker
[color]="getColorPickerColor(control) | async"
[isInPage]="isColorPickerInPage(control) | async"
[ngClass]="getFormControlClasses(control) | async"
[cssClass]="getColorPickerCssClass(control) | async"
[cardColor]="getColorPickerCardColor(control) | async"
[showSelectedColorPreview]="
colorPickerShowSelectedColorPreview(control) | async
"
[cardTitle]="getColorPickerCardTitle(control) | async"
[representColorFormats]="
getColorPickerRepresentColorFormats(control) | async
"
[presetColorsLableColor]="
getColorPickerPresetColorsLableColor(control) | async
"
[copyToClipboardIconColor]="
getColorPickerCopyToClipboardIconColor(control) | async
"
[copyToClipboardIconLabel]="
getColorPickerCopyToClipboardIconLabel(control) | async
"
[cursorColor]="getColorPickerCursorColor(control) | async"
*ngIf="!(isColorPickerPresentWithDialog(control) | async)"
[wrapWithCard]="isColorPickerWrapWithCard(control) | async"
[cardSubTitle]="getColorPickerCardSubTitle(control) | async"
[presetColors]="getColorPickerPresetColors(control) | async"
[outputFormat]="getColorPickerOutputFormat(control) | async"
[cardShowFooter]="colorPickercardShowFooter(control) | async"
[showHueChannel]="colorPickerShowHueChannel(control) | async"
[showColorValue]="colorPickerShowColorValue(control) | async"
[showColorInput]="colorPickerShowColorInput(control) | async"
[selectedColor]="getColorPickerSelectedColor(control) | async"
[actionProvider]="getColorPickerActionProvider(control) | async"
[colorTextColor]="getColorPickerColorTextColor(control) | async"
[foregroundColor]="isColorPickerForegroundColor(control) | async"
[showPresetColors]="colorPickerShowPresetColors(control) | async"
[showAlphaChannel]="colorPickerShowAlphaChannel(control) | async"
(colorSelected)="handleColorPickerColorSelected(control, $event)"
[uiDisabled]="uiDisabled || (getControlDisabled(control) | async)"
[showPaletteChannel]="colorPickerShowPaletteChannel(control) | async"
[presetColorsLable]="getColorPickerPresetColorsLable(control) | async"
[showCopyToClipboard]="colorPickerShowCopyToClipboard(control) | async"
[cardForegroundColor]="isColorPickerCardForegroundColor(control) | async"
[clearColorIconColor]="getColorPickerClearColorIconColor(control) | async"
[clearColorIconLabel]="getColorPickerClearColorIconLabel(control) | async"
[colorInputIconColor]="getColorPickerColorInputIconColor(control) | async"
[colorInputIconLabel]="getColorPickerColorInputIconLabel(control) | async"
>
</x-color-picker>
</ng-template>
<!-- //#endregion -->
<!-- By Icon Label Template -->
<ng-template #byIconLabelRef let-control>
<!-- Label and Icons -->
<x-slotter
[layout]="SlotLayouts.HORIZONTAL"
[hasStartOrTopSlot]="
(controlHasIcons(control) | async) &&
(controlHasPrefixIcon(control) | async)
"
[hasEndOrBottomSlot]="
(controlHasIcons(control) | async) &&
(controlHasSuffixIcon(control) | async)
"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Prefix Icon -->
<ng-container
*ngTemplateOutlet="prefixIconRef; context: { $implicit: control }"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<!-- label -->
<ng-container
*ngTemplateOutlet="
defaultFieldLabelRef;
context: { $implicit: control }
"
></ng-container>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Suffix Icon -->
<ng-container
*ngTemplateOutlet="suffixIconRef; context: { $implicit: control }"
></ng-container>
</x-slot>
</x-slotter>
</ng-template>
<!-- By Icon Label Template -->
<ng-template #byIconContentRef let-control let-contentRef="contentRef">
<!-- Label and Icons -->
<x-slotter
[layout]="SlotLayouts.HORIZONTAL"
[hasStartOrTopSlot]="
(controlHasIcons(control) | async) &&
(controlHasPrefixIcon(control) | async)
"
[hasEndOrBottomSlot]="
(controlHasIcons(control) | async) &&
(controlHasSuffixIcon(control) | async)
"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Prefix Icon -->
<ng-container
*ngTemplateOutlet="prefixIconRef; context: { $implicit: control }"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<ng-container *ngIf="contentRef">
<ng-container
*ngTemplateOutlet="contentRef; context: { $implicit: control }"
></ng-container>
</ng-container>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Suffix Icon -->
<ng-container
*ngTemplateOutlet="suffixIconRef; context: { $implicit: control }"
></ng-container>
</x-slot>
</x-slotter>
</ng-template>
<!-- Prefix Icon Template -->
<ng-template #prefixIconRef let-control>
<!-- Prefix Icon -->
<x-icon
matPrefix
[name]="getControlIconName(icon) | async"
(clicked)="handleControlIconClicked(icon)"
[color]="getControlIconColor(icon) | async"
[matTooltip]="getControlIconTooltip(icon) | async"
*ngIf="getControlPrefixIcon(control) | async as icon"
[clickable]="notNullOrUndefinedValue(icon.handler) | async"
[uiDisabled]="(getValue(uiDisabled) | async) && !icon.handler"
[class.x-status-handler]="getControlIconApplyStateColor(icon) | async"
>
</x-icon>
</ng-template>
<!-- Suffix Icon Template -->
<ng-template #suffixIconRef let-control>
<!-- Suffix Icon -->
<x-icon
matSuffix
[name]="getControlIconName(icon) | async"
(clicked)="handleControlIconClicked(icon)"
[color]="getControlIconColor(icon) | async"
[matTooltip]="getControlIconTooltip(icon) | async"
*ngIf="getControlSuffixIcon(control) | async as icon"
[clickable]="notNullOrUndefinedValue(icon.handler) | async"
[uiDisabled]="(getValue(uiDisabled) | async) && !icon.handler"
[class.x-status-handler]="getControlIconApplyStateColor(icon) | async"
>
</x-icon>
</ng-template>
<!-- Loading Ref Template -->
<ng-template #loadingRef let-control>
<ion-progress-bar
type="indeterminate"
[color]="getProgressBarColor(control) | async"
*ngIf="
(controlHasProgressBar(control) | async) &&
getControlStatus(control) === FormStatuses.Pending
"
></ion-progress-bar>
</ng-template>
<!-- Hint Template -->
<ng-template #hintRef let-control>
<mat-hint
[ngClass]="getFormControlHintClasses(control) | async"
*ngIf="notEmptyValue(getControlHint(control) | async) | async"
>{{ getControlHint(control) | async }}</mat-hint
>
</ng-template>
<!-- Errors Ref Template -->
<ng-template #errorsRef let-control>
<div
*ngIf="
(controlHasErrors(control) | async) &&
(controlHasErrorHandlers(control) | async)
"
[ngClass]="getControlErrorsClasses(control) | async"
>
<ng-container
*ngIf="getControlErrorHandlers(control) | async as errorHandlers"
>
<mat-error
*ngFor="let handler of errorHandlers"
[class.show]="controlHasError(control, handler) | async"
[ngClass]="getControlErrorClasses(control, handler) | async"
>
<span class="x-error-message">
{{ getErrorHandlerErrorMessage(handler, control) | async }}
</span>
</mat-error>
</ng-container>
</div>
</ng-template>
<!-- XFormField Template -->
<ng-template
#xFormFieldRef
let-control
let-controlIndex="controlIndex"
let-fieldLabelRef="fieldLabelRef"
let-fieldInputRef="fieldInputRef"
let-fieldContentRef="fieldContentRef"
>
<!-- XForm Field -->
<div
xFocusHandler
[tabIndex]="controlIndex"
[ngClass]="getFormFieldClasses(control) | async"
[class.apply-status]="getValue(applyStatusOnControls) | async"
[enableHandler]="
!uiDisabled && !loading && !(getControlDisabled(control) | async)
"
>
<!-- Label -->
<ng-container *ngIf="fieldLabelRef">
<div [ngClass]="getFormControlFieldLabelClasses(control) | async">
<ng-container
*ngTemplateOutlet="fieldLabelRef; context: { $implicit: control }"
></ng-container>
</div>
</ng-container>
<!-- Input -->
<ng-container *ngIf="fieldInputRef">
<ng-container
*ngTemplateOutlet="fieldInputRef; context: { $implicit: control }"
></ng-container>
</ng-container>
<!-- Show hint in below of input if exists -->
<ng-container *ngIf="fieldInputRef">
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="loadingRef; context: { $implicit: control }"
></ng-container>
</ng-container>
<!-- Content -->
<ng-container
*ngTemplateOutlet="fieldContentRef; context: { $implicit: control }"
></ng-container>
<!-- Show hint in below of content when input not exists -->
<ng-container *ngIf="!fieldInputRef">
<!-- Progressbar for Loading -->
<ng-container
*ngTemplateOutlet="loadingRef; context: { $implicit: control }"
></ng-container>
</ng-container>
</div>
<!-- Hint -->
<ng-container
*ngTemplateOutlet="hintRef; context: { $implicit: control }"
></ng-container>
<!-- Errors -->
<ng-container
*ngTemplateOutlet="errorsRef; context: { $implicit: control }"
></ng-container>
</ng-template>
<!-- XField Label Template -->
<ng-template #defaultFieldLabelRef let-control>
<!-- label -->
<mat-label
class="x-field-label"
*ngIf="notEmptyValue(getControlLabel(control)) | async"
>{{ getControlLabel(control) | async }}</mat-label
>
</ng-template>
<!-- byIcon Input Element Template -->
<ng-template #byIconInputElemntRef let-control>
<!-- Control Input Element -->
<x-slotter
[hasStartOrTopSlot]="true"
[hasEndOrBottomSlot]="true"
[layout]="SlotLayouts.HORIZONTAL"
[startTopSlotCssClass]="'auto-size-flex'"
[endBottomSlotCssClass]="'auto-size-flex'"
*ngIf="notNullOrUndefinedValue(control) | async"
>
<!-- Start -->
<x-slot [name]="SlotNames.START">
<!-- Prefix Icon -->
<ng-container
*ngTemplateOutlet="prefixIconRef; context: { $implicit: control }"
></ng-container>
<!-- Action Prefix Icons -->
<ng-container
*ngTemplateOutlet="
actionIconsRef;
context: {
$implicit: control,
position: ControlIconPositions.Prefix
}
"
></ng-container>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER">
<ng-container
*ngTemplateOutlet="
defaultXInputElement;
context: { $implicit: control }
"
></ng-container>
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END">
<!-- Suffix Icon -->
<ng-container
*ngTemplateOutlet="suffixIconRef; context: { $implicit: control }"
></ng-container>
<!-- Action Suffix Icons -->
<ng-container
*ngTemplateOutlet="
actionIconsRef;
context: {
$implicit: control,
position: ControlIconPositions.Suffix
}
"
></ng-container>
</x-slot>
</x-slotter>
</ng-template>
<!-- Default X Input Element Template -->
<ng-template #defaultXInputElement let-control>
<!-- Has Formatter Input Control -->
<ng-container *ngIf="controlHasFormatter(control) | async">
<input
class="x-input"
autocomplete="off"
xFromInputFormatter
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
(blur)="handleControlBlured(control.propName.toString())"
[locale]="getFormatterLocale(control) | async"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[seperator]="getFormatterSeperator(control) | async"
[placeholder]="getControlPlaceHolder(control) | async"
[inputFormatterType]="getFormatterType(control) | async"
[ngClass]="getControlInputElementClasses(control) | async"
[currencyLable]="getFormatterCurrencyLabel(control) | async"
[enabledInputFormatter]="controlHasFormatter(control) | async"
[stringFormatter]="getFormatterStringFormatter(control) | async"
[stringInputFormatterType]="getFormatterInputType(control) | async"
/>
</ng-container>
<!-- Has not Formatter Input Control -->
<ng-container *ngIf="!(controlHasFormatter(control) | async)">
<input
class="x-input"
autocomplete="off"
[formControlName]="control.propName.toString()"
[id]="getControlInputElementId(control)"
[type]="getControlType(control) | async"
(blur)="handleControlBlured(control.propName.toString())"
(focus)="handleControlFocused(control.propName.toString())"
[matTooltip]="getControlTooltip(control) | async"
[xFocus]="getControlFocusHandler(control) | async"
[placeholder]="getControlPlaceHolder(control) | async"
[ngClass]="getControlInputElementClasses(control) | async"
/>
</ng-container>
</ng-template>
<!-- Action Icons Template -->
<ng-template #actionIconsRef let-control let-position="position">
<!-- Clear -->
<ng-container
*ngIf="
controlHasValue(control.propName.toString()) &&
(hasControlClearIcon(control) | async) &&
(notNullOrUndefinedValue(control) | async)
"
>
<ng-container *ngIf="getControlClearIcon(control) | async as descriptor">
<ng-container
*ngIf="
(getControlIconDescriptorPosition(descriptor) | async) === position
"
>
<ng-container
*ngTemplateOutlet="
actionIconRef;
context: {
$implicit: descriptor,
role: ControlIconRoles.Clear,
control: control
}
"
></ng-container>
</ng-container>
</ng-container>
</ng-container>
<!-- Select -->
<ng-container *ngIf="getControlType(control) | async as controlType">
<!-- Recieve Control Type for Handling Without Dialog Actions -->
<ng-container
*ngIf="
(controlType !== ControlTypes.Map &&
controlType !== ControlTypes.ColorPicker) ||
(controlType === ControlTypes.Map &&
(isMapPresentWithDialog(control) | async)) ||
(controlType === ControlTypes.ColorPicker &&
(isColorPickerPresentWithDialog(control) | async))
"
>
<!-- if Map/ColorPicker Control Presented Without Dialog, there is no need to has Select icon ... -->
<ng-container *ngIf="getControlSelectIcon(control) | async as descriptor">
<ng-container
*ngIf="
(getControlIconDescriptorPosition(descriptor) | async) === position
"
>
<ng-container
*ngTemplateOutlet="
actionIconRef;
context: {
control: control,
$implicit: descriptor,
role: ControlIconRoles.Select
}
"
></ng-container>
</ng-container>
</ng-container>
</ng-container>
</ng-container>
</ng-template>
<!-- Action Icon Template -->
<ng-template
#actionIconRef
let-descriptor
let-role="role"
let-control="control"
>
<x-icon
[clickable]="true"
class="x-action-icon"
[uiDisabled]="getValue(uiDisabled) | async"
[uiDisabled]="
(getControlDisabled(control) | async) ||
(getControlDisableIcon(control) | async)
"
[class.x-status-handler]="
getControlIconDescriptorApplyStateColor(descriptor) | async
"
[name]="getControlIconDescriptorName(role, descriptor) | async"
[color]="getControlIconDescriptorColor(role, descriptor) | async"
(clicked)="handleControlActionIconClicked(role, descriptor, control)"
[matTooltip]="getControlIconDescriptorTooltip(role, descriptor) | async"
>
</x-icon>
</ng-template>
<!-- Nothing Template -->
<ng-template #nothingRef></ng-template>
### 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<XFormComponent>('formConfig')
);
if (isFormConfigChanged) {
await this.prepareFormGroup();
}
//
// Action Provider ...
const isActionProviderChanged = changeKeys.includes(
nameof<XFormComponent>('actionProvider')
);
if (isActionProviderChanged) {
await this.registerActionProvider();
}
//
//#region UI Disabled or Loading ...
const isUiDisabledChanged = changeKeys.includes(
nameof<XFormComponent>('uiDisabled')
);
if (isUiDisabledChanged) {
await this.handleUiDisabledChanged();
}
//#endregion
//
//#region Color Change Detecotrs ...
//
const isRegularColorChanged = changeKeys.includes(
nameof<XFormComponent>('regularColor')
);
if (isRegularColorChanged) {
await this.applyRegularColor();
}
//
const isAccentColorChanged = changeKeys.includes(
nameof<XFormComponent>('accentColor')
);
if (isAccentColorChanged) {
await this.applyAccentColor();
}
//
const isHintColorChanged = changeKeys.includes(
nameof<XFormComponent>('hintColor')
);
if (isHintColorChanged) {
await this.applyHintColor();
}
//
const isPendingColorChanged = changeKeys.includes(
nameof<XFormComponent>('pendingColor')
);
if (isPendingColorChanged) {
await this.applyPendingColor();
}
//
const isActiveColorChanged = changeKeys.includes(
nameof<XFormComponent>('activeColor')
);
if (isActiveColorChanged) {
await this.applyActiveColor();
}
//
const isValidColorChanged = changeKeys.includes(
nameof<XFormComponent>('validColor')
);
if (isValidColorChanged) {
await this.applyValidColor();
}
//
const isInvalidColorChanged = changeKeys.includes(
nameof<XFormComponent>('invalidColor')
);
if (isInvalidColorChanged) {
await this.applyInvalidColor();
}
//
const isFillColorChanged = changeKeys.includes(
nameof<XFormComponent>('fillColor')
);
if (isFillColorChanged) {
await this.applyFillColor();
}
//
const isDisabledColorChanged = changeKeys.includes(
nameof<XFormComponent>('disabledColor')
);
if (isDisabledColorChanged) {
await this.applyDisabledColor();
}
//
const isDisabledFillColorChanged = changeKeys.includes(
nameof<XFormComponent>('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 <T> this type is Partial<T> ...
*/
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<boolean> {
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<XControlIconDescriptor> {
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<boolean> {
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<XControlIconDescriptor> {
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<XMarkdownActionModel>();
}
//
return this.actionProviders[
control.propName
] as Subject<XMarkdownActionModel>;
} 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<XMapLocation> {
//
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<XSearchBarActionModel>();
}
//
return this.actionProviders[key] as Subject<XSearchBarActionModel>;
} 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<XMapActionModel>();
}
//
return this.actionProviders[
control.propName
] as Subject<XMapActionModel>;
} 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<XMapActionModel>();
}
//
return this.actionProviders[
control.propName
] as Subject<XColorPickerActionModel>;
} 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<XAvatarUploadActionModel>();
}
//
return this.actionProviders[
control.propName
] as Subject<XAvatarUploadActionModel>;
} 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<XFileDropAreaActionModel>();
}
//
return this.actionProviders[key] as Subject<XFileDropAreaActionModel>;
} 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<XFormControlAppearanceDescriptor> {
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<any>
) {
//
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<any>
) {
//
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<File>
) {
//
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<any>();
}
//
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<XFormActionModel>();
}
//
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<T extends XBaseDto = any> {
opened?: XStandardType<boolean>;
color?: XStandardType<XColorIdentifier>;
onSelect?: (item: T) => XStandardType<void>;
items: () => XStandardType<XOneOrManyType<T>>;
itemTemplate: XStandardType<TemplateRef<any>>;
cssClass?: XStandardType<XOneOrManyType<string>>;
onEscape?: () => XStandardType<void>;
onOutsideClicked?: () => XStandardType<void>;
}
//#endregion
//
//#region XForm Validator Model ...
export type XFormValidatorDescriptor = Partial<
Pick<AbstractControlOptions, 'validators' | 'asyncValidators'>
>;
//#endregion
//
//#region Error Handler Configs ...
export interface XFormErrorHandler {
errorName: XStandardType<string>;
errorMessage: XStandardType<XResourceIdentifier>;
errorDataProvider?: (errorObject: any) => XStandardType<XResourceIdentifier>;
}
//#endregion
//
//#region Formatter Config ...
export interface XFormControlFormatterConfig {
locale?: XStandardType<XLocale>;
seperator?: XStandardType<string>;
type: XStandardType<XFormInputFormatterIdentifier>;
inputType?: XStandardType<XStringInputFormatTypeIdentifier>;
currencyLable?: XStandardType<XResourceIdentifier>;
stringFormatter?: XStandardType<XOneOrManyType<number>>;
}
//#endregion
//
//#region Control Progressbar Config ...
export interface XFormControlProgressbarConfig {
color: XStandardType<XColorIdentifier>;
}
//#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<boolean>;
disabled?: XStandardType<boolean>;
hint?: XStandardType<XResourceIdentifier>;
label: XStandardType<XResourceIdentifier>;
tooltip?: XStandardType<XResourceIdentifier>;
placeholder?: XStandardType<XResourceIdentifier>;
cssClass?: XStandardType<XOneOrManyType<string>>;
icons?: XStandardType<XFormControlIconDescriptor>;
formatter?: XStandardType<XFormControlFormatterConfig>;
progressBar?: XStandardType<XFormControlProgressbarConfig>;
autoComplete?: XStandardType<XFormControlAutoCompleteConfig>;
appearance?: XStandardType<XFormControlAppearanceIdentifier>;
labelPosition?: XStandardType<XFormControlLabelPositionIdentifier>;
}
//#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<void>;
name?: XStandardType<XIconIdentifier>;
color?: XStandardType<XColorIdentifier>;
applyStateColor?: XStandardType<boolean>;
tooltip?: XStandardType<XResourceIdentifier>;
position?: XStandardType<XControlIconPositionIdentifier>;
}
export interface XFormIconDescriptor
extends Pick<
Partial<XControlIconDescriptor>,
'handler' | 'name' | 'color' | 'applyStateColor' | 'tooltip'
> {}
export interface XFormControlIconDescriptor {
suffix?: XStandardType<XFormIconDescriptor>;
prefix?: XStandardType<XFormIconDescriptor>;
}
//#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<void>;
valueChanged?: (
model: XFormControlValueChangeEventModel
) => XStandardType<void>;
onBlured?: (model: XBaseFormControlActionModel) => XStandardType<void>;
onFocused?: (model: XBaseFormControlActionModel) => XStandardType<void>;
}
//#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<XFormControlActionIdentifier>,
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<XFormControlTypeIdentifier>;
config?: XStandardType<XFormControlTypeConfig>;
}
//
//#region Type Configs ...
//
//#region Input Type ...
export interface XFormInputControlConfig {
readonly?: XStandardType<boolean>;
}
//#endregion
//
//#region Select Type ...
export interface XFormSelectControlOption<T extends XBaseDto = any> {
value: XStandardType<T>;
viewValue: XStandardType<string>;
}
export interface XFormSelectControlConfig<T extends XBaseDto = any> {
options?: XStandardType<XOneOrManyType<XFormSelectControlOption<T>>>;
multiple?: XStandardType<boolean>;
}
//#endregion
//
//#region Radio Type ...
export interface XFormRadioControlOption<T extends XBaseDto = any> {
value: XStandardType<T>;
viewValue: XStandardType<string>;
}
export interface XFormRadioControlConfig<T extends XBaseDto = any> {
options?: XStandardType<XOneOrManyType<XFormRadioControlOption<T>>>;
}
//#endregion
//
//#region Date Control Config ...
export enum XFormDatePickerControlPickerPosition {
Suffix = 'suffix',
Prefix = 'prefix',
}
export type XFormDatePickerControlPickerPositionIdentifier =
| XFormDatePickerControlPickerPosition
| string;
export interface XFormDatePickerControlConfig {
startAt?: XStandardType<Date>;
dateFilter?: (d: any) => boolean;
applyStateColor?: XStandardType<boolean>;
toggleIcon?: XStandardType<XIconIdentifier>;
iconColor?: XStandardType<XColorIdentifier>;
datePickerPosition: XStandardType<XFormDatePickerControlPickerPositionIdentifier>;
disableInput?: XStandardType<boolean>;
disablePicker?: XStandardType<boolean>;
iconTooltip?: XStandardType<XResourceIdentifier>;
dateInput?: (event: Date) => XStandardType<void>;
dateChange?: (event: Date) => XStandardType<void>;
}
//#endregion
//
//#region Slider Control ...
export interface XFormSliderControlConfig {
min?: XStandardType<number>;
max?: XStandardType<number>;
step?: XStandardType<number>;
invert?: XStandardType<boolean>;
vertical?: XStandardType<boolean>;
thumbLabel?: XStandardType<boolean>;
formatter?: (value: number) => string;
}
//#endregion
//
//#region Markdown Control Config ...
export interface XFormMarkdownControlConfig {
//
isInPage?: XStandardType<boolean>;
hasToolbar?: XStandardType<boolean>;
wrapWithCard?: XStandardType<boolean>;
cardColor?: XStandardType<XColorIdentifier>;
cardForegroundColor?: XStandardType<boolean>;
mode?: XStandardType<XMarkdownModeIdentifier>;
toolbarColor?: XStandardType<XColorIdentifier>;
cardTitle?: XStandardType<XResourceIdentifier>;
actionProvider?: Subject<XMarkdownActionModel>;
toolbarForegroundColor?: XStandardType<boolean>;
cssClass?: XStandardType<XOneOrManyType<string>>;
editorBoxColor?: XStandardType<XColorIdentifier>;
previewBoxColor?: XStandardType<XColorIdentifier>;
cardSubTitle?: XStandardType<XResourceIdentifier>;
toolbarCssClass?: XStandardType<XOneOrManyType<string>>;
contentChanged?: (content: string) => XStandardType<void>;
toolbarConfig?: XStandardType<XMarkdownToolbarConfigProps>;
}
//#endregion
//
//#region Check Box Config ...
export interface XFormCheckBoxControlConfig {
checkedChanged?: (checked: boolean) => XStandardType<any>;
}
//#endregion
//
//#region Map Config ...
export enum XFormMapControlPresentType {
WithDialog = 'width_dialog',
WithoutDialog = 'without_dialog',
}
export type XFormMapControlPresentTypeIdentifier =
| XFormMapControlPresentType
| string;
//
export interface XFormMapControlConfig
extends Pick<
Partial<IXMapContainer>,
| '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<boolean>;
disableInput?: XStandardType<boolean>;
actionProvider?: Subject<XMapActionModel>;
clearIcon?: XStandardType<XControlIconDescriptor>;
selectIcon?: XStandardType<XControlIconDescriptor>;
inputCssClass?: XStandardType<XOneOrManyType<string>>;
inputValueChanged?: (value?: string) => XStandardType<string>;
presentType?: XStandardType<XFormMapControlPresentTypeIdentifier>;
}
//#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<XColorPickerDialogConfig>,
| '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<boolean>;
disableIcon?: XStandardType<boolean>;
disableInput?: XStandardType<boolean>;
wrapWithCard?: XStandardType<boolean>;
showCardFooter?: XStandardType<boolean>;
colorViewBorderWidth?: XStandardType<number>;
actionProvider?: Subject<XColorPickerActionModel>;
clearIcon?: XStandardType<XControlIconDescriptor>;
selectIcon?: XStandardType<XControlIconDescriptor>;
inputCssClass?: XStandardType<XOneOrManyType<string>>;
colorViewBorderColor?: XStandardType<XColorIdentifier>;
colorViewBorderStyle?: XStandardType<XBorderStyleIdentifier>;
inputValueChanged?: (value?: string) => XStandardType<string>;
presentType?: XStandardType<XFormColorPickerControlPresentTypeIdentifier>;
}
//#endregion
//
//#region Avatar Upload Config ...
export interface XFormAvatarUploadControlConfig {
fileDropAreaFilesChangeEmiter?: (
files?: XOneOrManyType<File>
) => XStandardType<void>;
canDrop?: XStandardType<boolean>;
isInPage?: XStandardType<boolean>;
wrapWithCard?: XStandardType<boolean>;
color?: XStandardType<XColorIdentifier>;
showCardFooter?: XStandardType<boolean>;
foregroundColor?: XStandardType<boolean>;
placeHolderAvatar?: XStandardType<string>;
minAllowedFileSize?: XStandardType<number>;
maxAllowedFileSize?: XStandardType<number>;
cardColor?: XStandardType<XColorIdentifier>;
cardForegroundColor?: XStandardType<boolean>;
fileDropAreaIsInPage?: XStandardType<boolean>;
cardTitle?: XStandardType<XResourceIdentifier>;
cssClass?: XStandardType<XOneOrManyType<string>>;
fileDropAreaWrapWithCard?: XStandardType<boolean>;
fileDropAreaIcon?: XStandardType<XIconIdentifier>;
fileDropAreaDragDisabled?: XStandardType<boolean>;
cardSubTitle?: XStandardType<XResourceIdentifier>;
actionProvider?: Subject<XAvatarUploadActionModel>;
fileDropAreaShowCardFooter?: XStandardType<boolean>;
fileDropAreaColor?: XStandardType<XColorIdentifier>;
fileDropAreaForegroundColor?: XStandardType<boolean>;
avatarChange?: (avatar?: File) => XStandardType<void>;
fileDropAreaDisableFileCheck?: XStandardType<boolean>;
fileDropAreaCardColor?: XStandardType<XColorIdentifier>;
fileDropAreaCardForegroundColor?: XStandardType<boolean>;
emptyFileException?: XStandardType<XExceptionIdentifier>;
fileDropAreaErrorColor?: XStandardType<XColorIdentifier>;
fileDropAreaMessage?: XStandardType<XResourceIdentifier>;
fileDropAreaAccentColor?: XStandardType<XColorIdentifier>;
allowedExtensions?: XStandardType<XOneOrManyType<string>>;
fileDropAreaCardTitle?: XStandardType<XResourceIdentifier>;
fileDropAreaSuccessColor?: XStandardType<XColorIdentifier>;
fileDropAreaSupportsMultipleFiles?: XStandardType<boolean>;
fileDropAreaCssClass?: XStandardType<XOneOrManyType<string>>;
fileDropAreaCardSubTitle?: XStandardType<XResourceIdentifier>;
notAllowedFileException?: XStandardType<XExceptionIdentifier>;
fileDropAreaContentTemplate?: XStandardType<TemplateRef<any>>;
fileDropAreaActionProvider?: Subject<XFileDropAreaActionModel>;
minAllowedFileSizeException?: XStandardType<XExceptionIdentifier>;
maxAllowedFileSizeException?: XStandardType<XExceptionIdentifier>;
actions?: XStandardType<XOneOrManyType<XAvatarUploadActionButton>>;
fileDropAreaAllowedExtensions?: XStandardType<XOneOrManyType<string>>;
}
//#endregion
//
//#region Selector Config ...
export interface XFormSelectorControlConfig
extends Partial<XSelectorDialogConfig> {
//
clearIcon?: XStandardType<XControlIconDescriptor>;
selectIcon?: XStandardType<XControlIconDescriptor>;
inputCssClass?: XStandardType<XOneOrManyType<string>>;
inputValueChanged?: (value?: string) => XStandardType<string>;
formatSelectedItem?: (item: XOneOrManyType<any>) => XStandardType<string>;
}
//#endregion
//#endregion
//#endregion
//
//#region Form Control Config ...
export interface XFormControlConfig<T extends XBaseDto = any> {
index: number;
propName: keyof Partial<T>;
focusHandler?: Subject<any>;
type: XStandardType<XFormControlTypeDescriptor>;
updateOn?: XStandardType<XFormUpdateOnIdentifier>;
validators?: XStandardType<XFormValidatorDescriptor>;
actionProvider?: Subject<XFormControlActionProviderModel>;
eventHandlers?: XStandardType<XFormControlEventsDescriptor>;
appearance: XStandardType<XFormControlAppearanceDescriptor>;
errorHandlers?: XStandardType<XOneOrManyType<XFormErrorHandler>>;
}
//#endregion
//
// Form Config ...
export interface XFormConfig<T extends XBaseDto = any> {
name: XStandardType<string>;
model?: XStandardType<Partial<T>>;
updateOn?: XStandardType<XFormUpdateOnIdentifier>;
validators?: XStandardType<XFormValidatorDescriptor>;
controls: XStandardType<XOneOrManyType<XFormControlConfig<T>>>;
errorHandlers?: XStandardType<XOneOrManyType<XFormErrorHandler>>;
}
//
//#region Inside Card Container ...
export interface IXFormContainer extends IXComponentCardContainer {
//
actionProvider: Subject<XFormActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
formConfig: XStandardType<XFormConfig>;
applyStatusOnControls: XStandardType<boolean>;
//
regularColor: XStandardType<XColorIdentifier>;
accentColor: XStandardType<XColorIdentifier>;
hintColor: XStandardType<XColorIdentifier>;
activeColor: XStandardType<XColorIdentifier>;
validColor: XStandardType<XColorIdentifier>;
invalidColor: XStandardType<XColorIdentifier>;
pendingColor: XStandardType<XColorIdentifier>;
fillColor: XStandardType<XColorIdentifier>;
disabledColor: XStandardType<XColorIdentifier>;
disabledFillColor: XStandardType<XColorIdentifier>;
//
valueChanged: EventEmitter<XFormValueChangeEventModel>;
statusChanged: EventEmitter<XFormStatusChangeEventModel>;
controlFocused: EventEmitter<XBaseFormControlActionModel>;
controlBlured: EventEmitter<XBaseFormControlActionModel>;
controlValueChanged: EventEmitter<XFormControlValueChangeEventModel>;
controlStatusChanged: EventEmitter<XFormControlStatusChangeEventModel>;
}
@Injectable({
providedIn: 'root',
})
export class XFormContainer
extends XComponentCardContainer
implements Readonly<IXFormContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XFormActionModel> =
new Subject<XFormActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
readonly formConfig: XStandardType<XFormConfig> = null;
readonly applyStatusOnControls: XStandardType<boolean> = false;
//
readonly regularColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly accentColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Secondary;
readonly hintColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Tertiary;
readonly activeColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Tertiary;
readonly validColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Success;
readonly invalidColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Danger;
readonly pendingColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Warning;
readonly fillColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.SecondaryTint;
readonly disabledColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.LightTint;
readonly disabledFillColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.LightShade;
//
readonly valueChanged: EventEmitter<XFormValueChangeEventModel> =
new EventEmitter<XFormValueChangeEventModel>();
readonly statusChanged: EventEmitter<XFormStatusChangeEventModel> =
new EventEmitter<XFormStatusChangeEventModel>();
readonly controlFocused: EventEmitter<XBaseFormControlActionModel> =
new EventEmitter<XBaseFormControlActionModel>();
readonly controlBlured: EventEmitter<XBaseFormControlActionModel> =
new EventEmitter<XBaseFormControlActionModel>();
readonly controlValueChanged: EventEmitter<XFormControlValueChangeEventModel> =
new EventEmitter<XFormControlValueChangeEventModel>();
readonly controlStatusChanged: EventEmitter<XFormControlStatusChangeEventModel> =
new EventEmitter<XFormControlStatusChangeEventModel>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XFormContainerComponent
extends XComponentCardContainerComponent
implements IXFormContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XFormActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
formConfig: XStandardType<XFormConfig> = this.propertyProvider.formConfig;
@Input()
applyStatusOnControls: XStandardType<boolean> =
this.propertyProvider.applyStatusOnControls;
//
@Input()
regularColor: XStandardType<XColorIdentifier> =
this.propertyProvider.regularColor;
@Input()
accentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.accentColor;
@Input()
hintColor: XStandardType<XColorIdentifier> = this.propertyProvider.hintColor;
@Input()
activeColor: XStandardType<XColorIdentifier> =
this.propertyProvider.activeColor;
@Input()
validColor: XStandardType<XColorIdentifier> =
this.propertyProvider.validColor;
@Input()
invalidColor: XStandardType<XColorIdentifier> =
this.propertyProvider.invalidColor;
@Input()
pendingColor: XStandardType<XColorIdentifier> =
this.propertyProvider.pendingColor;
@Input()
fillColor: XStandardType<XColorIdentifier> = this.propertyProvider.fillColor;
@Input()
disabledColor: XStandardType<XColorIdentifier> =
this.propertyProvider.disabledColor;
@Input()
disabledFillColor: XStandardType<XColorIdentifier> =
this.propertyProvider.disabledFillColor;
//
@Output()
valueChanged: EventEmitter<XFormValueChangeEventModel> = new EventEmitter();
@Output()
statusChanged: EventEmitter<XFormStatusChangeEventModel> = new EventEmitter();
@Output()
controlFocused: EventEmitter<XBaseFormControlActionModel> = new EventEmitter();
@Output()
controlBlured: EventEmitter<XBaseFormControlActionModel> = new EventEmitter();
@Output()
controlValueChanged: EventEmitter<XFormControlValueChangeEventModel> = new EventEmitter();
@Output()
controlStatusChanged: EventEmitter<XFormControlStatusChangeEventModel> = 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<IXFormContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="v-card v-no-margin-card"
[color]="getValue(cardColor) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[ngClass]="getValue(cardCssClass) | async"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[subTitle]="getResourceValue(cardSubTitle) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" actions *ngIf="getValue(cardShowActions) | async">
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div class="x-footer" footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<div [ngClass]="getCssClasses('container') | async">
<!-- iFrame By ContentURL -->
<ng-container *ngIf="notEmptyValue(contentUrl) | async">
<iframe
[id]="id"
#frameView
scrolling="no"
[src]="contentUrl"
allowtransparency="true"
(load)="onContentLoaded.emit($event)"
*ngIf="notEmptyValue(contentUrl) | async"
[ngClass]="getCssClasses('frame') | async"
></iframe>
</ng-container>
<!-- iFrame By Content -->
<ng-container *ngIf="notEmptyValue(content) | async">
<iframe
[id]="id"
#frameView
scrolling="no"
[srcdoc]="contentHTML"
allowtransparency="true"
*ngIf="notEmptyValue(content) | async"
(load)="onContentLoaded.emit($event)"
[ngClass]="getCssClasses('frame') | async"
></iframe>
</ng-container>
</div>
</ng-template>
### 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<HTMLIFrameElement> = null;
//
@ViewChild('frameView', { static: false })
set frameView(v: ElementRef<HTMLIFrameElement>) {
//
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<XFrameComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Url Changed ...
const isUrlChanged = changeKeys.includes(nameof<XFrameComponent>('url'));
if (isUrlChanged) {
this.prepareContentUrl();
}
//#endregion
//
//#region Content ...
const isContentChanged = changeKeys.includes(
nameof<XFrameComponent>('content')
);
if (isContentChanged) {
this.prepareContent();
}
//#endregion
//
//#region VFrame Props ...
//
//#region Allow ...
const isAllowChanged = changeKeys.includes(
nameof<XFrameComponent>('allow')
);
if (isAllowChanged) {
this.handleAllowChanged();
}
//#endregion
//
//#region FrameLoading ...
const isFrameLoadingChanged = changeKeys.includes(
nameof<XFrameComponent>('frameLoading')
);
if (isFrameLoadingChanged) {
this.handleFrameLoadingChanged();
}
//#endregion
//
//#region FrameReferrerPolicy ...
const isReferrerPolicyChanged = changeKeys.includes(
nameof<XFrameComponent>('referrerPolicy')
);
if (isReferrerPolicyChanged) {
this.handleReferrerPolicyChanged();
}
//#endregion
//
//#region FrameSandbox ...
const isSandboxChanged = changeKeys.includes(
nameof<XFrameComponent>('sandbox')
);
if (isSandboxChanged) {
this.handleSandboxChanged();
}
//#endregion
//
//#region AllowFullScreen ...
const isAllowFullScreenChanged = changeKeys.includes(
nameof<XFrameComponent>('allowFullscreen')
);
if (isAllowFullScreenChanged) {
this.handleAllowFullScreenChanged();
}
//#endregion
//
//#region AllowPaymentRequest ...
const isAllowPaymentRequestChanged = changeKeys.includes(
nameof<XFrameComponent>('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<XFrameActionModel>();
}
//
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<HTMLIFrameElement>
) {
//
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<XFrameActionIdentifier> {}
//
//#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<string>;
content: XStandardType<string>;
onContentLoaded: EventEmitter<any>;
allowFullscreen: XStandardType<boolean>;
actionProvider: Subject<XFrameActionModel>;
allowPaymentRequest: XStandardType<boolean>;
allow: XStandardType<XOneOrManyType<string>>;
cssClass: XStandardType<XOneOrManyType<string>>;
sandbox: XStandardType<XFrameSandboxIdentifier>;
frameLoading: XStandardType<XFrameLoadingIdentifier>;
referrerPolicy: XStandardType<XOneOrManyType<XFrameReferrerPolicyIdentifier>>;
}
@Injectable({
providedIn: 'root',
})
export class XFrameContainer
extends XComponentCardContainer
implements Readonly<IXFrameContainer>
{
//
//#region Props ...
readonly url: XStandardType<string>;
readonly content: XStandardType<string>;
readonly referrerPolicy: XStandardType<
XOneOrManyType<XFrameReferrerPolicyIdentifier>
> = null;
readonly actionProvider: Subject<XFrameActionModel> =
new Subject<XFrameActionModel>();
readonly allow: XStandardType<XOneOrManyType<string>>;
readonly allowFullscreen: XStandardType<boolean> = false;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
readonly allowPaymentRequest: XStandardType<boolean> = false;
readonly sandbox: XStandardType<XFrameSandboxIdentifier> = null;
readonly frameLoading: XStandardType<XFrameLoadingIdentifier> = null;
readonly onContentLoaded: EventEmitter<any> = new EventEmitter<any>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XFrameContainerComponent
extends XComponentCardContainerComponent
implements IXFrameContainer
{
//
//#region Props ...
@Input()
allowFullscreen: XStandardType<boolean> =
this.propertyProvider.allowFullscreen;
@Input()
actionProvider: Subject<XFrameActionModel> =
this.propertyProvider.actionProvider;
@Input()
allowPaymentRequest: XStandardType<boolean> =
this.propertyProvider.allowPaymentRequest;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
sandbox: XStandardType<XFrameSandboxIdentifier> =
this.propertyProvider.sandbox;
@Input()
frameLoading: XStandardType<XFrameLoadingIdentifier> =
this.propertyProvider.frameLoading;
@Input()
url: XStandardType<string> = this.propertyProvider.url;
@Input()
content: XStandardType<string> = this.propertyProvider.content;
@Input()
referrerPolicy: XStandardType<
XOneOrManyType<XFrameReferrerPolicyIdentifier>
> = this.propertyProvider.referrerPolicy;
@Output()
onContentLoaded: EventEmitter<any> = this.propertyProvider.onContentLoaded;
@Input()
allow: XStandardType<XOneOrManyType<string>> = 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<IXFrameContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else holderRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="holderRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Grid Template -->
<ng-template #holderRef>
<div class="x-grid x-wrapper" [class.mobile]="isMobileUi$ | async">
<!-- Handle Childs -->
<ng-container *ngIf="items && items.length > 0">
<ng-container *ngIf="preparedType">
<!-- Item Holder -->
<ng-container
*ngTemplateOutlet="
isTypeLinear()
? linearRef
: isTypeGrid()
? gridRef
: isTypeFlex()
? flexRef
: isTypeStaggedGrid()
? staggedGrid
: nothingRef
"
></ng-container>
</ng-container>
</ng-container>
<!-- Empty Handler -->
<ng-container
*ngIf="
(getValue(showEmpty) | async) &&
(!items || (items && items.length === 0))
"
>
<x-empty
(refresh)="emptyRefresh.emit($event)"
[color]="getValue(emptyColor) | async"
[message]="getResourceValue(emptyMessage) | async"
[refreshIcon]="getValue(emptyRefreshIcon) | async"
[messageColor]="getValue(emptyMessageColor) | async"
[hasRefresh]="getValue(emptyHasRefresh) | async"
[foregroundRefreshButtonColor]="
getValue(emptyForegroundRefreshButtonColor) | async
"
[foregroundColor]="getValue(emptyForegroundColor) | async"
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
></x-empty>
</ng-container>
</div>
</ng-template>
<!-- Linear Ref -->
<ng-template #linearRef>
<!-- -->
<ion-list [ngClass]="getValue(cssClass) | async">
<ng-container *ngFor="let item of items; index as i">
<ion-item lines="none" class="transparent">
<ng-container
*ngTemplateOutlet="itemHolderRef; context: { $implicit: item }"
>
</ng-container>
</ion-item>
</ng-container>
</ion-list>
</ng-template>
<!-- Grid Ref -->
<ng-template #gridRef>
<!-- -->
<ion-grid [ngClass]="getValue(cssClass) | async">
<ng-container *ngFor="let item of items; index as i">
<ng-container *ngIf="isNewRow(i, preparedCols)">
<ng-container
*ngTemplateOutlet="rowRef; context: { $implicit: i }"
></ng-container>
</ng-container>
</ng-container>
</ion-grid>
</ng-template>
<!-- Flex Ref -->
<ng-template #flexRef>
<!-- -->
<div
class="grid-box"
[fxLayoutGap]="gap"
[fxLayout]="layout"
[fxLayoutAlign]="align"
*ngIf="items && items.length > 0"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<ng-container *ngFor="let item of items; index as i">
<div [fxFlexAlign]="'stretch'">
<ng-container
*ngTemplateOutlet="itemHolderRef; context: { $implicit: item }"
>
</ng-container>
</div>
</ng-container>
</div>
</ng-template>
<!-- StaggedGrid Ref -->
<ng-template #staggedGrid>
<gridster
#gridster
*ngIf="options"
[options]="options"
[ngClass]="getValue(cssClass) | async"
[class.inCard]="getValue(wrapWithCard) | async"
>
<gridster-item
[item]="toStaggedGrid(idx)"
*ngFor="let item of items; index as idx"
>
<ng-container
*ngTemplateOutlet="itemHolderRef; context: { $implicit: item }"
>
</ng-container>
</gridster-item>
</gridster>
</ng-template>
<!-- Nothing Ref -->
<ng-template #nothingRef></ng-template>
<!-- Grid Row Template -->
<ng-template #rowRef let-index>
<ion-row>
<ion-col *ngFor="let item of colItems; index as i">
<ng-container
*ngTemplateOutlet="
itemHolderRef;
context: { $implicit: items[i + index] }
"
>
</ng-container>
</ion-col>
</ion-row>
</ng-template>
<!-- Item Holder Template -->
<ng-template #itemHolderRef let-item>
<button
matRipple
*ngIf="item"
class="transparent"
class="x-grid-item-wrapper"
(click)="handleItemSelected(item)"
[hidden]="getItemHide(item) | async"
[disabled]="getItemDisabled(item) | async"
[matRippleDisabled]="
(getItemDisabled(item) | async) || !(getValue(selectableItems) | async)
"
>
<ng-container
*ngTemplateOutlet="
itemTemplate ? itemTemplate : defaultItemRef;
context: { $implicit: item }
"
></ng-container>
</button>
</ng-template>
<!-- Default Item Ref -->
<ng-template #defaultItemRef let-item>
<h5>{{ item | json }}</h5>
</ng-template>
### 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<XGridComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
const isColsChanged = changeKeys.includes(nameof<XGridComponent>('cols'));
const isTypeChanged = changeKeys.includes(nameof<XGridComponent>('type'));
const isOptionsChanged = changeKeys.includes(
nameof<XGridComponent>('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<any>) {
//
if (!item || !item.href) {
return toObservable('');
}
//
return this.getValue(item.href);
}
//
getItemHide(item?: XGridItem<any>) {
//
if (!item || !item.hide) {
return toObservable(false);
}
//
return this.getValue(item.hide);
}
//
getItemDisabled(item?: XGridItem<any>) {
//
if (!item || !item.disabled) {
return toObservable(false);
}
//
return this.getValue(item.disabled);
}
//#endregion
//
//#region Type Detectors ...
//#endregion
//
//#region Actions ...
async handleItemSelected(item: XGridItem<any>) {
//
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<XGridActionModel>();
}
//
// 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<T> {
data: T;
hide?: XStandardType<boolean>;
disabled?: XStandardType<boolean>;
href?: XStandardType<XOneOrManyType<string>>;
}
export interface XStaggedGridOptions extends Partial<GridsterConfig> {}
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<XGridActionIdentifier> {}
//
//#region Inside Card/Empty Container ...
export interface IXGridContainer extends IXCardEmptyContainer {
//
actionProvider: Subject<XGridActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
options: XStandardType<XStaggedGridOptions>;
cols: XStandardType<number>;
type: XStandardType<XGridPresentType>;
gap: string;
layout: string;
align: string;
selectableItems: XStandardType<boolean>;
items: XGridItem<any>[];
itemTemplate: TemplateRef<any>;
//
itemSelected: EventEmitter<XGridItem<any>>;
}
@Injectable({
providedIn: 'root',
})
export class XGridContainer
extends XCardEmptyContainer
implements Readonly<IXGridContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XGridActionModel> =
new Subject<XGridActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly options: XStandardType<XStaggedGridOptions>;
readonly cols: XStandardType<number>;
readonly type: XStandardType<XGridPresentType>;
readonly gap: string = '1px';
readonly layout: string = 'row wrap';
readonly align: string = 'center start';
readonly selectableItems: XStandardType<boolean> = false;
readonly items: XGridItem<any>[];
readonly itemTemplate: TemplateRef<any>;
//
readonly itemSelected: EventEmitter<XGridItem<any>>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XGridContainerComponent
extends XCardEmptyContainerComponent
implements IXGridContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XGridActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
options: XStandardType<XStaggedGridOptions> = this.propertyProvider.options;
@Input()
cols: XStandardType<number> = this.propertyProvider.cols;
@Input()
type: XStandardType<XGridPresentType> = this.propertyProvider.type;
@Input()
gap: string = this.propertyProvider.gap;
@Input()
layout: string = this.propertyProvider.layout;
@Input()
align: string = this.propertyProvider.align;
@Input()
selectableItems: XStandardType<boolean> =
this.propertyProvider.selectableItems;
@Input()
items: XGridItem<any>[] = this.propertyProvider.items;
@Input()
itemTemplate: TemplateRef<any> = this.propertyProvider.itemTemplate;
//
@Output()
itemSelected: EventEmitter<XGridItem<any>> = 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<IXGridContainer> {
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
<!-- Wrapper -->
<div
*ngIf="getValue(name) | async"
[slot]="getValue(slot) | async"
(click)="handleClicked($event)"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[isForeground]="getValue(foregroundColor) | async"
class="x-icon x-wrapper ion-no-margin ion-no-padding"
[class.ion-activatable]="
(getValue(selectable) | async) || (getValue(clickable) | async)
"
[class.rtl]="(getValue(applyDirection) | async) && managerService.isRtl"
>
<!-- Ripple Effect -->
<ion-ripple-effect
*ngIf="
!(getValue(uiDisabled) | async) &&
((getValue(selectable) | async) || (getValue(clickable) | async))
"
></ion-ripple-effect>
<!-- Regular Icons -->
<ion-icon
class="ion-no-margin ion-no-padding"
[name]="!(isCustomIcon() | async) ? (icon | async) : ''"
[src]="(isCustomIcon() | async) ? (customIconUrl() | async) : ''"
>
</ion-icon>
</div>
### 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<XIconComponent>('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<XIconActionModel>();
}
//
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<XIconActionIdentifier> {}
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<XIconActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
slot: XStandardType<XIconSlot>;
name: XStandardType<XIconIdentifier>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
applyDirection: XStandardType<boolean>;
//
selectable: XStandardType<boolean>;
clickable: XStandardType<boolean>;
clicked: EventEmitter<Event>;
}
@Injectable({
providedIn: 'root',
})
export class XIconContainer
extends XBaseContainer
implements Readonly<IXIconContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XIconActionModel> =
new Subject<XIconActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly slot: XStandardType<XIconSlot> = 'start';
readonly name: XStandardType<XIconIdentifier>;
//
readonly color: XStandardType<XColorIdentifier>;
readonly foregroundColor: XStandardType<boolean> = true;
readonly selectable: XStandardType<boolean> = false;
readonly clickable: XStandardType<boolean> = false;
readonly applyDirection: XStandardType<boolean> = false;
//
readonly clicked = new EventEmitter<Event>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XIconContainerComponent
extends XBaseContainerComponent
implements IXIconContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XIconActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
slot: XStandardType<XIconSlot> = this.propertyProvider.slot;
@Input()
name: XStandardType<XIconIdentifier> = this.propertyProvider.name;
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
@Input()
selectable: XStandardType<boolean> = this.propertyProvider.selectable;
@Input()
clickable: XStandardType<boolean> = this.propertyProvider.clickable;
@Input()
applyDirection: XStandardType<boolean> = this.propertyProvider.applyDirection;
@Output()
clicked: EventEmitter<Event> = new EventEmitter<Event>();
//#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<IXIconContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[subTitle]="getResourceValue(cardSubTitle) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" actions *ngIf="getValue(cardShowActions) | async">
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div class="x-footer" footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<div
class="x-component-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<!-- Toolbar -->
<x-action-bar
[color]="actionBarColor"
[cssClass]="actionBarCssClass"
[actionProvider]="actionBarActionProvider"
[foregroundColor]="actionBarForegroundColor"
(actionFired)="handleActionBarActionFired($event)"
*ngIf="
(getValue(showActionBar) | async) &&
(hasChildValue(actionBarActions) | async) &&
(hasChildValue(availableActionBarItems) | async)
"
[actions]="getArrayValue(actionBarActions) | async"
></x-action-bar>
<!-- Tabs -->
<ng-container *ngIf="(countChildsValue(Sessions) | async) > 1">
<x-tabs
[loopTabs]="true"
[swipable]="false"
[actionProvider]="tabsActionProvider"
[alignTabs]="getValue(alignTabs) | async"
[headerPosition]="TabHeaderPositions.ABOVE"
[tabIndicatorColor]="ColorNames.Transparent"
[headerColor]="getValue(tabHeaderColor) | async"
[activeTabColor]="getValue(activeTabColor) | async"
(selectedTabChange)="handleTabsSelectedTabChanged($event)"
>
<x-tab *ngFor="let tab of Sessions">
<div x-tab-label>
{{ tab.name }}
</div>
</x-tab>
</x-tabs>
</ng-container>
<!-- Editor -->
<div class="code-editor" #codeEditor></div>
</div>
</ng-template>
### 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<string>();
//
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<XTabsActionModel>();
//#endregion
//
@ViewChild('codeEditor')
codeEditorElmRef: ElementRef<HTMLDivElement>;
@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<void> {
//
//#region Action Provider Changed ...
//
const isActionProviderChaged = changeKeys.includes(
nameof<XIDEComponent>('actionProvider')
);
if (isActionProviderChaged) {
this.registerActionProvider();
}
//#endregion
//
//#region Theme Changed ...
const isThemeChanged = changeKeys.includes(nameof<XIDEComponent>('theme'));
if (isThemeChanged) {
this.setTheme(this.theme);
}
//#endregion
//
//#region Mode Changed ...
const isModeChanged = changeKeys.includes(nameof<XIDEComponent>('mode'));
if (isModeChanged) {
this.setMode(this.mode);
}
//#endregion
//
//#region MinLines Changed ...
const isMinLinesChanged = changeKeys.includes(
nameof<XIDEComponent>('minLines')
);
if (isMinLinesChanged) {
this.setMinLines(this.minLines);
}
//#endregion
//
//#region MaxLines Changed ...
const isMaxLinesChanged = changeKeys.includes(
nameof<XIDEComponent>('maxLines')
);
if (isMaxLinesChanged) {
this.setMaxLines(this.maxLines);
}
//#endregion
//
//#region FontSize Changed ...
const isFontSizeChanged = changeKeys.includes(
nameof<XIDEComponent>('fontSize')
);
if (isFontSizeChanged) {
this.setFontSize(this.fontSize);
}
//#endregion
//
//#region Readonly Changed ...
const isReadonlyChanged = changeKeys.includes(
nameof<XIDEComponent>('readonly')
);
if (isReadonlyChanged) {
this.setReadOnly(this.readonly);
}
//#endregion
//
//#region Content Changed ...
const isContentChanged = changeKeys.includes(
nameof<XIDEComponent>('content')
);
if (isContentChanged) {
this.setContent(this.content);
}
//#endregion
//
//#region WordWrapping Changed ...
const isWordWrappingChanged = changeKeys.includes(
nameof<XIDEComponent>('wordWrapping')
);
if (isWordWrappingChanged) {
this.setWordWrapping(this.wordWrapping);
}
//#endregion
//
//#region ShowPrintMargin Changed ...
const isShowPrintMarginChanged = changeKeys.includes(
nameof<XIDEComponent>('showPrintMargin')
);
if (isShowPrintMarginChanged) {
this.setShowPrintMargin(this.showPrintMargin);
}
//#endregion
//
//#region HighlightActiveLine Changed ...
const isHighlightActiveLineChanged = changeKeys.includes(
nameof<XIDEComponent>('highlightActiveLine')
);
if (isHighlightActiveLineChanged) {
this.setHighlightActiveLine(this.highlightActiveLine);
}
//#endregion
//
//#region BasicAutocompletion Changed ...
const isBasicAutocompletionChanged = changeKeys.includes(
nameof<XIDEComponent>('basicAutocompletion')
);
if (isBasicAutocompletionChanged) {
this.setBasicAutocompletion(this.basicAutocompletion);
}
//#endregion
//
//#region DefaultTabName Changed ...
const isDefaultTabNameChanged = changeKeys.includes(
nameof<XIDEComponent>('defaultTabName')
);
if (isDefaultTabNameChanged) {
await this.handleDefaultTabNameChanged(this.defaultTabName);
}
//#endregion
//
//#region ActionBar ...
const isDefaultActionBarItemColorChanged = changeKeys.includes(
nameof<XIDEComponent>('defaultActionBarItemColor')
);
const isAvailableActionBarItemsChanged = changeKeys.includes(
nameof<XIDEComponent>('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<XIDEThemeIdentifier>) {
//
if (isNullOrUndefined(this.CODE_EDITOR)) {
return;
}
//
this.getValue(theme).subscribe((value) => {
//
if (isNullOrEmptyString(value)) {
return;
}
//
this.CODE_EDITOR.setTheme(value);
});
}
setMode (mode: XStandardType<XIDEModeIdentifier>) {
//
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<number>) {
//
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<number>) {
//
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<number>) {
//
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<boolean>) {
//
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<boolean>) {
//
if (isNullOrUndefined(this.CODE_EDITOR)) {
return;
}
//
this.getValue(highlightActiveLine).subscribe((value) => {
//
this.CODE_EDITOR.setOption('highlightActiveLine', value);
this.detectChanges();
});
}
setBasicAutocompletion (basicAutocompletion: XStandardType<boolean>) {
//
if (isNullOrUndefined(this.CODE_EDITOR)) {
return;
}
//
this.getValue(basicAutocompletion).subscribe((value) => {
//
this.CODE_EDITOR.setOption('enableBasicAutocompletion' as any, value);
this.detectChanges();
});
}
setWordWrapping (wordWrapping: XStandardType<boolean>) {
//
if (isNullOrUndefined(this.CODE_EDITOR)) {
return;
}
//
this.getValue(wordWrapping).subscribe((value) => {
//
this.CODE_EDITOR.getSession().setUseWrapMode(value);
this.detectChanges();
});
}
setShowLineNumbers (showLineNumbers: XStandardType<boolean>) {
//
if (isNullOrUndefined(this.CODE_EDITOR)) {
return;
}
//
this.getValue(showLineNumbers).subscribe((value) => {
//
this.CODE_EDITOR.setOption('showLineNumbers', value);
this.detectChanges();
});
}
setShowPrintMargin (showPrintMargin: XStandardType<boolean>) {
//
if (isNullOrUndefined(this.CODE_EDITOR)) {
return;
}
//
this.getValue(showPrintMargin).subscribe((value) => {
//
this.CODE_EDITOR.setShowPrintMargin(value);
this.detectChanges();
});
}
setShowFoldWidgets (showFoldWidgets: XStandardType<boolean>) {
//
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<string>) {
//
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<XIDETabDescriptor, 'canSave' | 'canBeautify'>
) {
//
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<XIDETabDescriptor>('canSave')
);
const hasCanBeautify = optionsKeys.includes(
nameof<XIDETabDescriptor>('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<XIDETabDescriptor, 'name' | 'mode' | 'content' | 'forceShow'>
) {
//
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<Pick<XIDETabDescriptor, 'name' | 'mode' | 'content'>>
) {
//
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<XIDEActionModel>();
}
//
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<string>
) {
//
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<XIDEActionIdentifier> {}
//#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<ace.Ace.EditorOptions> & 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<string>;
minLines: XStandardType<number>;
maxLines: XStandardType<number>;
fontSize: XStandardType<number>;
readonly: XStandardType<boolean>;
contentChange: EventEmitter<string>;
wordWrapping: XStandardType<boolean>;
defaultTabName: XStandardType<string>;
showLineNumbers: XStandardType<boolean>;
showPrintMargin: XStandardType<boolean>;
showFoldWidgets: XStandardType<boolean>;
mode: XStandardType<XIDEModeIdentifier>;
actionProvider: Subject<XIDEActionModel>;
theme: XStandardType<XIDEThemeIdentifier>;
highlightActiveLine: XStandardType<boolean>;
basicAutocompletion: XStandardType<boolean>;
hasCloseOnDefaultTab: XStandardType<boolean>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
//#region Tabs ...
alignTabs: XStandardType<XTabAlignIdentifier>;
tabHeaderColor: XStandardType<XColorIdentifier>;
activeTabColor: XStandardType<XColorIdentifier>;
//#endregion
//
//#region ActionBar ...
defaultActionBarItemColor: XStandardType<XColorIdentifier>;
availableActionBarItems: XStandardType<
XOneOrManyType<XIDEAvailableActionBarItem>
>;
//#endregion
//#endregion
}
@Injectable({
providedIn: 'root',
})
export class XIDEContainer extends XBaseContainer implements IXIDEContainer {
//
//#region Props ...
//
//#region Self Props ...
readonly content: XStandardType<string> = '';
readonly minLines: XStandardType<number> = 10;
readonly fontSize: XStandardType<number> = XIDEMinFontSize;
readonly readonly: XStandardType<boolean> = false;
readonly actionProvider: Subject<XIDEActionModel> =
new Subject<XIDEActionModel>();
readonly maxLines: XStandardType<number> = Infinity;
readonly wordWrapping: XStandardType<boolean> = true;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
readonly showLineNumbers: XStandardType<boolean> = true;
readonly showFoldWidgets: XStandardType<boolean> = true;
readonly showPrintMargin: XStandardType<boolean> = false;
readonly highlightActiveLine: XStandardType<boolean> = true;
readonly basicAutocompletion: XStandardType<boolean> = true;
readonly hasCloseOnDefaultTab: XStandardType<boolean> = false;
readonly defaultTabName: XStandardType<string> = XIDEDefaultTabName;
readonly mode: XStandardType<XIDEModeIdentifier> = XIDEMode.Typescript;
readonly theme: XStandardType<XIDEThemeIdentifier> = XIDETheme.Dracula;
readonly contentChange: EventEmitter<string> = new EventEmitter<string>();
//
//#region Tabs ...
readonly alignTabs: XStandardType<XTabAlignIdentifier> = XTabAlign.START;
readonly tabHeaderColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly activeTabColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Warning;
//#endregion
//
readonly availableActionBarItems: XStandardType<
XOneOrManyType<XIDEAvailableActionBarItem>
> = [
{
actionId: XIDEActionBarItem.Save,
},
{
actionId: XIDEActionBarItem.Close,
},
{
actionId: XIDEActionBarItem.Undo,
},
{
actionId: XIDEActionBarItem.Redo,
},
{
actionId: XIDEActionBarItem.Beautify,
},
{
actionId: XIDEActionBarItem.ChangeTheme,
},
{
actionId: XIDEActionBarItem.ChangeMode,
},
];
readonly defaultActionBarItemColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
//#endregion
//
//#region ComponentCard Props ...
readonly isInPage: XStandardType<boolean> =
this.cardPropertyProvider.isInPage;
readonly wrapWithCard: XStandardType<boolean> =
this.cardPropertyProvider.wrapWithCard;
readonly cardActionProvider: Subject<XCardActionModel> =
this.cardPropertyProvider.cardActionProvider;
readonly cardCssClass: XStandardType<XOneOrManyType<string>> =
this.cardPropertyProvider.cardCssClass;
readonly cardColor: XStandardType<XColorIdentifier> =
this.cardPropertyProvider.cardColor;
readonly cardForegroundColor: XStandardType<boolean> =
this.cardPropertyProvider.cardForegroundColor;
readonly cardTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardTitle;
readonly cardSubTitle: XStandardType<XResourceIdentifier> =
this.cardPropertyProvider.cardSubTitle;
readonly cardShowFooter: XStandardType<boolean> =
this.cardPropertyProvider.cardShowFooter;
readonly cardShowActions: XStandardType<boolean> =
this.cardPropertyProvider.cardShowActions;
//#endregion
//
//#region ComponentActionBar Props ...
readonly showActionBar: XStandardType<boolean> =
this.actionBarPropertyProvider.showActionBar;
readonly actionBarActionProvider: Subject<XActionBarActionModel> =
this.actionBarPropertyProvider.actionBarActionProvider;
readonly actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.actionBarPropertyProvider.actionBarCssClass;
readonly actionBarColor: XStandardType<XColorIdentifier> =
this.actionBarPropertyProvider.actionBarColor;
readonly actionBarForegroundColor: XStandardType<boolean> =
this.actionBarPropertyProvider.actionBarForegroundColor;
readonly actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.actionBarPropertyProvider.actionBarActions;
readonly actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
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<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
defaultTabName: XStandardType<string> = this.propertyProvider.defaultTabName;
@Input()
hasCloseOnDefaultTab: XStandardType<boolean> = this.propertyProvider.hasCloseOnDefaultTab;
@Input()
theme: XStandardType<XIDEThemeIdentifier> = this.propertyProvider.theme;
@Input()
mode: XStandardType<XIDEModeIdentifier> = this.propertyProvider.mode;
@Input()
minLines: XStandardType<number> = this.propertyProvider.minLines;
@Input()
maxLines: XStandardType<number> = this.propertyProvider.maxLines;
@Input()
fontSize: XStandardType<number> = this.propertyProvider.fontSize;
@Input()
readonly: XStandardType<boolean> = this.propertyProvider.readonly;
@Input()
highlightActiveLine: XStandardType<boolean> =
this.propertyProvider.highlightActiveLine;
@Input()
wordWrapping: XStandardType<boolean> = this.propertyProvider.wordWrapping;
@Input()
showLineNumbers: XStandardType<boolean> =
this.propertyProvider.showLineNumbers;
@Input()
showPrintMargin: XStandardType<boolean> =
this.propertyProvider.showPrintMargin;
@Input()
showFoldWidgets: XStandardType<boolean> =
this.propertyProvider.showFoldWidgets;
@Input()
basicAutocompletion: XStandardType<boolean> =
this.propertyProvider.basicAutocompletion;
@Input()
content: XStandardType<string> = this.propertyProvider.content;
//
@Input()
actionProvider: Subject<XIDEActionModel> =
this.propertyProvider.actionProvider;
@Output()
contentChange: EventEmitter<string> = this.propertyProvider.contentChange;
//
//#region Tabs ...
@Input()
alignTabs: XStandardType<XTabAlignIdentifier> =
this.propertyProvider.alignTabs;
@Input()
tabHeaderColor: XStandardType<XColorIdentifier> =
this.propertyProvider.tabHeaderColor;
@Input()
activeTabColor: XStandardType<XColorIdentifier> =
this.propertyProvider.activeTabColor;
//#endregion
//
//#region ActionBar ...
@Input()
defaultActionBarItemColor: XStandardType<XColorIdentifier> =
this.propertyProvider.defaultActionBarItemColor;
@Input()
availableActionBarItems: XStandardType<
XOneOrManyType<XIDEAvailableActionBarItem>
> = this.propertyProvider.availableActionBarItems;
//#endregion
//#endregion
//
//#region ComponentCard Props ...
@Input()
isInPage: XStandardType<boolean> = this.propertyProvider.isInPage;
@Input()
wrapWithCard: XStandardType<boolean> = this.propertyProvider.wrapWithCard;
@Input()
cardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
@Input()
cardColor: XStandardType<XColorIdentifier> = this.propertyProvider.cardColor;
@Input()
cardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
@Input()
cardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
@Input()
cardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
@Input()
cardShowFooter: XStandardType<boolean> = this.propertyProvider.cardShowFooter;
@Input()
cardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
@Input()
cardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
//#endregion
//
//#region ComponentActionBar Props ...
@Input()
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
@Input()
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.actionBarCssClass;
@Input()
actionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.actionBarColor;
@Input()
actionBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.actionBarForegroundColor;
@Input()
actionBarActionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.actionBarActionProvider;
@Output()
actionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
this.propertyProvider.actionBarActionFired;
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
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<IXIDEContainer> {
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
<div
xOnEscPress="onCancel()"
[style.text-align]="alignImage"
class="x-image-croppert x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<img
#sourceImage
class="source-image"
[src]="safeImgDataUrl"
(load)="handleImageLoadedInView()"
[style.visibility]="imageVisible ? 'visible' : 'hidden'"
/>
<div
class="cropper"
*ngIf="imageVisible"
[class.rounded]="roundCropper"
[style.top.px]="cropper.y1"
[style.left.px]="cropper.x1"
[style.width.px]="cropper.x2 - cropper.x1"
[style.height.px]="cropper.y2 - cropper.y1"
[style.margin-left]="alignImage === 'center' ? marginLeft : null"
[style.visibility]="imageVisible ? 'visible' : 'hidden'"
>
<div
(mousedown)="handleStartMove($event, 'move')"
(touchstart)="handleStartMove($event, 'move')"
class="move"
>
&nbsp;
</div>
<span
class="resize topleft"
(mousedown)="handleStartMove($event, 'resize', 'topleft')"
(touchstart)="handleStartMove($event, 'resize', 'topleft')"
><span class="square"></span
></span>
<span class="resize top"><span class="square"></span></span>
<span
class="resize topright"
(mousedown)="handleStartMove($event, 'resize', 'topright')"
(touchstart)="handleStartMove($event, 'resize', 'topright')"
><span class="square"></span
></span>
<span class="resize right"><span class="square"></span></span>
<span
class="resize bottomright"
(mousedown)="handleStartMove($event, 'resize', 'bottomright')"
(touchstart)="handleStartMove($event, 'resize', 'bottomright')"
><span class="square"></span
></span>
<span class="resize bottom"><span class="square"></span></span>
<span
class="resize bottomleft"
(mousedown)="handleStartMove($event, 'resize', 'bottomleft')"
(touchstart)="handleStartMove($event, 'resize', 'bottomleft')"
><span class="square"></span
></span>
<span class="resize left"><span class="square"></span></span>
<span
class="resize-bar top"
(mousedown)="handleStartMove($event, 'resize', 'top')"
(touchstart)="handleStartMove($event, 'resize', 'top')"
></span>
<span
class="resize-bar right"
(mousedown)="handleStartMove($event, 'resize', 'right')"
(touchstart)="handleStartMove($event, 'resize', 'right')"
></span>
<span
class="resize-bar bottom"
(mousedown)="handleStartMove($event, 'resize', 'bottom')"
(touchstart)="handleStartMove($event, 'resize', 'bottom')"
></span>
<span
class="resize-bar left"
(mousedown)="handleStartMove($event, 'resize', 'left')"
(touchstart)="handleStartMove($event, 'resize', 'left')"
></span>
</div>
<div class="actions" fxLayout="col" fxLayoutAlign="space-between center">
<button color="primary" mat-raised-button (click)="handleCancel()">
<x-icon [name]="'cancel'"></x-icon>
</button>
<button color="primary" mat-raised-button (click)="handleRotateLeft()">
<x-icon [name]="'rotate_left'"></x-icon>
</button>
<button color="primary" mat-raised-button (click)="handleFlipHorizontal()">
<x-icon [name]="'swap_horiz'"></x-icon>
</button>
<button color="primary" mat-raised-button (click)="handleFlipVertical()">
<x-icon [name]="'swap_vert'"></x-icon>
</button>
<button color="primary" mat-raised-button (click)="handleRotateRight()">
<x-icon [name]="'rotate_right'"></x-icon>
</button>
<button color="primary" mat-raised-button (click)="handleOk()">
<x-icon [name]="'done'"></x-icon>
</button>
</div>
</div>
### 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<XImageCropperComponent>
) {
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<XImageCropperComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region ImageFileChanged ...
const isImageFileChangedChanged = changeKeys.includes(
nameof<XImageCropperComponent>('imageFileChanged')
);
if (isImageFileChangedChanged) {
//
this.initCropper();
if (this.imageFileChanged) {
this.loadImageFile(this.imageFileChanged);
}
}
//#endregion
//
//#region Image Changed Event Changed ...
const isImageChangedEventChanged = changeKeys.includes(
nameof<XImageCropperComponent>('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<XImageCropperComponent>('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<XImageCropperComponent>('aspectRatio')
);
if (isAspectRatioChanged && this.imageVisible) {
this.resetCropperPosition();
}
//#endregion
//
//#region ImageBase64 Changed ...
const isImageBase64Changed = changeKeys.includes(
nameof<XImageCropperComponent>('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<XImageCroppedEvent>).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<XImageCroppedEvent> | 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<XImageCropperActionModel>();
}
//
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<XImageCroppedEvent> {
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<Blob | null> {
return this.getCanvasBlob(cropCanvas).then((result: Blob | null) => {
if (result) {
this.imageCroppedFile.emit(result);
}
return result;
});
}
private getCanvasBlob(cropCanvas: HTMLCanvasElement): Promise<Blob | null> {
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<XImageCropperComponent>;
//
// tslint:disable-next-line:no-output-on-prefix
@Output()
onResult = new EventEmitter<XImageCropperResult>();
//
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<XImageCropperActionIdentifier> {}
//
//#region Container ...
export interface IXImageCropperContainer extends IXBaseContainer {
//
actionProvider: Subject<XImageCropperActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
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<void>;
imageCropped: EventEmitter<XImageCroppedEvent>;
imageCroppedBase64: EventEmitter<string>;
imageCroppedFile: EventEmitter<Blob>;
imageLoaded: EventEmitter<void>;
cropperReady: EventEmitter<void>;
loadImageFailed: EventEmitter<void>;
}
@Injectable({
providedIn: 'root',
})
export class XImageCropperContainer
extends XBaseContainer
implements Readonly<IXImageCropperContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XImageCropperActionModel> =
new Subject<XImageCropperActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
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<void> = new EventEmitter<void>();
readonly imageCropped: EventEmitter<XImageCroppedEvent> =
new EventEmitter<XImageCroppedEvent>();
readonly imageCroppedBase64: EventEmitter<string> =
new EventEmitter<string>();
readonly imageCroppedFile: EventEmitter<Blob> = new EventEmitter<Blob>();
readonly imageLoaded: EventEmitter<void> = new EventEmitter<void>();
readonly cropperReady: EventEmitter<void> = new EventEmitter<void>();
readonly loadImageFailed: EventEmitter<void> = new EventEmitter<void>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XImageCropperContainerComponent
extends XBaseContainerComponent
implements IXImageCropperContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XImageCropperActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
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<void> = new EventEmitter();
@Output()
imageCropped: EventEmitter<XImageCroppedEvent> = new EventEmitter();
@Output()
imageCroppedBase64: EventEmitter<string> = new EventEmitter();
@Output()
imageCroppedFile: EventEmitter<Blob> = new EventEmitter();
@Output()
imageLoaded: EventEmitter<void> = new EventEmitter();
@Output()
cropperReady: EventEmitter<void> = new EventEmitter();
@Output()
loadImageFailed: EventEmitter<void> = 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<IXImageCropperContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else listRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="listRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- List ItSelf Template -->
<ng-template #listRef>
<div class="x-list x-wrapper" [class.mobile]="isMobileUi$ | async">
<!-- Action and Search Area Container -->
<div
class="x-list-toolbar"
*ngIf="getValue(showToolbar) | async"
[class.sticky]="getValue(stickyToolbar) | async"
>
<!-- ActionBar -->
<x-action-bar
*ngIf="getValue(showActionBar) | async"
[color]="getValue(actionBarColor) | async"
[actionProvider]="actionBarActionProvider"
[cssClass]="getValue(actionBarCssClass) | async"
(actionFired)="handleActionBarActionFired($event)"
[actions]="getArrayValue(actionBarActions) | async"
[foregroundColor]="getValue(actionBarForegroundColor) | async"
></x-action-bar>
<!-- SearchBar -->
<x-search-bar
(queryChange)="filterItems($event)"
*ngIf="getValue(showSearchBar) | async"
(onEvent)="searchBarOnEvent.emit($event)"
[type]="getValue(searchBarType) | async"
[actionProvider]="searchBarActionProvider"
[color]="getValue(searchBarColor) | async"
[value]="getValue(searchBarValue) | async"
[debounce]="getValue(searchBarDebounce) | async"
[cssClass]="getValue(searchBarCssClass) | async"
[title]="getResourceValue(searchBarTitle) | async"
[spellcheck]="getValue(searchBarSpellcheck) | async"
[foregroundSearchInputColor]="
getValue(searchBarForegroundSearchInputColor) | async
"
[enterKeyHint]="getValue(searchBarEnterKeyHint) | async"
[keyboardType]="getValue(searchBarKeyboardType) | async"
[clearButtonIcon]="getValue(searchBarClearButtonIcon) | async"
[foregroundColor]="getValue(searchBarForegroundColor) | async"
[searchButtonIcon]="getValue(searchBarSearchButtonIcon) | async"
[searchInputColor]="getValue(searchBarSearchInputColor) | async"
[cancelButtonIcon]="getValue(searchBarCancelButtonIcon) | async"
[showCancelButton]="getValue(searchBarShowCancelButton) | async"
[cancelButtonTitle]="getValue(searchBarCancelButtonTitle) | async"
[clearButtonIconColor]="getValue(searchBarClearButtonIconColor) | async"
[searchButtonIconColor]="
getValue(searchBarSearchButtonIconColor) | async
"
></x-search-bar>
</div>
<!-- List -->
<ion-list
#list
class="ion-no-padding ion-no-margin"
[ngClass]="getValue(cssClass) | async"
*ngIf="hasChildValue(filteredItems) | async"
>
<ion-reorder-group
id="reorder"
disabled="false"
(ionItemReorder)="handleDoReorderItems($event)"
>
<ng-container *ngFor="let item of filteredItems; let idx = index">
<ng-container
*ngTemplateOutlet="
(getValue(showOptionsAsSlide) | async) &&
(hasChildValue(item.slideOptions) | async)
? slidingItemRef
: nonSlidingItemRef;
context: { item: item, index: idx }
"
></ng-container>
</ng-container>
</ion-reorder-group>
</ion-list>
<!-- Empty List Handler -->
<ng-container
*ngIf="
!filteredItems ||
(filteredItems &&
filteredItems.length === 0 &&
(getValue(showEmpty) | async))
"
>
<ng-container *ngTemplateOutlet="defaultEmptyListRef"></ng-container>
</ng-container>
</div>
</ng-template>
<!-- Sliding Item Ref -->
<ng-template #slidingItemRef let-item="item" let-index="index">
<ion-item-sliding
#slide
[xColor]="getValue(color) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<!-- Item It Self Clickable -->
<ion-item
class="item slidable"
xStopClickPropagation
[button]="clickableItems"
[xColor]="getValue(color) | async"
[lines]="getIonItemLine() | async"
[class.mobile]="isMobileUi$ | async"
(click)="handleActionItemSelected(item)"
[disabled]="getValue(item.disabled) | async"
[class.ion-hide]="getValue(item.hide) | async"
[class.in-card]="getValue(wrapWithCard) | async"
[detail]="getValue(item.showDetailedIcon) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<ng-container
*ngTemplateOutlet="itemHolderRef; context: { item: item, index: index }"
>
</ng-container>
<!-- Itemp ReOrdering -->
<ion-reorder slot="end" *ngIf="enableReordering"></ion-reorder>
<!-- Menu Button -->
<ion-button
slot="end"
class="x-menu"
[xColor]="'inherit'"
xStopClickPropagation
[class.button-solid]="false"
[disabled]="getValue(item.disabled) | async"
*ngIf="
(getValue(showItemOptions) | async) &&
(getValue(showOptionsAsMenu) | async) &&
(hasChildValue(item.slideOptions) | async)
"
(click)="handleMoreButtonClicked($event, slide, item)"
>
<x-icon [name]="'menu_vertical'"></x-icon>
</ion-button>
</ion-item>
<!-- Item End Menus -->
<ion-item-options
side="end"
*ngIf="
(getValue(showItemOptions) | async) &&
(hasChildValue(item.slideOptions) | async)
"
>
<ion-item-option
xStopClickPropagation
[slot]="getOptionSlot(option) | async"
[color]="getValue(option.color) | async"
[matTooltip]="getResourceValue(option.title) | async"
*ngFor="let option of getEndSlides(item)"
[disabled]="
(getValue(item.disabled) | async) ||
(getValue(option.disabled) | async)
"
(click)="handleActionOptionSelected(slide, option.id, item)"
>
<ng-container
*ngTemplateOutlet="
slidingOptionTemplate
? slidingOptionTemplate
: defaultSlidingOptionRef;
context: { $implicit: option }
"
></ng-container>
</ion-item-option>
</ion-item-options>
<!-- Item Start Menus -->
<ion-item-options
side="start"
*ngIf="
(getValue(showItemOptions) | async) &&
(hasChildValue(item.slideOptions) | async)
"
>
<ion-item-option
xStopClickPropagation
[slot]="getOptionSlot(option) | async"
[color]="getValue(option.color) | async"
[matTooltip]="getResourceValue(option.title) | async"
*ngFor="let option of getStartSlides(item)"
[disabled]="
(getValue(item.disabled) | async) ||
(getValue(option.disabled) | async)
"
(click)="handleActionOptionSelected(slide, option.id, item)"
>
<ng-container
*ngTemplateOutlet="
slidingOptionTemplate
? slidingOptionTemplate
: defaultSlidingOptionRef;
context: { $implicit: option }
"
></ng-container>
</ion-item-option>
</ion-item-options>
</ion-item-sliding>
</ng-template>
<!-- Non Sliding Item Ref -->
<ng-template #nonSlidingItemRef let-item="item" let-index="index">
<!-- Item It Self -->
<ion-item
xStopClickPropagation
class="item not-slideable"
[button]="clickableItems"
[xColor]="getValue(color) | async"
[lines]="getIonItemLine() | async"
[class.mobile]="isMobileUi$ | async"
(click)="handleActionItemSelected(item)"
[disabled]="getValue(item.disabled) | async"
[class.ion-hide]="getValue(item.hide) | async"
[class.in-card]="getValue(wrapWithCard) | async"
[isForeground]="getValue(foregroundColor) | async"
[detail]="getValue(item.showDetailedIcon) | async"
>
<ng-container
*ngTemplateOutlet="itemHolderRef; context: { item: item, index: index }"
>
</ng-container>
<!-- Menu Button -->
<ion-button
slot="end"
class="x-menu"
[xColor]="'inherit'"
xStopClickPropagation
[class.button-solid]="false"
[disabled]="getValue(item.disabled) | async"
*ngIf="
(getValue(showItemOptions) | async) &&
(getValue(showOptionsAsMenu) | async) &&
(hasChildValue(item.slideOptions) | async)
"
(click)="handleMoreButtonClicked($event, null, item)"
>
<x-icon [name]="'menu_vertical'"></x-icon>
</ion-button>
<!-- Item Menus -->
<ion-buttons
slot="end"
*ngIf="
(getValue(showItemOptions) | async) &&
!(getValue(showOptionsAsMenu) | async) &&
(hasChildValue(item.slideOptions) | async)
"
>
<!-- Start Options -->
<ion-button
xStopClickPropagation
[slot]="getOptionSlot(option) | async"
[color]="getValue(option.color) | async"
[disabled]="
(getValue(item.disabled) | async) ||
(getValue(option.disabled) | async)
"
*ngFor="let option of getStartSlides(item)"
[matTooltip]="getResourceValue(option.title) | async"
(click)="handleActionOptionSelected(null, option.id, item)"
>
<ng-container
*ngTemplateOutlet="
nonSlidingOptionTemplate
? nonSlidingOptionTemplate
: defaultNonSlidingOptionRef;
context: { $implicit: option }
"
></ng-container>
</ion-button>
<!-- End Options -->
<ion-button
xStopClickPropagation
[slot]="getOptionSlot(option) | async"
[color]="getValue(option.color) | async"
[disabled]="
(getValue(item.disabled) | async) ||
(getValue(option.disabled) | async)
"
*ngFor="let option of getEndSlides(item)"
[matTooltip]="getResourceValue(option.title) | async"
(click)="handleActionOptionSelected(null, option.id, item)"
>
<ng-container
*ngTemplateOutlet="
nonSlidingOptionTemplate
? nonSlidingOptionTemplate
: defaultNonSlidingOptionRef;
context: { $implicit: option }
"
></ng-container>
</ion-button>
</ion-buttons>
<!-- Itemp ReOrdering -->
<ion-reorder
slot="end"
*ngIf="
(getValue(enableReordering) | async) &&
(countChildsValue(items) | async) ===
(countChildsValue(filteredItems) | async)
"
></ion-reorder>
</ion-item>
</ng-template>
<!-- Item Holder Template -->
<ng-template #itemHolderRef let-item="item" let-index="index">
<!-- Itemp Template -->
<ng-container
*ngTemplateOutlet="
itemTemplate ? itemTemplate : defaultItemRef;
context: { item: item, index: index }
"
>
</ng-container>
<!-- Itemp Checkbox -->
<ion-checkbox
slot="start"
class="x-check"
[checked]="item.isSelected"
*ngIf="getValue(selectableItems) | async"
[disabled]="getValue(item.disabled) | async"
></ion-checkbox>
</ng-template>
<!-- Default Sliding Option Ref -->
<ng-template #defaultSlidingOptionRef let-option>
<ion-item lines="none">
<ion-label
*ngIf="
(notEmptyValue(option.title) | async) &&
(getOptionOnlyIcon(option) | async) === false
"
>{{ getResourceValue(option.title) | async }}</ion-label
>
<x-icon
*ngIf="option.icon"
[foregroundColor]="false"
[name]="getValue(option.icon) | async"
[color]="getValue(option.color) | async"
></x-icon>
</ion-item>
</ng-template>
<!-- Default Non Sliding Option Ref -->
<ng-template #defaultNonSlidingOptionRef let-option>
<ng-container *ngIf="!(getOptionOnlyIcon(option) | async)">
{{ getResourceValue(option.title) | async }}
</ng-container>
<x-icon
*ngIf="option.icon"
[foregroundColor]="true"
[name]="getValue(option.icon) | async"
[color]="getValue(option.color) | async"
></x-icon>
</ng-template>
<!-- Default Item Ref -->
<ng-template #defaultItemRef let-item="item" let-index="index">
<h5 style="width: 100%">{{ item | json }}</h5>
</ng-template>
<!-- Default Empty Content -->
<ng-template #defaultEmptyListRef>
<x-empty
(refresh)="emptyRefresh.emit($event)"
[color]="getValue(emptyColor) | async"
[message]="getResourceValue(emptyMessage) | async"
[refreshIcon]="getValue(emptyRefreshIcon) | async"
[messageColor]="getValue(emptyMessageColor) | async"
[hasRefresh]="getValue(emptyHasRefresh) | async"
[foregroundRefreshButtonColor]="
getValue(emptyForegroundRefreshButtonColor) | async
"
[foregroundColor]="getValue(emptyForegroundColor) | async"
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
></x-empty>
</ng-template>
### 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<any>[] = [];
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
//
private ACTION_BAR_ACTION_PROVIDER_SUBSCRIPTION: Subscription;
//
private HIDE_ADD = false;
private DISABLE_ADD = false;
private addDisablerSubject = new BehaviorSubject<boolean>(false);
//
private HIDE_REMOVE = false;
private DISABLE_REMOVE = false;
private removeDisablerSubject = new BehaviorSubject<boolean>(true);
//
private HIDE_SELECT_ALL = false;
private DISABLE_SELECT_ALL = false;
private selectAllDisablerSubject = new BehaviorSubject<boolean>(true);
//
private HIDE_DESELECT_ALL = false;
private DISABLE_DESELECT_ALL = false;
private deSelectAllDisablerSubject = new BehaviorSubject<boolean>(true);
//
private HIDE_INVERSE_SELECTION = false;
private DISABLE_INVERSE_SELECTION = false;
private inverseSelectionDisablerSubject = new BehaviorSubject<boolean>(true);
//
readonly ButtonTypes = Object.assign({}, XButtonType);
//
filteredItems: XListItem<any>[] = [];
//
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<XListComponent>('actionProvider')
);
const isActionBarActionProviderChanged = changeKeys.includes(
nameof<XListComponent>('actionBarActionProvider')
);
if (isActionProviderChanged || isActionBarActionProviderChanged) {
this.registerActionProvider();
}
//
const isItemsChanged = changeKeys.includes(nameof<XListComponent>('items'));
if (isItemsChanged) {
//
await this.handleStartup();
this.itemsChanged.emit();
}
//
const isActionBarActionsChanged = changeKeys.includes(
nameof<XListComponent>('actionBarActions')
);
const isActionBarHideActionsChanged = changeKeys.includes(
nameof<XListComponent>('actionBarHideActions')
);
if (isActionBarActionsChanged || isActionBarHideActionsChanged) {
await this.prepareActionBarActions();
}
}
registerViewHandlers() {
super.registerViewHandlers();
//
this.registerActionProvider();
}
onDestroy() {
super.onDestroy();
//
this.unregisterActionProvider();
}
//#endregion
//
//#region UI Providers ...
getStartSlides(item: XListItem<any>) {
return item && item.slideOptions
? item.slideOptions.filter((opt) => opt.slot === 'start')
: null;
}
getEndSlides(item: XListItem<any>) {
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<any>) {
//
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<any>
) {
//
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<any>
) {
//
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<XListActionModel>();
}
//
if (!this.actionBarActionProvider) {
this.actionBarActionProvider = new Subject<XActionBarActionModel>();
}
//
// 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<any>;
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<any>[];
if (newItems) {
//
this.items = [...newItems];
this.itemsChanged.emit();
this.handleChangeDetection();
}
break;
//
case XListAction.Remove:
//
const mustRemoveItem = model.payload as XListItem<any>;
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<XActionBarItem> = [];
//
// 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<File>[]) {
//
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<XIconIdentifier>;
title?: XStandardType<XResourceIdentifier>;
color?: XStandardType<XColorIdentifier>;
onlyIcon?: XStandardType<boolean>;
slot: XStandardType<XListItemOptionSlot>;
handler?: (info?: any) => XStandardType<void>;
disabled?: XStandardType<boolean>;
}
export interface XListItem<T> {
data: T;
hide?: XStandardType<boolean>;
disabled?: XStandardType<boolean>;
isSelected?: boolean;
href?: XOneOrManyType<string>;
showDetailedIcon?: XStandardType<boolean>;
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<XListActionIdentifier> {}
export type XListFilteringHandler = (
query: string,
source: XListItem<any>[]
) => XStandardType<XListItem<any>[]>;
export function itemToJson(item: any) {
return isFile(item) ? fileToJsonString(item) : toJsonString(item);
}
export const defaultListFilteringHandler: XListFilteringHandler = (
query: string,
items: XListItem<any>[]
) => {
//
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<XListActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
actionBarHideActions: XStandardType<
XOneOrManyType<XActionBarActionIdentifier>
>;
//
useDefaultActions: XStandardType<boolean>;
//
showToolbar: XStandardType<boolean>;
stickyToolbar: XStandardType<boolean>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
enableReordering: XStandardType<boolean>;
showDivider: XStandardType<boolean>;
showOptionsAsSlide: XStandardType<boolean>;
closeOptionsAfterSelect: XStandardType<boolean>;
showOptionsAsMenu: XStandardType<boolean>;
//
selectableItems: XStandardType<boolean>;
clickableItems: XStandardType<boolean>;
itemTemplate: TemplateRef<any>;
slidingOptionTemplate: TemplateRef<any>;
nonSlidingOptionTemplate: TemplateRef<any>;
//
itemSelected: EventEmitter<XListItem<any>>;
optionSelected: EventEmitter<XListItemOptionSelectedEvent>;
confirmRemove: XStandardType<boolean>;
removeItems: EventEmitter<XBaseRangeRequestDto<any>>;
//
selectionChanged: EventEmitter<XListItem<any>[]>;
orderChanged: EventEmitter<void>;
items: XStandardType<XListItem<any>[]>;
showItemOptions: XStandardType<boolean>;
itemsChanged: EventEmitter<void>;
filteringHandler: XListFilteringHandler;
}
@Injectable({
providedIn: 'root',
})
export class XListContainer
extends XCardEmptyActionSearchBarContainer
implements Readonly<IXListContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XListActionModel> =
new Subject<XListActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly actionBarHideActions: XStandardType<
XOneOrManyType<XActionBarActionIdentifier>
>;
readonly useDefaultActions: XStandardType<boolean> = true;
readonly showToolbar: XStandardType<boolean> = false;
readonly stickyToolbar: XStandardType<boolean> = true;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly enableReordering: XStandardType<boolean> = false;
readonly showDivider: XStandardType<boolean> = true;
readonly showOptionsAsSlide: XStandardType<boolean> = false;
readonly closeOptionsAfterSelect: XStandardType<boolean> = true;
readonly showOptionsAsMenu: XStandardType<boolean> = false;
//
readonly selectableItems: XStandardType<boolean> = false;
readonly clickableItems: XStandardType<boolean> = false;
readonly itemTemplate: TemplateRef<any>;
readonly slidingOptionTemplate: TemplateRef<any>;
readonly nonSlidingOptionTemplate: TemplateRef<any>;
//
readonly itemSelected: EventEmitter<XListItem<any>> = new EventEmitter<
XListItem<any>
>();
readonly optionSelected: EventEmitter<XListItemOptionSelectedEvent> =
new EventEmitter<XListItemOptionSelectedEvent>();
readonly confirmRemove: XStandardType<boolean> = true;
readonly removeItems: EventEmitter<XBaseRangeRequestDto<any>> =
new EventEmitter<XBaseRangeRequestDto<any>>();
//
readonly selectionChanged: EventEmitter<XListItem<any>[]> = new EventEmitter<
XListItem<any>[]
>();
readonly orderChanged: EventEmitter<void> = new EventEmitter<void>();
readonly items: XStandardType<XListItem<any>[]> = [];
readonly showItemOptions: XStandardType<boolean> = true;
readonly itemsChanged: EventEmitter<void> = new EventEmitter<void>();
readonly filteringHandler: XListFilteringHandler =
defaultListFilteringHandler;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XListContainerComponent
extends XCardEmptyActionSearchBarContainerComponent
implements IXListContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XListActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
actionBarHideActions: XStandardType<
XOneOrManyType<XActionBarActionIdentifier>
> = this.propertyProvider.actionBarHideActions;
@Input()
useDefaultActions: XStandardType<boolean> =
this.propertyProvider.useDefaultActions;
@Input()
showToolbar: XStandardType<boolean> = this.propertyProvider.showToolbar;
@Input()
stickyToolbar: XStandardType<boolean> = this.propertyProvider.stickyToolbar;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Input()
enableReordering: XStandardType<boolean> =
this.propertyProvider.enableReordering;
@Input()
showDivider: XStandardType<boolean> = this.propertyProvider.showDivider;
@Input()
showOptionsAsSlide: XStandardType<boolean> =
this.propertyProvider.showOptionsAsSlide;
@Input()
closeOptionsAfterSelect: XStandardType<boolean> =
this.propertyProvider.closeOptionsAfterSelect;
@Input()
showOptionsAsMenu: XStandardType<boolean> =
this.propertyProvider.showOptionsAsMenu;
@Input()
selectableItems: XStandardType<boolean> =
this.propertyProvider.selectableItems;
@Input()
clickableItems: XStandardType<boolean> = this.propertyProvider.clickableItems;
@Input()
itemTemplate: TemplateRef<any> = this.propertyProvider.itemTemplate;
@Input()
slidingOptionTemplate: TemplateRef<any> =
this.propertyProvider.slidingOptionTemplate;
@Input()
nonSlidingOptionTemplate: TemplateRef<any> =
this.propertyProvider.nonSlidingOptionTemplate;
//
@Output()
itemSelected: EventEmitter<XListItem<any>> = new EventEmitter();
@Output()
optionSelected: EventEmitter<XListItemOptionSelectedEvent> = new EventEmitter();
@Input()
confirmRemove: XStandardType<boolean> = this.propertyProvider.confirmRemove;
@Output()
removeItems: EventEmitter<XBaseRangeRequestDto<any>> = new EventEmitter();
//
@Output()
selectionChanged: EventEmitter<XListItem<any>[]> = new EventEmitter();
@Output()
orderChanged: EventEmitter<void> = new EventEmitter();
//
@Input()
items: XStandardType<XListItem<any>[]> = this.propertyProvider.items;
@Input()
showItemOptions: XStandardType<boolean> =
this.propertyProvider.showItemOptions;
@Output()
itemsChanged: EventEmitter<void> = 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<IXListContainer> {
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<boolean>;
}
@Injectable({
providedIn: 'root',
})
export class XComponentListContainer
extends XBaseComponentContainer
implements Readonly<IXComponentListContainer>
{
//
//#region Props ...
//
//#region Self ...
//
readonly showList: XStandardType<boolean> = true;
//
readonly listActionProvider: Subject<XListActionModel> =
this.propertyProvider.actionProvider;
readonly listCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly listActionBarHideActions: XStandardType<
XOneOrManyType<XActionBarActionIdentifier>
> = this.propertyProvider.actionBarHideActions;
readonly listUseDefaultActions: XStandardType<boolean> =
this.propertyProvider.useDefaultActions;
readonly listShowToolbar: XStandardType<boolean> =
this.propertyProvider.showToolbar;
readonly listStickyToolbar: XStandardType<boolean> =
this.propertyProvider.stickyToolbar;
//
readonly listColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
readonly listForegroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
readonly listEnableReordering: XStandardType<boolean> =
this.propertyProvider.enableReordering;
readonly listShowDivider: XStandardType<boolean> =
this.propertyProvider.showDivider;
readonly listShowOptionsAsSlide: XStandardType<boolean> =
this.propertyProvider.showOptionsAsSlide;
readonly listCloseOptionsAfterSelect: XStandardType<boolean> =
this.propertyProvider.closeOptionsAfterSelect;
readonly listShowOptionsAsMenu: XStandardType<boolean> =
this.propertyProvider.showOptionsAsMenu;
//
readonly listSelectableItems: XStandardType<boolean> =
this.propertyProvider.selectableItems;
readonly listClickableItems: XStandardType<boolean> =
this.propertyProvider.clickableItems;
readonly listItemTemplate: TemplateRef<any> =
this.propertyProvider.itemTemplate;
readonly listSlidingOptionTemplate: TemplateRef<any> =
this.propertyProvider.slidingOptionTemplate;
readonly listNonSlidingOptionTemplate: TemplateRef<any> =
this.propertyProvider.nonSlidingOptionTemplate;
//
readonly listItemSelected: EventEmitter<XListItem<any>> =
this.propertyProvider.itemSelected;
readonly listOptionSelected: EventEmitter<XListItemOptionSelectedEvent> =
this.propertyProvider.optionSelected;
readonly listConfirmRemove: XStandardType<boolean> =
this.propertyProvider.confirmRemove;
readonly listRemoveItems: EventEmitter<XBaseRangeRequestDto<any>> =
this.propertyProvider.removeItems;
//
readonly listSelectionChanged: EventEmitter<XListItem<any>[]> =
this.propertyProvider.selectionChanged;
readonly listOrderChanged: EventEmitter<void> =
this.propertyProvider.orderChanged;
readonly listItems: XStandardType<XListItem<any>[]> =
this.propertyProvider.items;
readonly listShowItemOptions: XStandardType<boolean> =
this.propertyProvider.showItemOptions;
readonly listItemsChanged: EventEmitter<void> =
this.propertyProvider.itemsChanged;
readonly listFilteringHandler: XListFilteringHandler =
this.propertyProvider.filteringHandler;
//#endregion
//
//#region List Card ...
readonly listIsInPage: XStandardType<boolean> =
this.propertyProvider.isInPage;
readonly listWrapWithCard: XStandardType<boolean> =
this.propertyProvider.wrapWithCard;
readonly listCardShowFooter: XStandardType<boolean> =
this.propertyProvider.cardShowFooter;
readonly listCardShowActions: XStandardType<boolean> =
this.propertyProvider.cardShowActions;
readonly listCardColor: XStandardType<XColorIdentifier> =
this.propertyProvider.cardColor;
readonly listCardForegroundColor: XStandardType<boolean> =
this.propertyProvider.cardForegroundColor;
readonly listCardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardTitle;
readonly listCardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.cardActionProvider;
readonly listCardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cardSubTitle;
readonly listCardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cardCssClass;
//#endregion
//
//#region List Empty ...
//
readonly listShowEmpty: XStandardType<boolean> =
this.propertyProvider.showEmpty;
readonly listEmptyHasRefresh: XStandardType<boolean> =
this.propertyProvider.emptyHasRefresh;
readonly listEmptyActionProvider: Subject<XEmptyActionModel> =
this.propertyProvider.emptyActionProvider;
readonly listEmptyCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.emptyCssClass;
readonly listEmptyColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyColor;
readonly listEmptyForegroundColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundColor;
readonly listEmptyMessageColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyMessageColor;
readonly listEmptyForegroundMessageColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundMessageColor;
readonly listEmptyRefreshButtonColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyRefreshButtonColor;
readonly listEmptyForegroundRefreshButtonColor: XStandardType<boolean> =
this.propertyProvider.emptyForegroundRefreshButtonColor;
readonly listEmptyMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.emptyMessage;
readonly listEmptyRefreshIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.emptyRefreshIcon;
readonly listEmptyRefresh: EventEmitter<void> =
this.propertyProvider.emptyRefresh;
//#endregion
//
//#region ActionBar ...
//
readonly listShowActionBar: XStandardType<boolean> =
this.propertyProvider.showActionBar;
//
readonly listActionBarActionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.actionBarActionProvider;
readonly listActionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.actionBarCssClass;
//
readonly listActionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.actionBarColor;
readonly listActionBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.actionBarForegroundColor;
//
readonly listActionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.propertyProvider.actionBarActions;
//
readonly listActionBarActionFired: EventEmitter<XActionBarActionFiredModel> =
this.propertyProvider.actionBarActionFired;
//#endregion
//
//#region SearchBar ...
//
readonly listShowSearchBar: XStandardType<boolean> =
this.propertyProvider.showSearchBar;
//
readonly listSearchBarActionProvider: Subject<XSearchBarActionModel> =
this.propertyProvider.searchBarActionProvider;
readonly listSearchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.searchBarCssClass;
//
readonly listSearchBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarColor;
readonly listSearchBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundColor;
//
readonly listSearchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchInputColor;
readonly listSearchBarForegroundSearchInputColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundSearchInputColor;
//
readonly listSearchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarType;
readonly listSearchBarTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarTitle;
readonly listSearchBarValue: XStandardType<string> =
this.propertyProvider.searchBarValue;
readonly listSearchBarEnterKeyHint: XStandardType<string> =
this.propertyProvider.searchBarEnterKeyHint;
readonly listSearchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarKeyboardType;
readonly listSearchBarSpellcheck: XStandardType<boolean> =
this.propertyProvider.searchBarSpellcheck;
readonly listSearchBarDebounce: XStandardType<number> =
this.propertyProvider.searchBarDebounce;
//
readonly listSearchBarShowCancelButton: XStandardType<string> =
this.propertyProvider.searchBarShowCancelButton;
readonly listSearchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarCancelButtonIcon;
readonly listSearchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarCancelButtonTitle;
readonly listSearchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarCancelButtonIconColor;
//
readonly listSearchBarShowClearButton: XStandardType<string> =
this.propertyProvider.searchBarShowClearButton;
readonly listSearchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarClearButtonIcon;
readonly listSearchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarClearButtonIconColor;
//
readonly listSearchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarSearchButtonIcon;
readonly listSearchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchButtonIconColor;
//
readonly listSearchBarQueryChange: EventEmitter<string> =
this.propertyProvider.searchBarQueryChange;
readonly listSearchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> =
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<boolean> = this.propertyProvider.showList;
//
@Input()
listActionProvider: Subject<XListActionModel> =
this.propertyProvider.listActionProvider;
@Input()
listCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.listCssClass;
//
@Input()
listActionBarHideActions: XStandardType<
XOneOrManyType<XActionBarActionIdentifier>
> = this.propertyProvider.listActionBarHideActions;
@Input()
listUseDefaultActions: XStandardType<boolean> =
this.propertyProvider.listUseDefaultActions;
@Input()
listShowToolbar: XStandardType<boolean> =
this.propertyProvider.listShowToolbar;
@Input()
listStickyToolbar: XStandardType<boolean> =
this.propertyProvider.listStickyToolbar;
//
@Input()
listColor: XStandardType<XColorIdentifier> = this.propertyProvider.listColor;
@Input()
listForegroundColor: XStandardType<boolean> =
this.propertyProvider.listForegroundColor;
//
@Input()
listEnableReordering: XStandardType<boolean> =
this.propertyProvider.listEnableReordering;
@Input()
listShowDivider: XStandardType<boolean> =
this.propertyProvider.listShowDivider;
@Input()
listShowOptionsAsSlide: XStandardType<boolean> =
this.propertyProvider.listShowOptionsAsSlide;
@Input()
listCloseOptionsAfterSelect: XStandardType<boolean> =
this.propertyProvider.listCloseOptionsAfterSelect;
@Input()
listShowOptionsAsMenu: XStandardType<boolean> =
this.propertyProvider.listShowOptionsAsMenu;
//
@Input()
listSelectableItems: XStandardType<boolean> =
this.propertyProvider.listSelectableItems;
@Input()
listClickableItems: XStandardType<boolean> =
this.propertyProvider.listClickableItems;
@Input()
listItemTemplate: TemplateRef<any> = this.propertyProvider.listItemTemplate;
@Input()
listSlidingOptionTemplate: TemplateRef<any> =
this.propertyProvider.listSlidingOptionTemplate;
@Input()
listNonSlidingOptionTemplate: TemplateRef<any> =
this.propertyProvider.listNonSlidingOptionTemplate;
//
@Output()
listItemSelected: EventEmitter<XListItem<any>> = new EventEmitter();
@Output()
listOptionSelected: EventEmitter<XListItemOptionSelectedEvent> = new EventEmitter();
@Input()
listConfirmRemove: XStandardType<boolean> =
this.propertyProvider.listConfirmRemove;
@Output()
listRemoveItems: EventEmitter<XBaseRangeRequestDto<any>> = new EventEmitter();
//
@Output()
listSelectionChanged: EventEmitter<XListItem<any>[]> = new EventEmitter();
@Output()
listOrderChanged: EventEmitter<void> = new EventEmitter();
@Input()
listItems: XStandardType<XListItem<any>[]> = this.propertyProvider.listItems;
@Input()
listShowItemOptions: XStandardType<boolean> =
this.propertyProvider.listShowItemOptions;
@Output()
listItemsChanged: EventEmitter<void> = new EventEmitter();
@Input()
listFilteringHandler: XListFilteringHandler =
this.propertyProvider.listFilteringHandler;
//#endregion
//
//#region List Card ...
@Input()
listIsInPage: XStandardType<boolean> = this.propertyProvider.listIsInPage;
@Input()
listWrapWithCard: XStandardType<boolean> =
this.propertyProvider.listWrapWithCard;
@Input()
listCardShowFooter: XStandardType<boolean> =
this.propertyProvider.listCardShowFooter;
@Input()
listCardShowActions: XStandardType<boolean> =
this.propertyProvider.listCardShowActions;
@Input()
listCardColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listCardColor;
@Input()
listCardForegroundColor: XStandardType<boolean> =
this.propertyProvider.listCardForegroundColor;
@Input()
listCardTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.listCardTitle;
@Input()
listCardActionProvider: Subject<XCardActionModel> =
this.propertyProvider.listCardActionProvider;
@Input()
listCardSubTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.listCardSubTitle;
@Input()
listCardCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.listCardCssClass;
//#endregion
//
//#region List Empty ...
//
@Input()
listShowEmpty: XStandardType<boolean> = this.propertyProvider.listShowEmpty;
@Input()
listEmptyHasRefresh: XStandardType<boolean> =
this.propertyProvider.listEmptyHasRefresh;
@Input()
listEmptyActionProvider: Subject<XEmptyActionModel> =
this.propertyProvider.listEmptyActionProvider;
@Input()
listEmptyCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.listEmptyCssClass;
@Input()
listEmptyColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listEmptyColor;
@Input()
listEmptyForegroundColor: XStandardType<boolean> =
this.propertyProvider.listEmptyForegroundColor;
@Input()
listEmptyMessageColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listEmptyMessageColor;
@Input()
listEmptyForegroundMessageColor: XStandardType<boolean> =
this.propertyProvider.listEmptyForegroundMessageColor;
@Input()
listEmptyRefreshButtonColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listEmptyRefreshButtonColor;
@Input()
listEmptyForegroundRefreshButtonColor: XStandardType<boolean> =
this.propertyProvider.listEmptyForegroundRefreshButtonColor;
@Input()
listEmptyMessage: XStandardType<XResourceIdentifier> =
this.propertyProvider.listEmptyMessage;
@Input()
listEmptyRefreshIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.listEmptyRefreshIcon;
@Output()
listEmptyRefresh: EventEmitter<void> = new EventEmitter();
//#endregion
//
//#region ActionBar ...
//
@Input()
listShowActionBar: XStandardType<boolean> =
this.propertyProvider.listShowActionBar;
//
@Input()
listActionBarActionProvider: Subject<XActionBarActionModel> =
this.propertyProvider.listActionBarActionProvider;
@Input()
listActionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.listActionBarCssClass;
//
@Input()
listActionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listActionBarColor;
@Input()
listActionBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.listActionBarForegroundColor;
//
@Input()
listActionBarActions: XStandardType<XOneOrManyType<XActionBarItem>> =
this.propertyProvider.listActionBarActions;
//
@Output()
listActionBarActionFired: EventEmitter<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
//#endregion
//
//#region SearchBar ...
//
@Input()
listShowSearchBar: XStandardType<boolean> =
this.propertyProvider.listShowSearchBar;
//
@Input()
listSearchBarActionProvider: Subject<XSearchBarActionModel> =
this.propertyProvider.listSearchBarActionProvider;
@Input()
listSearchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.listSearchBarCssClass;
//
@Input()
listSearchBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listSearchBarColor;
@Input()
listSearchBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.listSearchBarForegroundColor;
//
@Input()
listSearchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listSearchBarSearchInputColor;
@Input()
listSearchBarForegroundSearchInputColor: XStandardType<boolean> =
this.propertyProvider.listSearchBarForegroundSearchInputColor;
//
@Input()
listSearchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.listSearchBarType;
@Input()
listSearchBarTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.listSearchBarTitle;
@Input()
listSearchBarValue: XStandardType<string> =
this.propertyProvider.listSearchBarValue;
@Input()
listSearchBarEnterKeyHint: XStandardType<string> =
this.propertyProvider.listSearchBarEnterKeyHint;
@Input()
listSearchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.listSearchBarKeyboardType;
@Input()
listSearchBarSpellcheck: XStandardType<boolean> =
this.propertyProvider.listSearchBarSpellcheck;
@Input()
listSearchBarDebounce: XStandardType<number> =
this.propertyProvider.listSearchBarDebounce;
//
@Input()
listSearchBarShowCancelButton: XStandardType<string> =
this.propertyProvider.listSearchBarShowCancelButton;
@Input()
listSearchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.listSearchBarCancelButtonIcon;
@Input()
listSearchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.listSearchBarCancelButtonTitle;
@Input()
listSearchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listSearchBarCancelButtonIconColor;
//
@Input()
listSearchBarShowClearButton: XStandardType<string> =
this.propertyProvider.listSearchBarShowClearButton;
@Input()
listSearchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.listSearchBarClearButtonIcon;
@Input()
listSearchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listSearchBarClearButtonIconColor;
//
@Input()
listSearchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.listSearchBarSearchButtonIcon;
@Input()
listSearchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.listSearchBarSearchButtonIconColor;
//
@Output()
listSearchBarQueryChange: EventEmitter<string> = new EventEmitter();
@Output()
listSearchBarOnEvent: EventEmitter<string> = 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<IXComponentListContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else mapRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="mapRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Map Ref -->
<ng-template #mapRef>
<div class="x-map x-wrapper" [hidden]="!(getValue(showMapView) | async)">
<!-- Map View -->
<div #mapView [id]="componentId" class="x-map-inner"></div>
<!-- Top -->
<div class="x-map-top">
<!-- Search -->
<ng-container
*ngTemplateOutlet="
(getValue(showSearchBar) | async) &&
(getValue(searchBarPosition) | async) === ItemPositions.TOP
? searchRef
: nothingRef
"
>
</ng-container>
<!-- ProgressBar -->
<ng-container
*ngTemplateOutlet="
(getValue(showProgressBar) | async) &&
(getValue(progressBarPosition) | async) === ItemPositions.TOP
? progressBarRef
: nothingRef
"
>
</ng-container>
<!-- Plugins -->
<div #pluginsBar>
<ng-container
*ngTemplateOutlet="
(canShowPlugins(ItemPositions.TOP) | async)
? pluginsRef
: nothingRef;
context: { position: ItemPositions.TOP }
"
>
</ng-container>
</div>
</div>
<!-- Bottom -->
<div class="x-map-bottom">
<!-- Plugins -->
<ng-container
*ngTemplateOutlet="
(canShowPlugins(ItemPositions.BOTTOM) | async)
? pluginsRef
: nothingRef;
context: { position: ItemPositions.BOTTOM }
"
>
</ng-container>
<!-- Search -->
<ng-container
*ngTemplateOutlet="
(getValue(showSearchBar) | async) &&
(getValue(searchBarPosition) | async) === ItemPositions.BOTTOM
? searchRef
: nothingRef
"
>
</ng-container>
<!-- ProgressBar -->
<ng-container
*ngTemplateOutlet="
(getValue(showProgressBar) | async) &&
(getValue(progressBarPosition) | async) === ItemPositions.BOTTOM
? progressBarRef
: nothingRef
"
>
</ng-container>
</div>
</div>
</ng-template>
<!-- Search Template -->
<ng-template #searchRef>
<!-- SearchBar -->
<x-search-bar
#searchBar
(queryChange)="handleSeach($event)"
*ngIf="getValue(showSearchBar) | async"
[type]="getValue(searchBarType) | async"
(onEvent)="handleSearchBarEvents($event)"
[loading]="getValue(isSearching) | async"
[actionProvider]="searchBarActionProvider"
[color]="getValue(searchBarColor) | async"
[value]="getValue(searchBarValue) | async"
[uiDisabled]="getValue(isSearching) | async"
[debounce]="getValue(searchBarDebounce) | async"
[cssClass]="getValue(searchBarCssClass) | async"
[title]="getResourceValue(searchBarTitle) | async"
[spellcheck]="getValue(searchBarSpellcheck) | async"
[foregroundSearchInputColor]="
getValue(searchBarForegroundSearchInputColor) | async
"
[enterKeyHint]="getValue(searchBarEnterKeyHint) | async"
[keyboardType]="getValue(searchBarKeyboardType) | async"
[foregroundColor]="getValue(searchBarForegroundColor) | async"
[clearButtonIcon]="getValue(searchBarClearButtonIcon) | async"
[searchButtonIcon]="getValue(searchBarSearchButtonIcon) | async"
[searchInputColor]="getValue(searchBarSearchInputColor) | async"
[cancelButtonIcon]="getValue(searchBarCancelButtonIcon) | async"
[showCancelButton]="getValue(searchBarShowCancelButton) | async"
[cancelButtonTitle]="getValue(searchBarCancelButtonTitle) | async"
[clearButtonIconColor]="getValue(searchBarClearButtonIconColor) | async"
[searchButtonIconColor]="getValue(searchBarSearchButtonIconColor) | async"
></x-search-bar>
<!-- Search Result -->
<x-list
xMouseHandler
[showEmpty]="false"
[wrapWithCard]="false"
[clickableItems]="true"
class="x-map-search-list"
[uiDisabled]="uiDisabled"
[itemTemplate]="resultRef"
[items]="searchResultListItems"
(itemSelected)="handleChangeLocation($event)"
[class.open]="getValue(searchPaneOpen) | async"
[color]="getValue(searchResultListColor) | async"
[enableHandler]="getValue(searchPaneOpen) | async"
[class.has-search]="getValue(showSearchBar) | async"
(onWindowFinished)="handleLocationResultClickOutside($event)"
></x-list>
</ng-template>
<!-- ProgressBar Template -->
<ng-template #progressBarRef>
<!-- Progressbar for Loading -->
<ion-progress-bar
type="indeterminate"
[color]="getValue(progressBarColor) | async"
*ngIf="
(getValue(showProgressBar) | async) &&
(getValue(loading) | async)
"
></ion-progress-bar>
</ng-template>
<!-- Plugins Template -->
<ng-template #pluginsRef let-position="position">
<div class="x-map-plugins-wrapper">
<x-slotter
[hasCenterSlot]="false"
[layout]="SlotLayouts.HORIZONTAL"
[endBottomSlotCssClass]="'x-auto-size-flex'"
>
<!-- Start -->
<x-slot [name]="SlotNames.START" [cssClass]="'ion-text-start'">
<!-- Locator -->
<ng-container
*ngTemplateOutlet="
(getValue(showLocator) | async) &&
(getValue(locatorPosition) | async) === position
? locatorRef
: nothingRef
"
></ng-container>
<!-- Go Marked Place -->
<ng-container
*ngTemplateOutlet="
(getValue(showGoMarkedPlace) | async) &&
(getValue(goMarkedPlacePosition) | async) === position
? goMarkedPlaceRef
: nothingRef
"
></ng-container>
<!-- Clear Marker -->
<ng-container
*ngTemplateOutlet="
(getValue(showClearMarker) | async) &&
(getValue(clearMarkerPosition) | async) === position
? clearMarkerRef
: nothingRef
"
></ng-container>
</x-slot>
<!-- End -->
<x-slot
[name]="SlotNames.END"
class="x-auto-size-flex"
[cssClass]="'ion-text-end'"
>
<!-- Selected Location -->
<ng-container
*ngTemplateOutlet="
(getValue(showSelectedLocation) | async) &&
(getValue(selectedLocationPosition) | async) === position
? selectedLocationRef
: nothingRef
"
></ng-container>
</x-slot>
</x-slotter>
</div>
</ng-template>
<!-- SelectedLocation Template -->
<ng-template #selectedLocationRef>
<span
*ngIf="notEmptyValue(currentPosition) | async"
class="x-map-plugin x-selected-location ol-control"
>
<button (click)="handleSlectedLocationClicked(currentPosition)">
{{ getValue(currentPosition) | async }}
</button>
</span>
</ng-template>
<!-- Locator Template -->
<ng-template #locatorRef>
<span class="x-map-plugin x-locator ol-control">
<button
(click)="handleLocate()"
[disabled]="
(getValue(uiDisabled) | async) || (getValue(loading) | async)
"
>
<ion-icon name="locate-outline"></ion-icon>
</button>
</span>
</ng-template>
<!-- GoMarkedLocation Template -->
<ng-template #goMarkedPlaceRef>
<span
*ngIf="getValue(hasMarker) | async"
class="x-map-plugin x-go-marked-place ol-control"
>
<button
(click)="handleGoMarkedPlace()"
[disabled]="
(getValue(uiDisabled) | async) || (getValue(loading) | async)
"
>
<ion-icon name="navigate"></ion-icon>
</button>
</span>
</ng-template>
<!-- ClearMarker Template -->
<ng-template #clearMarkerRef>
<span
*ngIf="getValue(hasMarker) | async"
class="x-map-plugin x-clear-marker ol-control"
>
<button
(click)="handleClearMarker()"
[disabled]="
(getValue(uiDisabled) | async) || (getValue(loading) | async)
"
>
<ion-icon name="close-outline"></ion-icon>
</button>
</span>
</ng-template>
<!-- Place Result Template -->
<ng-template #resultRef let-item>
{{ item.data.display_name }}
</ng-template>
<!-- Nothing Template -->
<ng-template #nothingRef></ng-template>
### 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<any>;
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<string>();
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
private searchFilterSubject$ = new Subject<string>();
//
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<boolean> = false;
searchResultListItems: XListItem<XPlaceResult>[] = [];
//
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<HTMLDivElement>;
@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<XMapComponent>('canSelect')
);
if (isCanSelectChanged) {
await this.applyCanSelect();
}
//#endregion
//
//#region ActionProvider changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XMapComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Location Info changed ...
// const isZoomChanged = changeKeys.includes(nameof<XMapComponent>('zoom'));
// const isLatitudeChanged = changeKeys.includes(
// nameof<XMapComponent>('latitude')
// );
// const isLongitudeChanged = changeKeys.includes(
// nameof<XMapComponent>('longitude')
// );
// const isAddMarkerOnSelectedLocationChanged = changeKeys.includes(
// nameof<XMapComponent>('addMarkerOnSelectedLocation')
// );
// if (
// isZoomChanged ||
// isLatitudeChanged ||
// isLongitudeChanged ||
// isAddMarkerOnSelectedLocationChanged
// ) {
// await this.applyLocationInfo();
// }
//#endregion
//
//#region Show Zoom changed ...
const isShowZoomChanged = changeKeys.includes(
nameof<XMapComponent>('showZoom')
);
if (isShowZoomChanged) {
await this.applyZoom();
}
//#endregion
//
//#region Show Rotate changed ...
const isShowRotateChanged = changeKeys.includes(
nameof<XMapComponent>('showRotate')
);
if (isShowRotateChanged) {
await this.applyRotate();
}
//#endregion
//
//#region Show Zoom Slider changed ...
const isShowZoomSliderChanged = changeKeys.includes(
nameof<XMapComponent>('showZoomSlider')
);
if (isShowZoomSliderChanged) {
await this.applyZoomSlider();
}
//#endregion
//
//#region Offset Height Handling ...
const isShowSearchBarChanged = changeKeys.includes(
nameof<XMapComponent>('showSearchBar')
);
const isSearchBarPositionChanged = changeKeys.includes(
nameof<XMapComponent>('searchBarPosition')
);
const isShowSelectedLoactionChanged = changeKeys.includes(
nameof<XMapComponent>('showSelectedLocation')
);
const isSelectedLocationPositionChanged = changeKeys.includes(
nameof<XMapComponent>('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<number>,
longitude?: number | XStandardType<number>
) {
//
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<XPlaceResult>) {
//
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<number>) {
//
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<number>,
longitude?: number | XStandardType<number>,
zoom?: number | XStandardType<number>
) {
//
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<number>,
longitude?: number | XStandardType<number>,
zoom?: number | XStandardType<number>
) {
//
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<XMapActionModel>();
}
//
// 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<number>
) {
const result = await this.getValueAsync(latitude || this.latitude || 0);
return result || 0;
}
private async getNormallizedLongitude(
longitude?: number | XStandardType<number>
) {
const result = await this.getValueAsync(longitude || this.longitude || 0);
return result || 0;
}
private async getNormallizedZoom(zoom?: number | XStandardType<number>) {
//
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<number>,
longitude?: number | XStandardType<number>
) {
//
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<number>,
longitude?: number | XStandardType<number>
) {
//
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<XPlaceResult[]> {
//
const headers: HttpHeaders = new HttpHeaders();
headers.set(XHeader.Accept, XContentType.AppJson);
//
return applyFinally(
this.applyLoadingWrapper(
this.managerService.httpClient
.get<XPlaceResult[]>(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<XPlaceResult> = {
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<number>) {
//
if (isString(source)) {
return fromLongLat(source as string);
}
//
if (!isArray(source) || countChild(source as Array<number>) < 2) {
return null;
}
//
const longLatArr = source as Array<number>;
//
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<XMapActionIdentifier> {}
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<XMapActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
zoom: XStandardType<number>;
latitude: XStandardType<number>;
longitude: XStandardType<number>;
canSelect: XStandardType<boolean>;
addMarkerOnSelectedLocation: XStandardType<boolean>;
//
isReady: EventEmitter<void>;
viewChanged: EventEmitter<XMapLocation>;
locationSelected: EventEmitter<XMapLocation>;
// zoomChanged: EventEmitter<number>;
markerStyle: XStandardType<XMapStyle>;
showProgressBar: XStandardType<boolean>;
progressBarColor: XStandardType<XColorIdentifier>;
progressBarPosition: XStandardType<XMapItemPositionIdentifier>;
showSelectedLocation: XStandardType<boolean>;
selectedLocationPosition: XStandardType<XMapItemPositionIdentifier>;
showGoMarkedPlace: XStandardType<boolean>;
goMarkedPlacePosition: XStandardType<XMapItemPositionIdentifier>;
showClearMarker: XStandardType<boolean>;
clearMarkerPosition: XStandardType<XMapItemPositionIdentifier>;
showLocator: XStandardType<boolean>;
locatorPosition: XStandardType<XMapItemPositionIdentifier>;
showZoom: XStandardType<boolean>;
showRotate: XStandardType<boolean>;
showZoomSlider: XStandardType<boolean>;
//
searchBarPosition: XStandardType<XMapItemPositionIdentifier>;
searchPlaceProvider: (query: string) => string;
searchResultListColor: XStandardType<XColorIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XMapContainer
extends XComponentCardContainer
implements Readonly<IXMapContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XMapActionModel> =
new Subject<XMapActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly zoom: XStandardType<number> = 0;
readonly latitude: XStandardType<number> = 0;
readonly longitude: XStandardType<number> = 0;
readonly canSelect: XStandardType<boolean> = true;
readonly addMarkerOnSelectedLocation: XStandardType<boolean> = true;
//
readonly isReady: EventEmitter<void> = new EventEmitter();
readonly viewChanged: EventEmitter<XMapLocation> =
new EventEmitter<XMapLocation>();
readonly locationSelected: EventEmitter<XMapLocation> =
new EventEmitter<XMapLocation>();
// zoomChanged: EventEmitter<number>;
readonly markerStyle: XStandardType<XMapStyle> = defaultMarkerStyle;
readonly showProgressBar: XStandardType<boolean> = true;
readonly progressBarColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Warning;
readonly progressBarPosition: XStandardType<XMapItemPositionIdentifier> =
XMapItemPosition.TOP;
readonly showSelectedLocation: XStandardType<boolean> = true;
readonly selectedLocationPosition: XStandardType<XMapItemPositionIdentifier> =
XMapItemPosition.TOP;
readonly showGoMarkedPlace: XStandardType<boolean> = true;
readonly goMarkedPlacePosition: XStandardType<XMapItemPositionIdentifier> =
XMapItemPosition.TOP;
readonly showClearMarker: XStandardType<boolean> = true;
readonly clearMarkerPosition: XStandardType<XMapItemPositionIdentifier> =
XMapItemPosition.TOP;
readonly showLocator: XStandardType<boolean> = true;
readonly locatorPosition: XStandardType<XMapItemPositionIdentifier> =
XMapItemPosition.TOP;
readonly showZoom: XStandardType<boolean> = true;
readonly showRotate: XStandardType<boolean> = true;
readonly showZoomSlider: XStandardType<boolean> = false;
//
readonly searchBarPosition: XStandardType<XMapItemPositionIdentifier> =
XMapItemPosition.TOP;
readonly searchPlaceProvider: (query: string) => string =
defaultMapSearchPlaceProvider;
readonly searchResultListColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
//
//#region ComponentSearchBar ...
//
readonly showSearchBar: XStandardType<boolean> =
this.searchBarPropertyProvider.showSearchBar;
//
readonly searchBarActionProvider: Subject<XSearchBarActionModel> =
this.searchBarPropertyProvider.searchBarActionProvider;
readonly searchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.searchBarPropertyProvider.searchBarCssClass;
//
readonly searchBarColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarColor;
readonly searchBarForegroundColor: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarForegroundColor;
//
readonly searchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarSearchInputColor;
readonly searchBarForegroundSearchInputColor: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarForegroundSearchInputColor;
//
readonly searchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.searchBarPropertyProvider.searchBarType;
readonly searchBarTitle: XStandardType<XResourceIdentifier> =
this.searchBarPropertyProvider.searchBarTitle;
readonly searchBarValue: XStandardType<string> =
this.searchBarPropertyProvider.searchBarValue;
readonly searchBarEnterKeyHint: XStandardType<string> =
this.searchBarPropertyProvider.searchBarEnterKeyHint;
readonly searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.searchBarPropertyProvider.searchBarKeyboardType;
readonly searchBarSpellcheck: XStandardType<boolean> =
this.searchBarPropertyProvider.searchBarSpellcheck;
readonly searchBarDebounce: XStandardType<number> =
this.searchBarPropertyProvider.searchBarDebounce;
//
readonly searchBarShowCancelButton: XStandardType<string> =
this.searchBarPropertyProvider.searchBarShowCancelButton;
readonly searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonIcon;
readonly searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonTitle;
readonly searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarCancelButtonIconColor;
//
readonly searchBarShowClearButton: XStandardType<string> =
this.searchBarPropertyProvider.searchBarShowClearButton;
readonly searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarClearButtonIcon;
readonly searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarClearButtonIconColor;
//
readonly searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.searchBarPropertyProvider.searchBarSearchButtonIcon;
readonly searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.searchBarPropertyProvider.searchBarSearchButtonIconColor;
//
readonly searchBarQueryChange: EventEmitter<string> =
this.searchBarPropertyProvider.searchBarQueryChange;
readonly searchBarOnEvent: EventEmitter<string> =
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<XMapActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
zoom: XStandardType<number> = this.propertyProvider.zoom;
@Input()
latitude: XStandardType<number> = this.propertyProvider.latitude;
@Input()
longitude: XStandardType<number> = this.propertyProvider.longitude;
@Input()
canSelect: XStandardType<boolean> = this.propertyProvider.canSelect;
@Input()
addMarkerOnSelectedLocation: XStandardType<boolean> =
this.propertyProvider.addMarkerOnSelectedLocation;
//
@Output()
isReady: EventEmitter<void> = new EventEmitter();
@Output()
viewChanged: EventEmitter<XMapLocation> = new EventEmitter();
@Output()
locationSelected: EventEmitter<XMapLocation> = new EventEmitter();
// zoomChanged: EventEmitter<number>;
@Input()
markerStyle: XStandardType<XMapStyle> = this.propertyProvider.markerStyle;
@Input()
showProgressBar: XStandardType<boolean> =
this.propertyProvider.showProgressBar;
@Input()
progressBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.progressBarColor;
@Input()
progressBarPosition: XStandardType<XMapItemPositionIdentifier> =
this.propertyProvider.progressBarPosition;
@Input()
showSelectedLocation: XStandardType<boolean> =
this.propertyProvider.showSelectedLocation;
@Input()
selectedLocationPosition: XStandardType<XMapItemPositionIdentifier> =
this.propertyProvider.selectedLocationPosition;
@Input()
showGoMarkedPlace: XStandardType<boolean> =
this.propertyProvider.showGoMarkedPlace;
@Input()
goMarkedPlacePosition: XStandardType<XMapItemPositionIdentifier> =
this.propertyProvider.goMarkedPlacePosition;
@Input()
showClearMarker: XStandardType<boolean> =
this.propertyProvider.showClearMarker;
@Input()
clearMarkerPosition: XStandardType<XMapItemPositionIdentifier> =
this.propertyProvider.clearMarkerPosition;
@Input()
showLocator: XStandardType<boolean> = this.propertyProvider.showLocator;
@Input()
locatorPosition: XStandardType<XMapItemPositionIdentifier> =
this.propertyProvider.locatorPosition;
@Input()
showZoom: XStandardType<boolean> = this.propertyProvider.showZoom;
@Input()
showRotate: XStandardType<boolean> = this.propertyProvider.showRotate;
@Input()
showZoomSlider: XStandardType<boolean> = this.propertyProvider.showZoomSlider;
//
@Input()
searchBarPosition: XStandardType<XMapItemPositionIdentifier> =
this.propertyProvider.searchBarPosition;
@Input()
searchPlaceProvider: (query: string) => string =
this.propertyProvider.searchPlaceProvider;
@Input()
searchResultListColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchResultListColor;
//
//#region ComponentSearchBar ...
//
@Input()
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
//
@Input()
searchBarActionProvider: Subject<XSearchBarActionModel> =
this.propertyProvider.searchBarActionProvider;
@Input()
searchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.searchBarCssClass;
//
@Input()
searchBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarColor;
@Input()
searchBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundColor;
//
@Input()
searchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchInputColor;
@Input()
searchBarForegroundSearchInputColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundSearchInputColor;
//
@Input()
searchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarType;
@Input()
searchBarTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarTitle;
@Input()
searchBarValue: XStandardType<string> = this.propertyProvider.searchBarValue;
@Input()
searchBarEnterKeyHint: XStandardType<string> =
this.propertyProvider.searchBarEnterKeyHint;
@Input()
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarKeyboardType;
@Input()
searchBarSpellcheck: XStandardType<boolean> =
this.propertyProvider.searchBarSpellcheck;
@Input()
searchBarDebounce: XStandardType<number> =
this.propertyProvider.searchBarDebounce;
//
@Input()
searchBarShowCancelButton: XStandardType<string> =
this.propertyProvider.searchBarShowCancelButton;
@Input()
searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarCancelButtonIcon;
@Input()
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarCancelButtonTitle;
@Input()
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarCancelButtonIconColor;
//
@Input()
searchBarShowClearButton: XStandardType<string> =
this.propertyProvider.searchBarShowClearButton;
@Input()
searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarClearButtonIcon;
@Input()
searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarClearButtonIconColor;
//
@Input()
searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarSearchButtonIcon;
@Input()
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchButtonIconColor;
//
@Output()
searchBarQueryChange: EventEmitter<string> = new EventEmitter();
@Output()
searchBarOnEvent: EventEmitter<string> = 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<IXMapContainer> {
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
<section #mapDialogContainer class="x-map-dialog-container">
<!-- Title Toolbar -->
<section #mapDialogToolbar>
<ion-toolbar class="v-toolbar" [xColor]="'primary'">
<!-- Slots -->
<div class="toolbar-area">
<x-slotter>
<!-- Start -->
<x-slot
[name]="SlotNames.START"
[cssClass]="['ion-text-start', 'ion-float-start']"
>
<div
matRipple
(click)="handleBack()"
class="toolbar-item toolbar-button center-vertical-flex"
>
<x-icon
[name]="backIcon"
[loading]="loading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
<!-- Center -->
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
<ion-title class="toolbar-item center-vertical-flex">
<h3>
{{ getTitle() | async }}
</h3>
</ion-title>
</x-slot>
<!-- End -->
<x-slot
[name]="SlotNames.END"
[cssClass]="['ion-text-end', 'ion-float-end']"
>
<div
matRipple
(click)="handleSelect()"
*ngIf="dialogCanSelect() && (canSelect | async)"
class="toolbar-item toolbar-button center-vertical-flex"
>
<x-icon
[name]="selectIcon"
[loading]="loading"
[color]="'cb-inherit'"
[uiDisabled]="uiDisabled"
></x-icon>
</div>
</x-slot>
</x-slotter>
</div>
</ion-toolbar>
</section>
<!-- Map Component -->
<x-map
[isInPage]="false"
[zoom]="zoom | async"
[loading]="loading"
[wrapWithCard]="false"
[showSearchBar]="true"
[uiDisabled]="uiDisabled"
[latitude]="latitude | async"
[cssClass]="cssClass | async"
[showZoom]="showZoom | async"
(isReady)="handleMapIsReady()"
[longitude]="longitude | async"
[canSelect]="canSelect | async"
[showRotate]="showRotate | async"
[actionProvider]="actionProvider"
[showLocator]="showLocator | async"
[markerStyle]="markerStyle | async"
[searchBarType]="searchBarType | async"
[searchBarValue]="searchBarValue | async"
[searchBarColor]="searchBarColor | async"
[searchBarTitle]="searchBarTitle | async"
[searchBarColor]="searchBarColor | async"
[showZoomSlider]="showZoomSlider | async"
[searchBarPosition]="MapItemPositions.TOP"
[showProgressBar]="showProgressBar | async"
[showClearMarker]="showClearMarker | async"
[locatorPosition]="locatorPosition | async"
[progressBarPosition]="MapItemPositions.TOP"
[progressBarColor]="progressBarColor | async"
[searchBarForegroundSearchInputColor]="
searchBarForegroundSearchInputColor | async
"
[searchBarForegroundSearchInputColor]="
searchBarForegroundSearchInputColor | async
"
[showGoMarkedPlace]="showGoMarkedPlace | async"
[searchBarDebounce]="searchBarDebounce | async"
[searchBarCssClass]="searchBarCssClass | async"
[searchBarSpellcheck]="searchBarSpellcheck | async"
[searchPlaceProvider]="searchPlaceProvider | async"
[clearMarkerPosition]="clearMarkerPosition | async"
[showSelectedLocation]="showSelectedLocation | async"
(locationSelected)="handleMapLocationSelected($event)"
[goMarkedPlacePosition]="goMarkedPlacePosition | async"
[searchBarKeyboardType]="searchBarKeyboardType | async"
[searchBarEnterKeyHint]="searchBarEnterKeyHint | async"
[searchResultListColor]="searchResultListColor | async"
(searchBarQueryChange)="handleSearchBarQueryChange($event)"
[searchBarActionProvider]="searchBarActionProvider | async"
[selectedLocationPosition]="selectedLocationPosition | async"
[searchBarClearButtonIcon]="searchBarClearButtonIcon | async"
[searchBarForegroundColor]="searchBarForegroundColor | async"
[searchBarSearchButtonIcon]="searchBarSearchButtonIcon | async"
[searchBarSearchInputColor]="searchBarSearchInputColor | async"
[searchBarShowCancelButton]="searchBarShowCancelButton | async"
[searchBarCancelButtonIcon]="searchBarCancelButtonIcon | async"
[searchBarClearButtonIconColor]="searchBarClearIconColor | async"
[searchBarCancelButtonTitle]="searchBarCancelButtonTitle | async"
[searchBarSearchButtonIconColor]="searchBarSearchButtonIconColor | async"
>
</x-map>
</section>
### 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<XMapActionModel>();
//
@ViewChild('mapDialogContainer')
mapDialogContainer: ElementRef<HTMLElement>;
@ViewChild('mapDialogToolbar')
mapDialogToolbar: ElementRef<HTMLElement>;
//#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<XMapDialogComponent>
) {
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<XSearchBarActionModel>()
)
);
}
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<XMapDialogComponent>;
//
isMobile$ = this.managerService.isMobileUi$;
// tslint:disable-next-line:no-output-on-prefix
@Output()
onResult = new EventEmitter<XMapDialogResult>();
//#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<IXMapContainer>,
| '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
<!-- WrapWithCard Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
<x-card
class="x-card"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[showActions]="getValue(cardShowActions) | async"
[subTitle]="getResourceValue(cardSubTitle) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
[showHeader]="
(notEmptyValue(getResourceValue(cardTitle) | async) | async) ||
(notEmptyValue(getResourceValue(cardSubTitle) | async) | async)
"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component Template -->
<ng-template #componentRef>
<div
*ngIf="preparedMode"
class="x-markdown x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<!-- Toolbar -->
<div
class="x-toolbar-wrapper"
*ngIf="
(getValueStream(hasToolbar) | async) &&
((isEditMode() | async) || (isBothMode() | async))
"
>
<ion-toolbar
class="x-editor-toolbar"
[xColor]="getValue(toolbarColor) | async"
[ngClass]="getValue(toolbarCssClass) | async"
[isForeground]="getValue(toolbarForegroundColor) | async"
>
<!-- Start Slot -->
<ion-buttons slot="start" *ngIf="preparedToolbarConfig">
<ng-container
*ngTemplateOutlet="toolbarRef; context: { $implicit: 'start' }"
></ng-container>
</ion-buttons>
<!-- End Slot -->
<ion-buttons slot="end" *ngIf="preparedToolbarConfig">
<ng-container
*ngTemplateOutlet="toolbarRef; context: { $implicit: 'end' }"
></ng-container>
</ion-buttons>
</ion-toolbar>
</div>
<!-- Content -->
<x-slotter
[hasCenterSlot]="false"
[layout]="getSlotterLayout() | async"
[hasStartOrTopSlot]="(isEditMode() | async) || (isBothMode() | async)"
[hasEndOrBottomSlot]="(isPreviewMode() | async) || (isBothMode() | async)"
>
<!-- Edit Area -->
<x-slot [name]="'start'">
<div class="x-editor-wrapper">
<!-- Editor -->
<textarea
#markdownEditor
class="x-editor"
[(ngModel)]="innerContent"
(keyup)="handleContentChanged(innerContent)"
(change)="handleContentChanged(innerContent)"
(ngModelChange)="handleContentChanged(innerContent)"
[xColor]="(getValue(editorBoxColor) | async) || 'cb-inherit'"
></textarea>
</div>
</x-slot>
<!-- Preview Area -->
<x-slot [name]="'end'">
<div
class="x-preview-wrapper"
[class.no-border]="isPreviewMode() | async"
[xColor]="(getValue(previewBoxColor) | async) || 'cb-inherit'"
>
<markdown class="x-preview" [data]="innerContent || ' '"> </markdown>
</div>
</x-slot>
</x-slotter>
</div>
</ng-template>
<!-- Toolbar Template Ref -->
<ng-template #toolbarRef let-slot>
<ng-container *ngIf="preparedToolbarConfig">
<ng-container *ngFor="let name of toolbarItems">
<ng-container
*ngIf="hasToolbarItem(name) && getToolbarItem(name).slot === slot"
>
<ng-container
*ngTemplateOutlet="
name === 'guide' ? guideToolbarItemRef : toolbarItemRef;
context: { $implicit: name }
"
></ng-container>
</ng-container>
</ng-container>
</ng-container>
</ng-template>
<!-- Toolbar Guide Item Template Ref -->
<ng-template #guideToolbarItemRef let-name>
<a
target="_blank"
style="text-decoration: none; color: unset"
href="https://guides.github.com/features/mastering-markdown/"
>
<x-icon
[clickable]="false"
[selectable]="true"
[loading]="loading"
class="x-toolbar-icon"
[color]="'transparent'"
[uiDisabled]="uiDisabled"
[foregroundColor]="false"
[name]="getValue(getToolbarItem(name).icon)"
[matTooltip]="getResourceValue(getToolbarItem(name).title) | async"
></x-icon>
</a>
</ng-template>
<!-- Toolbar Item Template Ref -->
<ng-template #toolbarItemRef let-name>
<x-icon
[clickable]="true"
[selectable]="true"
[loading]="loading"
class="x-toolbar-icon"
[color]="'transparent'"
[uiDisabled]="uiDisabled"
[foregroundColor]="false"
(clicked)="handleToolbarItemClicked(name)"
[name]="getValue(getToolbarItem(name).icon)"
[matTooltip]="getResourceValue(getToolbarItem(name).title) | async"
></x-icon>
</ng-template>
### 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<XMarkdownComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Content Chaned ...
const isContentChanged = changeKeys.includes(
nameof<XMarkdownComponent>('content')
);
if (isContentChanged && this.content !== this.innerContent) {
this.innerContent = this.content;
this.detectChanges();
}
//#endregion
//
//#region Model Changed ...
const isModeChanged = changeKeys.includes(
nameof<XMarkdownComponent>('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<XMarkdownActionModel>();
}
//
// 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<XMarkdownToolbarConfigProps>
) {
//
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<XMarkdownActionIdentifier> {}
//
//#region Inside Card Container ...
export interface IXMarkdownContainer extends IXComponentCardContainer {
//
actionProvider: Subject<XMarkdownActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
content: string;
contentChange: EventEmitter<string>;
//
mode: XStandardType<XMarkdownModeIdentifier>;
//
editorBoxColor: XStandardType<XColorIdentifier>;
previewBoxColor: XStandardType<XColorIdentifier>;
//
//#region Toolbar ...
hasToolbar: XStandardType<boolean>;
toolbarCssClass: XStandardType<XOneOrManyType<string>>;
toolbarColor: XStandardType<XColorIdentifier>;
toolbarForegroundColor: XStandardType<boolean>;
toolbarConfig: XStandardType<XMarkdownToolbarConfigProps>;
//#endregion
}
@Injectable({
providedIn: 'root',
})
export class XMarkdownContainer
extends XComponentCardContainer
implements Readonly<IXMarkdownContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XMarkdownActionModel> =
new Subject<XMarkdownActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly content: string = '';
readonly contentChange = new EventEmitter<string>();
//
readonly mode: XStandardType<XMarkdownModeIdentifier> = XMarkdownMode.BOTH;
//
readonly editorBoxColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Transparent;
readonly previewBoxColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Transparent;
//
//#region Toolbar ...
readonly hasToolbar: XStandardType<boolean> = true;
readonly toolbarCssClass: XStandardType<XOneOrManyType<string>>;
readonly toolbarColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly toolbarForegroundColor: XStandardType<boolean> = false;
readonly toolbarConfig: XStandardType<XMarkdownToolbarConfigProps>;
//#endregion
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XMarkdownContainerComponent
extends XComponentCardContainerComponent
implements IXMarkdownContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XMarkdownActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
content: string = this.propertyProvider.content;
@Output()
contentChange: EventEmitter<string> = new EventEmitter();
//
@Input()
mode: XStandardType<XMarkdownModeIdentifier> = this.propertyProvider.mode;
//
@Input()
editorBoxColor: XStandardType<XColorIdentifier> =
this.propertyProvider.editorBoxColor;
@Input()
previewBoxColor: XStandardType<XColorIdentifier> =
this.propertyProvider.previewBoxColor;
//
//#region Toolbar ...
@Input()
hasToolbar: XStandardType<boolean> = this.propertyProvider.hasToolbar;
@Input()
toolbarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.toolbarCssClass;
@Input()
toolbarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.toolbarColor;
@Input()
toolbarForegroundColor: XStandardType<boolean> =
this.propertyProvider.toolbarForegroundColor;
@Input()
toolbarConfig: XStandardType<XMarkdownToolbarConfigProps> =
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<IXMarkdownContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentsRef"></ng-container>
<!-- Actions -->
<div class="x-actions" [ngClass]="getValue(cssClass) | async" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component's itSelf Template -->
<ng-template #componentsRef>
<!-- Check Prepared Model Exists -->
<div
class="x-model-presenter x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
*ngIf="notNullOrUndefinedValue(preparedModel) | async"
>
<x-expandable-panel
[isAccordion]="false"
[applyColors]="false"
[multiExpanded]="true"
class="x-model-presenter-panel"
[actionProvider]="panelActionProvider"
[hideDescriptionOnSmallScreens]="false"
[cardColor]="getValue(cardColor) | async"
[wrapWithCard]="getValue(wrapWithCard) | async"
[cssClass]="getArrayValue(panelCssClass) | async"
[cardForegroundColor]="getValue(cardForegroundColor) | async"
>
<ng-container *ngFor="let key of keys(preparedModel)">
<ng-container *ngIf="canShowKey(key) | async as canShowTheKey">
<x-panel
[id]="key"
[uiDisabled]="
!(hasContentItem(key) | async) &&
(canDescribe(key, preparedModel[key]) | async)
"
[hideToggle]="
!(hasContentItem(key) | async) &&
(canDescribe(key, preparedModel[key]) | async)
"
>
<!-- Title (Key) -->
<div
x-panel-title
[isForeground]="true"
class="x-model-presenter-title"
*ngIf="
canShowTheKey &&
(getValue(showLabels) | async) &&
(canShowLabelKey(key) | async)
"
[class.hasLabel]="
canShowTheKey &&
(getValue(showLabels) | async) &&
(canShowLabelKey(key) | async)
"
[xColor]="getValue(labelColor) | async"
[ngClass]="getModelPresenterTitleClasses(key)"
>
<span class="x-title-span text-truncate">
{{ getTitle(key) | async }}
</span>
</div>
<!-- Content (Value) -->
<!-- if Has Not ContentItem and Descibeable -->
<div
x-panel-description
[isForeground]="true"
class="x-model-presenter-content"
[xColor]="getValue(valueColor) | async"
*ngIf="
!(hasContentItem(key) | async) &&
(canDescribe(key, preparedModel[key]) | async)
"
[ngClass]="getModelPresenterContentClasses(key)"
>
<x-slotter
[hasCenterSlot]="false"
[cssClass]="'full-with'"
[layout]="SlotLayouts.HORIZONTAL"
[hasEndOrBottomSlot]="
notNullOrUndefinedValue(propertyActionTemplate) | async
"
>
<!-- Start -->
<x-slot
[name]="SlotNames.START"
[cssClass]="['ion-text-start', 'text-truncate']"
>
{{ getContent(key, preparedModel[key]) | async }}
</x-slot>
<!-- End -->
<x-slot [name]="SlotNames.END" [cssClass]="'ion-text-end'">
<!-- propertyActionTemplate -->
<ng-container
*ngIf="
notNullOrUndefinedValue(propertyActionTemplate) | async
"
>
<ng-container
*ngTemplateOutlet="
propertyActionTemplate;
context: {
key: key,
prefix: prefix,
value: preparedModel[key]
}
"
>
</ng-container>
</ng-container>
</x-slot>
</x-slotter>
</div>
<!-- if Has not ContentItem && not Describeable -->
<div
[isForeground]="true"
class="x-model-presenter-content"
[xColor]="getValue(valueColor) | async"
[ngClass]="getModelPresenterContentClasses(key)"
*ngIf="
!(hasContentItem(key) | async) &&
!(canDescribe(key, preparedModel[key]) | async)
"
>
<ng-container
*ngTemplateOutlet="
nestedRef;
context: {
key: key,
value: preparedModel[key],
prefix: getKeyPrefix(key),
hiddenModelKeys: (getHiddenModelKeys(key) | async),
availableModelKeys: (getAvailableModelKeys(key) | async),
sortOrderModelKeys: (getSortOrderModelKeys(key) | async),
hiddenLabelModelKeys: (getHiddenLabelModelKeys(key) | async)
}
"
>
</ng-container>
</div>
<!-- if Has ContentItem -->
<div
[isForeground]="true"
class="x-model-presenter-content"
*ngIf="hasContentItem(key) | async"
[xColor]="getValue(valueColor) | async"
[ngClass]="getModelPresenterContentClasses(key)"
>
<ng-container
*ngTemplateOutlet="
(getContentItem(key, preparedModel[key]) | async).content
"
></ng-container>
</div>
</x-panel>
</ng-container>
</ng-container>
</x-expandable-panel>
</div>
</ng-template>
<!-- NestedRef -->
<ng-template
#nestedRef
let-key="key"
let-value="value"
let-prefix="prefix"
let-hiddenModelKeys="hiddenModelKeys"
let-availableModelKeys="availableModelKeys"
let-sortOrderModelKeys="sortOrderModelKeys"
let-hiddenLabelModelKeys="hiddenLabelModelKeys"
>
<x-model-presenter
[model]="value"
[attr.keyPrefix]="prefix"
[panelCssClass]="panelCssClass"
[actionProvider]="actionProvider"
[color]="getValue(color) | async"
[hiddenModelKeys]="hiddenModelKeys"
[modelKeyProvider]="modelKeyProvider"
[availableModelKeys]="availableModelKeys"
[sortOrderModelKeys]="sortOrderModelKeys"
[modelValueProvider]="modelValueProvider"
[panelActionProvider]="panelActionProvider"
[showLabels]="getValue(showLabels) | async"
[labelColor]="getValue(labelColor) | async"
[valueColor]="getValue(valueColor) | async"
[cssClass]="getArrayValue(cssClass) | async"
[hiddenLabelModelKeys]="hiddenLabelModelKeys"
[headerColor]="getValue(headerColor) | async"
(onModelChanged)="onModelChanged.emit($event)"
[contentColor]="getValue(contentColor) | async"
[startupState]="getValue(startupState) | async"
[propertyActionTemplate]="propertyActionTemplate"
[foregroundColor]="getValue(foregroundColor) | async"
[hideOptionalValues]="getValue(hideOptionalValues) | async"
[headerHighlightColor]="getValue(headerHighlightColor) | async"
*ngIf="
(notEmptyValue(key) | async) && (notNullOrUndefinedValue(value) | async)
"
>
</x-model-presenter>
</ng-template>
### 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<T> {
//
//#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<XModelPresenterItemComponent>;
//#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<XModelPresenterComponent>('model')
);
//
if (isModelChanged) {
await this.prepareModel();
}
//#endregion
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XModelPresenterComponent>('actionProvider')
);
const isPanelActionProviderChanged = changeKeys.includes(
nameof<XModelPresenterComponent>('panelActionProvider')
);
if (isActionProviderChanged || isPanelActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Color Changes ...
//
//#region Color Changed ...
const isColorChanged = changeKeys.includes(
nameof<XModelPresenterComponent>('color')
);
if (isColorChanged) {
await this.applyPanelColor();
}
//#endregion
//
//#region Header Highlight Color Changed ...
const isHeaderHighlightColorChanged = changeKeys.includes(
nameof<XModelPresenterComponent>('headerHighlightColor')
);
if (isHeaderHighlightColorChanged) {
await this.applyHeaderHighlightColor();
}
//#endregion
//
//#region Header Color Changed ...
const isHeaderColorChanged = changeKeys.includes(
nameof<XModelPresenterComponent>('headerColor')
);
if (isHeaderColorChanged) {
await this.applyHeaderColor();
}
//#endregion
//
//#region Content Color Changed ...
const isContentColorChanged = changeKeys.includes(
nameof<XModelPresenterComponent>('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<string> {
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<XModelPresenterItemComponent> {
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<string> {
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<XModelPresenterActionModel>();
}
//
if (!this.panelActionProvider) {
this.panelActionProvider = new Subject<XExpandablePanelActionModel>();
}
//
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<string>
) {
//
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<XModelPresenterActionIdentifier> {}
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<T = any>
extends IXComponentCardContainer {
//
actionProvider: Subject<XModelPresenterActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
headerColor: XStandardType<XColorIdentifier>;
headerHighlightColor: XStandardType<XColorIdentifier>;
contentColor: XStandardType<XColorIdentifier>;
labelColor: XStandardType<XColorIdentifier>;
valueColor: XStandardType<XColorIdentifier>;
//
showLabels: XStandardType<boolean>;
propertyActionTemplate: TemplateRef<any>;
startupState: XStandardType<XModelPresenterStartupStateIdentifier>;
//
panelCssClass: XStandardType<XOneOrManyType<string>>;
panelActionProvider: Subject<XExpandablePanelActionModel>;
//
model: XStandardType<T>;
//
hideOptionalValues: XStandardType<boolean>;
availableModelKeys: XModelFieldsType<T>;
hiddenModelKeys: XModelFieldsType<T>;
hiddenLabelModelKeys: XModelFieldsType<T>;
sortOrderModelKeys: XModelFieldsType<T>;
modelKeyProvider: XModelKeyProvider<T>;
modelValueProvider: XModelValueProvider<T>;
//
onModelChanged: EventEmitter<T>;
}
@Injectable({
providedIn: 'root',
})
export class XModelPresenterContainer<T = any>
extends XComponentCardContainer
implements Readonly<IXModelPresenterContainer<T>>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XModelPresenterActionModel> =
new Subject<XModelPresenterActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly headerColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly headerHighlightColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.LightShade;
readonly contentColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly labelColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.TertiaryShade;
readonly valueColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
//
readonly showLabels: XStandardType<boolean> = true;
readonly propertyActionTemplate: TemplateRef<any>;
readonly startupState: XStandardType<XModelPresenterStartupStateIdentifier> =
XModelPresenterStartupState.CollapseAll;
//
readonly panelCssClass: XStandardType<XOneOrManyType<string>>;
readonly panelActionProvider: Subject<XExpandablePanelActionModel> =
new Subject<XExpandablePanelActionModel>();
//
readonly model: XStandardType<T>;
//
readonly hideOptionalValues: XStandardType<boolean> = false;
readonly availableModelKeys: XModelFieldsType<T>;
readonly hiddenModelKeys: XModelFieldsType<T>;
readonly hiddenLabelModelKeys: XModelFieldsType<T>;
readonly sortOrderModelKeys: XModelFieldsType<T>;
readonly modelKeyProvider: XModelKeyProvider<T>;
readonly modelValueProvider: XModelValueProvider<T>;
//
readonly onModelChanged: EventEmitter<T> = new EventEmitter<T>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XModelPresenterContainerComponent<T = any>
extends XComponentCardContainerComponent
implements IXModelPresenterContainer<T>
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XModelPresenterActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Input()
headerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.headerColor;
@Input()
headerHighlightColor: XStandardType<XColorIdentifier> =
this.propertyProvider.headerHighlightColor;
@Input()
contentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.contentColor;
@Input()
labelColor: XStandardType<XColorIdentifier> =
this.propertyProvider.labelColor;
@Input()
valueColor: XStandardType<XColorIdentifier> =
this.propertyProvider.valueColor;
//
@Input()
showLabels: XStandardType<boolean> = this.propertyProvider.showLabels;
@Input()
propertyActionTemplate: TemplateRef<any> =
this.propertyProvider.propertyActionTemplate;
@Input()
startupState: XStandardType<XModelPresenterStartupStateIdentifier> =
this.propertyProvider.startupState;
//
@Input()
panelCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.panelCssClass;
@Input()
panelActionProvider: Subject<XExpandablePanelActionModel> =
this.propertyProvider.panelActionProvider;
//
@Input()
model: XStandardType<T> = this.propertyProvider.model;
//
@Input()
hideOptionalValues: XStandardType<boolean> =
this.propertyProvider.hideOptionalValues;
@Input()
availableModelKeys: XModelFieldsType<T> =
this.propertyProvider.availableModelKeys;
@Input()
hiddenModelKeys: XModelFieldsType<T> = this.propertyProvider.hiddenModelKeys;
@Input()
hiddenLabelModelKeys: XModelFieldsType<T> =
this.propertyProvider.hiddenLabelModelKeys;
@Input()
sortOrderModelKeys: XModelFieldsType<T> =
this.propertyProvider.sortOrderModelKeys;
@Input()
modelKeyProvider: XModelKeyProvider<T> =
this.propertyProvider.modelKeyProvider;
@Input()
modelValueProvider: XModelValueProvider<T> =
this.propertyProvider.modelValueProvider;
//
@Output()
onModelChanged: EventEmitter<T> = 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<IXModelPresenterContainer> {
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
<ng-template #content>
<ng-content></ng-content>
</ng-template>
### 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<any>;
//
@Input()
name: XStandardType<string>;
@Input()
value: XStandardType<any>;
//
@Input()
cssClass: XStandardType<XOneOrManyType<string>>;
//
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
@Input()
actionProvider = new Subject<XModelPresenterItemModel>();
//#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<XModelPresenterItemComponent>('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<XModelPresenterItemModel>();
}
//
// 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<XModelPresenterItemActionIdentifier> {}
### FILE: C:\Users\SaherElm\Documents\Projects\xSaherelmWorkspace\Modules\xFrameworkComponentsHolder\projects\x-framework-components\src\lib\x-page\x-page.component.html
<!-- Component Content -->
<section
class="x-page x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<!-- Screen Capture -->
<x-screen-capture
[uiDisabled]="uiDisabled"
(imageCaptured)="imageCaptured.emit($event)"
[enable]="getValue(enableCaptureMode) | async"
[topOffset]="getValue(captureTopOffset) | async"
[bottomOffset]="getValue(captureBottomOffset) | async"
[downloadCapturedImage]="getValue(downloadCapturedImage) | async"
>
<!-- Toolbar -->
<x-toolbar
#toolbar
[uiDisabled]="uiDisabled"
*ngIf="getValue(showToolbar) | async"
[color]="getValue(toolbarColor) | async"
[title]="getValue(toolbarTitle) | async"
[contentTemplate]="toolbarContentTemplate"
[class.menu-opened]="isMenuOpen() | async"
[logoUrl]="getValue(toolbarLogoUrl) | async"
[hasMenu]="getValue(toolbarHasMenu) | async"
[hasBack]="getValue(toolbarHasBack) | async"
[logoSlot]="getValue(toolbarLogoSlot) | async"
[showLogo]="getValue(toolbarShowLogo) | async"
[showBack]="getValue(toolbarShowBack) | async"
[subTitle]="getValue(toolbarSubTitle) | async"
[showMenu]="getValue(toolbarShowMenu) | async"
[cssClass]="getValue(toolbarCssClass) | async"
[backSlot]="getValue(toolbarBackSlot) | async"
[menuSlot]="getValue(toolbarMenuSlot) | async"
[showTitle]="getValue(toolbarShowTitle) | async"
[titleSlot]="getValue(toolbarTitleSlot) | async"
[contentSlot]="getValue(toolbarContentSlot) | async"
[defaultHref]="getValue(toolbarDefaultHref) | async"
[backHandler]="getValue(toolbarBackHandler) | async"
[autoHideMenu]="getValue(toolbarAutoHideMenu) | async"
[showSubTitle]="getValue(toolbarShowSubTitle) | async"
[endSlotButtonsTemplate]="toolbarEndSlotButtonsTemplate"
[showProgressBar]="getValue(toolbarShowProgressBar) | async"
[startSlotButtonsTemplate]="toolbarStartSlotButtonsTemplate"
[progressBarColor]="getValue(toolbarProgressBarColor) | async"
>
</x-toolbar>
<!-- Split Pane -->
<ion-split-pane
contentId="x-menu-wrapper"
[when]="getValue(toggleMenuWhen) | async"
[disabled]="emptyValue(toggleMenuWhen) | async"
(ionSplitPaneVisible)="handleChangeSplitPane($event)"
>
<ng-container *ngTemplateOutlet="insideContentRef"></ng-container>
</ion-split-pane>
<!-- Footer -->
<x-footer
#footer
[uiDisabled]="uiDisabled"
*ngIf="getValue(showFooter) | async"
[color]="getValue(footerColor) | async"
[contentTemplate]="footerContentTemplate"
></x-footer>
</x-screen-capture>
</section>
<!-- Page Inside Content Template -->
<ng-template #insideContentRef>
<!-- Ion Menu -->
<!-- [disabled]="uiDisabled" -->
<ion-menu
id="menu"
class="x-menu"
contentId="x-menu-wrapper"
*ngIf="getValue(hasSide) | async"
[side]="getValue(sideSlot) | async"
[type]="getValue(sideType) | async"
(ionDidOpen)="handleMenuStateChanged(MenuStates.Opened)"
(ionDidClose)="handleMenuStateChanged(MenuStates.Closed)"
(ionWillOpen)="handleMenuStateChanged(MenuStates.WillOpen)"
(ionWillClose)="handleMenuStateChanged(MenuStates.WillClose)"
>
<!-- Menu Content -->
<ion-content #menuContent [color]="getValue(sideColor) | async">
<!-- Content -->
<div class="x-page-side-wrapper">
<ng-content select="[side]"></ng-content>
</div>
</ion-content>
</ion-menu>
<!-- Page Content -->
<ion-content
#pageContent
id="x-menu-wrapper"
[xColor]="getValue(color) | async"
class="ion-no-margin ion-no-padding"
[ngClass]="getValue(cssClass) | async"
(scrolling)="handleScrollingEvent($event)"
(scrollEnded)="scrolledEvent.emit($event)"
(scrollStarted)="handleScrollStarted($event)"
[scrollingActionProvider]="scrollEventActionProvider"
[scrollEvents]="getValue(provideScrollEvents) | async"
[xScrollBehaviour]="getValue(scrollBehaviour) | async"
[scrollEndClasses]="getValue(scrollEndClasses) | async"
[scrollStartClasses]="getValue(scrollStartClasses) | async"
>
<!-- Swipe Refresh -->
<ion-refresher
slot="fixed"
[disabled]="uiDisabled"
(ionRefresh)="handleRefresh($event)"
*ngIf="getValue(showPageRefresher) | async"
>
<ion-refresher-content
[refreshingText]="getValue(refreshingText) | async"
[pullingText]="getValue(refreshPullingText) | async"
[pullingIcon]="getValue(refreshPullingIcon) | async"
[refreshingSpinner]="getValue(refreshingSpinner) | async"
>
</ion-refresher-content>
</ion-refresher>
<!-- Page Content -->
<ng-content></ng-content>
<!-- Infinite Scroll -->
<ion-infinite-scroll
(ionInfinite)="handleLoadMore($event)"
*ngIf="getValue(showPageInfinityScroller) | async"
[disabled]="getValue(infinityScrollDisabled) | async"
[threshold]="getValue(infinityScrollThreshold) | async"
>
<ion-infinite-scroll-content
[loadingText]="getValue(infinityScrollerLoadingText) | async"
[loadingSpinner]="getValue(infinityScrollerLoadingSpinner) | async"
>
</ion-infinite-scroll-content>
</ion-infinite-scroll>
<!-- Fab Actions -->
<ng-container *ngIf="getValue(actions) | async">
<x-fab
pageFab
[loading]="loading"
[uiDisabled]="uiDisabled"
[item]="getValue(actions) | async"
(xOnOutsideClicked)="closeActions()"
[actionProvider]="actionsActionProvider"
>
</x-fab>
</ng-container>
</ion-content>
</ng-template>
### 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<XPageComponent>('sideMenuWidth')
);
const isSideMenuMinWidthChanged = changeKeys.includes(
nameof<XPageComponent>('sideMenuMinWidth')
);
const isSideMenuMaxWidthChanged = changeKeys.includes(
nameof<XPageComponent>('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<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
//
enableCaptureMode: XStandardType<boolean>;
downloadCapturedImage: XStandardType<boolean>;
captureTopOffset: XStandardType<number>;
captureBottomOffset: XStandardType<number>;
imageCaptured: EventEmitter<string | Blob>;
//
provideScrollEvents: XStandardType<boolean>;
scrollStartClasses: XOneOrManyType<string>;
scrollEndClasses: XOneOrManyType<string>;
scrollingClasses: XOneOrManyType<string>;
scrollBehaviour: XOneOrManyType<string>;
scrollEventActionProvider: Subject<XBehaviourEventType>;
scrolledEvent: EventEmitter<XBehaviourEvent>;
//
toggleMenuWhen: XStandardType<XPageSizeIdentifier>;
hasSide: XStandardType<boolean>;
sideSlot: XStandardType<XSideSlotIdentifier>;
sideType: XStandardType<XSideTypeIdentifier>;
sideColor: XStandardType<XColorIdentifier>;
sideMenuWidth: XStandardType<number>;
sideMenuMinWidth: XStandardType<number>;
sideMenuMaxWidth: XStandardType<number>;
menuState: XStandardType<XMenuState>;
menuActionProvider: Subject<XMenuAction>;
splitterStateChanged: EventEmitter<boolean>;
menuStateChange: EventEmitter<XMenuState>;
//
showPageRefresher: XStandardType<boolean>;
refreshPage: EventEmitter<XPageLoadingEvent>;
refreshingText: XStandardType<string>;
refreshPullingText: XStandardType<string>;
refreshPullingIcon: XStandardType<XIconIdentifier>;
refreshingSpinner: XStandardType<XSpinnerIdentifier>;
//
showPageInfinityScroller: XStandardType<boolean>;
infinityScrollDisabled: XStandardType<boolean>;
infinityScrollThreshold: XStandardType<string>;
infinityScrollerLoadingText: XStandardType<string>;
infinityScrollerLoadingSpinner: XStandardType<XSpinnerIdentifier>;
loadMore: EventEmitter<XPageLoadingEvent>;
//
actions: XStandardType<XFabItem>;
actionsActionProvider: Subject<XFabActionModel>;
}
@Injectable({
providedIn: 'root',
})
export class XPageContainer
extends XToolbarFooterContainer
implements Readonly<IXPageContainer>
{
//
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> =
XColorWithBrightness.LightShade;
//
readonly enableCaptureMode: XStandardType<boolean> = false;
readonly downloadCapturedImage: XStandardType<boolean> = true;
readonly captureTopOffset: XStandardType<number> = 0;
readonly captureBottomOffset: XStandardType<number> = 0;
readonly imageCaptured: EventEmitter<string | Blob> = new EventEmitter<
string | Blob
>();
//
readonly provideScrollEvents: XStandardType<boolean>;
readonly scrollStartClasses: XOneOrManyType<string>;
readonly scrollEndClasses: XOneOrManyType<string>;
readonly scrollingClasses: XOneOrManyType<string>;
readonly scrollBehaviour: XOneOrManyType<string>;
readonly scrollEventActionProvider: Subject<XBehaviourEventType> =
new Subject<XBehaviourEventType>();
readonly scrolledEvent: EventEmitter<XBehaviourEvent> =
new EventEmitter<XBehaviourEvent>();
//
readonly toggleMenuWhen: XStandardType<XPageSizeIdentifier> =
XPageSize.Medium;
readonly hasSide: XStandardType<boolean> = true;
readonly sideSlot: XStandardType<XSideSlotIdentifier> = XSideSlot.Start;
readonly sideType: XStandardType<XSideTypeIdentifier> = XSideType.Overlay;
readonly sideColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.PrimaryShade;
readonly sideMenuWidth: XStandardType<number> = 200;
readonly sideMenuMinWidth: XStandardType<number> = 100;
readonly sideMenuMaxWidth: XStandardType<number> = 200;
readonly menuState: XStandardType<XMenuState> = XMenuState.Opened;
readonly menuActionProvider = new Subject<XMenuAction>();
readonly splitterStateChanged = new EventEmitter<boolean>();
readonly menuStateChange = new EventEmitter<XMenuState>();
//
readonly showPageRefresher: XStandardType<boolean> = false;
readonly refreshPage: EventEmitter<XPageLoadingEvent> =
new EventEmitter<XPageLoadingEvent>();
readonly refreshingText: XStandardType<string>;
readonly refreshPullingText: XStandardType<string>;
readonly refreshPullingIcon: XStandardType<XIconIdentifier>;
readonly refreshingSpinner: XStandardType<XSpinnerIdentifier> =
XSpinner.Circular;
//
readonly showPageInfinityScroller: XStandardType<boolean> = false;
readonly infinityScrollDisabled: XStandardType<boolean> = false;
readonly infinityScrollThreshold: XStandardType<string> = '200px';
readonly infinityScrollerLoadingText: XStandardType<string>;
readonly infinityScrollerLoadingSpinner: XStandardType<XSpinnerIdentifier> =
XSpinner.Circular;
readonly loadMore: EventEmitter<XPageLoadingEvent> =
new EventEmitter<XPageLoadingEvent>();
//
readonly actions: XStandardType<XFabItem>;
readonly actionsActionProvider: Subject<XFabActionModel> =
new Subject<XFabActionModel>();
}
@Injectable()
@Component({
template: ``,
})
export abstract class XPageContainerComponent
extends XBasePage
implements IXPageContainer
{
//
//#region Props ...
//
//#region Page ...
//
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
//
@Input()
enableCaptureMode: XStandardType<boolean> =
this.propertyProvider.enableCaptureMode;
@Input()
downloadCapturedImage: XStandardType<boolean> =
this.propertyProvider.downloadCapturedImage;
@Input()
captureTopOffset: XStandardType<number> =
this.propertyProvider.captureTopOffset;
@Input()
captureBottomOffset: XStandardType<number> =
this.propertyProvider.captureBottomOffset;
@Output()
imageCaptured: EventEmitter<string | Blob> = new EventEmitter();
//
@Input()
provideScrollEvents: XStandardType<boolean> =
this.propertyProvider.provideScrollEvents;
@Input()
scrollStartClasses: XOneOrManyType<string> =
this.propertyProvider.scrollStartClasses;
@Input()
scrollEndClasses: XOneOrManyType<string> =
this.propertyProvider.scrollEndClasses;
@Input()
scrollingClasses: XOneOrManyType<string> =
this.propertyProvider.scrollingClasses;
@Input()
scrollBehaviour: XOneOrManyType<string> =
this.propertyProvider.scrollBehaviour;
@Input()
scrollEventActionProvider: Subject<XBehaviourEventType> =
this.propertyProvider.scrollEventActionProvider;
@Output()
scrolledEvent: EventEmitter<XBehaviourEvent> = new EventEmitter();
//
@Input()
toggleMenuWhen: XStandardType<XPageSizeIdentifier> =
this.propertyProvider.toggleMenuWhen;
@Input()
hasSide: XStandardType<boolean> = this.propertyProvider.hasSide;
@Input()
sideSlot: XStandardType<XSideSlotIdentifier> = this.propertyProvider.sideSlot;
@Input()
sideType: XStandardType<XSideTypeIdentifier> = this.propertyProvider.sideType;
@Input()
sideColor: XStandardType<XColorIdentifier> = this.propertyProvider.sideColor;
@Input()
sideMenuWidth: XStandardType<number> = this.propertyProvider.sideMenuWidth;
@Input()
sideMenuMinWidth: XStandardType<number> =
this.propertyProvider.sideMenuMinWidth;
@Input()
sideMenuMaxWidth: XStandardType<number> =
this.propertyProvider.sideMenuMaxWidth;
@Input()
menuState: XStandardType<XMenuState> = this.propertyProvider.menuState;
@Input()
menuActionProvider: Subject<XMenuAction> =
this.propertyProvider.menuActionProvider;
@Output()
splitterStateChanged: EventEmitter<boolean> = new EventEmitter();
@Output()
menuStateChange: EventEmitter<XMenuState> = new EventEmitter();
//
@Input()
showPageRefresher: XStandardType<boolean> =
this.propertyProvider.showPageRefresher;
@Output()
refreshPage: EventEmitter<XPageLoadingEvent> = new EventEmitter();
@Input()
refreshingText: XStandardType<string> = this.propertyProvider.refreshingText;
@Input()
refreshPullingText: XStandardType<string> =
this.propertyProvider.refreshPullingText;
@Input()
refreshPullingIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.refreshPullingIcon;
@Input()
refreshingSpinner: XStandardType<XSpinnerIdentifier> =
this.propertyProvider.refreshingSpinner;
//
@Input()
showPageInfinityScroller: XStandardType<boolean> =
this.propertyProvider.showPageInfinityScroller;
@Input()
infinityScrollDisabled: XStandardType<boolean> =
this.propertyProvider.infinityScrollDisabled;
@Input()
infinityScrollThreshold: XStandardType<string> =
this.propertyProvider.infinityScrollThreshold;
@Input()
infinityScrollerLoadingText: XStandardType<string> =
this.propertyProvider.infinityScrollerLoadingText;
@Input()
infinityScrollerLoadingSpinner: XStandardType<XSpinnerIdentifier> =
this.propertyProvider.infinityScrollerLoadingSpinner;
@Output()
loadMore: EventEmitter<XPageLoadingEvent> = new EventEmitter();
//
@Input()
actions: XStandardType<XFabItem> = this.propertyProvider.actions;
@Input()
actionsActionProvider: Subject<XFabActionModel> =
this.propertyProvider.actionsActionProvider;
//#endregion
//
//#region Toolbar ...
//
@Input()
showToolbar: XStandardType<boolean> = this.propertyProvider.showToolbar;
//
@Input()
toolbarActionProvider: Subject<XToolbarActionModel> =
this.propertyProvider.toolbarActionProvider;
@Input()
toolbarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.toolbarCssClass;
//
@Input()
toolbarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.toolbarColor;
//
@Input()
toolbarShowProgressBar: XStandardType<boolean> =
this.propertyProvider.toolbarShowProgressBar;
@Input()
toolbarProgressBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.toolbarProgressBarColor;
//
@Input()
toolbarShowTitle: XStandardType<boolean> =
this.propertyProvider.toolbarShowTitle;
@Input()
toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
this.propertyProvider.toolbarTitleSlot;
@Input()
toolbarTitle: XStandardType<string> = this.propertyProvider.toolbarTitle;
//
@Input()
toolbarShowSubTitle: XStandardType<boolean> =
this.propertyProvider.toolbarShowSubTitle;
@Input()
toolbarSubTitle: XStandardType<string> =
this.propertyProvider.toolbarSubTitle;
//
@Input()
toolbarShowLogo: XStandardType<boolean> =
this.propertyProvider.toolbarShowLogo;
@Input()
toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
this.propertyProvider.toolbarLogoSlot;
@Input()
toolbarLogoUrl: XStandardType<string> = this.propertyProvider.toolbarLogoUrl;
//
@Input()
toolbarHasBack: XStandardType<boolean> = this.propertyProvider.toolbarHasBack;
@Input()
toolbarShowBack: XStandardType<boolean> =
this.propertyProvider.toolbarShowBack;
@Input()
toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
this.propertyProvider.toolbarBackSlot;
@Input()
toolbarBackHandler?: () => XStandardType<void> = () => {
this.managerService.historyService.back();
};
@Input()
toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref;
//
@Input()
toolbarHasMenu: XStandardType<boolean> = this.propertyProvider.toolbarHasMenu;
@Input()
toolbarShowMenu: XStandardType<boolean> =
this.propertyProvider.toolbarShowMenu;
@Input()
toolbarAutoHideMenu: XStandardType<boolean> =
this.propertyProvider.toolbarAutoHideMenu;
@Input()
toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
this.propertyProvider.toolbarMenuSlot;
//
@Input()
toolbarStartSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.toolbarStartSlotButtonsTemplate;
@Input()
toolbarEndSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.toolbarEndSlotButtonsTemplate;
//
@Input()
toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
this.propertyProvider.toolbarContentSlot;
@Input()
toolbarContentTemplate: TemplateRef<any> =
this.propertyProvider.toolbarContentTemplate;
//#endregion
//
//#region Footer ...
//
@Input()
showFooter: XStandardType<boolean> = this.propertyProvider.showFooter;
//
@Input()
footerActionProvider: Subject<XFooterActionModel> =
this.propertyProvider.footerActionProvider;
@Input()
footerCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.footerCssClass;
//
@Input()
footerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.footerColor;
@Input()
footerContentTemplate: TemplateRef<any> =
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<IXPageContainer> {
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
<ion-footer
class="x-footer x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<ion-toolbar [color]="getValue(color) | async">
<ion-title class="ion-text-center">
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
</ion-title>
</ion-toolbar>
</ion-footer>
### 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<XFooterComponent>('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<XFooterActionModel>();
}
//
// 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<XFooterActionIdentifier> {}
//
//#region Container ...
export interface IXFooterContainer extends IXBaseContainer {
//
actionProvider: Subject<XFooterActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
contentTemplate: TemplateRef<any>;
}
@Injectable({
providedIn: 'root'
})
export class XFooterContainer
extends XBaseContainer
implements Readonly<IXFooterContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XFooterActionModel> =
new Subject<XFooterActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly contentTemplate: TemplateRef<any>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XFooterContainerComponent
extends XBaseContainerComponent
implements IXFooterContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XFooterActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
contentTemplate: TemplateRef<any> = 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<IXFooterContainer> {
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<boolean>;
}
@Injectable({
providedIn: 'root'
})
export class XComponentFooterContainer
extends XBaseComponentContainer
implements Readonly<IXComponentFooterContainer>
{
//
//#region Props ...
//
readonly showFooter: XStandardType<boolean> = true;
//
readonly footerActionProvider: Subject<XFooterActionModel> =
this.propertyProvider.actionProvider;
readonly footerCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly footerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
readonly footerContentTemplate: TemplateRef<any> =
this.propertyProvider.contentTemplate;
//#endregion
//
//#region Constructor ...
constructor(protected propertyProvider: XFooterContainer) {
super();
}
//#endregion
}
@Injectable({
providedIn: 'root'
})
@Component({
template: `
<!--
<ng-container *ngIf="extractProps() | async as props">
<ng-container *ngIf="props.showFooter">
<x-footer
[footerColor]="props.footerColor"
[footerCssClass]="props.footerCssClass"
[footerActionProvider]="props.footerActionProvider"
[footerContentTemplate]="props.footerContentTemplate"
>
</x-footer>
</ng-container>
</ng-container>
-->
`,
})
export abstract class XComponentFooterContainerComponent
extends XBaseComponentContainerComponent
implements IXComponentFooterContainer
{
//
//#region Props ...
//
@Input()
showFooter: XStandardType<boolean> = this.propertyProvider.showFooter;
//
@Input()
footerActionProvider: Subject<XFooterActionModel> =
this.propertyProvider.footerActionProvider;
@Input()
footerCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.footerCssClass;
//
@Input()
footerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.footerColor;
@Input()
footerContentTemplate: TemplateRef<any> =
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<IXComponentFooterContainer> {
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
<x-expandable-list
[loading]="loading"
[supportRouting]="true"
[uiDisabled]="uiDisabled"
class="x-navigator x-wrapper"
[childTemplate]="childTempRef"
[parentTemplate]="parentTempRef"
[class.mobile]="isMobileUi$ | async"
[cssClass]="getValue(cssClass) | async"
(itemSelected)="itemSelected.emit($event)"
[childColor]="getValue(childColor) | async"
[parentColor]="getValue(parentColor) | async"
[items]="getArrayValue(preparedItems) | async"
[startupState]="getValue(startupState) | async"
[itemCssClass]="getValue(itemCssClass) | async"
[dividerColor]="getValue(dividerColor) | async"
[closeSiblings]="getValue(closeSiblings) | async"
[highlightColor]="getValue(highlightColor) | async"
[childActiveColor]="getValue(childActiveColor) | async"
[parentActiveColor]="getValue(parentActiveColor) | async"
[showChildDetailIcon]="getValue(showChildDetailIcon) | async"
[showParentDetailIcon]="getValue(showParentDetailIcon) | async"
[disableParentRouting]="getValue(disableParentRouting) | async"
>
</x-expandable-list>
<ng-template #parentTempRef let-item>
<div
fxLayout="row"
fxLayoutAlign="start center"
class="nav-item nav-item-parent"
[ngClass]="getValue(itemCssClass) | async"
>
<div class="start">
<ng-container *ngIf="isStartSlotted() | async">
<ng-container
*ngTemplateOutlet="iconRef; context: { $implicit: item }"
></ng-container>
</ng-container>
</div>
<div fxFill class="center">
<h4 class="x-nav-item-title ion-no-margin ion-no-padding text-truncate">
{{ getResourceValue(item.title) | async }}
</h4>
</div>
<div class="end">
<ng-container *ngIf="isEndSlotted() | async">
<ng-container
*ngTemplateOutlet="iconRef; context: { $implicit: item }"
></ng-container>
</ng-container>
</div>
</div>
</ng-template>
<ng-template #childTempRef let-item>
<div
fxLayout="row"
fxLayoutAlign="start center"
class="nav-item nav-item-child"
[ngClass]="getValue(itemCssClass) | async"
>
<div class="start" *ngIf="getValue(showChildIcon) | async">
<ng-container *ngIf="isStartSlotted() | async">
<ng-container
*ngTemplateOutlet="iconRef; context: { $implicit: item }"
></ng-container>
</ng-container>
</div>
<div fxFill class="center">
<h4 class="x-nav-item-title ion-no-margin ion-no-padding text-truncate">
{{ getResourceValue(item.title) | async }}
</h4>
</div>
<div class="end" *ngIf="getValue(showChildIcon) | async">
<ng-container *ngIf="isEndSlotted() | async">
<ng-container
*ngTemplateOutlet="iconRef; context: { $implicit: item }"
></ng-container>
</ng-container>
</div>
</div>
</ng-template>
<ng-template #iconRef let-item>
<x-icon [cssClass]="'cb-inherit'" [name]="getValue(item.icon) | async">
</x-icon>
</ng-template>
### 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<XExpandableListItem<any>>;
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<XNavigatorComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Items Changed ...
const isItemsChanged = changeKeys.includes(
nameof<XNavigatorComponent>('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<XNavigatorActionModel>();
}
//
// 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<any> = {
//
...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<XPage>): 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<XPage>) {
//
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<XPage>) {
//
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<any>,
| 'id'
| 'href'
| 'title'
| 'opened'
| 'hidden'
| 'disabled'
| 'replaceUrl'
| 'description'
>;
export interface XNavigatorListItem extends XNavigatorListItemBase {
icon?: XStandardType<XIconIdentifier>;
childs?: XStandardType<XOneOrManyType<XNavigatorListItem>>;
}
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<XNavigatorActionIdentifier> {}
//
//#region Container ...
export interface IXNavigatorContainer extends IXBaseContainer {
//
actionProvider: Subject<XNavigatorActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
itemCssClass: XStandardType<XOneOrManyType<string>>;
items: XStandardType<XOneOrManyType<XNavigatorListItem>>;
//
closeSiblings: XStandardType<boolean>;
iconSlot: XStandardType<XNavigatorItemIconSlotIdentifier>;
startupState: XStandardType<XNavigatorStartupStateIdentifier>;
//
showChildIcon: XStandardType<boolean>;
showChildDetailIcon: XStandardType<boolean>;
showParentIcon: XStandardType<boolean>;
showParentDetailIcon: XStandardType<boolean>;
disableParentRouting: XStandardType<boolean>;
//
childColor: XStandardType<XColorIdentifier>;
childActiveColor: XStandardType<XColorIdentifier>;
parentColor: XStandardType<XColorIdentifier>;
parentActiveColor: XStandardType<XColorIdentifier>;
highlightColor: XStandardType<XColorIdentifier>;
dividerColor: XStandardType<XColorIdentifier>;
//
itemSelected: EventEmitter<XNavigatorListItem>;
}
@Injectable({
providedIn: 'root',
})
export class XNavigatorContainer
extends XBaseContainer
implements Readonly<IXNavigatorContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XNavigatorActionModel> =
new Subject<XNavigatorActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly itemCssClass: XStandardType<XOneOrManyType<string>>;
readonly items: XStandardType<XOneOrManyType<XNavigatorListItem>>;
//
readonly closeSiblings: XStandardType<boolean> = true;
readonly iconSlot: XStandardType<XNavigatorItemIconSlotIdentifier> =
XNavigatorItemIconSlot.Start;
readonly startupState: XStandardType<XNavigatorStartupStateIdentifier> =
XNavigatorStartupState.ExpandAll;
//
readonly showChildIcon: XStandardType<boolean> = true;
readonly showChildDetailIcon: XStandardType<boolean> = true;
readonly showParentIcon: XStandardType<boolean> = true;
readonly showParentDetailIcon: XStandardType<boolean> = true;
readonly disableParentRouting: XStandardType<boolean> = true;
//
readonly childColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.PrimaryShade;
readonly childActiveColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly parentColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.TertiaryTint;
readonly parentActiveColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly highlightColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Warning;
readonly dividerColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
//
readonly itemSelected: EventEmitter<XNavigatorListItem> =
new EventEmitter<XNavigatorListItem>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XNavigatorContainerComponent
extends XBaseContainerComponent
implements IXNavigatorContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XNavigatorActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
itemCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.itemCssClass;
@Input()
items: XStandardType<XOneOrManyType<XNavigatorListItem>> =
this.propertyProvider.items;
//
@Input()
closeSiblings: XStandardType<boolean> = this.propertyProvider.closeSiblings;
@Input()
iconSlot: XStandardType<XNavigatorItemIconSlotIdentifier> =
this.propertyProvider.iconSlot;
@Input()
startupState: XStandardType<XNavigatorStartupStateIdentifier> =
this.propertyProvider.startupState;
//
@Input()
showChildIcon: XStandardType<boolean> = this.propertyProvider.showChildIcon;
@Input()
showChildDetailIcon: XStandardType<boolean> =
this.propertyProvider.showChildDetailIcon;
@Input()
showParentIcon: XStandardType<boolean> = this.propertyProvider.showParentIcon;
@Input()
showParentDetailIcon: XStandardType<boolean> =
this.propertyProvider.showParentDetailIcon;
@Input()
disableParentRouting: XStandardType<boolean> =
this.propertyProvider.disableParentRouting;
//
@Input()
childColor: XStandardType<XColorIdentifier> =
this.propertyProvider.childColor;
@Input()
childActiveColor: XStandardType<XColorIdentifier> =
this.propertyProvider.childActiveColor;
@Input()
parentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.parentColor;
@Input()
parentActiveColor: XStandardType<XColorIdentifier> =
this.propertyProvider.parentActiveColor;
@Input()
highlightColor: XStandardType<XColorIdentifier> =
this.propertyProvider.highlightColor;
@Input()
dividerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.dividerColor;
//
@Output()
itemSelected: EventEmitter<XNavigatorListItem> = 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<IXNavigatorContainer> {
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
<ion-header>
<!-- Toolbar -->
<ion-toolbar
matRipple
[color]="getValue(color) | async"
[ngClass]="getValue(cssClass) | async"
>
<div class="x-toolbar-slot-container">
<!-- Start Slot Content -->
<div slot="start" class="x-toolbar-slot x-toolbar-start-slot">
<!-- Start Slot Buttons -->
<ion-buttons>
<!-- Back Button -->
<ng-container
*ngIf="(getValue(showBack) | async) && (isStartSlotBack() | async)"
>
<ng-container *ngTemplateOutlet="backButtonRef"></ng-container>
</ng-container>
<!-- Menu Button -->
<ng-container
*ngIf="(getValue(showMenu) | async) && (isStartSlotMenu() | async)"
>
<ion-menu-button
*ngIf="getValue(hasMenu) | async"
(click)="handleMenuButtonClicked()"
[autoHide]="getValue(autoHideMenu) | async"
></ion-menu-button>
</ng-container>
<!-- Custom Start Buttons -->
<ng-container *ngIf="startSlotButtonsTemplate">
<ng-container
*ngTemplateOutlet="startSlotButtonsTemplate"
></ng-container>
</ng-container>
</ion-buttons>
<!-- Logo -->
<ion-thumbnail
class="x-toolbar-thumbnail"
*ngIf="(getValue(showLogo) | async) && (isStartSlotLogo() | async)"
>
<ion-img [src]="getValue(logoUrl) | async"></ion-img>
</ion-thumbnail>
<!-- Title and SubTitle -->
<span
class="x-toolbar-title-wrapper ion-text-start"
*ngIf="(getValue(showTitle) | async) && (isStartSlotTitle() | async)"
>
<ng-container *ngTemplateOutlet="titleSubTitleRef"></ng-container>
</span>
<!-- Custom Content -->
<ng-container *ngIf="contentTemplate && (isStartSlotContent() | async)">
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
</ng-container>
</div>
<!-- Middle Content -->
<div
class="x-toolbar-slot x-toolbar-middle-slot"
*ngIf="contentTemplate && (isMiddleSlotContent() | async)"
>
<!-- Custom Content -->
<ng-container
*ngIf="contentTemplate && (isMiddleSlotContent() | async)"
>
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
</ng-container>
</div>
<!-- End Slot Content -->
<div class="x-toolbar-slot x-toolbar-end-slot" slot="end">
<!-- Custom Content -->
<ng-container *ngIf="contentTemplate && (isEndSlotContent() | async)">
<ng-container *ngTemplateOutlet="contentTemplate"></ng-container>
</ng-container>
<!-- Title and SubTitle -->
<span
class="x-toolbar-title-wrapper ion-text-end"
*ngIf="(getValue(showTitle) | async) && (isEndSlotTitle() | async)"
>
<ng-container *ngTemplateOutlet="titleSubTitleRef"></ng-container>
</span>
<!-- Logo -->
<ion-thumbnail
class="x-toolbar-thumbnail"
*ngIf="(getValue(showLogo) | async) && (isEndSlotLogo() | async)"
>
<ion-img [src]="getValue(logoUrl) | async"></ion-img>
</ion-thumbnail>
<!-- End Slot Buttons -->
<ion-buttons>
<!-- Custom Start Buttons -->
<ng-container *ngIf="endSlotButtonsTemplate">
<ng-container
*ngTemplateOutlet="endSlotButtonsTemplate"
></ng-container>
</ng-container>
<!-- Menu Button -->
<ng-container
*ngIf="(getValue(showMenu) | async) && (isEndSlotMenu() | async)"
>
<ion-menu-button
*ngIf="getValue(hasMenu) | async"
(click)="handleMenuButtonClicked()"
[autoHide]="getValue(autoHideMenu) | async"
></ion-menu-button>
</ng-container>
<!-- Back Button -->
<ng-container
*ngIf="(getValue(showBack) | async) && (isEndSlotBack() | async)"
>
<ng-container *ngTemplateOutlet="backButtonRef"></ng-container>
</ng-container>
</ion-buttons>
</div>
</div>
</ion-toolbar>
<!-- Progressbar for Loading -->
<ion-progress-bar
type="indeterminate"
*ngIf="getValue(showProgressBar) | async"
[color]="getValue(progressBarColor) | async"
></ion-progress-bar>
</ion-header>
<!-- Back Bottun Template -->
<ng-template #backButtonRef>
<x-button
class="x-toolbar-back"
[type]="ButtonTypes.Icon"
[title]="ResourceIDs.back"
[color]="getValue(color) | async"
(clicked)="handleBackButtonClicked($event)"
>
<x-icon
[foregroundColor]="false"
[name]="IconNames.arrow_back"
[color]="getValue(color) | async"
></x-icon>
</x-button>
</ng-template>
<!-- Title/SubTitle Template -->
<ng-template #titleSubTitleRef>
<!-- Title -->
<h3
[class.mobile]="managerService.isMobileUi$ | async"
class="x-toolbar-title ion-no-padding ion-no-margin"
[class.text-truncate]="managerService.isMobileUi$ | async"
>
{{ getValue(title) | async }}
</h3>
<!-- SubTitle -->
<h5
*ngIf="getValue(showSubTitle) | async"
[matTooltip]="getValue(subTitle) | async"
[class.mobile]="managerService.isMobileUi$ | async"
class="x-toolbar-sub-title ion-no-margin ion-no-padding"
[class.text-truncate]="managerService.isMobileUi$ | async"
>
{{ getValue(subTitle) | async }}
</h5>
</ng-template>
### 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<XToolbarComponent>('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<string>(XParam.ReturnUrl);
}
canBack() {
//
return this.getValue(this.hasBack).pipe(
map((hasBack) => {
//
if (
!hasBack &&
this.managerService.isContainQueryParam(XParam.HasBack)
) {
hasBack =
hasBack ||
this.managerService.getQueryParamValOfType<boolean>(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<string>(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<XToolbarActionModel>();
}
//
// 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<XToolbarActionIdentifier> {}
//
//#region Container ...
export interface IXToolbarContainer extends IXBaseContainer {
//
actionProvider: Subject<XToolbarActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
//
showProgressBar: XStandardType<boolean>;
progressBarColor: XStandardType<XColorIdentifier>;
//
showTitle: XStandardType<boolean>;
titleSlot: XStandardType<XTitleSlotIdentifier>;
title: XStandardType<string>;
//
showSubTitle: XStandardType<boolean>;
subTitle: XStandardType<string>;
//
showLogo: XStandardType<boolean>;
logoSlot: XStandardType<XLogoSlotIdentifier>;
logoUrl: XStandardType<string>;
//
hasBack: XStandardType<boolean>;
showBack: XStandardType<boolean>;
backSlot: XStandardType<XBackSlotIdentifier>;
backHandler?: () => XStandardType<void>;
defaultHref: string;
//
hasMenu: XStandardType<boolean>;
showMenu: XStandardType<boolean>;
autoHideMenu: XStandardType<boolean>;
menuSlot: XStandardType<XMenuSlotIdentifier>;
//
startSlotButtonsTemplate: TemplateRef<any>;
endSlotButtonsTemplate: TemplateRef<any>;
//
contentSlot: XStandardType<XContentSlotIdentifier>;
contentTemplate: TemplateRef<any>;
}
@Injectable({
providedIn: 'root',
})
export class XToolbarContainer
extends XBaseContainer
implements Readonly<IXToolbarContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XToolbarActionModel> =
new Subject<XToolbarActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> =
XColorWithBrightness.Primary;
//
readonly showProgressBar: XStandardType<boolean> = false;
readonly progressBarColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Warning;
//
readonly showTitle: XStandardType<boolean> = true;
readonly titleSlot: XStandardType<XTitleSlotIdentifier> = XTitleSlot.End;
readonly title: XStandardType<string>;
//
readonly showSubTitle: XStandardType<boolean> = false;
readonly subTitle: XStandardType<string>;
//
readonly showLogo: XStandardType<boolean> = false;
readonly logoSlot: XStandardType<XLogoSlotIdentifier> = XLogoSlot.Start;
readonly logoUrl: XStandardType<string>;
//
readonly hasBack: XStandardType<boolean> = true;
readonly showBack: XStandardType<boolean> = false;
readonly backSlot: XStandardType<XBackSlotIdentifier> = XBackSlot.Start;
readonly backHandler?: () => XStandardType<void>;
readonly defaultHref: string;
//
readonly hasMenu: XStandardType<boolean> = true;
readonly showMenu: XStandardType<boolean> = false;
readonly autoHideMenu: XStandardType<boolean> = true;
readonly menuSlot: XStandardType<XMenuSlotIdentifier> = XMenuSlot.Start;
//
readonly startSlotButtonsTemplate: TemplateRef<any>;
readonly endSlotButtonsTemplate: TemplateRef<any>;
//
readonly contentSlot: XStandardType<XContentSlotIdentifier> =
XContentSlot.End;
readonly contentTemplate: TemplateRef<any>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XToolbarContainerComponent
extends XBaseContainerComponent
implements IXToolbarContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XToolbarActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
//
@Input()
showProgressBar: XStandardType<boolean> =
this.propertyProvider.showProgressBar;
@Input()
progressBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.progressBarColor;
//
@Input()
showTitle: XStandardType<boolean> = this.propertyProvider.showTitle;
@Input()
titleSlot: XStandardType<XTitleSlotIdentifier> =
this.propertyProvider.titleSlot;
@Input()
title: XStandardType<string> = this.propertyProvider.title;
//
@Input()
showSubTitle: XStandardType<boolean> = this.propertyProvider.showSubTitle;
@Input()
subTitle: XStandardType<string> = this.propertyProvider.subTitle;
//
@Input()
showLogo: XStandardType<boolean> = this.propertyProvider.showLogo;
@Input()
logoSlot: XStandardType<XLogoSlotIdentifier> = this.propertyProvider.logoSlot;
@Input()
logoUrl: XStandardType<string> = this.propertyProvider.logoUrl;
//
@Input()
hasBack: XStandardType<boolean> = this.propertyProvider.hasBack;
@Input()
showBack: XStandardType<boolean> = this.propertyProvider.showBack;
@Input()
backSlot: XStandardType<XBackSlotIdentifier> = this.propertyProvider.backSlot;
@Input()
backHandler?: () => XStandardType<void> = this.propertyProvider.backHandler;
@Input()
defaultHref: string = this.propertyProvider.defaultHref;
//
@Input()
hasMenu: XStandardType<boolean> = this.propertyProvider.hasMenu;
@Input()
showMenu: XStandardType<boolean> = this.propertyProvider.showMenu;
@Input()
autoHideMenu: XStandardType<boolean> = this.propertyProvider.autoHideMenu;
@Input()
menuSlot: XStandardType<XMenuSlotIdentifier> = this.propertyProvider.menuSlot;
//
@Input()
startSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.startSlotButtonsTemplate;
@Input()
endSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.endSlotButtonsTemplate;
//
@Input()
contentSlot: XStandardType<XContentSlotIdentifier> =
this.propertyProvider.contentSlot;
@Input()
contentTemplate: TemplateRef<any> = 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<IXToolbarContainer> {
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<boolean>;
}
@Injectable({
providedIn: 'root',
})
export class XComponentToolbarContainer
extends XBaseComponentContainer
implements Readonly<IXComponentToolbarContainer>
{
//
//#region Props ...
//
readonly showToolbar: XStandardType<boolean> = true;
//
readonly toolbarActionProvider: Subject<XToolbarActionModel> =
this.propertyProvider.actionProvider;
readonly toolbarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly toolbarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
//
readonly toolbarShowProgressBar: XStandardType<boolean> =
this.propertyProvider.showProgressBar;
readonly toolbarProgressBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.progressBarColor;
//
readonly toolbarShowTitle: XStandardType<boolean> =
this.propertyProvider.showTitle;
readonly toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
this.propertyProvider.titleSlot;
readonly toolbarTitle: XStandardType<string> = this.propertyProvider.title;
//
readonly toolbarShowSubTitle: XStandardType<boolean> =
this.propertyProvider.showSubTitle;
readonly toolbarSubTitle: XStandardType<string> =
this.propertyProvider.subTitle;
//
readonly toolbarShowLogo: XStandardType<boolean> =
this.propertyProvider.showLogo;
readonly toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
this.propertyProvider.logoSlot;
readonly toolbarLogoUrl: XStandardType<string> =
this.propertyProvider.logoUrl;
//
readonly toolbarHasBack: XStandardType<boolean> =
this.propertyProvider.hasBack;
readonly toolbarShowBack: XStandardType<boolean> =
this.propertyProvider.showBack;
readonly toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
this.propertyProvider.backSlot;
readonly toolbarBackHandler?: () => XStandardType<void> =
this.propertyProvider.backHandler;
readonly toolbarDefaultHref: string = this.propertyProvider.defaultHref;
//
readonly toolbarHasMenu: XStandardType<boolean> =
this.propertyProvider.hasMenu;
readonly toolbarShowMenu: XStandardType<boolean> =
this.propertyProvider.showMenu;
readonly toolbarAutoHideMenu: XStandardType<boolean> =
this.propertyProvider.autoHideMenu;
readonly toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
this.propertyProvider.menuSlot;
//
readonly toolbarStartSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.startSlotButtonsTemplate;
readonly toolbarEndSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.endSlotButtonsTemplate;
//
readonly toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
this.propertyProvider.contentSlot;
readonly toolbarContentTemplate: TemplateRef<any> =
this.propertyProvider.contentTemplate;
//#endregion
//
//#region Constructor ...
constructor(protected propertyProvider: XToolbarContainer) {
super();
}
//#endregion
}
@Injectable({
providedIn: 'root',
})
@Component({
template: `
<!--
<ng-container *ngIf="extractProps() | async as props">
<ng-container *ngIf="props.showToolbar">
<x-toolbar
[toolbarTitle]="props.toolbarTitle"
[toolbarColor]="props.toolbarColor"
[toolbarLogoUrl]="props.toolbarLogoUrl"
[toolbarHasBack]="props.toolbarHasBack"
[toolbarHasMenu]="props.toolbarHasMenu"
[toolbarSubTitle]="props.toolbarSubTitle"
[toolbarShowLogo]="props.toolbarShowLogo"
[toolbarLogoSlot]="props.toolbarLogoSlot"
[toolbarShowBack]="props.toolbarShowBack"
[toolbarBackSlot]="props.toolbarBackSlot"
[toolbarShowMenu]="props.toolbarShowMenu"
[toolbarAutoHideMenu]="props.toolbarAutoHideMenu"
[toolbarMenuSlot]="props.toolbarMenuSlot"
[toolbarCssClass]="props.toolbarCssClass"
[toolbarShowTitle]="props.toolbarShowTitle"
[toolbarTitleSlot]="props.toolbarTitleSlot"
[toolbarBackHandler]="props.toolbarBackHandler"
[toolbarDefaultHref]="props.toolbarDefaultHref"
[toolbarContentSlot]="props.toolbarContentSlot"
[toolbarShowSubTitle]="props.toolbarShowSubTitle"
[toolbarActionProvider]="props.toolbarActionProvider"
[toolbarShowProgressBar]="props.toolbarShowProgressBar"
[toolbarContentTemplate]="props.toolbarContentTemplate"
[toolbarProgressBarColor]="props.toolbarProgressBarColor"
[toolbarEndSlotButtonsTemplate]="props.toolbarEndSlotButtonsTemplate"
[toolbarStartSlotButtonsTemplate]="props.toolbarStartSlotButtonsTemplate"
>
</x-toolbar>
</ng-container>
</ng-container>
-->
`,
})
export abstract class XComponentToolbarContainerComponent
extends XBaseComponentContainerComponent
implements IXComponentToolbarContainer
{
//
//#region Props ...
//
@Input()
showToolbar: XStandardType<boolean> = this.propertyProvider.showToolbar;
//
@Input()
toolbarActionProvider: Subject<XToolbarActionModel> =
this.propertyProvider.toolbarActionProvider;
@Input()
toolbarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.toolbarCssClass;
//
@Input()
toolbarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.toolbarColor;
//
@Input()
toolbarShowProgressBar: XStandardType<boolean> =
this.propertyProvider.toolbarShowProgressBar;
@Input()
toolbarProgressBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.toolbarProgressBarColor;
//
@Input()
toolbarShowTitle: XStandardType<boolean> =
this.propertyProvider.toolbarShowTitle;
@Input()
toolbarTitleSlot: XStandardType<XTitleSlotIdentifier> =
this.propertyProvider.toolbarTitleSlot;
@Input()
toolbarTitle: XStandardType<string> = this.propertyProvider.toolbarTitle;
//
@Input()
toolbarShowSubTitle: XStandardType<boolean> =
this.propertyProvider.toolbarShowSubTitle;
@Input()
toolbarSubTitle: XStandardType<string> =
this.propertyProvider.toolbarSubTitle;
//
@Input()
toolbarShowLogo: XStandardType<boolean> =
this.propertyProvider.toolbarShowLogo;
@Input()
toolbarLogoSlot: XStandardType<XLogoSlotIdentifier> =
this.propertyProvider.toolbarLogoSlot;
@Input()
toolbarLogoUrl: XStandardType<string> = this.propertyProvider.toolbarLogoUrl;
//
@Input()
toolbarHasBack: XStandardType<boolean> = this.propertyProvider.toolbarHasBack;
@Input()
toolbarShowBack: XStandardType<boolean> =
this.propertyProvider.toolbarShowBack;
@Input()
toolbarBackSlot: XStandardType<XBackSlotIdentifier> =
this.propertyProvider.toolbarBackSlot;
@Input()
toolbarBackHandler?: () => XStandardType<void> =
this.propertyProvider.toolbarBackHandler;
@Input()
toolbarDefaultHref: string = this.propertyProvider.toolbarDefaultHref;
//
@Input()
toolbarHasMenu: XStandardType<boolean> = this.propertyProvider.toolbarHasMenu;
@Input()
toolbarShowMenu: XStandardType<boolean> =
this.propertyProvider.toolbarShowMenu;
@Input()
toolbarAutoHideMenu: XStandardType<boolean> =
this.propertyProvider.toolbarAutoHideMenu;
@Input()
toolbarMenuSlot: XStandardType<XMenuSlotIdentifier> =
this.propertyProvider.toolbarMenuSlot;
//
@Input()
toolbarStartSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.toolbarStartSlotButtonsTemplate;
@Input()
toolbarEndSlotButtonsTemplate: TemplateRef<any> =
this.propertyProvider.toolbarEndSlotButtonsTemplate;
//
@Input()
toolbarContentSlot: XStandardType<XContentSlotIdentifier> =
this.propertyProvider.toolbarContentSlot;
@Input()
toolbarContentTemplate: TemplateRef<any> =
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<IXComponentToolbarContainer> {
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
<section class="x-progress-bar x-wrapper">
<ion-progress-bar
class="x-progress-bar-spinner"
[type]="getValue(type) | async"
[color]="getValue(color) | async"
[value]="getValue(value) | async"
[buffer]="getValue(buffer) | async"
></ion-progress-bar>
</section>
### 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<XProgressBarComponent>('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<XProgressBarActionModel>();
}
//
// 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<XProgressBarActionIdentifier> { }
//#endregion
//
//#region Container ...
export interface IXProgressBarContainer extends IXBaseContainer {
//
actionProvider: Subject<XProgressBarActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
//
type: XStandardType<XProgressBarTypeIdentifier>;
//
value: XStandardType<number>;
buffer: XStandardType<number>;
}
@Injectable({
providedIn: 'root',
})
export class XProgressBarContainer
extends XBaseContainer
implements Readonly<IXProgressBarContainer>
{
//
//#region Props ...
//
readonly actionProvider = new Subject<XProgressBarActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Warning;
//
readonly type: XStandardType<XProgressBarTypeIdentifier> = XProgressBarType.Indeterminate;
//
readonly value: XStandardType<number>;
readonly buffer: XStandardType<number>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XProgressBarContainerComponent
extends XBaseContainerComponent
implements IXProgressBarContainer {
//
//#region Props ...
//
@Input()
actionProvider: Subject<XProgressBarActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
//
@Input()
type: XStandardType<XProgressBarTypeIdentifier> =
this.propertyProvider.type;
//
@Input()
value: XStandardType<number> =
this.propertyProvider.value;
@Input()
buffer: XStandardType<number> =
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<IXProgressBarContainer> {
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<boolean>;
}
@Injectable({
providedIn: 'root',
})
export class XComponentProgressBarContainer
extends XBaseComponentContainer
implements Readonly<IXComponentProgressBarContainer> {
//
//#region Props ...
//
readonly showProgressBar: XStandardType<boolean> = false;
//
readonly progressBarActionProvider =
this.propertyProvider.actionProvider;
readonly progressBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly progressBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
//
readonly progressBarType: XStandardType<XProgressBarTypeIdentifier> =
this.propertyProvider.type;
//
readonly progressBarValue: XStandardType<number> =
this.propertyProvider.value;
readonly progressBarBuffer: XStandardType<number> =
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
<div class="x-screen-capture x-wrapper" [class.mobile]="isMobileUi$ | async">
<!-- Content -->
<div #content class="x-content">
<ng-content></ng-content>
</div>
<!-- Overlay -->
<div
#over
xMouseHandler
class="x-overlay"
[class.enabled]="false"
(moved)="handleMouseMoved($event)"
(started)="handleMouseStarted($event)"
[hidden]="!(getValue(enable) | async)"
(finished)="handleMouseFinished($event)"
[enableHandler]="getValue(enable) | async"
>
<div #rect class="x-rectangle" [class.drawing]="isDrawing"></div>
</div>
</div>
### 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<XScreenCaptureComponent>('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<boolean>;
topOffset: XStandardType<number>;
bottomOffset: XStandardType<number>;
downloadCapturedImage: XStandardType<boolean>;
imageCaptured: EventEmitter<string | Blob>;
}
@Injectable({
providedIn: 'root',
})
export class XScreenCaptureContainer
extends XBaseContainer
implements Readonly<IXScreenCaptureContainer>
{
//
//#region Props ...
readonly enable: XStandardType<boolean> = false;
readonly topOffset: XStandardType<number> = 0;
readonly bottomOffset: XStandardType<number> = 0;
readonly downloadCapturedImage: XStandardType<boolean> = true;
readonly imageCaptured: EventEmitter<string | Blob> = new EventEmitter<
string | Blob
>();
//#endregion
}
@Injectable({
providedIn: 'root',
})
@Component({
template: `
<!--
<ng-container *ngIf="extractProps() | async as props">
</ng-container>
-->
`,
})
export abstract class XScreenCaptureContainerComponent
extends XBaseContainerComponent
implements IXScreenCaptureContainer
{
//
//#region Props ...
@Input()
enable: XStandardType<boolean> = this.propertyProvider.enable;
@Input()
topOffset: XStandardType<number> = this.propertyProvider.topOffset;
@Input()
bottomOffset: XStandardType<number> = this.propertyProvider.bottomOffset;
@Input()
downloadCapturedImage: XStandardType<boolean> =
this.propertyProvider.downloadCapturedImage;
@Output()
imageCaptured: EventEmitter<string | Blob> = 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<IXScreenCaptureContainer> {
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
<ion-toolbar
class="x-search-bar x-wrapper"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<ion-searchbar
class="x-search-bar"
[type]="getValue(type) | async"
[value]="getValue(value) | async"
[disabled]="uiDisabled || loading"
[debounce]="getValue(debounce) | async"
[spellcheck]="getValue(spellcheck) | async"
[inputmode]="getValue(keyboardType) | async"
[xColor]="getValue(searchInputColor) | async"
(ionBlur)="onEvent.emit(SearchBarEvents.BLUR)"
[clearIcon]="getValue(clearButtonIcon) | async"
[enterkeyhint]="getValue(enterKeyHint) | async"
[placeholder]="getResourceValue(title) | async"
(ionFocus)="onEvent.emit(SearchBarEvents.FOCUS)"
(ionClear)="onEvent.emit(SearchBarEvents.CLEAR)"
(ionInput)="onEvent.emit(SearchBarEvents.INPUT)"
[searchIcon]="getValue(searchButtonIcon) | async"
(ionCancel)="onEvent.emit(SearchBarEvents.CANCEL)"
(ionChange)="handleSearchQueryValueChange($event)"
[showCancelButton]="getValue(showCancelButton) | async"
[showClearButton]="getValue(showClearButton) | async"
[cancelButtonIcon]="getValue(cancelButtonIcon) | async"
[isForeground]="getValue(foregroundSearchInputColor) | async"
[cancelButtonText]="getResourceValue(cancelButtonTitle) | async"
></ion-searchbar>
</ion-toolbar>
### 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<XSearchBarComponent>('actionProvider')
);
if (isActionProviderChaged) {
this.registerActionProvider();
}
//#endregion
//
//#region Colors ...
//
const isCancelButtonIconColorChanged = changeKeys.includes(
nameof<XSearchBarComponent>('cancelButtonIconColor')
);
if (isCancelButtonIconColorChanged) {
await this.applyCancelButtonIconColor();
}
//
const isClearButtonIconColorChanged = changeKeys.includes(
nameof<XSearchBarComponent>('clearButtonIconColor')
);
if (isClearButtonIconColorChanged) {
await this.applyClearButtonIconColor();
}
//
const isSearchButtonIconColorChanged = changeKeys.includes(
nameof<XSearchBarComponent>('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<XSearchBarActionModel>();
}
//
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<XSearchBarActionIdentifier> {}
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<XSearchBarActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
//
searchInputColor: XStandardType<XColorIdentifier>;
foregroundSearchInputColor: XStandardType<boolean>;
//
type: XStandardType<XSearchBarTypeIdentifier>;
title: XStandardType<XResourceIdentifier>;
value: XStandardType<string>;
enterKeyHint: XStandardType<XSearchBarEnterKeyHintIdentifier>;
keyboardType: XStandardType<XSearchBarTypeIdentifier>;
spellcheck: XStandardType<boolean>;
debounce: XStandardType<number>;
//
showCancelButton: XStandardType<XSearchBarShowButtonIdentifier>;
cancelButtonIcon: XStandardType<XIconIdentifier>;
cancelButtonTitle: XStandardType<XResourceIdentifier>;
cancelButtonIconColor: XStandardType<XColorIdentifier>;
//
showClearButton: XStandardType<XSearchBarShowButtonIdentifier>;
clearButtonIcon: XStandardType<XIconIdentifier>;
clearButtonIconColor: XStandardType<XColorIdentifier>;
//
searchButtonIcon: XStandardType<XIconIdentifier>;
searchButtonIconColor: XStandardType<XColorIdentifier>;
//
queryChange: EventEmitter<string>;
onEvent: EventEmitter<XSearchBarEventIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XSearchBarContainer
extends XBaseContainer
implements Readonly<IXSearchBarContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XSearchBarActionModel> =
new Subject<XSearchBarActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
//
readonly searchInputColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly foregroundSearchInputColor: XStandardType<boolean> = false;
//
readonly type: XStandardType<XSearchBarTypeIdentifier> =
XSearchBarType.Search;
readonly title: XStandardType<XResourceIdentifier> = XResourceIDs.search;
readonly value: XStandardType<string>;
readonly enterKeyHint: XStandardType<XSearchBarEnterKeyHintIdentifier> =
XSearchBarEnterKeyHint.Search;
readonly keyboardType: XStandardType<XSearchBarTypeIdentifier> =
XSearchBarType.Search;
readonly spellcheck: XStandardType<boolean> = false;
readonly debounce: XStandardType<number> =
this.config.defaultSearchDebounceTime || 500;
//
readonly showCancelButton: XStandardType<XSearchBarShowButtonIdentifier> =
XSearchBarShowButton.Never;
readonly cancelButtonIcon: XStandardType<XIconIdentifier>;
readonly cancelButtonTitle: XStandardType<XResourceIdentifier>;
readonly cancelButtonIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Primary;
//
readonly showClearButton: XStandardType<XSearchBarShowButtonIdentifier> =
XSearchBarShowButton.Always;
readonly clearButtonIcon: XStandardType<XIconIdentifier>;
readonly clearButtonIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Danger;
//
readonly searchButtonIcon: XStandardType<XIconIdentifier>;
readonly searchButtonIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Primary;
//
readonly queryChange: EventEmitter<string> = new EventEmitter<string>();
readonly onEvent: EventEmitter<XSearchBarEventIdentifier> =
new EventEmitter<XSearchBarEventIdentifier>();
//#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<XSearchBarActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
@Input()
searchInputColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchInputColor;
@Input()
foregroundSearchInputColor: XStandardType<boolean> =
this.propertyProvider.foregroundSearchInputColor;
//
@Input()
type: XStandardType<XSearchBarTypeIdentifier> = this.propertyProvider.type;
@Input()
title: XStandardType<XResourceIdentifier> = this.propertyProvider.title;
@Input()
value: XStandardType<string> = this.propertyProvider.value;
@Input()
enterKeyHint: XStandardType<XSearchBarEnterKeyHintIdentifier> =
this.propertyProvider.enterKeyHint;
@Input()
keyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.keyboardType;
@Input()
spellcheck: XStandardType<boolean> = this.propertyProvider.spellcheck;
@Input()
debounce: XStandardType<number> = this.propertyProvider.debounce;
//
@Input()
showCancelButton: XStandardType<XSearchBarShowButtonIdentifier> =
this.propertyProvider.showCancelButton;
@Input()
cancelButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.cancelButtonIcon;
@Input()
cancelButtonTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cancelButtonTitle;
@Input()
cancelButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.cancelButtonIconColor;
//
@Input()
showClearButton: XStandardType<XSearchBarShowButtonIdentifier> =
this.propertyProvider.showClearButton;
@Input()
clearButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.clearButtonIcon;
@Input()
clearButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.clearButtonIconColor;
//
@Input()
searchButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchButtonIcon;
@Input()
searchButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchButtonIconColor;
//
@Output()
queryChange: EventEmitter<string> = new EventEmitter();
@Output()
onEvent: EventEmitter<XSearchBarEventIdentifier> = 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<IXSearchBarContainer> {
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<boolean>;
//
searchBarActionProvider: Subject<XSearchBarActionModel>;
searchBarCssClass: XStandardType<XOneOrManyType<string>>;
//
searchBarColor: XStandardType<XColorIdentifier>;
searchBarForegroundColor: XStandardType<boolean>;
//
searchBarSearchInputColor: XStandardType<XColorIdentifier>;
searchBarForegroundSearchInputColor: XStandardType<boolean>;
//
searchBarType: XStandardType<XSearchBarTypeIdentifier>;
searchBarTitle: XStandardType<XResourceIdentifier>;
searchBarValue: XStandardType<string>;
searchBarEnterKeyHint: XStandardType<XSearchBarEnterKeyHintIdentifier>;
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier>;
searchBarSpellcheck: XStandardType<boolean>;
searchBarDebounce: XStandardType<number>;
//
searchBarShowCancelButton: XStandardType<XSearchBarShowButtonIdentifier>;
searchBarCancelButtonIcon: XStandardType<XIconIdentifier>;
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier>;
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier>;
//
searchBarShowClearButton: XStandardType<XSearchBarShowButtonIdentifier>;
searchBarClearButtonIcon: XStandardType<XIconIdentifier>;
searchBarClearButtonIconColor: XStandardType<XColorIdentifier>;
//
searchBarSearchButtonIcon: XStandardType<XIconIdentifier>;
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier>;
//
searchBarQueryChange: EventEmitter<string>;
searchBarOnEvent: EventEmitter<XSearchBarEventIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XComponentSearchBarContainer
extends XBaseComponentContainer
implements Readonly<IXComponentSearchBarContainer>
{
//
//#region Props ...
//
readonly showSearchBar: XStandardType<boolean> = true;
//
readonly searchBarActionProvider: Subject<XSearchBarActionModel> =
this.propertyProvider.actionProvider;
readonly searchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
readonly searchBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.color;
readonly searchBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
//
readonly searchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchInputColor;
readonly searchBarForegroundSearchInputColor: XStandardType<boolean> =
this.propertyProvider.foregroundSearchInputColor;
//
readonly searchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.type;
readonly searchBarTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.title;
readonly searchBarValue: XStandardType<string> = this.propertyProvider.value;
readonly searchBarEnterKeyHint: XStandardType<string> =
this.propertyProvider.enterKeyHint;
readonly searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.keyboardType;
readonly searchBarSpellcheck: XStandardType<boolean> =
this.propertyProvider.spellcheck;
readonly searchBarDebounce: XStandardType<number> =
this.propertyProvider.debounce;
//
readonly searchBarShowCancelButton: XStandardType<string> =
this.propertyProvider.showCancelButton;
readonly searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.cancelButtonIcon;
readonly searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.cancelButtonTitle;
readonly searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.cancelButtonIconColor;
//
readonly searchBarShowClearButton: XStandardType<string> =
this.propertyProvider.showClearButton;
readonly searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.clearButtonIcon;
readonly searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.clearButtonIconColor;
//
readonly searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchButtonIcon;
readonly searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchButtonIconColor;
//
readonly searchBarQueryChange: EventEmitter<string> =
this.propertyProvider.queryChange;
readonly searchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> =
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<boolean> = this.propertyProvider.showSearchBar;
//
@Input()
searchBarActionProvider: Subject<XSearchBarActionModel> =
this.propertyProvider.searchBarActionProvider;
@Input()
searchBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.searchBarCssClass;
//
@Input()
searchBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarColor;
@Input()
searchBarForegroundColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundColor;
//
@Input()
searchBarSearchInputColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchInputColor;
@Input()
searchBarForegroundSearchInputColor: XStandardType<boolean> =
this.propertyProvider.searchBarForegroundSearchInputColor;
//
@Input()
searchBarType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarType;
@Input()
searchBarTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarTitle;
@Input()
searchBarValue: XStandardType<string> = this.propertyProvider.searchBarValue;
@Input()
searchBarEnterKeyHint: XStandardType<string> =
this.propertyProvider.searchBarEnterKeyHint;
@Input()
searchBarKeyboardType: XStandardType<XSearchBarTypeIdentifier> =
this.propertyProvider.searchBarKeyboardType;
@Input()
searchBarSpellcheck: XStandardType<boolean> =
this.propertyProvider.searchBarSpellcheck;
@Input()
searchBarDebounce: XStandardType<number> =
this.propertyProvider.searchBarDebounce;
//
@Input()
searchBarShowCancelButton: XStandardType<string> =
this.propertyProvider.searchBarShowCancelButton;
@Input()
searchBarCancelButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarCancelButtonIcon;
@Input()
searchBarCancelButtonTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchBarCancelButtonTitle;
@Input()
searchBarCancelButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarCancelButtonIconColor;
//
@Input()
searchBarShowClearButton: XStandardType<string> =
this.propertyProvider.searchBarShowClearButton;
@Input()
searchBarClearButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarClearButtonIcon;
@Input()
searchBarClearButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarClearButtonIconColor;
//
@Input()
searchBarSearchButtonIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.searchBarSearchButtonIcon;
@Input()
searchBarSearchButtonIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarSearchButtonIconColor;
//
@Output()
searchBarQueryChange: EventEmitter<string> = new EventEmitter();
@Output()
searchBarOnEvent: EventEmitter<string> = 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<IXComponentSearchBarContainer> {
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.$(
`<div class="swiper-slide-shadow-${
isHorizontal ? 'left' : 'top'
}"></div>`
);
// $slideEl.append($shadowBeforeEl);
}
if ($shadowAfterEl.length === 0) {
$shadowAfterEl = swiper.$(
`<div class="swiper-slide-shadow-${
isHorizontal ? 'right' : 'bottom'
}"></div>`
);
// $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.$('<div class="swiper-cube-shadow"></div>');
$wrapperEl.append($cubeShadowEl);
}
$cubeShadowEl.css({ height: `${swiperWidth}px` });
} else {
$cubeShadowEl = $el.find('.swiper-cube-shadow');
if ($cubeShadowEl.length === 0) {
$cubeShadowEl = swiper.$('<div class="swiper-cube-shadow"></div>');
$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.$(
`<div class="swiper-slide-shadow-${
isHorizontal ? 'left' : 'top'
}"></div>`
);
$slideEl.append(shadowBefore);
}
if (shadowAfter.length === 0) {
shadowAfter = swiper.$(
`<div class="swiper-slide-shadow-${
isHorizontal ? 'right' : 'bottom'
}"></div>`
);
$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.$(
`<div class="swiper-slide-shadow-${
swiper.isHorizontal() ? 'left' : 'top'
}"></div>`
);
$slideEl.append(shadowBefore);
}
if (shadowAfter.length === 0) {
shadowAfter = swiper.$(
`<div class="swiper-slide-shadow-${
swiper.isHorizontal() ? 'right' : 'bottom'
}"></div>`
);
$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
<!-- WrapWithCard Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component Template -->
<ng-template #componentRef>
<section
class="x-slider x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<ion-slides
#slider
class="slider"
[options]="sliderConfig"
[pager]="hasPager() | async"
[class.no-pager]="hasPager() | async"
(ionSlideTap)="handleSlideChanged()"
(ionSlideNextEnd)="handleSlideChanged()"
(ionSlidePrevEnd)="handleSlideChanged()"
(ionSlideTouchEnd)="handleSlideChanged()"
(ionSlideDidChange)="handleSlideChanged()"
(ionSlideTransitionEnd)="handleSlideChanged()"
>
<ng-container *ngFor="let slide of slides">
<ng-container *ngTemplateOutlet="slide.template"></ng-container>
</ng-container>
</ion-slides>
</section>
</ng-template>
### 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<XSlideComponent>;
//
@ContentChildren(XSlideComponent)
set slides(s: QueryList<XSlideComponent>) {
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<XSliderComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
const isConfigChanged = changeKeys.includes(
nameof<XSliderComponent>('options')
);
const isAnimationChanged = changeKeys.includes(
nameof<XSliderComponent>('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<XSliderActionModel>();
}
//
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<XSliderActionIdentifier> {}
//
//#region Inside Card Container ...
export interface IXSliderContainer extends IXComponentCardContainer {
//
actionProvider: Subject<XSliderActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
options: XStandardType<XSliderConfig>;
animation: XStandardType<XSliderAnimationIdentifier>;
//
onSlideChange: EventEmitter<number>;
}
@Injectable({
providedIn: 'root',
})
export class XSliderContainer
extends XComponentCardContainer
implements Readonly<IXSliderContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XSliderActionModel> =
new Subject<XSliderActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly options: XStandardType<XSliderConfig> = defaultXSliderConfig;
readonly animation: XStandardType<XSliderAnimationIdentifier> =
XSliderAnimation.Coverflow;
//
readonly onSlideChange = new EventEmitter<number>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XSliderContainerComponent
extends XComponentCardContainerComponent
implements IXSliderContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XSliderActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
options: XStandardType<XSliderConfig> = this.propertyProvider.options;
@Input()
animation: XStandardType<XSliderAnimationIdentifier> =
this.propertyProvider.animation;
//
@Output()
onSlideChange: EventEmitter<number> = 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<IXSliderContainer> {
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
<ng-template #content>
<ion-slide>
<div class="full-width">
<ng-content></ng-content>
</div>
</ion-slide>
</ng-template>
### 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<any>;
//#endregion
//
//#region LifeCycles ...
onChange(changeKeys: string[]) {
super.onChange(changeKeys);
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XSlideComponent>('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<XSlideActionModel>();
}
//
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<XSlideActionIdentifier> {}
//
//#region Container ...
export interface IXSlideContainer extends IXBaseContainer {
actionProvider: Subject<XSlideActionModel>;
}
@Injectable({
providedIn: 'root'
})
export class XSlideContainer
extends XBaseContainer
implements Readonly<IXSlideContainer>
{
//
//#region Props ...
actionProvider: Subject<XSlideActionModel> = new Subject<XSlideActionModel>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XSlideContainerComponent
extends XBaseContainerComponent
implements IXSlideContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XSlideActionModel> =
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<IXSlideContainer> {
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
<div
class="x-slotter x-wrapper"
[fxLayout]="getLayout() | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<!-- Chack Has Slots -->
<ng-container *ngIf="hasSlots()">
<div
fxFlex
class="x-start-top-slot"
*ngIf="getHasStartOrTopSlot() | async"
[ngClass]="getValue(startTopSlotCssClass) | async"
>
<!-- Start / Top -->
<ng-container *ngFor="let slot of startOrTopSlots">
<div
class="x-start-top-slot-inner-container"
[ngClass]="getValue(slot.cssClass) | async"
*ngIf="notNullOrUndefinedValue(slot.content) | async"
>
<ng-container *ngTemplateOutlet="slot.content"></ng-container>
</div>
</ng-container>
</div>
<!-- Center -->
<div
fxFlex
class="x-center-slot"
*ngIf="getHasCenterSlot() | async"
[ngClass]="getValue(centerSlotCssClass) | async"
>
<ng-container *ngFor="let slot of cneterSlots">
<div
class="x-center-slot-inner-container"
[ngClass]="getValue(slot.cssClass) | async"
*ngIf="notNullOrUndefinedValue(slot.content) | async"
>
<ng-container *ngTemplateOutlet="slot.content"></ng-container>
</div>
</ng-container>
</div>
<!-- end / Bottom -->
<div
fxFlex
class="x-end-bottom-slot"
*ngIf="getHasEndOrBottomSlot() | async"
[ngClass]="getValue(endBottomSlotCssClass) | async"
>
<ng-container *ngFor="let slot of endOrBottomSlots">
<div
class="x-end-bottom-slot-inner-container"
[ngClass]="getValue(slot.cssClass) | async"
*ngIf="notNullOrUndefinedValue(slot.content) | async"
>
<ng-container *ngTemplateOutlet="slot.content"></ng-container>
</div>
</ng-container>
</div>
</ng-container>
</div>
### 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<XSlotComponent>;
//
@ContentChildren(XSlotComponent)
set slots(s: QueryList<XSlotComponent>) {
//
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<XSlotterComponent>('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<XSlotterActionModel>();
}
//
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<XSlotterActionIdentifier> {}
//
//#region Container ...
export interface IXSlotterContainer extends IXBaseContainer {
//
actionProvider: Subject<XSlotterActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
layout: XStandardType<XSlotLayoutIdentifier>;
//
hasStartOrTopSlot: XStandardType<boolean>;
startTopSlotCssClass: XStandardType<XOneOrManyType<string>>;
//
hasCenterSlot: XStandardType<boolean>;
centerSlotCssClass: XStandardType<XOneOrManyType<string>>;
//
hasEndOrBottomSlot: XStandardType<boolean>;
endBottomSlotCssClass: XStandardType<XOneOrManyType<string>>;
}
@Injectable({
providedIn: 'root'
})
export class XSlotterContainer
extends XBaseContainer
implements Readonly<IXSlotterContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XSlotterActionModel>;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly layout: XStandardType<XSlotLayoutIdentifier> =
XSlotLayout.HORIZONTAL;
//
readonly hasStartOrTopSlot: XStandardType<boolean> = true;
readonly startTopSlotCssClass: XStandardType<XOneOrManyType<string>>;
//
readonly hasCenterSlot: XStandardType<boolean> = true;
readonly centerSlotCssClass: XStandardType<XOneOrManyType<string>>;
//
readonly hasEndOrBottomSlot: XStandardType<boolean> = true;
readonly endBottomSlotCssClass: XStandardType<XOneOrManyType<string>>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XSlotterContainerComponent
extends XBaseContainerComponent
implements IXSlotterContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XSlotterActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
layout: XStandardType<XSlotLayoutIdentifier> = this.propertyProvider.layout;
//
@Input()
hasStartOrTopSlot: XStandardType<boolean> =
this.propertyProvider.hasStartOrTopSlot;
@Input()
startTopSlotCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.startTopSlotCssClass;
//
@Input()
hasCenterSlot: XStandardType<boolean> = this.propertyProvider.hasCenterSlot;
@Input()
centerSlotCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.centerSlotCssClass;
//
@Input()
hasEndOrBottomSlot: XStandardType<boolean> =
this.propertyProvider.hasEndOrBottomSlot;
@Input()
endBottomSlotCssClass: XStandardType<XOneOrManyType<string>> =
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<IXSlotterContainer> {
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
<ng-template #content>
<ng-content></ng-content>
</ng-template>
### 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<any>;
//#endregion
//
//#region LifeCycles ...
onChange(changeKeys: string[]) {
super.onChange(changeKeys);
//
const isActionProviderChanged = changeKeys.includes(
nameof<XSlotComponent>('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<XSlotActionModel>();
}
//
// 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<XSlotActionIdentifier> {}
//
//#region Container ...
export interface IXSlotContainer extends IXBaseContainer {
//
actionProvider: Subject<XSlotActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
name: XStandardType<XSlotNameIdentifier>;
}
@Injectable({
providedIn: 'root'
})
export class XSlotContainer
extends XBaseContainer
implements Readonly<IXSlotContainer>
{
//
//#region Props ...
//
readonly actionProvider = new Subject<XSlotActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly name: XStandardType<XSlotNameIdentifier>;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XSlotContainerComponent
extends XBaseContainerComponent
implements IXSlotContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XSlotActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
name: XStandardType<XSlotNameIdentifier> = 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<IXSlotContainer> {
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
<ion-spinner
[isForeground]="true"
[name]="getValue(name) | async"
[xColor]="getValue(color) | async"
[paused]="getValue(paused) | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[duration]="getValue(duration) | async"
class="x-spinner x-wrapper ion-no-margin ion-no-padding ion-no-border"
></ion-spinner>
### 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<XSpinnerComponent>('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<XSpinnerActionModel>();
}
//
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<XSpinnerActionIdentifier> {}
//
//#region Container ...
export interface IXSpinnerContainer extends IXBaseContainer {
//
actionProvider: Subject<XSpinnerActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
name: XStandardType<XSpinnerIdentifier>;
duration: XStandardType<number>;
color: XStandardType<XColorIdentifier>;
paused: XStandardType<boolean>;
}
@Injectable({
providedIn: 'root'
})
export class XSpinnerContainer
extends XBaseContainer
implements Readonly<IXSpinnerContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XSpinnerActionModel>;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly name: XStandardType<XSpinnerIdentifier> = XSpinner.Circular;
readonly duration: XStandardType<number> = undefined;
readonly color: XStandardType<XColorIdentifier> =
XColorWithBrightness.SecondaryShade;
readonly paused: XStandardType<boolean> = false;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XSpinnerContainerComponent
extends XBaseContainerComponent
implements IXSpinnerContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XSpinnerActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
name: XStandardType<XSpinnerIdentifier> = this.propertyProvider.name;
@Input()
duration: XStandardType<number> = this.propertyProvider.duration;
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
paused: XStandardType<boolean> = 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<IXSpinnerContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else wrapperRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="wrapperRef"></ng-container>
<!-- Actions -->
<div class="x-actions" actions>
<ng-content select="[actions]"></ng-content>
</div>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Components itSelf Template -->
<ng-template #wrapperRef>
<!-- Stepper Element -->
<div
class="x-stepper x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[class.disableHeader]="!(getValue(selectableHeaders) | async)"
>
<!-- Mat Stepper -->
<mat-stepper
#stepper
[orientation]="getOrientation() | async"
[selectedIndex]="getValue(selectedIndex) | async"
[labelPosition]="getLabelPositionValue() | async"
(selectionChange)="handleSelectionChanged($event)"
>
<!-- Icons Templates -->
<ng-template matStepperIcon="number" let-index="index">
{{ applyLocale(index + 1) }}
</ng-template>
<ng-template matStepperIcon="edit" let-index="index">
{{ applyLocale(index + 1) }}
</ng-template>
<!-- Steps -->
<!-- Check Has Steps -->
<ng-container *ngIf="hasSteps()">
<ng-container *ngFor="let step of steps">
<!-- Step Implementation -->
<mat-step [attr.stepperId]="step.id">
<!-- Step Label -->
<ng-template matStepLabel *ngIf="getValue(showLabel) | async">
<ng-container *ngTemplateOutlet="step.label"></ng-container>
</ng-template>
<!-- Step Content Representation -->
<ng-container *ngTemplateOutlet="step.content"></ng-container>
<!-- Step Buttons -->
<ng-container
*ngTemplateOutlet="
stepperActionsRef;
context: { stepper: stepper, step: step }
"
></ng-container>
</mat-step>
</ng-container>
</ng-container>
</mat-stepper>
</div>
</ng-template>
<!-- Actions Template -->
<ng-template #stepperActionsRef let-stepper="stepper" let-step="step">
<!-- Step Buttons -->
<div class="x-step-actions">
<x-slotter *ngIf="hasActions(step) | async">
<!-- Next -->
<x-slot
[name]="getValue(step.nextPosition) | async"
[cssClass]="getValue(step.nextCssClass) | async"
>
<ng-container *ngIf="hasStepAction(step, NPRButtonTypes.Next) | async">
<ng-container
*ngTemplateOutlet="
buttonRef;
context: {
stepper: stepper,
step: step,
type: NPRButtonTypes.Next
}
"
></ng-container>
</ng-container>
</x-slot>
<!-- Reset -->
<x-slot
[name]="getValue(step.resetPosition) | async"
[cssClass]="getValue(step.resetCssClass) | async"
>
<ng-container *ngIf="hasStepAction(step, NPRButtonTypes.Reset) | async">
<ng-container
*ngTemplateOutlet="
buttonRef;
context: {
stepper: stepper,
step: step,
type: NPRButtonTypes.Reset
}
"
></ng-container>
</ng-container>
</x-slot>
<!-- Prev -->
<x-slot
[name]="getValue(step.prevPosition) | async"
[cssClass]="getValue(step.prevCssClass) | async"
>
<ng-container *ngIf="hasStepAction(step, NPRButtonTypes.Prev) | async">
<ng-container
*ngTemplateOutlet="
buttonRef;
context: {
stepper: stepper,
step: step,
type: NPRButtonTypes.Prev
}
"
></ng-container>
</ng-container>
</x-slot>
</x-slotter>
<!-- Specified Actions -->
<div
class="x-step-custom-actions-wrapper"
*ngIf="getValue(step.hasCustomActions) | async"
>
<ng-container *ngTemplateOutlet="step.actions"></ng-container>
</div>
</div>
</ng-template>
<!-- Button Template -->
<ng-template #buttonRef let-stepper="stepper" let-step="step" let-type="type">
<x-button
[icon]="getButtonIcon(step, type) | async"
[type]="getButtonType(step, type) | async"
[title]="getButtonTitle(step, type) | async"
[color]="getButtonColor(step, type) | async"
(clicked)="handleNPRStep(stepper, step, type)"
[cssClass]="getButtonCssClass(step, type) | async"
[uiDisabled]="getButtonDisabled(step, type) | async"
[iconColor]="getButtonIconColor(step, type) | async"
[class.disabled]="getButtonDisabled(step, type) | async"
[iconPosition]="getButtonIconPosition(step, type) | async"
[foregroundColor]="getButtonForegroundColor(step, type) | async"
></x-button>
</ng-template>
### 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<XStepComponent>;
//
@ContentChildren(XStepComponent)
set steps(s: QueryList<XStepComponent>) {
//
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<XStepperComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Colors Changed ...
//
const isIconColorChanged = changeKeys.includes(
nameof<XStepperComponent>('iconColor')
);
if (isIconColorChanged) {
await this.applyIconColor();
}
//
const isTitleColorChanged = changeKeys.includes(
nameof<XStepperComponent>('titleColor')
);
if (isTitleColorChanged) {
await this.applyTitleColor();
}
//
const isHeaderColorChanged = changeKeys.includes(
nameof<XStepperComponent>('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<string>, 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<XStepperActionModel>();
}
//
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<XStepperActionIdentifier> {
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<XStepperActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
type: XStandardType<XStepperTypeIdentifier>;
showLabel: XStandardType<boolean>;
labelPosition: XStandardType<XStepperLabelPositionIdentifier>;
//
selectableHeaders: XStandardType<boolean>;
//
selectedIndex: XStandardType<number>;
selectedChange: EventEmitter<string>;
//
iconColor: XStandardType<XColorIdentifier>;
titleColor: XStandardType<XColorIdentifier>;
headerColor: XStandardType<XColorIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XStepperContainer
extends XNextPrevResetAndHostContainer
implements Readonly<IXStepperContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XStepperActionModel> =
new Subject<XStepperActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly type: XStandardType<XStepperTypeIdentifier> =
XStepperType.HORIZONTAL;
readonly showLabel: XStandardType<boolean> = true;
readonly labelPosition: XStandardType<XStepperLabelPositionIdentifier> =
XStepperLabelPosition.END;
//
readonly selectableHeaders: XStandardType<boolean> = false;
//
readonly selectedIndex: XStandardType<number>;
readonly selectedChange: EventEmitter<string> = new EventEmitter<string>();
//
readonly iconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Tertiary;
readonly titleColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Secondary;
readonly headerColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XStepperContainerComponent
extends XNextPrevResetAndHostContainerComponent
implements IXStepperContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XStepperActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
type: XStandardType<XStepperTypeIdentifier> = this.propertyProvider.type;
@Input()
showLabel: XStandardType<boolean> = this.propertyProvider.showLabel;
@Input()
labelPosition: XStandardType<XStepperLabelPositionIdentifier> =
this.propertyProvider.labelPosition;
//
@Input()
selectableHeaders: XStandardType<boolean> =
this.propertyProvider.selectableHeaders;
//
@Input()
selectedIndex: XStandardType<number> = this.propertyProvider.selectedIndex;
@Output()
selectedChange: EventEmitter<string> = new EventEmitter();
//
@Input()
iconColor: XStandardType<XColorIdentifier> = this.propertyProvider.iconColor;
@Input()
titleColor: XStandardType<XColorIdentifier> =
this.propertyProvider.titleColor;
@Input()
headerColor: XStandardType<XColorIdentifier> =
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<IXStepperContainer> {
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
<!-- Label -->
<ng-template #label>
<ng-content select="[x-step-label]"></ng-content>
</ng-template>
<!-- Content -->
<ng-template #content>
<ng-content></ng-content>
</ng-template>
<!-- Actions -->
<ng-template #actions>
<ng-content select="[x-step-actions]"></ng-content>
</ng-template>
### 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<any>;
//
@ViewChild('content', { static: false })
content!: TemplateRef<any>;
//
@ViewChild('actions', { static: false })
actions!: TemplateRef<any>;
//#endregion
//#endregion
//
//#region LifeCycles ...
onChange(changeKeys: string[]) {
super.onChange(changeKeys);
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XStepComponent>('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<XStepActionModel>();
}
//
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<boolean>((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<XStepActionIdentifier> {
force?: boolean;
}
//
//#region Container ...
export interface IXStepContainer extends IXNextPrevResetContainer {
actionProvider: Subject<XStepActionModel>;
id: XStandardType<string>;
hasCustomActions: XStandardType<boolean>;
}
@Injectable({
providedIn: 'root',
})
export class XStepContainer
extends XNextPrevResetContainer
implements Readonly<IXStepContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XStepActionModel> =
new Subject<XStepActionModel>();
readonly id: XStandardType<string>; // = generateUuid('XStepComponent');
readonly hasCustomActions: XStandardType<boolean> = false;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XStepContainerComponent
extends XNextPrevResetContainerComponent
implements IXStepContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XStepActionModel> =
this.propertyProvider.actionProvider;
@Input()
id: XStandardType<string> = generateUuid('XStepComponent');
@Input()
hasCustomActions: XStandardType<boolean> =
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<IXStepContainer> {
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
<div
class="x-tab-navigator x-wrapper"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<ion-tabs>
<ion-tab-bar
[xColor]="getValue(color) | async"
[slot]="getValue(navigatorSlot) | async"
[isForeground]="getValue(foregroundColor) | async"
>
<ng-container *ngFor="let item of preparedItems">
<ion-tab-button
*ngIf="item"
class="x-nav-button"
[tab]="getItemRoute(item) | async"
[href]="getItemRoute(item) | async"
[disabled]="isDisabled(item) | async"
[layout]="getValue(item.layout) | async"
[matTooltip]="getItemTooltip(item) | async"
[download]="getOptionalValue(item.download) | async"
[target]="getOptionalValue(item.routerTarget) | async"
>
<!-- Icon -->
<x-icon
class="x-icon"
[color]="'cb-inherit'"
[name]="getValue(item.icon) | async"
*ngIf="notEmptyValue(item.icon) | async"
[cssClass]="'ion-no-padding ion-no-margin'"
>
</x-icon>
<!-- Label -->
<ion-label class="x-tab-label" *ngIf="!(hideTabTitle(item) | async)">
{{ getResourceValue(item.title) | async }}
</ion-label>
<!-- Badge Number -->
<ion-badge *ngIf="hasBadgeNumber(item) | async">
{{ getItemBadgeNumber(item) | async }}
</ion-badge>
</ion-tab-button>
</ng-container>
</ion-tab-bar>
</ion-tabs>
</div>
### 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<XTabNavigatorComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Items Changed ...
const isItemsChanged = changeKeys.includes(
nameof<XTabNavigatorComponent>('items')
);
if (isItemsChanged) {
await this.prepareItems();
}
//#endregion
//
//#region Colors Changed ...
//
// Color ...
const isColorChanged = changeKeys.includes(
nameof<XTabNavigatorComponent>('color')
);
if (isColorChanged) {
await this.applyColor();
}
//
// Icon Color ...
const isIconColorChanged = changeKeys.includes(
nameof<XTabNavigatorComponent>('iconColor')
);
if (isIconColorChanged) {
await this.applyIconColor();
}
//
// HighLight Color ...
const isHighLightColorChanged = changeKeys.includes(
nameof<XTabNavigatorComponent>('highlightColor')
);
if (isHighLightColorChanged) {
await this.applyHighLightedColor();
}
//
// Selected Color ...
const isSelectedColorChanged = changeKeys.includes(
nameof<XTabNavigatorComponent>('selectedColor')
);
if (isSelectedColorChanged) {
await this.applySelectedColor();
}
//
// Badge Color ...
const isBadgeColorChanged = changeKeys.includes(
nameof<XTabNavigatorComponent>('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<boolean>).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<number>).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<XTabNavigatorActionModel>();
}
//
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<XIconIdentifier>;
badge?: XStandardType<number>;
//
download?: XStandardType<string>;
routerTarget?: XStandardType<XRouterTargetIdentifier>;
//
layout: XStandardType<XTabNavigatorItemLayout>;
}
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<XTabNavigatorActionIdentifier> {}
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<XTabNavigatorActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
navigatorSlot: XStandardType<XTabNavigatorNavigatorSlotIdentifier>;
hideTabLabelsOnSmallScreens: XStandardType<boolean>;
items: XStandardType<XTabNavigatorItem[]>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
iconColor: XStandardType<XColorIdentifier>;
badgeColor: XStandardType<XColorIdentifier>;
highlightColor: XStandardType<XColorIdentifier>;
selectedColor: XStandardType<XColorIdentifier>;
}
@Injectable({
providedIn: 'root'
})
export class XTabNavigatorContainer
extends XBaseContainer
implements Readonly<IXTabNavigatorContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XTabNavigatorActionModel> =
new Subject<XTabNavigatorActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly navigatorSlot: XStandardType<XTabNavigatorNavigatorSlotIdentifier> =
XTabNavigatorNavigatorSlot.BOTTOM;
readonly hideTabLabelsOnSmallScreens: XStandardType<boolean> = true;
readonly items: XStandardType<XTabNavigatorItem[]> = [];
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
readonly iconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly badgeColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.WarningTint;
readonly highlightColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.WarningShade;
readonly selectedColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.TertiaryShade;
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XTabNavigatorContainerComponent
extends XBaseContainerComponent
implements IXTabNavigatorContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XTabNavigatorActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
navigatorSlot: XStandardType<XTabNavigatorNavigatorSlotIdentifier> =
this.propertyProvider.navigatorSlot;
@Input()
hideTabLabelsOnSmallScreens: XStandardType<boolean> =
this.propertyProvider.hideTabLabelsOnSmallScreens;
@Input()
items: XStandardType<XTabNavigatorItem[]> = this.propertyProvider.items;
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
@Input()
iconColor: XStandardType<XColorIdentifier> = this.propertyProvider.iconColor;
@Input()
badgeColor: XStandardType<XColorIdentifier> =
this.propertyProvider.badgeColor;
@Input()
highlightColor: XStandardType<XColorIdentifier> =
this.propertyProvider.highlightColor;
@Input()
selectedColor: XStandardType<XColorIdentifier> =
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<IXTabNavigatorContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else tableRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="tableRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Table ItSelf Template -->
<ng-template #tableRef>
<!-- Wrapper -->
<div class="x-table x-wrapper" [class.mobile]="isMobileUi$ | async">
<!-- SearchBar -->
<ng-container *ngIf="isSearchbarTopPositioned() | async">
<ng-container *ngTemplateOutlet="searchBarRef"></ng-container>
</ng-container>
<!-- Table Actions -->
<ng-container
*ngIf="
(getValue(showActionBar) | async) &&
(isActionBarTopPositioned() | async)
"
>
<ng-container *ngTemplateOutlet="actionsRef"></ng-container>
</ng-container>
<!-- Table Paginator -->
<ng-container
*ngIf="
(hasChildValue(data) | async) &&
(getValue(showPaginator) | async) &&
(isPaginatorTopPositioned() | async)
"
>
<ng-container *ngTemplateOutlet="paginatorRef"></ng-container>
</ng-container>
<!-- Table if there is Data -->
<mat-table
matSort
class="x-table"
[dataSource]="dataSource"
[xColor]="getValue(color) | async"
*ngIf="hasChildValue(data) | async"
[ngClass]="getValue(cssClass) | async"
[isForeground]="getValue(foregroundColor) | async"
[matSortDisableClear]="!(getValue(canClearSort) | async)"
>
<!-- Columns -->
<ng-container *ngFor="let col of columnsData">
<!-- Selection Column -->
<ng-container
[sticky]="true"
*ngIf="isSelectionRow(col) | async"
[matColumnDef]="getColumnName(col) | async"
>
<!-- Selection Header Cell -->
<mat-header-cell
*matHeaderCellDef
[ngClass]="getHeaderClass(col) | async"
class="x-table-header x-table-selection"
[xColor]="getValue(headerColor) | async"
[isForeground]="getValue(headerForegroundColor) | async"
>
<ion-checkbox
[disabled]="!selection"
[class.hydrated]="false"
[hidden]="!(getValue(allowMultiSelect) | async)"
class="x-check-box x-selection-master ion-margin-end"
>
</ion-checkbox>
</mat-header-cell>
<!-- Selection Table Cell -->
<mat-cell
*matCellDef="let row"
[ngClass]="getCellClass(col) | async"
class="x-table-cell x-table-selection"
>
<ion-checkbox
[checked]="isSelected(row)"
class="x-check-box ion-margin-end"
[disabled]="!isRowsSelectable || !selection"
(ionChange)="handleRowSelected($event, row)"
>
</ion-checkbox>
</mat-cell>
</ng-container>
<!-- Model Displayed Columns -->
<ng-container
*ngIf="!(isSelectionRow(col) | async)"
[matColumnDef]="getColumnName(col) | async"
>
<!-- Header Cell -->
<mat-header-cell
mat-sort-header
*matHeaderCellDef
class="x-table-header"
[ngClass]="getHeaderClass(col) | async"
[xColor]="getValue(headerColor) | async"
[hidden]="getOptionalValue(col.hidden) | async"
[disabled]="!(getOptionalValue(col.sortable) | async)"
[isForeground]="getValue(headerForegroundColor) | async"
[matTooltip]="getResourceValue(col.description) | async"
>
<ng-container
*ngTemplateOutlet="
headerCellRef;
context: { $implicit: getResourceValue(col.title) | async }
"
></ng-container>
</mat-header-cell>
<!-- Table Cell -->
<mat-cell
class="x-table-cell"
*matCellDef="let element"
[ngClass]="getCellClass(col) | async"
[hidden]="getOptionalValue(col.hidden) | async"
>
<!-- Determine which Template to used based on Custom Column or Displayed Columns and pass Proper Data to it -->
<ng-container
*ngTemplateOutlet="
(getOptionalValue(col.customColumn) | async)
? customCellTemplate || defaultCustomCellRef
: cellTemplate || defaultCellRef;
context: {
$implicit:
(getOptionalValue(col.customColumn) | async)
? element
: element[col.name],
name: col.name
}
"
></ng-container>
</mat-cell>
</ng-container>
</ng-container>
<!-- Header Rows -->
<ng-container *ngIf="getValue(showHeader) | async">
<!-- Header Row -->
<mat-header-row
mat-header-row
class="x-table-header-row"
*matHeaderRowDef="
displayedColumns;
sticky: getValue(stickyHeader) | async
"
></mat-header-row>
</ng-container>
<!-- Items Row -->
<mat-row
matRipple
class="x-table-row"
(click)="handleRowClicked(row)"
[xColor]="getValue(color) | async"
[matRippleDisabled]="
!(getValue(clickableRows) | async) &&
!(getValue(selectableRows) | async)
"
*matRowDef="let row; columns: displayedColumns"
[isForeground]="getValue(foregroundColor) | async"
></mat-row>
</mat-table>
<!-- SearchBar -->
<ng-container *ngIf="!(isSearchbarTopPositioned() | async)">
<ng-container *ngTemplateOutlet="searchBarRef"></ng-container>
</ng-container>
<!-- Table Actions -->
<ng-container
*ngIf="
(getValue(showActionBar) | async) &&
!(isActionBarTopPositioned() | async)
"
>
<ng-container *ngTemplateOutlet="actionsRef"></ng-container>
</ng-container>
<!-- Table Paginator -->
<ng-container
*ngIf="
(hasChildValue(data) | async) &&
(getValue(showPaginator) | async) &&
!(isPaginatorTopPositioned() | async)
"
>
<ng-container *ngTemplateOutlet="paginatorRef"></ng-container>
</ng-container>
<!-- Empty -->
<ng-container
*ngIf="(getValue(showEmpty) | async) && !(hasChildValue(data) | async)"
>
<ng-container *ngTemplateOutlet="defaultEmptyListRef"></ng-container>
</ng-container>
</div>
</ng-template>
<!-- Header Cell Ref -->
<ng-template #headerCellRef let-title>
<div class="x-header-title text-truncate">
{{ title }}
</div>
</ng-template>
<!-- Default Empty Content -->
<ng-template #defaultEmptyListRef>
<x-empty
(refresh)="emptyRefresh.emit($event)"
[color]="getValue(emptyColor) | async"
[message]="getResourceValue(emptyMessage) | async"
[refreshIcon]="getValue(emptyRefreshIcon) | async"
[messageColor]="getValue(emptyMessageColor) | async"
[hasRefresh]="getValue(emptyHasRefresh) | async"
[foregroundRefreshButtonColor]="
getValue(emptyForegroundRefreshButtonColor) | async
"
[foregroundColor]="getValue(emptyForegroundColor) | async"
[refreshButtonColor]="getValue(emptyRefreshButtonColor) | async"
[foregroundMessageColor]="getValue(emptyForegroundMessageColor) | async"
></x-empty>
</ng-template>
<!-- Default Element Template -->
<ng-template #defaultCellRef let-value let-name="name">
<div class="text-truncate">
{{ value }}
</div>
</ng-template>
<!-- Default Custom Template -->
<ng-template #defaultCustomCellRef let-item> </ng-template>
<!-- SearchBar Ref -->
<ng-template #searchBarRef>
<ion-toolbar
class="x-search-bar"
*ngIf="getValue(showSearchBar) | async"
[xColor]="getValue(searchBarColor) | async"
>
<ion-searchbar
class="x-list-actions"
[xColor]="getValue(searchBarColor) | async"
[placeholder]="getResourceValue(searchTitle) | async"
(ionChange)="handleFilterData($event)"
></ion-searchbar>
</ion-toolbar>
</ng-template>
<!-- PaginatorRef -->
<ng-template #paginatorRef>
<ion-toolbar
class="x-paginator-bar"
*ngIf="getValue(showPaginator) | async"
[xColor]="getValue(paginatorColor) | async"
>
<!-- Mat Paginator Component -->
<mat-paginator
#matPaginator
[hidden]="true"
*ngIf="preparedPaginatorOptions"
[pageSize]="getValue(preparedPaginatorOptions.pageSize) | async"
></mat-paginator>
<!-- Start Slot Contents -->
<ion-buttons slot="start" *ngIf="preparedPaginatorOptions">
<!-- First -->
<ion-button
#first
(click)="firstPage()"
*ngIf="preparedPaginatorOptions.first"
[hidden]="getValue(preparedPaginatorOptions.first.hidden) | async"
[disabled]="
uiDisabled ||
loading ||
(getValue(preparedPaginatorOptions.first.disabled) | async)
"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(preparedPaginatorOptions.first.icon) | async,
tooltip:
getResourceValue(preparedPaginatorOptions.first.title) | async,
color: getValue(preparedPaginatorOptions.first.color) | async,
applyDirection: true
}
"
></ng-container>
</ion-button>
<!-- Previous -->
<ion-button
#previous
(click)="previousPage()"
*ngIf="preparedPaginatorOptions.prev"
[hidden]="getValue(preparedPaginatorOptions.prev.hidden) | async"
[disabled]="
uiDisabled ||
loading ||
(getValue(preparedPaginatorOptions.prev.disabled) | async)
"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(preparedPaginatorOptions.prev.icon) | async,
tooltip:
getResourceValue(preparedPaginatorOptions.prev.title) | async,
color: getValue(preparedPaginatorOptions.prev.color) | async,
applyDirection: true
}
"
></ng-container>
</ion-button>
</ion-buttons>
<!-- Pagination Info -->
<div class="x-table-paginator-wrapper">
<div fxLayout="row" fxLayoutAlign="center stretch">
<!-- Current Page -->
<div fxFlex="auto" *ngIf="currentPage">
<ion-button
fill="clear"
expand="full"
class="cb-inherit"
*ngIf="!pageNumberInput"
[disabled]="uiDisabled || loading"
(click)="pageNumberInput = true"
>
{{
preparedPaginatorOptions.pageInfoProvider(
managerService.currentLocale,
currentPage,
pageSize,
totalPages,
totalItems
)
}}
</ion-button>
<!-- Change Current Page -->
<ion-input
step="1"
[min]="1"
type="number"
debounce="500"
required="true"
autofocus="true"
[max]="totalPages"
class="cb-inherit"
inputmode="numeric"
[value]="currentPage"
*ngIf="pageNumberInput"
(ionBlur)="pageNumberInput = false"
[disabled]="uiDisabled || loading"
(ionChange)="handlePageChange($event)"
></ion-input>
</div>
<!-- Page Size -->
<div fxFlex="auto">
<ion-button
fill="clear"
expand="full"
*ngIf="pageSize"
class="cb-inherit"
(click)="handlePageSizeChange()"
[disabled]="uiDisabled || loading"
>
{{ applyLocale(pageSize) }}
</ion-button>
</div>
</div>
</div>
<!-- End Slot Content -->
<ion-buttons slot="end" *ngIf="preparedPaginatorOptions">
<!-- Noxt -->
<ion-button
#next
(click)="nextPage()"
*ngIf="preparedPaginatorOptions.next"
[hidden]="getValue(preparedPaginatorOptions.next.hidden) | async"
[disabled]="
uiDisabled ||
loading ||
(getValue(preparedPaginatorOptions.next.disabled) | async)
"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(preparedPaginatorOptions.next.icon) | async,
tooltip:
getResourceValue(preparedPaginatorOptions.next.title) | async,
color: getValue(preparedPaginatorOptions.next.color) | async,
applyDirection: true
}
"
></ng-container>
</ion-button>
<!-- Last -->
<ion-button
#last
(click)="lastPage()"
*ngIf="preparedPaginatorOptions.last"
[hidden]="getValue(preparedPaginatorOptions.last.hidden) | async"
[disabled]="
uiDisabled ||
loading ||
(getValue(preparedPaginatorOptions.last.disabled) | async)
"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(preparedPaginatorOptions.last.icon) | async,
tooltip:
getResourceValue(preparedPaginatorOptions.last.title) | async,
color: getValue(preparedPaginatorOptions.prev.color) | async,
applyDirection: true
}
"
></ng-container>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ng-template>
<!-- ActionsRef -->
<ng-template #actionsRef>
<ion-toolbar
class="x-actions-bar"
[xColor]="getValue(actionBarColor) | async"
*ngIf="preparedActionOptions && getValue(showActionBar) | async"
>
<!-- Start Slot Content -->
<ion-buttons slot="start">
<ng-container *ngFor="let action of preparedActionOptions.start">
<ng-container
*ngTemplateOutlet="actionButtonRef; context: { $implicit: action }"
></ng-container>
</ng-container>
</ion-buttons>
<!-- Custom Content -->
<div
fxLayout="row"
class="x-table-paginator-wrapper"
fxLayoutAlign="center stretch"
>
<ng-content select="[actions]"></ng-content>
</div>
<!-- End Slot Content -->
<ion-buttons slot="end">
<ng-container *ngFor="let action of preparedActionOptions.end">
<ng-container
*ngTemplateOutlet="actionButtonRef; context: { $implicit: action }"
></ng-container>
</ng-container>
</ion-buttons>
</ion-toolbar>
</ng-template>
<!-- Icon Template -->
<ng-template
#iconRef
let-name="name"
let-tooltip="tooltip"
let-color="color"
let-applyDirection="applyDirection"
>
<x-icon
[name]="name"
[color]="color"
[matTooltip]="tooltip"
[applyDirection]="applyDirection"
[foregroundColor]="true"
[cssClass]="!color ? 'cb-inherit' : null"
></x-icon>
</ng-template>
<!-- Action Button Ref -->
<ng-template #actionButtonRef let-action>
<ion-button
*ngIf="action"
[hidden]="getValue(action.hidden) | async"
[disabled]="getValue(action.disabled) | async"
(click)="handleActionBarItemClick(action, selection.selected)"
>
<ng-container
*ngTemplateOutlet="
iconRef;
context: {
name: getValue(action.icon) | async,
tooltip: getResourceValue(action.title) | async,
color: getValue(action.color) | async,
applyDirection: false
}
"
></ng-container>
</ion-button>
</ng-template>
### 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<any>();
private COLUMNS_DATA: XTableColumnOption<any>[];
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<XTableComponent>('loading')
);
let isUiDisabledChanged = changeKeys.includes(
nameof<XTableComponent>('uiDisabled')
);
if (isLoadingChanged || isUiDisabledChanged) {
await this.prepareActionOptions();
}
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XTableComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
// Handle Prepare Data Source ...
if (
changeKeys.includes(nameof<XTableComponent>('properties')) ||
changeKeys.includes(nameof<XTableComponent>('selectableRows'))
) {
await this.prepareDataSource();
}
//
// Handle Prepare Selection ...
if (
changeKeys.includes(nameof<XTableComponent>('allowMultiSelect')) ||
changeKeys.includes(nameof<XTableComponent>('initialSelectedValues'))
) {
await this.prepareSelection();
}
//
// Handle Paginator Options ...
if (changeKeys.includes(nameof<XTableComponent>('paginatorOptions'))) {
await this.preparePaginatorOptions();
}
//
// Handle Action Options ...
if (changeKeys.includes(nameof<XTableComponent>('actionOptions'))) {
await this.prepareActionOptions();
}
//
// Handle UI Data ...
if (changeKeys.includes(nameof<XTableComponent>('selectableRows'))) {
await this.prepareUIData();
}
}
onDestroy() {
super.onDestroy();
//
this.unregisterActionProvider();
}
registerViewHandlers() {
super.registerViewHandlers();
//
this.registerActionProvider();
}
//#endregion
//
//#region UI Providers ...
isSelectionRow(col: XTableColumnOption<any>) {
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<any>) {
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<any>) {
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<any>) {
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<XTableActionModel>();
}
//
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<any>,
];
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<any>(
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<T> = keyof T;
export type XTableColumnIdentifier<T> = XTableColumn<T> | string;
export interface XTableColumnOption<T> {
//
hidden?: XStandardType<boolean>;
name: XTableColumnIdentifier<T>;
sortable?: XStandardType<boolean>;
icon?: XStandardType<XIconIdentifier>;
customColumn?: XStandardType<boolean>;
title: XStandardType<XResourceIdentifier>;
description?: XStandardType<XResourceIdentifier>;
}
export interface XTableConfig<T> {
//
items: XStandardType<T[]>;
columns: XTableColumnOption<T>[];
}
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<boolean>;
disabled?: XStandardType<boolean>;
icon?: XStandardType<XIconIdentifier>;
color?: XStandardType<XColorIdentifier>;
title?: XStandardType<XResourceIdentifier>;
handler?: (item?: any) => XStandardType<void>;
}
export interface XTablePaginatorOptions {
pageSizes?: XStandardType<number[]>;
pageSize?: XStandardType<number>;
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<XTableActionIdentifier> {}
//
//#region Inside Card/Empty Container ...
export interface IXTableContainer extends IXCardEmptyContainer {
//
//#region Other Props ...
//
actionProvider: Subject<XTableActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
foregroundColor: XStandardType<boolean>;
canClearSort: XStandardType<boolean>;
cellCssClass: XStandardType<XOneOrManyType<string>>;
properties: XTableConfig<any>;
cellTemplate: TemplateRef<any>;
customCellTemplate: TemplateRef<any>;
//#endregion
//
//#region Header Props ...
//
showHeader: XStandardType<boolean>;
stickyHeader: XStandardType<boolean>;
headerCellCssClass: XStandardType<XOneOrManyType<string>>;
//
headerColor: XStandardType<XColorIdentifier>;
headerForegroundColor: XStandardType<boolean>;
//#endregion
//
//#region Click Props ...
clickableRows: XStandardType<boolean>;
rowClicked: EventEmitter<any>;
//#endregion
//
//#region Selection props ...
selectableRows: XStandardType<boolean>;
rowSelected: EventEmitter<any>;
rowSelectionChanged: EventEmitter<any[]>;
allowMultiSelect: XStandardType<boolean>;
initialSelectedValues: XStandardType<any[]>;
//#endregion
//
//#region Filter/Search Props ...
showSearchBar: XStandardType<boolean>;
searchBarPosition: XStandardType<XTableItemPositionIdentifier>;
searchBarColor: XStandardType<XColorIdentifier>;
searchTitle: XStandardType<XResourceIdentifier>;
//#endregion
//
//#region Paginator Props ...
showPaginator: XStandardType<boolean>;
paginatorPosition: XStandardType<XTableItemPositionIdentifier>;
paginatorColor: XStandardType<XColorIdentifier>;
paginatorOptions: XStandardType<XTablePaginatorOptions>;
pageChanged: EventEmitter<number>;
//#endregion
//
//#region Action Props ...
showActionBar: XStandardType<boolean>;
actionBarPosition: XStandardType<XTableItemPositionIdentifier>;
actionBarColor: XStandardType<XColorIdentifier>;
actionOptions: XStandardType<XTableActionOptions>;
removeItems: EventEmitter<any[]>;
//#endregion
}
@Injectable({
providedIn: 'root',
})
export class XTableContainer
extends XCardEmptyContainer
implements Readonly<IXTableContainer>
{
//
//#region Props ...
//
//#region Other Props ...
//
readonly actionProvider: Subject<XTableActionModel> =
new Subject<XTableActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
readonly foregroundColor: XStandardType<boolean> = false;
readonly canClearSort: XStandardType<boolean> = true;
readonly cellCssClass: XStandardType<XOneOrManyType<string>>;
readonly properties: XTableConfig<any>;
readonly cellTemplate: TemplateRef<any>;
readonly customCellTemplate: TemplateRef<any>;
//#endregion
//
//#region Header Props ...
//
readonly showHeader: XStandardType<boolean> = true;
readonly stickyHeader: XStandardType<boolean> = true;
readonly headerCellCssClass: XStandardType<XOneOrManyType<string>>;
//
readonly headerColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly headerForegroundColor: XStandardType<boolean> = false;
//#endregion
//
//#region Click Props ...
readonly clickableRows: XStandardType<boolean> = false;
readonly rowClicked: EventEmitter<any> = new EventEmitter<any>();
//#endregion
//
//#region Selection props ...
readonly selectableRows: XStandardType<boolean> = false;
readonly rowSelected: EventEmitter<any> = new EventEmitter<any>();
readonly rowSelectionChanged: EventEmitter<any[]> = new EventEmitter<any[]>();
readonly allowMultiSelect: XStandardType<boolean> = true;
readonly initialSelectedValues: XStandardType<any[]> = [];
//#endregion
//
//#region Filter/Search Props ...
readonly showSearchBar: XStandardType<boolean> = false;
readonly searchBarPosition: XStandardType<XTableItemPositionIdentifier> =
XTableItemPosition.TOP;
readonly searchBarColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly searchTitle: XStandardType<XResourceIdentifier> =
XResourceIDs.search;
//#endregion
//
//#region Paginator Props ...
readonly showPaginator: XStandardType<boolean>;
readonly paginatorPosition: XStandardType<XTableItemPositionIdentifier> =
XTableItemPosition.BOTTOM;
readonly paginatorColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly paginatorOptions: XStandardType<XTablePaginatorOptions>;
readonly pageChanged: EventEmitter<number> = new EventEmitter<number>();
//#endregion
//
//#region Action Props ...
readonly showActionBar: XStandardType<boolean>;
readonly actionBarPosition: XStandardType<XTableItemPositionIdentifier> =
XTableItemPosition.TOP;
readonly actionBarColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly actionOptions: XStandardType<XTableActionOptions>;
readonly removeItems: EventEmitter<any[]> = new EventEmitter<any[]>();
//#endregion
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XTableContainerComponent
extends XCardEmptyContainerComponent
implements IXTableContainer
{
//
//#region Props ...
//
//#region Other Props ...
@Input()
actionProvider: Subject<XTableActionModel> =
this.propertyProvider.actionProvider;
@Input()
canClearSort: XStandardType<boolean> = this.propertyProvider.canClearSort;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
foregroundColor: XStandardType<boolean> =
this.propertyProvider.foregroundColor;
@Input()
cellCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cellCssClass;
@Input()
properties: XTableConfig<any> = this.propertyProvider.properties;
@Input()
cellTemplate: TemplateRef<any> = this.propertyProvider.cellTemplate;
@Input()
customCellTemplate: TemplateRef<any> =
this.propertyProvider.customCellTemplate;
//#endregion
//
//#region Header Props ...
@Input()
showHeader: XStandardType<boolean> = this.propertyProvider.showHeader;
@Input()
stickyHeader: XStandardType<boolean> = this.propertyProvider.stickyHeader;
@Input()
headerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.headerColor;
@Input()
headerForegroundColor: XStandardType<boolean> =
this.propertyProvider.headerForegroundColor;
@Input()
headerCellCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.headerCellCssClass;
//#endregion
//
//#region Click Props ...
@Input()
clickableRows: XStandardType<boolean> = this.propertyProvider.clickableRows;
@Output()
rowClicked: EventEmitter<any> = new EventEmitter();
//#endregion
//
//#region Selection props ...
@Input()
selectableRows: XStandardType<boolean> = this.propertyProvider.selectableRows;
@Output()
rowSelected: EventEmitter<any> = new EventEmitter();
@Output()
rowSelectionChanged: EventEmitter<any[]> = new EventEmitter();
@Input()
allowMultiSelect: XStandardType<boolean> =
this.propertyProvider.allowMultiSelect;
@Input()
initialSelectedValues: XStandardType<any[]> =
this.propertyProvider.initialSelectedValues;
//#endregion
//
//#region Filter/Search Props ...
@Input()
showSearchBar: XStandardType<boolean> = this.propertyProvider.showSearchBar;
@Input()
searchBarPosition: XStandardType<XTableItemPositionIdentifier> =
this.propertyProvider.searchBarPosition;
@Input()
searchBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.searchBarColor;
@Input()
searchTitle: XStandardType<XResourceIdentifier> =
this.propertyProvider.searchTitle;
//#endregion
//
//#region Paginator Props ...
@Input()
showPaginator: XStandardType<boolean> = this.propertyProvider.showPaginator;
@Input()
paginatorPosition: XStandardType<XTableItemPositionIdentifier> =
this.propertyProvider.paginatorPosition;
@Input()
paginatorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.paginatorColor;
@Input()
paginatorOptions: XStandardType<XTablePaginatorOptions> =
this.propertyProvider.paginatorOptions;
@Output()
pageChanged: EventEmitter<number> = new EventEmitter();
//#endregion
//
//#region Action Props ...
@Input()
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
@Input()
actionBarPosition: XStandardType<XTableItemPositionIdentifier> =
this.propertyProvider.actionBarPosition;
@Input()
actionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.actionBarColor;
@Input()
actionOptions: XStandardType<XTableActionOptions> =
this.propertyProvider.actionOptions;
@Output()
removeItems: EventEmitter<any[]> = 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<IXTableContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else tabsRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="tabsRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component Ref -->
<ng-template #tabsRef>
<div
xSwipable
class="x-tabs x-wrapper"
[supportedDirections]="2"
(swipeEnd)="handleSwipeEnd()"
(swipeStart)="handleSwipeStart()"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
[swipeDisabled]="swipeDisabled() | async"
[class.swipable]="!(swipeDisabled() | async)"
[class.hide-header]="!(getValue(showHeader) | async)"
>
<mat-tab-group
#group
[(selectedIndex)]="selectedIndex"
[color]="getValue(color) | async"
(animationDone)="animationDone.emit()"
[dynamicHeight]="isDynamicHeight() | async"
[headerPosition]="getHeaderPosition() | async"
[attr.mat-stretch-tabs]="isStretched() | async"
[disableRipple]="getValue(disableRipple) | async"
[attr.mat-align-tabs]="getTabAlignValue() | async"
(selectedTabChange)="handleSelectedTabChanged($event)"
[disablePagination]="getValue(disablePagination) | async"
[animationDuration]="getValue(animationDuration) | async"
>
<mat-tab
*ngFor="let tab of tabs"
[disabled]="uiDisabled || (getValueStream(disablePagination) | async)"
>
<ng-template mat-tab-label>
<div [xColor]="getValue(headerColor) | async" [isForeground]="false">
<ng-container *ngTemplateOutlet="tab.label"></ng-container>
</div>
</ng-template>
<ng-template matTabContent>
<ng-container *ngTemplateOutlet="tab.content"></ng-container>
</ng-template>
</mat-tab>
</mat-tab-group>
</div>
</ng-template>
### 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<XTabComponent>;
private ACTION_PROVIDER_SUBSCRIPTION: Subscription;
//
canPrev$ = new Subject<boolean>();
canNext$ = new Subject<boolean>();
//
get tabs() {
return this.TABS;
}
//
@ContentChildren(XTabComponent)
set tabs(s: QueryList<XTabComponent>) {
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<XTabsComponent>('selectedIndex')
);
if (hasSelectedIndex) {
await this.handleSelectedIndex();
}
//
//#region Color Changed ...
//
// Tab Header Color ...
const isTabHeaderColorChanged = changeKeys.includes(
nameof<XTabsComponent>('headerColor')
);
if (isTabHeaderColorChanged) {
await this.applyTabHeaderColor();
}
//
// Active Tab Color ...
const isActiveTabColorChanged = changeKeys.includes(
nameof<XTabsComponent>('activeTabColor')
);
if (isActiveTabColorChanged) {
await this.applyActiveTabColor();
}
//
// Tab Indicator Color ...
const isTabIndicatorColorChanged = changeKeys.includes(
nameof<XTabsComponent>('tabIndicatorColor')
);
if (isTabIndicatorColorChanged) {
await this.applyTabIndicatorColor();
}
//
// Tab Paginator Color ...
const isTabPaginatorColorChanged = changeKeys.includes(
nameof<XTabsComponent>('tabPaginatorColor')
);
if (isTabPaginatorColorChanged) {
await this.applyTabPaginatorColor();
}
//#endregion
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XTabsComponent>('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<XTabsActionModel>();
}
//
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<MatTabChangeEvent, 'index'> {
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<XTabsActionIdentifier> {}
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<XTabsActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
selectedIndex: number;
selectedIndexChange: EventEmitter<number>;
//
showHeader: XStandardType<boolean>;
disablePagination: XStandardType<boolean>;
alignTabs: XStandardType<XTabAlignIdentifier>;
dynamicHeight: XStandardType<boolean>;
animationDuration: XStandardType<string>;
disableRipple: XStandardType<boolean>;
headerPosition: XStandardType<XTabsHeaderPositionIdentifier>;
//
loopTabs: XStandardType<boolean>;
swipable: XStandardType<boolean>;
animationDone: EventEmitter<void>;
//
lock: XStandardType<boolean>;
//
color: XStandardType<XColorIdentifier>;
headerColor: XStandardType<XColorIdentifier>;
activeTabColor: XStandardType<XColorIdentifier>;
tabIndicatorColor: XStandardType<XColorIdentifier>;
tabPaginatorColor: XStandardType<XColorIdentifier>;
//
selectedTabChange: EventEmitter<XTabChangeEvent>;
}
@Injectable({
providedIn: 'root',
})
export class XTabsContainer
extends XComponentCardContainer
implements Readonly<IXTabsContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XTabsActionModel> =
new Subject<XTabsActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly selectedIndex: number = 0;
readonly selectedIndexChange: EventEmitter<number> =
new EventEmitter<number>();
//
readonly showHeader: XStandardType<boolean> = true;
readonly disablePagination: XStandardType<boolean> = false;
readonly alignTabs: XStandardType<XTabAlignIdentifier> = XTabAlign.START;
readonly dynamicHeight: XStandardType<boolean> = false;
readonly disableRipple: XStandardType<boolean> = false;
readonly headerPosition: XStandardType<XTabsHeaderPositionIdentifier> =
XTabsHeaderPosition.ABOVE;
//
readonly loopTabs: XStandardType<boolean> = true;
readonly swipable: XStandardType<boolean> = false;
readonly animationDuration: XStandardType<string> = '500ms';
//
readonly lock: XStandardType<boolean> = false;
//
readonly color: XStandardType<XColorIdentifier> =
XColorWithBrightness.Transparent;
readonly headerColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Primary;
readonly activeTabColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Secondary;
readonly tabIndicatorColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.SecondaryTint;
readonly tabPaginatorColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.SecondaryShade;
//
readonly animationDone: EventEmitter<void> = new EventEmitter();
readonly selectedTabChange: EventEmitter<XTabChangeEvent> =
new EventEmitter<XTabChangeEvent>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export class XTabsContainerComponent
extends XComponentCardContainerComponent
implements IXTabsContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XTabsActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
selectedIndex: number = this.propertyProvider.selectedIndex;
@Output()
selectedIndexChange: EventEmitter<number> = new EventEmitter();
//
@Input()
showHeader: XStandardType<boolean> = this.propertyProvider.showHeader;
@Input()
disablePagination: XStandardType<boolean> =
this.propertyProvider.disablePagination;
@Input()
alignTabs: XStandardType<XTabAlignIdentifier> =
this.propertyProvider.alignTabs;
@Input()
dynamicHeight: XStandardType<boolean> = this.propertyProvider.dynamicHeight;
@Input()
disableRipple: XStandardType<boolean> = this.propertyProvider.disableRipple;
@Input()
headerPosition: XStandardType<XTabsHeaderPositionIdentifier> =
this.propertyProvider.headerPosition;
//
@Input()
loopTabs: XStandardType<boolean> = this.propertyProvider.loopTabs;
@Input()
swipable: XStandardType<boolean> = this.propertyProvider.swipable;
@Input()
animationDuration: XStandardType<string> =
this.propertyProvider.animationDuration;
//
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
@Input()
headerColor: XStandardType<XColorIdentifier> =
this.propertyProvider.headerColor;
@Input()
activeTabColor: XStandardType<XColorIdentifier> =
this.propertyProvider.activeTabColor;
@Input()
tabIndicatorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.tabIndicatorColor;
@Input()
tabPaginatorColor: XStandardType<XColorIdentifier> =
this.propertyProvider.tabPaginatorColor;
//
@Output()
animationDone: EventEmitter<void> = new EventEmitter();
@Output()
selectedTabChange: EventEmitter<XTabChangeEvent> = 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<IXTabsContainer> {
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
<ng-template #label>
<ng-content select="[x-tab-label]"></ng-content>
</ng-template>
<ng-template #content>
<ng-content></ng-content>
</ng-template>
### 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<any>;
//
@ViewChild('content', { static: false })
content!: TemplateRef<any>;
//#endregion
//
//#region LifeCycles ...
onChange(changeKeys: string[]) {
super.onChange(changeKeys);
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XTabComponent>('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<XTabActionModel>();
}
//
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<XTabActionIdentifier> {}
//
//#region Container ...
export interface IXTabContainer extends IXBaseContainer {
actionProvider: Subject<XTabActionModel>;
}
@Injectable({
providedIn: 'root'
})
export class XTabContainer
extends XBaseContainer
implements Readonly<IXTabContainer>
{
//
//#region Props ...
readonly actionProvider: Subject<XTabActionModel> =
new Subject<XTabActionModel>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XTabContainerComponent
extends XBaseContainerComponent
implements IXTabContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XTabActionModel> =
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<IXTabContainer> {
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
<!-- Card Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component Ref -->
<ng-template #componentRef>
<div
class="x-theme-manager x-wrapper"
[xColor]="getValue(color) | async"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<!-- Tabs -->
<x-tabs
#xTabs
[swipable]="false"
[loading]="loading"
[showHeader]="false"
[dynamicHeight]="true"
[color]="'transparent'"
[uiDisabled]="uiDisabled"
[disablePagination]="true"
[(selectedIndex)]="currentTab"
[actionProvider]="tabsActionProvider"
(selectedTabChange)="handleSelectedTabChanged($event)"
>
<!-- List Tab -->
<x-tab>
<!-- Theme List -->
<x-list
#listPresenter
[items]="listItems"
[loading]="loading"
[showToolbar]="true"
[stickyToolbar]="true"
[selectableItems]="false"
[foregroundColor]="false"
[uiDisabled]="uiDisabled"
[enableReordering]="false"
[itemTemplate]="themeListItemRef"
[color]="getValue(color) | async"
(emptyRefresh)="handleListRefresh()"
[actionProvider]="listActionProvider"
[filteringHandler]="listFilteringHandler"
[actionBarColor]="getValue(actionBarColor)"
*ngIf="
(getValue(listShowSearchBar) | async) &&
(hasChildValue(listItems) | async)
"
[actionBarForegroundColor]="
getValue(actionBarForegroundColor) | async
"
[showEmpty]="getValue(listShowEmpty) | async"
[emptyColor]="getValue(listEmptyColor) | async"
[emptyActionProvider]="listEmptyActionProvider"
[emptyRefreshButtonColor]="
getValue(listEmptyRefreshButtonColor) | async
"
[searchBarForegroundColor]="
getValue(listSearchBarForegroundColor) | async
"
[cssClass]="getArrayValue(listCssClass) | async"
[searchBarCancelButtonIcon]="
getValue(listSearchBarCancelButtonIcon) | async
"
[searchBarSearchInputColor]="
getValue(listSearchBarSearchInputColor) | async
"
[showDivider]="getValue(listShowDivider) | async"
[showActionBar]="getValue(showActionBar) | async"
[searchBarType]="getValue(searchBarType) | async"
[searchBarShowCancelButton]="
getValue(listSearchBarShowCancelButton) | async
"
[searchBarCancelButtonTitle]="
getValue(listSearchBarCancelButtonTitle) | async
"
[searchBarSpellcheck]="
getOptionalValue(listSearchBarSpellcheck) | async
"
[emptyForegroundMessageColor]="
getValue(listEmptyForegroundMessageColor) | async
"
[searchBarActionProvider]="searchBarActionProvider"
[emptyCssClass]="getValue(listEmptyCssClass) | async"
[searchBarClearButtonIconColor]="
getValue(listSearchBarClearButtonIconColor) | async
"
[searchBarSearchButtonIconColor]="
getValue(listSearchBarSearchButtonIconColor) | async
"
(searchBarOnEvent)="handleListSearchBarOnEvent($event)"
[searchBarColor]="getValue(listSearchBarColor) | async"
[searchBarValue]="getValue(listSearchBarValue) | async"
[emptyForegroundRefreshButtonColor]="
getValue(listEmptyForegroundRefreshButtonColor) | async
"
[emptyHasRefresh]="getValue(listEmptyHasRefresh) | async"
[emptyMessage]="getResourceValue(listEmptyMessage) | async"
[emptyRefreshIcon]="getValue(listEmptyRefreshIcon) | async"
[showSearchBar]="(countChildsValue(listItems) | async) > 2"
[searchBarForegroundSearchInputColor]="
getValue(listSearchBarForegroundSearchInputColor) | async
"
[actionBarActions]="getArrayValue(actionBarActions) | async"
[searchBarDebounce]="getValue(listSearchBarDebounce) | async"
[emptyMessageColor]="getValue(listEmptyMessageColor) | async"
[actionBarCssClass]="getArrayValue(actionBarCssClass) | async"
[searchBarTitle]="getResourceValue(listSearchBarTitle) | async"
(actionBarActionFired)="handleListActionBarActionFired($event)"
(searchBarQueryChange)="handleListSearchBarQueryChange($event)"
[searchBarCssClass]="getArrayValue(listSearchBarCssClass) | async"
[emptyForegroundColor]="getValue(listEmptyForegroundColor) | async"
[searchBarKeyboardType]="getValue(listSearchBarKeyboardType) | async"
[searchBarEnterKeyHint]="getValue(listSearchBarEnterKeyHint) | async"
[searchBarClearButtonIcon]="
getValue(listSearchBarClearButtonIcon) | async
"
[searchBarSearchButtonIcon]="
getValue(listSearchBarSearchButtonIcon) | async
"
>
</x-list>
</x-tab>
<!-- Preview/Details Tab -->
<x-tab>
<!-- Theme Preview -->
<x-model-presenter
[color]="getValue(color) | async"
[modelKeyProvider]="themeKeyProvider"
[hiddenModelKeys]="hiddenThemModelKeys"
[model]="getValue(selectedTheme) | async"
[cardColor]="getValue(cardColor) | async"
[propertyActionTemplate]="previewActionRef"
[labelColor]="getValue(propertyLabelColor) | async"
[valueColor]="getValue(propertyValueColor) | async"
*ngIf="notNullOrUndefinedValue(selectedTheme) | async"
[headerHighlightColor]="
getValue(presenterHeaderHighlightColor) | async
"
[headerColor]="getValue(presenterHeaderColor) | async"
[contentColor]="getValue(presenterContentColor) | async"
[cardForegroundColor]="getValue(cardForegroundColor) | async"
>
</x-model-presenter>
</x-tab>
<!-- Edit -->
<x-tab>
<x-action-bar
*ngIf="getValue(showActionBar) | async"
[actionProvider]="actionBarActionProvider"
[color]="getValue(actionBarColor) | async"
[actions]="themeModelPresenterActionActions"
[cssClass]="getValue(actionBarCssClass) | async"
[foregroundColor]="getValue(actionBarForegroundColor) | async"
>
</x-action-bar>
<!-- Model Presenter -->
<x-model-presenter
[color]="getValue(color) | async"
[modelKeyProvider]="themeKeyProvider"
[hiddenModelKeys]="hiddenThemModelKeys"
[model]="getValue(selectedTheme) | async"
[cardColor]="getValue(cardColor) | async"
[propertyActionTemplate]="themeEditActionRef"
[labelColor]="getValue(propertyLabelColor) | async"
[valueColor]="getValue(propertyValueColor) | async"
[actionProvider]="themeModelPresenterActionProvider"
(onModelChanged)="handleThemeContentChanged($event)"
*ngIf="notNullOrUndefinedValue(selectedTheme) | async"
[headerHighlightColor]="
getValue(presenterHeaderHighlightColor) | async
"
[headerColor]="getValue(presenterHeaderColor) | async"
[contentColor]="getValue(presenterContentColor) | async"
[cardForegroundColor]="getValue(cardForegroundColor) | async"
>
</x-model-presenter>
<!-- Action -->
<div class="actions">
<x-slotter [layout]="SlotLayouts.HORIZONTAL">
<!-- Center -->
<x-slot [name]="SlotNames.CENTER" [cssClass]="'ion-text-center'">
<x-button
[loading]="loading"
[type]="ButtonTypes.Raised"
class="ion-margin-horizontal"
(clicked)="handleUpdateTheme()"
[color]="getValue(saveColor) | async"
[title]="getResourceValue(saveLabel) | async"
[uiDisabled]="!(getValue(canSaveTheme) | async)"
></x-button>
</x-slot>
</x-slotter>
</div>
</x-tab>
<!-- Import -->
<x-tab>
<x-file-upload
[showEmpty]="true"
[wrapWithCard]="false"
[showActionBar]="true"
[listShowToolbar]="true"
[emptyHasRefresh]="false"
[listStickyToolbar]="true"
[listEnableReordering]="false"
[actionProvider]="themeUploadActionProvider"
[allowedExtensions]="allowedThemeExtensions"
[color]="getValue(themeUploadColor) | async"
[emptyColor]="getValue(listEmptyColor) | async"
[actionBarColor]="getValue(actionBarColor) | async"
(fileChange)="handleThemeUploadFileChanged($event)"
[maxAllowedSize]="getValue(maxAllowedSize) | async"
[listActionProvider]="themeUploadListActionProvider"
[actionBarActions]="themeUploadListActionbarActions"
[listCssClass]="getArrayValue(listCssClass) | async"
[listShowDivider]="getValue(listShowDivider) | async"
[maxAllowedFiles]="getValue(maxAllowedFiles) | async"
[cssClass]="getArrayValue(themeUploadCssClass) | async"
[searchBarColor]="getValue(listSearchBarColor) | async"
[fileDropAreaAllowedExtensions]="allowedThemeExtensions"
[emptyMessage]="getValue(themeUploadEmptyMessage) | async"
[emptyCssClass]="getArrayValue(listEmptyCssClass) | async"
[minAllowedFileSize]="getValue(minAllowedFileSize) | async"
[maxAllowedFileSize]="getValue(maxAllowedFileSize) | async"
[actionBarHideActions]="themeUploadListActionBarHideActions"
(actionBarActionFired)="handleThemeUploadActionFired($event)"
[emptyMessageColor]="getValue(listEmptyMessageColor) | async"
[showSearchBar]="(countChildsValue(uploadThemes) | async) > 1"
[actionBarCssClass]="getArrayValue(actionBarCssClass) | async"
[foregroundColor]="getValue(themeUploadForegroundColor) | async"
[fileDropAreaSupportsMultipleFiles]="
getValue(themeUploadFileDropAreaSupportsMultipleFiles) | async
"
[searchBarCssClass]="getArrayValue(listSearchBarCssClass) | async"
[fileDropAreaIcon]="getValue(themeUploadFileDropAreaIcon) | async"
[emptyForegroundColor]="getValue(listEmptyForegroundColor) | async"
[fileDropAreaColor]="getValue(themeUploadFileDropAreaColor) | async"
[fileDropAreaActionProvider]="themeUploadFileDropAreaActionProvider"
[searchBarSearchInputColor]="
getValue(listSearchBarSearchInputColor) | async
"
[fileDropAreaErrorColor]="
getValue(themeUploadFileDropAreaErrorColor) | async
"
[fileDropAreaAccentColor]="
getValue(themeUploadFileDropAreaAccentColor) | async
"
[fileDropAreaSuccessColor]="
getValue(themeUploadFileDropAreaSuccessColor) | async
"
[fileDropAreaForegroundColor]="
getValue(themeUploadFileDropAreaForegroundColor) | async
"
[emptyForegroundMessageColor]="
getValue(themeUploadEmptyForegroundMessageColor) | async
"
[fileDropAreaMessage]="
getValue(themeUploadFileDropAreaMessage) | async
"
[fileDropAreaCssClass]="
getArrayValue(themeUploadFileDropAreaCssClass) | async
"
[showFileDropArea]="
(isNotMobileUi$ | async) && getValue(themeUploadShowFileDropArea)
| async
"
></x-file-upload>
</x-tab>
</x-tabs>
</div>
</ng-template>
<!-- pack List Item Template -->
<ng-template #themeListItemRef let-item="item" let-index="index">
{{ item.data.name }}
</ng-template>
<!-- previewActionRef -->
<ng-template
#previewActionRef
let-key="key"
let-prefix="prefix"
let-value="value"
>
<x-color
[showLabel]="false"
class="x-color-item"
*ngIf="key !== 'name'"
[value]="getColorValue(key, value)"
[borderColor]="getValue(colorViewBorderColor) | async"
[borderWidth]="getValue(colorViewBorderWidth) | async"
[borderStyle]="getValue(colorViewBorderStyle) | async"
></x-color>
</ng-template>
<!-- ThemeEditActionRef -->
<ng-template
#themeEditActionRef
let-key="key"
let-prefix="prefix"
let-value="value"
>
<ng-container *ngIf="key !== 'name'">
<!-- Color Viewer -->
<x-color
[showLabel]="false"
class="x-color-item"
[value]="getColorValue(key, value)"
[borderColor]="getValue(colorViewBorderColor) | async"
[borderWidth]="getValue(colorViewBorderWidth) | async"
[borderStyle]="getValue(colorViewBorderStyle) | async"
></x-color>
<!-- is Small Screen -->
<ng-container *ngIf="isMobileUi$ | async">
<!-- Property Selector -->
<x-icon
[clickable]="true"
[foregroundColor]="true"
[name]="getValue(propertyActionMenuIcon) | async"
[color]="getValue(propertyActionMenuIconColor) | async"
(clicked)="handleThemePropertyActionMenuClicked(key, prefix, value)"
></x-icon>
</ng-container>
<!-- is Big Screen -->
<ng-container *ngIf="isNotMobileUi$ | async">
<!-- Property Selector -->
<x-icon
[clickable]="true"
[foregroundColor]="true"
[name]="getValue(propertyEditIcon) | async"
(clicked)="handleThemePropertyEdit(key, prefix, value)"
[color]="
(notNullOrUndefinedValue(value) | async)
? (getValue(propertyEditIconColor) | async)
: (getValue(emptyPropertyEditIconColor) | async)
"
></x-icon>
</ng-container>
</ng-container>
</ng-template>
### 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<XListActionModel>();
readonly allowedThemeExtensions: XStandardType<XOneOrManyType<string>> = [
'.json',
];
readonly themeUploadActionProvider = new Subject<XFileUploadActionModel>();
readonly themeUploadListActionBarHideActions: XStandardType<
XOneOrManyType<string>
>;
readonly themeModelPresenterActionProvider =
new Subject<XModelPresenterActionModel>();
readonly themeUploadListActionbarActions: XStandardType<
XOneOrManyType<XActionBarItem>
>;
readonly themeUploadFileDropAreaActionProvider =
new Subject<XFileDropAreaActionModel>();
//
canSaveTheme = false;
listItems: XListItem<any>[];
selectedTheme: XThemePack = null;
uploadThemes: XOneOrManyType<File>;
currentTab: number = this.Tabs.List;
baseTheme: Readonly<XThemePack> = null;
showList: XStandardType<boolean> = true;
hiddenThemModelKeys: XOneOrManyType<string> = [
`${nameof<XThemePack>('dark')}.${nameof<XThemeDescriptor>('type')}`,
`${nameof<XThemePack>('light')}.${nameof<XThemeDescriptor>('type')}`,
];
themeKeyProvider: XModelKeyProvider = (key) => {
//
let result = key as string;
//
switch (key) {
//
case nameof<XThemePack>('name'):
result = this.resourceProvider(this.ResourceIDs.theme);
break;
//
case nameof<XThemePack>('dark'):
result = this.resourceProvider(this.ResourceIDs.theme_dark);
break;
//
case nameof<XThemePack>('light'):
result = this.resourceProvider(this.ResourceIDs.theme_light);
break;
//
case nameof<XThemeDescriptor>('colors'):
result = this.resourceProvider(this.ResourceIDs.colors);
break;
//
default:
result = key as string;
break;
}
//
return result;
};
listActionProvider = new Subject<XListActionModel>();
tabsActionProvider = new Subject<XTabsActionModel>();
searchBarType: XStandardType<string> = XSearchBarType.Search;
searchBarActionProvider = new Subject<XSearchBarActionModel>();
actionBarActionProvider = new Subject<XActionBarActionModel>();
actionBarActions: XStandardType<XOneOrManyType<XActionBarItem>>;
themeModelPresenterActionActions: XOneOrManyType<XActionBarItem> = [
{
//
...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<XThemeManagerComponent>('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<string>;
}
//#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<File>) {
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<any> = {
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<XThemeManagerActionModel>();
}
//
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<XThemePack>;
});
//
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<XThemePack>(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<XActionBarItem> = [];
//
// 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<XThemeManagerActionIdentifier> {}
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<XThemeManagerActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
color: XStandardType<XColorIdentifier>;
//
themeChange: EventEmitter<boolean>;
tabChange: EventEmitter<XStandardType<number>>;
//
restartAfterSetTheme: XStandardType<boolean>;
colorViewBorderWidth: XStandardType<number>;
colorViewBorderStyle: XStandardType<XBorderStyleIdentifier>;
//
propertyLabelColor: XStandardType<XColorIdentifier>;
propertyValueColor: XStandardType<XColorIdentifier>;
colorViewBorderColor: XStandardType<XColorIdentifier>;
//
propertyActionMenuIconColor: XStandardType<XColorIdentifier>;
propertyActionMenuIcon: XStandardType<XIconIdentifier>;
propertyEditIconColor: XStandardType<XColorIdentifier>;
propertyEditIcon: XStandardType<XIconIdentifier>;
propertyClearIconColor: XStandardType<XColorIdentifier>;
propertyClearIcon: XStandardType<XIconIdentifier>;
emptyPropertyEditIconColor: XStandardType<XColorIdentifier>;
//
presenterHeaderColor: XStandardType<XColorIdentifier>;
presenterContentColor: XStandardType<XColorIdentifier>;
presenterHeaderHighlightColor: XStandardType<XColorIdentifier>;
//
saveColor: XStandardType<XColorIdentifier>;
saveLabel: XStandardType<XResourceIdentifier>;
resetColor: XStandardType<XColorIdentifier>;
resetLabel: XStandardType<XResourceIdentifier>;
}
@Injectable({
providedIn: 'root',
})
export class XThemeManagerContainer
extends XComponentCardContainer
implements Readonly<IXThemeManagerContainer>
{
//
//#region Props ...
//
//#region Self ...
readonly actionProvider: Subject<XThemeManagerActionModel> =
new Subject<XThemeManagerActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly color: XStandardType<XColorIdentifier> = XColorWithBrightness.Light;
//
readonly themeChange: EventEmitter<boolean> = new EventEmitter<boolean>();
readonly tabChange: EventEmitter<XStandardType<number>> = new EventEmitter<
XStandardType<number>
>();
//
readonly restartAfterSetTheme: XStandardType<boolean> = true;
readonly colorViewBorderWidth: XStandardType<number> = 1;
readonly colorViewBorderStyle: XStandardType<XBorderStyleIdentifier> =
XBorderStyle.Solid;
//
readonly propertyLabelColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Tertiary;
readonly propertyValueColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly colorViewBorderColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.LightShade;
//
readonly propertyActionMenuIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly propertyActionMenuIcon: XStandardType<XIconIdentifier> =
XIconNames.menu_vertical;
readonly propertyEditIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Tertiary;
readonly propertyEditIcon: XStandardType<XIconIdentifier> = XIconNames.edit;
readonly propertyClearIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Danger;
readonly propertyClearIcon: XStandardType<XIconIdentifier> = XIconNames.clear;
readonly emptyPropertyEditIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Danger;
//
readonly presenterHeaderColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Light;
readonly presenterContentColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
readonly presenterHeaderHighlightColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.LightShade;
//
readonly saveColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Tertiary;
readonly saveLabel: XStandardType<XResourceIdentifier> = XResourceIDs.save;
//
readonly resetColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.WarningShade;
readonly resetLabel: XStandardType<XResourceIdentifier> = 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<XThemeManagerActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
color: XStandardType<XColorIdentifier> = this.propertyProvider.color;
//
@Output()
themeChange: EventEmitter<boolean> = new EventEmitter();
@Output()
tabChange: EventEmitter<XStandardType<number>> = new EventEmitter();
//
@Input()
restartAfterSetTheme: XStandardType<boolean> =
this.propertyProvider.restartAfterSetTheme;
@Input()
colorViewBorderWidth: XStandardType<number> =
this.propertyProvider.colorViewBorderWidth;
@Input()
colorViewBorderStyle: XStandardType<XBorderStyleIdentifier> =
this.propertyProvider.colorViewBorderStyle;
//
@Input()
propertyLabelColor: XStandardType<XColorIdentifier> =
this.propertyProvider.propertyLabelColor;
@Input()
propertyValueColor: XStandardType<XColorIdentifier> =
this.propertyProvider.propertyValueColor;
@Input()
colorViewBorderColor: XStandardType<XColorIdentifier> =
this.propertyProvider.colorViewBorderColor;
//
@Input()
propertyActionMenuIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.propertyActionMenuIconColor;
@Input()
propertyActionMenuIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.propertyActionMenuIcon;
@Input()
propertyEditIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.propertyEditIconColor;
@Input()
propertyEditIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.propertyEditIcon;
@Input()
propertyClearIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.propertyClearIconColor;
@Input()
propertyClearIcon: XStandardType<XIconIdentifier> =
this.propertyProvider.propertyClearIcon;
@Input()
emptyPropertyEditIconColor: XStandardType<XColorIdentifier> =
this.propertyProvider.emptyPropertyEditIconColor;
//
@Input()
presenterHeaderColor: XStandardType<XColorIdentifier> =
this.propertyProvider.presenterHeaderColor;
@Input()
presenterContentColor: XStandardType<XColorIdentifier> =
this.propertyProvider.presenterContentColor;
@Input()
presenterHeaderHighlightColor: XStandardType<XColorIdentifier> =
this.propertyProvider.presenterHeaderHighlightColor;
//
@Input()
saveColor: XStandardType<XColorIdentifier> = this.propertyProvider.saveColor;
@Input()
saveLabel: XStandardType<XResourceIdentifier> =
this.propertyProvider.saveLabel;
//
@Input()
resetColor: XStandardType<XColorIdentifier> =
this.propertyProvider.resetColor;
@Input()
resetLabel: XStandardType<XResourceIdentifier> =
this.propertyProvider.resetLabel;
//#endregion
//
//#region ActionBar ...
@Input()
showActionBar: XStandardType<boolean> = this.propertyProvider.showActionBar;
@Input()
actionBarColor: XStandardType<XColorIdentifier> =
this.propertyProvider.actionBarColor;
@Input()
actionBarCssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.actionBarCssClass;
@Input()
actionBarForegroundColor: XStandardType<boolean> =
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<void> = 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<XActionBarActionFiredModel> = new EventEmitter<XActionBarActionFiredModel>();
@Output()
listSearchBarOnEvent: EventEmitter<XSearchBarEventIdentifier> = new EventEmitter();
@Output()
listSearchBarQueryChange: EventEmitter<string> = 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<IXThemeManagerContainer> {
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<T>() {
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
<div
(click)="handleClicked()"
class="x-thumbnail x-wrapper"
*ngIf="preparedIdentifier"
[class.mobile]="isMobileUi$ | async"
[ngClass]="getValue(cssClass) | async"
>
<ion-thumbnail
*ngIf="preparedIdentifier"
class="x-thumbnail push-auto"
[class.circular]="getValue(circular) | async"
[class.ion-activatable]="
(getValue(selectable) | async) || (getValue(clickable) | async)
"
>
<!-- Ripple Effect -->
<ion-ripple-effect
*ngIf="!(getValue(uiDisabled) | async)"
></ion-ripple-effect>
<!-- General Type -->
<ng-container *ngIf="isTypeGeneral() | async">
<ng-container *ngTemplateOutlet="generalRef"></ng-container>
</ng-container>
<!-- Custom Type -->
<ng-container *ngIf="isTypeCustom() | async">
<ng-container *ngTemplateOutlet="customRef"></ng-container>
</ng-container>
</ion-thumbnail>
</div>
<!-- General Ref -->
<ng-template #generalRef>
<x-icon
class="x-item"
[name]="getGThumbnail(preparedIdentifier) | async"
></x-icon>
</ng-template>
<!-- By Url Ref -->
<ng-template #byUrlRef>
<img class="x-item" [src]="preparedIdentifier" />
</ng-template>
<!-- Image Type Ref -->
<ng-template #imageTypeRef>
<img
#thumbImage
class="x-item"
[xFileReader]="preparedIdentifier"
(onFileReaderFinish)="thumbImage.src = $event"
/>
</ng-template>
<!-- Custom Ref -->
<ng-template #customRef>
<ng-container
*ngTemplateOutlet="
(isUrlIdentifier() | async)
? byUrlRef
: (isImageTypeIdentifier() | async)
? imageTypeRef
: generalRef
"
>
</ng-container>
</ng-template>
### 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<XThumbnailComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Identifier Changed ...
const isIdentifierChanged = changeKeys.includes(
nameof<XThumbnailComponent>('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<XThumbnailActionModel>();
}
//
// 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<XThumbnailActionIdentifier> {}
//
//#region Container ...
export interface IXThumbnailContainer extends IXBaseContainer {
//
actionProvider: Subject<XThumbnailActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
circular: XStandardType<boolean>;
clickable: XStandardType<boolean>;
selectable: XStandardType<boolean>;
type: XStandardType<XThumbnailTypeIdentifier>;
identifier: XStandardType<XThumbnailInputType>;
//
clicked: EventEmitter<void>;
}
@Injectable({
providedIn: 'root',
})
export class XThumbnailContainer
extends XBaseContainer
implements Readonly<IXThumbnailContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XThumbnailActionModel> =
new Subject<XThumbnailActionModel>();
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly circular: XStandardType<boolean> = false;
readonly clickable: XStandardType<boolean> = false;
readonly selectable: XStandardType<boolean> = false;
readonly type: XStandardType<XThumbnailTypeIdentifier> = XThumbnailType.GENERAL;
readonly identifier: XStandardType<XThumbnailInputType>;
//
readonly clicked: EventEmitter<void> = new EventEmitter();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XThumbnailContainerComponent
extends XBaseContainerComponent
implements IXThumbnailContainer
{
//
//#region Props ...
@Input()
actionProvider: Subject<XThumbnailActionModel> =
this.propertyProvider.actionProvider;
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
@Input()
circular: XStandardType<boolean> = this.propertyProvider.circular;
@Input()
clickable: XStandardType<boolean> = this.propertyProvider.clickable;
@Input()
selectable: XStandardType<boolean> = this.propertyProvider.selectable;
@Input()
type: XStandardType<XThumbnailTypeIdentifier> = this.propertyProvider.type;
@Input()
identifier: XStandardType<XThumbnailInputType> =
this.propertyProvider.identifier;
@Output()
clicked: EventEmitter<void> = 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<IXThumbnailContainer> {
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
<!-- Component Template -->
<ng-container *ngIf="getValue(wrapWithCard) | async; else componentRef">
<x-card
class="x-card"
[showActions]="true"
[color]="getValue(cardColor) | async"
[ngClass]="getValue(cssClass) | async"
[isInPage]="getValue(isInPage) | async"
[showHeader]="
(notEmptyValue(cardTitle) | async) ||
(notEmptyValue(cardSubTitle) | async)
"
[subTitle]="getResourceValue(cardSubTitle)"
[title]="getResourceValue(cardTitle) | async"
[showFooter]="getValue(cardShowFooter) | async"
[showActions]="getValue(cardShowActions) | async"
[foregroundColor]="getValue(cardForegroundColor) | async"
>
<!-- Content -->
<ng-container *ngTemplateOutlet="componentRef"></ng-container>
<!-- Footer -->
<div footer *ngIf="getValue(cardShowFooter) | async">
<ng-content select="[footer]"></ng-content>
</div>
</x-card>
</ng-container>
<!-- Component Template -->
<ng-template #componentRef>
<ng-container
*ngIf="
(notNullOrUndefinedValue(treeControl) | async) &&
(notNullOrUndefinedValue(treeFlattener) | async) &&
(notNullOrUndefinedValue(dataSource) | async) &&
(hasChildValue(nodes) | async) &&
(hasChildValue(dataSource.data) | async)
"
>
<!-- Tree -->
<mat-tree
class="x-tree"
[dataSource]="dataSource"
[treeControl]="treeControl"
>
<!-- This is the tree node template for leaf nodes -->
<mat-tree-node
matTreeNodePadding
*matTreeNodeDef="let node"
[ngClass]="getNodeClassNames(node) | async"
>
<!-- Toggler Button -->
<button mat-icon-button disabled></button>
<!-- Body -->
<div class="x-tree-node-container">
<ng-container
*ngTemplateOutlet="
nodeTemplate;
context: { $implicit: node.data, nodeId: node.id }
"
></ng-container>
</div>
</mat-tree-node>
<!-- This is the tree node template for expandable nodes -->
<mat-tree-node
matTreeNodePadding
[ngClass]="getNodeClassNames(node) | async"
*matTreeNodeDef="let node; when: nodeHasChild"
>
<!-- Toggler Button -->
<button
mat-icon-button
matTreeNodeToggle
[disabled]="loading || uiDisabled"
[matTooltipDisabled]="loading || uiDisabled"
[matTooltip]="getResourceValue(node.tooltip) | async"
(click)="handleTreeNodeToggle(node.id, treeControl.isExpanded(node))"
>
<!-- Icon Button -->
<mat-icon
class="mat-icon-rtl-mirror"
[xColor]="getValue(toggleIconColor) | async"
[isForeground]="getValue(isForegroundToggleColor) | async"
>
{{ treeControl.isExpanded(node) ? "expand_more" : "chevron_right" }}
</mat-icon>
</button>
<!-- Body -->
<div class="x-tree-node-container">
<ng-container
*ngTemplateOutlet="
nodeTemplate;
context: { $implicit: node.data, nodeId: node.id }
"
></ng-container>
</div>
</mat-tree-node>
</mat-tree>
</ng-container>
</ng-template>
### 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<XTreeFlatNode, XTreeFlatNode> = null;
//
treeFlattener: MatTreeFlattener<
XTreeNode<any>,
XTreeFlatNode,
XTreeFlatNode
> = null;
//
dataSource: MatTreeFlatDataSource<
XTreeNode<any>,
XTreeFlatNode,
XTreeFlatNode
> = null;
//#endregion
//
//#region LifeCycles ...
async onChange(changeKeys: string[]) {
super.onChange(changeKeys);
//
//#region ActionProvider Changed ...
const isActionProviderChanged = changeKeys.includes(
nameof<XTreeComponent>('actionProvider')
);
if (isActionProviderChanged) {
this.registerActionProvider();
}
//#endregion
//
//#region Nodes Changes ...
const isNodesChanged = changeKeys.includes(nameof<XTreeComponent>('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<any>) {
//
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<XTreeActionModel>();
}
//
// 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<XTreeFlatNode>(
(node) => node.level,
(node) => node.expandable
);
//
this.treeFlattener = new MatTreeFlattener(
(node: XTreeNode<any>, 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<T = any> {
id: string;
data: T;
childs?: XOneOrManyType<XTreeNode<T>>;
tooltip?: XStandardType<XResourceIdentifier>;
}
export interface XTreeFlatNode<T = any> {
id: string;
level: number;
data: XTreeNode<T>;
expandable: boolean;
tooltip?: XStandardType<XResourceIdentifier>;
}
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<XTreeActionIdentifier> {}
//
//#region Component Container Typings ...
export interface IXTreeContainer extends IXComponentCardContainer {
//
//#region Props ...
//
actionProvider: Subject<XTreeActionModel>;
cssClass: XStandardType<XOneOrManyType<string>>;
//
isForegroundToggleColor: XStandardType<boolean>;
toggleIconColor: XStandardType<XColorIdentifier>;
//
nodes: XStandardType<XOneOrManyType<XTreeNode<any>>>;
//
nodeTemplate: TemplateRef<any>;
//
onNodeToggle: EventEmitter<XTreeNodeToggle>;
//#endregion
}
@Injectable({
providedIn: 'root',
})
export class XTreeContainer
extends XComponentCardContainer
implements Readonly<IXTreeContainer>
{
//
//#region Props ...
//
readonly actionProvider: Subject<XTreeActionModel>;
readonly cssClass: XStandardType<XOneOrManyType<string>>;
//
readonly isForegroundToggleColor: XStandardType<boolean> = true;
readonly toggleIconColor: XStandardType<XColorIdentifier> =
XColorWithBrightness.Dark;
//
readonly nodes: XStandardType<XOneOrManyType<XTreeNode<any>>>;
//
readonly nodeTemplate: TemplateRef<any>;
//
readonly onNodeToggle = new EventEmitter<XTreeNodeToggle>();
//#endregion
}
@Injectable()
@Component({
template: ``,
})
export abstract class XTreeContainerComponent
extends XComponentCardContainerComponent
implements IXTreeContainer
{
//
//#region Props ...
//
@Input()
actionProvider: Subject<XTreeActionModel> =
this.propertyProvider.actionProvider;
//
@Input()
cssClass: XStandardType<XOneOrManyType<string>> =
this.propertyProvider.cssClass;
//
@Input()
toggleIconColor: XStandardType<string> =
this.propertyProvider.toggleIconColor;
//
@Input()
isForegroundToggleColor: XStandardType<boolean> =
this.propertyProvider.isForegroundToggleColor;
//
@Input()
nodes: XStandardType<XOneOrManyType<XTreeNode<any>>> =
this.propertyProvider.nodes;
//
@Input()
nodeTemplate: TemplateRef<any> = this.propertyProvider.nodeTemplate;
//
@Output()
onNodeToggle = new EventEmitter<XTreeNodeToggle>();
//#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<IXTreeContainer> {
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