@ux-aspects/ux-aspects
Version:
Open source user interface framework for building modern, responsive, mobile big data applications
1,096 lines (1,070 loc) • 1.83 MB
JavaScript
import { Observable, BehaviorSubject, Subject, ReplaySubject, merge, of, combineLatest, timer, fromEvent, Subscription, from, isObservable, concat } from 'rxjs';
import * as i0 from '@angular/core';
import { Directive, InjectionToken, inject, Injectable, RendererFactory2, ElementRef, NgZone, EventEmitter, Output, Input, HostBinding, Component, NgModule, Renderer2, PLATFORM_ID, HostListener, ContentChildren, ChangeDetectorRef, QueryList, ChangeDetectionStrategy, ContentChild, TemplateRef, ViewChild, ViewContainerRef, forwardRef, LOCALE_ID, Pipe, ViewEncapsulation, DestroyRef, ViewChildren, SecurityContext, HostAttributeToken, Injector, ApplicationRef, ComponentFactoryResolver, DOCUMENT, IterableDiffers } from '@angular/core';
import { takeUntil, filter, debounceTime, map, switchMap, take, pairwise, distinctUntilChanged, first, tap, delay, combineLatest as combineLatest$1, auditTime, mergeMap, skip, withLatestFrom, startWith } from 'rxjs/operators';
import { coerceBooleanProperty, coerceNumberProperty, coerceArray, coerceCssPixelValue } from '@angular/cdk/coercion';
import { FocusMonitor, FocusKeyManager, A11yModule, CdkMonitorFocus, CdkTrapFocus, LiveAnnouncer } from '@angular/cdk/a11y';
import { isPlatformBrowser, CommonModule, AsyncPipe, NgClass, NgTemplateOutlet, formatDate, WeekDay, DatePipe, JsonPipe, DecimalPipe, LocationStrategy, isPlatformServer } from '@angular/common';
import { Platform, PlatformModule } from '@angular/cdk/platform';
import { SplitComponent, SplitAreaComponent, AngularSplitModule } from 'angular-split';
import { END, HOME, DOWN_ARROW, RIGHT_ARROW, UP_ARROW, LEFT_ARROW, TAB, ENTER, SPACE, ESCAPE, DELETE, BACKSPACE, PAGE_DOWN, PAGE_UP } from '@angular/cdk/keycodes';
import { RouterLink, RouterModule, Router, NavigationEnd, ActivatedRoute, NavigationCancel, NavigationError } from '@angular/router';
import * as i1 from '@angular/forms';
import { NG_VALUE_ACCESSOR, FormsModule, FormGroupDirective, NG_VALIDATORS } from '@angular/forms';
import { trigger, transition, style, animate, query, stagger, state } from '@angular/animations';
import { Overlay, OverlayModule, ScrollDispatcher } from '@angular/cdk/overlay';
import { TemplatePortal, ComponentPortal, DomPortalOutlet } from '@angular/cdk/portal';
import { CdkObserveContent, ObserversModule as ObserversModule$1 } from '@angular/cdk/observers';
import { ScrollDispatcher as ScrollDispatcher$1, ViewportRuler } from '@angular/cdk/scrolling';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { moveItemInArray, CdkDropListGroup, CdkDropList, CdkDrag, CdkDragHandle, CDK_DRAG_HANDLE, CDK_DRAG_PARENT, transferArrayItem, CDK_DROP_LIST, DragDropModule } from '@angular/cdk/drag-drop';
import { DomSanitizer } from '@angular/platform-browser';
import { HttpClient, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
import { select, transition as transition$1, easeCubic, pointer, interpolate, arc, zoom, zoomTransform, hierarchy, tree, linkVertical, scaleLinear, partition, sum } from 'd3';
import { ArrayDataSource } from '@angular/cdk/collections';
import { FlatTreeControl, CdkTree, CdkTreeNodeDef, CdkTreeNode, CdkTreeModule } from '@angular/cdk/tree';
import { AutofillMonitor } from '@angular/cdk/text-field';
var Color;
(function (Color) {
Color["Primary"] = "primary";
Color["Accent"] = "accent";
Color["Secondary"] = "secondary";
Color["Alternate1"] = "alternate1";
Color["Alternate2"] = "alternate2";
Color["Alternate3"] = "alternate3";
Color["Vibrant1"] = "vibrant1";
Color["Vibrant2"] = "vibrant2";
Color["Grey1"] = "grey1";
Color["Grey2"] = "grey2";
Color["Grey3"] = "grey3";
Color["Grey4"] = "grey4";
Color["Grey5"] = "grey5";
Color["Grey6"] = "grey6";
Color["Grey7"] = "grey7";
Color["Grey8"] = "grey8";
Color["Chart1"] = "chart1";
Color["Chart2"] = "chart2";
Color["Chart3"] = "chart3";
Color["Chart4"] = "chart4";
Color["Chart5"] = "chart5";
Color["Chart6"] = "chart6";
Color["Ok"] = "ok";
Color["Warning"] = "warning";
Color["Critical"] = "critical";
Color["Partition1"] = "partition1";
Color["Partition9"] = "partition9";
Color["Partition10"] = "partition10";
Color["Partition11"] = "partition11";
Color["Partition12"] = "partition12";
Color["Partition13"] = "partition13";
Color["Partition14"] = "partition14";
Color["SocialChartNode"] = "social-chart-node";
Color["SocialChartEdge"] = "social-chart-edge";
})(Color || (Color = {}));
/**
* Determine the type of icon based upon the identifier.
*
* We support the following iconset:
*
* - `ux-icon` - UX Icon Set
* - `component` - Component icon not tied to a specific set
*
* @param identifier - The name of the icon
*/
function getIconType(identifier) {
if (identifier && identifier.trim().indexOf('ux-') === 0) {
return IconType.UxIcon;
}
return IconType.Component;
}
var IconType;
(function (IconType) {
IconType["UxIcon"] = "ux-icon";
IconType["Component"] = "component";
})(IconType || (IconType = {}));
/**
* This is a simple RxJS operator to allow us to avoid the
* "expression has changed after it was checked issue"
* by making the subscription asynchronous. We could just use a
* delay operator but this uses a timeout which is significantly
* slower than using requestAnimationFrame.
*/
const tick = () => (source) => new Observable(subscriber => {
source.subscribe({
next(value) {
requestAnimationFrame(() => subscriber.next(value));
},
error(err) {
subscriber.error(err);
},
complete() {
subscriber.complete();
},
});
});
/**
* A button will trigger a click event whenever the a mouse click occurs or the enter key is pressed.
* These functions can be used to identify if a `click` event was caused by the keyboard or
* by a mouse.
*
* The `event.detail` property will change based on the source of the event.
* A mouse click will have varying values based on the browser, however
* the enter key will always have a value of `0` so we can check against that
*/
function isKeyboardTrigger(event) {
return event.detail === 0;
}
function isMouseTrigger(event) {
return !isKeyboardTrigger(event);
}
class AccordionPanelHeadingDirective {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionPanelHeadingDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: AccordionPanelHeadingDirective, isStandalone: true, selector: "ux-accordion-panel-header", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionPanelHeadingDirective, decorators: [{
type: Directive,
args: [{ selector: 'ux-accordion-panel-header' }]
}] });
const ACCESSIBILITY_OPTIONS_TOKEN = new InjectionToken('ACCESSIBILITY_OPTIONS');
class AccessibilityOptionsService {
constructor() {
/** Get the user specified options - but handle cases where they may not be specified */
this._options = inject(ACCESSIBILITY_OPTIONS_TOKEN, { optional: true });
/** Determine the default options */
this._defaultOptions = {
mouseFocusIndicator: false,
touchFocusIndicator: false,
keyboardFocusIndicator: true,
programmaticFocusIndicator: false,
};
}
/** Get the complete options populating unspecified options with the default values */
get options() {
return { ...this._defaultOptions, ...this._options };
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccessibilityOptionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccessibilityOptionsService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccessibilityOptionsService, decorators: [{
type: Injectable
}] });
class LocalFocusIndicatorOptions {
}
class FocusIndicator {
/** Apply a class when the item is focused */
set isFocused(isFocused) {
// update the class on the element
isFocused
? this._renderer.addClass(this._element, 'ux-focus-indicator-active')
: this._renderer.removeClass(this._element, 'ux-focus-indicator-active');
// emit the focus state
this.isFocused$.next(isFocused);
}
/** Provide a convenience getter to allow access to focus state without a subscription */
get isFocused() {
return this.isFocused$.value;
}
constructor(_element, _focusMonitor, _renderer, _options, _focusIndicatorOrigin) {
this._element = _element;
this._focusMonitor = _focusMonitor;
this._renderer = _renderer;
this._options = _options;
this._focusIndicatorOrigin = _focusIndicatorOrigin;
/** An observable to monitor the focus state */
this.isFocused$ = new BehaviorSubject(false);
/** An observable to monitor the focus origin */
this.origin$ = new Subject();
/** Remove all subscriptions on destroy */
this._onDestroy = new Subject();
// check if the element is already being monitored
if (!_element.classList.contains('ux-focus-indicator')) {
this.initialise();
}
}
/** Setup the focus monitoring */
initialise() {
// add a class to the element to specify we are controlling the focus
this._renderer.addClass(this._element, 'ux-focus-indicator');
// watch for any changes to the focus state
this._focusMonitor
.monitor(this._element, this._options.checkChildren)
.pipe(takeUntil(this._onDestroy))
.subscribe(this.onFocusChange.bind(this));
}
/** Focus the element with a specific origin */
focus(origin, options) {
this._focusIndicatorOrigin.setOrigin(origin);
this._element.focus(options);
}
/** Tear down the subscriptions */
destroy() {
this._onDestroy.next();
this._onDestroy.complete();
this.isFocused$.complete();
this._focusMonitor.stopMonitoring(this._element);
}
/** Allow the options to be updates */
setOptions(options) {
this._options = { ...this._options, ...options };
}
/** Monitor changes to an elements focus state */
onFocusChange(origin) {
// if the origin is null then we blurred
if (origin === null) {
this.isFocused = false;
this.origin$.next(null);
return;
}
// get the origin if there is one
const syntheticOrigin = this._focusIndicatorOrigin.getOrigin();
// emit the origin
this.origin$.next(syntheticOrigin || origin);
switch (syntheticOrigin || origin) {
case 'mouse':
this.isFocused = this._options.mouseFocusIndicator;
break;
case 'touch':
this.isFocused = this._options.touchFocusIndicator;
break;
case 'keyboard':
this.isFocused = this._options.keyboardFocusIndicator;
break;
case 'program':
this.isFocused = this._options.programmaticFocusIndicator;
break;
default:
this.isFocused = false;
}
}
}
class FocusIndicatorOriginService {
/** Store the event source origin */
setOrigin(origin) {
this._origin = origin;
}
/** Get the most recent event origin */
getOrigin() {
// get the most recent origin if there is one
const origin = this._origin;
// we should clear the origin so this value doesn't cause issues with future focus events
this._origin = null;
return origin;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorOriginService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorOriginService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorOriginService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}] });
class FocusIndicatorService {
constructor() {
this._localOptions = inject(ACCESSIBILITY_OPTIONS_TOKEN, { optional: true });
this.rendererFactory = inject(RendererFactory2);
this._focusMonitor = inject(FocusMonitor);
this._globalOptions = inject(AccessibilityOptionsService);
this._focusIndicatorOrigin = inject(FocusIndicatorOriginService);
// programmatically create a renderer as it can't be injected into a service
this._renderer = this.rendererFactory.createRenderer(null, null);
}
/** This is essentially just a factory method to prevent the user having to pass in focus monitor, renderer and global options each time */
monitor(element, options = {
...this._globalOptions.options,
...this._localOptions,
checkChildren: false,
}) {
return new FocusIndicator(element, this._focusMonitor, this._renderer, { ...this._globalOptions.options, ...this._localOptions, ...options }, this._focusIndicatorOrigin);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorService, decorators: [{
type: Injectable
}], ctorParameters: () => [] });
class FocusIndicatorDirective {
/** Specify whether or not we should mark this element as having focus if a child is focused */
set checkChildren(checkChildren) {
// allow a string to be used so we can skip checking a binding for performance benefits
checkChildren = coerceBooleanProperty(checkChildren);
if (checkChildren !== null && checkChildren !== undefined) {
this._checkChildren = checkChildren;
this.setOptions();
}
}
/** Indicate whether or not mouse events should cause the focus indicator to appear - will override any global setting */
set mouseFocusIndicator(mouseFocusIndicator) {
// allow a string to be used so we can skip checking a binding for performance benefits
mouseFocusIndicator = coerceBooleanProperty(mouseFocusIndicator);
if (mouseFocusIndicator !== null && mouseFocusIndicator !== undefined) {
this._options.set('mouseFocusIndicator', mouseFocusIndicator);
this.setOptions();
}
}
/** Indicate whether or not touch events should cause the focus indicator to appear - will override any global setting */
set touchFocusIndicator(touchFocusIndicator) {
// allow a string to be used so we can skip checking a binding for performance benefits
touchFocusIndicator = coerceBooleanProperty(touchFocusIndicator);
if (touchFocusIndicator !== null && touchFocusIndicator !== undefined) {
this._options.set('touchFocusIndicator', touchFocusIndicator);
this.setOptions();
}
}
/** Indicate whether or not keyboard events should cause the focus indicator to appear - will override any global setting */
set keyboardFocusIndicator(keyboardFocusIndicator) {
// allow a string to be used so we can skip checking a binding for performance benefits
keyboardFocusIndicator = coerceBooleanProperty(keyboardFocusIndicator);
if (keyboardFocusIndicator !== null && keyboardFocusIndicator !== undefined) {
this._options.set('keyboardFocusIndicator', keyboardFocusIndicator);
this.setOptions();
}
}
/** Indicate whether or not programmatic events should cause the focus indicator to appear - will override any global setting */
set programmaticFocusIndicator(programmaticFocusIndicator) {
// allow a string to be used so we can skip checking a binding for performance benefits
programmaticFocusIndicator = coerceBooleanProperty(programmaticFocusIndicator);
if (programmaticFocusIndicator !== null && programmaticFocusIndicator !== undefined) {
this._options.set('programmaticFocusIndicator', programmaticFocusIndicator);
this.setOptions();
}
}
constructor() {
this.optionsService = inject(AccessibilityOptionsService);
this._elementRef = inject(ElementRef);
this._focusIndicatorService = inject(FocusIndicatorService);
this._ngZone = inject(NgZone);
this.localOptions = inject(LocalFocusIndicatorOptions, { optional: true });
/** Emit the latest focus state */
this.indicator = new EventEmitter();
/** Store a private reference for the checkChildren option */
this._checkChildren = false;
/** Store all configuation options*/
this._options = new Map();
/** Unsubscribe on component destroy */
this._onDestroy = new Subject();
// set the inital option values based on global options
for (const option in this.optionsService.options || {}) {
this._options.set(option, this.optionsService.options[option]);
}
// set the inital option values based on local options (if there are any)
for (const option in this.localOptions || {}) {
this._options.set(option, this.localOptions[option]);
}
}
/** Setup the focus monitoring */
ngOnInit() {
// start the focus monitoring
this._focusIndicator = this._focusIndicatorService.monitor(this._elementRef.nativeElement, {
checkChildren: this._checkChildren,
mouseFocusIndicator: this._options.get('mouseFocusIndicator'),
touchFocusIndicator: this._options.get('touchFocusIndicator'),
keyboardFocusIndicator: this._options.get('keyboardFocusIndicator'),
programmaticFocusIndicator: this._options.get('programmaticFocusIndicator'),
});
// subscribe to the focus state to emit an event on change
this._focusIndicator.isFocused$.pipe(takeUntil(this._onDestroy)).subscribe(isFocused => {
// emit the latest value
this._ngZone.run(() => this.indicator.emit(isFocused));
});
}
/** Tear down the directive */
ngOnDestroy() {
if (this._focusIndicator) {
this._focusIndicator.destroy();
}
// unsubscribe from all observables
this._onDestroy.next();
this._onDestroy.complete();
}
/** Focus this element with a specific origin */
focus(origin, options) {
this._focusIndicator.focus(origin, options);
}
/** Update the focus indicator with the latest options */
setOptions() {
if (this._focusIndicator) {
this._focusIndicator.setOptions({
checkChildren: this._checkChildren,
mouseFocusIndicator: this._options.get('mouseFocusIndicator'),
touchFocusIndicator: this._options.get('touchFocusIndicator'),
keyboardFocusIndicator: this._options.get('keyboardFocusIndicator'),
programmaticFocusIndicator: this._options.get('programmaticFocusIndicator'),
});
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: FocusIndicatorDirective, isStandalone: true, selector: "[uxFocusIndicator]", inputs: { checkChildren: "checkChildren", mouseFocusIndicator: "mouseFocusIndicator", touchFocusIndicator: "touchFocusIndicator", keyboardFocusIndicator: "keyboardFocusIndicator", programmaticFocusIndicator: "programmaticFocusIndicator" }, outputs: { indicator: "indicator" }, exportAs: ["ux-focus-indicator"], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorDirective, decorators: [{
type: Directive,
args: [{
selector: '[uxFocusIndicator]',
exportAs: 'ux-focus-indicator',
}]
}], ctorParameters: () => [], propDecorators: { checkChildren: [{
type: Input
}], mouseFocusIndicator: [{
type: Input
}], touchFocusIndicator: [{
type: Input
}], keyboardFocusIndicator: [{
type: Input
}], programmaticFocusIndicator: [{
type: Input
}], indicator: [{
type: Output
}] } });
class AccordionService {
constructor() {
this.collapseOthers = false;
this.collapse = new Subject();
}
collapseAll() {
this.collapse.next();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionService, decorators: [{
type: Injectable
}] });
let uniqueId$e = 1;
class AccordionPanelComponent {
constructor() {
this.accordion = inject(AccordionService);
this.panelId = `ux-accordion-panel-${uniqueId$e++}`;
this.headingId = `${this.panelId}-heading`;
this.disabled = false;
this.expanded = false;
this.expandedChange = new EventEmitter();
this._onDestroy = new Subject();
}
ngOnInit() {
this.accordion.collapse.pipe(takeUntil(this._onDestroy)).subscribe(() => this.collapse());
}
ngOnDestroy() {
this._onDestroy.next();
this._onDestroy.complete();
}
toggle() {
if (this.expanded) {
this.collapse();
return;
}
// check if we should collapse others
if (this.accordion.collapseOthers) {
this.accordion.collapseAll();
}
// store the new expanded state
this.expand();
}
expand() {
if (this.disabled === false && this.expanded === false) {
this.expanded = true;
this.expandedChange.next(true);
}
}
collapse() {
if (this.disabled === false && this.expanded === true) {
this.expanded = false;
this.expandedChange.next(false);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.9", type: AccordionPanelComponent, isStandalone: true, selector: "ux-accordion-panel", inputs: { panelId: "panelId", headingId: "headingId", disabled: "disabled", heading: "heading", expanded: "expanded" }, outputs: { expandedChange: "expandedChange" }, host: { properties: { "class.panel-open": "this.expanded" }, classAttribute: "panel panel-default" }, ngImport: i0, template: "<div\n class=\"panel-heading\"\n role=\"button\"\n uxFocusIndicator\n [tabindex]=\"disabled ? -1 : 0\"\n [id]=\"headingId\"\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-disabled]=\"disabled\"\n (click)=\"toggle()\"\n (keydown.enter)=\"toggle()\"\n (keydown.space)=\"toggle(); $event.preventDefault()\"\n (keydown.spacebar)=\"toggle(); $event.preventDefault()\"\n>\n <div class=\"panel-title\">\n {{ heading }}\n <ng-content select=\"ux-accordion-panel-header\"></ng-content>\n </div>\n</div>\n\n<div\n [id]=\"panelId\"\n class=\"panel-collapse collapse\"\n [class.in]=\"expanded\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"headingId\"\n>\n <div class=\"panel-body\">\n <ng-content></ng-content>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: FocusIndicatorDirective, selector: "[uxFocusIndicator]", inputs: ["checkChildren", "mouseFocusIndicator", "touchFocusIndicator", "keyboardFocusIndicator", "programmaticFocusIndicator"], outputs: ["indicator"], exportAs: ["ux-focus-indicator"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionPanelComponent, decorators: [{
type: Component,
args: [{ selector: 'ux-accordion-panel', host: {
class: 'panel panel-default',
}, imports: [FocusIndicatorDirective], template: "<div\n class=\"panel-heading\"\n role=\"button\"\n uxFocusIndicator\n [tabindex]=\"disabled ? -1 : 0\"\n [id]=\"headingId\"\n [attr.aria-expanded]=\"expanded\"\n [attr.aria-controls]=\"panelId\"\n [attr.aria-disabled]=\"disabled\"\n (click)=\"toggle()\"\n (keydown.enter)=\"toggle()\"\n (keydown.space)=\"toggle(); $event.preventDefault()\"\n (keydown.spacebar)=\"toggle(); $event.preventDefault()\"\n>\n <div class=\"panel-title\">\n {{ heading }}\n <ng-content select=\"ux-accordion-panel-header\"></ng-content>\n </div>\n</div>\n\n<div\n [id]=\"panelId\"\n class=\"panel-collapse collapse\"\n [class.in]=\"expanded\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"headingId\"\n>\n <div class=\"panel-body\">\n <ng-content></ng-content>\n </div>\n</div>\n" }]
}], propDecorators: { panelId: [{
type: Input
}], headingId: [{
type: Input
}], disabled: [{
type: Input
}], heading: [{
type: Input
}], expanded: [{
type: Input
}, {
type: HostBinding,
args: ['class.panel-open']
}], expandedChange: [{
type: Output
}] } });
class AccordionComponent {
constructor() {
this._accordion = inject(AccordionService);
}
set collapseOthers(collapseOthers) {
this._accordion.collapseOthers = collapseOthers;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.9", type: AccordionComponent, isStandalone: true, selector: "ux-accordion", inputs: { collapseOthers: "collapseOthers" }, host: { attributes: { "aria-multiselectable": "true" }, classAttribute: "panel-group" }, providers: [AccordionService], ngImport: i0, template: "<ng-content></ng-content>\n" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: AccordionComponent, decorators: [{
type: Component,
args: [{ selector: 'ux-accordion', providers: [AccordionService], host: {
class: 'panel-group',
'aria-multiselectable': 'true',
}, template: "<ng-content></ng-content>\n" }]
}], propDecorators: { collapseOthers: [{
type: Input
}] } });
const KEPPEL_COLOR_SET = {
primary: '#00a7a2',
accent: '#7b63a3',
secondary: '#fff',
alternate1: '#3baa43',
alternate2: '#025662',
alternate3: '#b08f5c',
vibrant1: '#00cceb',
vibrant2: '#ff9048',
grey1: '#2a2a2a',
grey2: '#333',
grey3: '#666',
grey4: '#999',
grey5: '#ccc',
grey6: '#eee',
grey7: '#f5f5f5',
grey8: '#fafafa',
chart1: '#00a7a2',
chart2: '#7b63a3',
chart3: '#3baa43',
chart4: '#025662',
chart5: '#b08f5c',
chart6: '#ccc',
ok: '#3baa43',
warning: '#ff9048',
critical: '#ff454f',
partition1: '#635387',
partition9: '#4a4066',
partition10: '#308935',
partition11: '#023e42',
partition12: '#91744d',
partition13: '#999',
partition14: '#294266',
'social-chart-node': '#00cceb',
'social-chart-edge': '#00cceb',
};
const MICRO_FOCUS_COLOR_SET = {
'brand-blue': '#0073e7',
cerulean: '#1668c1',
aqua: '#29ceff',
aquamarine: '#2fd6c3',
fuchsia: '#c6179d',
indigo: '#7425ad',
'dark-blue': '#231ca5',
white: '#ffffff',
'slightly-gray': '#f5f7f8',
'bright-gray': '#f1f2f3',
gray: '#dcdedf',
silver: '#bdbec0',
'dim-gray': '#656668',
'dark-gray': '#323435',
black: '#000000',
'crimson-negative': '#e5004c',
apricot: '#f48b34',
yellow: '#fcdb1f',
'green-positive': '#1aac60',
ultramarine: '#3939c6',
skyblue: '#00abf3',
'pale-aqua': '#43e4ff',
'pale-green': '#1ffbba',
lime: '#75da4d',
orange: '#ffce00',
magenta: '#eb23c2',
'pale-purple': '#ba47e2',
'dark-ultramarine': '#271782',
steelblue: '#014272',
'arctic-blue': '#0b8eac',
emerald: '#00a989',
olive: '#5bba36',
goldenrod: '#ffb000',
purple: '#9b1e83',
'pale-eggplant': '#5216ac',
red: '#ff454f',
'pale-amber': '#ffb24d',
'pale-lemon': '#fde159',
'pale-emerald': '#33c180',
plum: '#b21646',
copper: '#e57828',
amber: '#ffc002',
'leaf-green': '#118c4f',
'forest-green': '#00645a',
primary: '#0073e7',
accent: '#7425ad',
secondary: '#ffffff',
alternate1: '#29ceff',
alternate2: '#2fd6c3',
alternate3: '#c6179d',
vibrant1: '#43e4ff',
vibrant2: '#ffce00',
grey1: '#000000',
grey2: '#323435',
grey3: '#656668',
grey4: '#bdbec0',
grey5: '#dcdedf',
grey6: '#f1f2f3',
grey7: '#f5f7f8',
grey8: '#ffffff',
chart1: '#3939c6',
chart2: '#00abf3',
chart3: '#75da4d',
chart4: '#ffce00',
chart5: '#eb23c2',
chart6: '#ba47e2',
info: '#00abf3',
ok: '#1aac60',
warning: '#fcdb1f',
danger: '#f48b34',
critical: '#e5004c',
partition1: '#7425ad',
partition9: '#5216ac',
partition10: '#5bba36',
partition11: '#014272',
partition12: '#ffb000',
partition13: '#bdbec0',
partition14: '#271782',
'social-chart-node': '#ff00ff',
'social-chart-edge': '#ff00ff',
};
const colorSets = {
keppel: {
colorValueSet: KEPPEL_COLOR_SET,
},
microFocus: {
colorValueSet: MICRO_FOCUS_COLOR_SET,
},
};
/** Provide a default color set for an application */
const COLOR_SET_TOKEN = new InjectionToken('COLOR_SET_TOKEN');
class ThemeColor {
constructor(_r, _g, _b, _a = '1') {
this._r = _r;
this._g = _g;
this._b = _b;
this._a = _a;
}
/**
* Create a ThemeColor object from a CSS color string
* @param value The CSS color string to derive a ThemeColor object from
*/
static parse(value) {
let r, g, b, a = '1';
const rgbaPattern = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/;
const shortHexPattern = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
const longHexPattern = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
const rgbaMatch = value.match(rgbaPattern);
const shortHexMatch = value.match(shortHexPattern);
const longHexMatch = value.match(longHexPattern);
if (rgbaMatch) {
r = rgbaMatch[1];
g = rgbaMatch[2];
b = rgbaMatch[3];
a = rgbaMatch[4] ? rgbaMatch[4] : '1';
}
else if (longHexMatch) {
r = parseInt(longHexMatch[1], 16).toString();
g = parseInt(longHexMatch[2], 16).toString();
b = parseInt(longHexMatch[3], 16).toString();
}
else if (shortHexMatch) {
r = parseInt(shortHexMatch[1] + shortHexMatch[1], 16).toString();
g = parseInt(shortHexMatch[2] + shortHexMatch[2], 16).toString();
b = parseInt(shortHexMatch[3] + shortHexMatch[3], 16).toString();
}
else {
throw new Error(`Cannot parse color - ${value} is not a valid color.`);
}
return new ThemeColor(r, g, b, a);
}
/**
* Clone a theme color so it can be modified without affecting other places using the color
* @param themeColor The original theme color to clone
*/
static from(themeColor) {
return new ThemeColor(themeColor.getRed(), themeColor.getGreen(), themeColor.getBlue(), themeColor.getAlpha());
}
/**
* Determine if an object is an instance of a theme color.
* Using a simple instanceof check will not always work in plunker
* where the ThemeColor is from @ux-aspects/ux-aspects and the color
* comes from @micro-focus/ux-aspects
*/
static isInstanceOf(themeColor) {
return (typeof themeColor === 'object' &&
// eslint-disable-next-line no-prototype-builtins
themeColor.hasOwnProperty('_r') &&
// eslint-disable-next-line no-prototype-builtins
themeColor.hasOwnProperty('_g') &&
// eslint-disable-next-line no-prototype-builtins
themeColor.hasOwnProperty('_b') &&
// eslint-disable-next-line no-prototype-builtins
themeColor.hasOwnProperty('_a'));
}
/**
* Convert the theme color to a CSS hex color code
*/
toHex() {
let red = parseInt(this._r).toString(16);
let green = parseInt(this._g).toString(16);
let blue = parseInt(this._b).toString(16);
if (red.length < 2) {
red = '0' + red;
}
if (green.length < 2) {
green = '0' + green;
}
if (blue.length < 2) {
blue = '0' + blue;
}
return '#' + red + green + blue;
}
/**
* Convert the theme color to a CSS rgb color code
*/
toRgb() {
return 'rgb(' + this._r + ', ' + this._g + ', ' + this._b + ')';
}
/**
* Convert the theme color to a CSS rgbs color code
*/
toRgba() {
return 'rgba(' + this._r + ', ' + this._g + ', ' + this._b + ', ' + this._a + ')';
}
/**
* Get the red value from the RGBA color value
*/
getRed() {
return this._r;
}
/**
* Get the green value from the RGBA color value
*/
getGreen() {
return this._g;
}
/**
* Get the blue value from the RGBA color value
*/
getBlue() {
return this._b;
}
/**
* Get the alpha value from the RGBA color value
*/
getAlpha() {
return this._a;
}
/**
* Set the red value from the RGBA color value
*/
setRed(red) {
this._r = red;
return this;
}
/**
* Set the green value from the RGBA color value
*/
setGreen(green) {
this._g = green;
return this;
}
/**
* Set the blue value from the RGBA color value
*/
setBlue(blue) {
this._b = blue;
return this;
}
/**
* Set the alpha value from the RGBA color value
*/
setAlpha(alpha) {
this._a = alpha.toString();
return this;
}
}
class ColorService {
/** Allow the color set to be provided in a forRoot function otherwise set it to the Keppel theme by default */
constructor() {
this._colorSet = inject(COLOR_SET_TOKEN, { optional: true });
// resolve the theme based on the colorset
this._theme = this.getTheme(this._colorSet);
}
/**
* Get a ThemeColor object from a color name
* @param colorName The name of the color from the color palette
*/
getColor(colorName) {
// get the matching ThemeColor from the active theme
const themeColor = this._theme[this.resolveColorName(colorName)];
// if there is not a match then throw an error
if (!themeColor) {
throw new Error('Color not found: ' + colorName);
}
return new ThemeColor(themeColor.getRed(), themeColor.getGreen(), themeColor.getBlue(), themeColor.getAlpha());
}
/**
* Get the active color set
*/
getColorSet() {
return this._colorSet;
}
/**
* Define the current color set and produce a Theme from it
*/
setColorSet(colorSet) {
this._colorSet = colorSet;
this._theme = this.getTheme(colorSet);
}
/**
* Resolve a color value. This may be the name of a color from the color set
* or it may simply be a hex or rgb(a) color value. This function will return
* a CSS color value regardless of which one of these formats it is
* @param value The color name, hex code or rgb(a) value to resolve
* @returns If the color is the name of a color in the set, the `rgba` color will be returned, otherwise the original CSS value will be returned.
*/
resolve(value) {
if (!value) {
return;
}
const colorName = this.resolveColorName(value);
for (const color in this._theme) {
if (colorName === color.toLowerCase()) {
return this.getColor(colorName).toRgba();
}
}
return value;
}
/**
* Converts a color name to an appropriate ColorSet name. For example
* a color may be written in lower-camel-case, however color sets are in
* kebab-case. This will convert to the appropriate naming format
* @param colorName The color name to resolve
*/
resolveColorName(colorName = '') {
return colorName.replace(/\s+/g, '-').toLowerCase();
}
/** Determine if the current colorset has a specific color */
colorExists(name) {
return !!Object.keys(this._theme).find(colorName => colorName === this.resolveColorName(name));
}
/** Create a theme from a colorset */
getTheme(colorSet) {
// create a new theme object
const theme = {};
// ensure we have a colorset
if (!colorSet) {
colorSet = colorSets.keppel;
}
// iterate over each hex code and convert it to a theme color
for (const color in colorSet.colorValueSet) {
theme[color] = ThemeColor.parse(colorSet.colorValueSet[color]);
}
return theme;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ColorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ColorService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ColorService, decorators: [{
type: Injectable
}], ctorParameters: () => [] });
class ColorServiceModule {
/**
* The function allows the consuming applications to specify the applications
* color set once in the app module, eg:
* ```
* ColorServiceModule.forRoot(colorSets.microFocus);
* ```
* @param colorSet The color set the application should use
*/
static forRoot(colorSet) {
return {
ngModule: ColorServiceModule,
providers: [
{ provide: COLOR_SET_TOKEN, useValue: colorSet ? colorSet : colorSets.keppel },
ColorService,
],
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ColorServiceModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.9", ngImport: i0, type: ColorServiceModule }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ColorServiceModule }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ColorServiceModule, decorators: [{
type: NgModule,
args: [{}]
}] });
class ContrastService {
/**
* Calculate the contract ratio between two colors.
* This uses the official WCAG Color Contrast Ratio
* Algorithm: https://www.w3.org/TR/WCAG20-TECHS/G17.html
*/
getContrastColor(backgroundColor, lightColor, darkColor) {
// get a ThemeColor from the ColorPickerColor
const themeColor = ThemeColor.parse(backgroundColor.toHex());
const background = this.getLuminance(themeColor);
const light = this.getLuminance(lightColor);
const dark = this.getLuminance(darkColor);
// determine the contrast for both black and white
const whiteContrast = (light + 0.05) / (background + 0.05);
const blackContrast = (background + 0.05) / (dark + 0.05);
// return the color with the most contrast ratio
return blackContrast > whiteContrast ? darkColor : lightColor;
}
getLuminance(color) {
// normalize the colors
let r = +color.getRed() / 255;
let g = +color.getGreen() / 255;
let b = +color.getBlue() / 255;
// calculate the value required for each color component
r = r <= 0.03928 ? r / 12.92 : Math.pow((r + 0.055) / 1.055, 2.4);
g = g <= 0.03928 ? g / 12.92 : Math.pow((g + 0.055) / 1.055, 2.4);
b = b <= 0.03928 ? b / 12.92 : Math.pow((b + 0.055) / 1.055, 2.4);
// return the luminance
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ContrastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ContrastService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ContrastService, decorators: [{
type: Injectable
}] });
class ColorContrastDirective {
constructor() {
this._colorService = inject(ColorService);
this._contrastService = inject(ContrastService);
/** Store the light color as a ThemeColor object */
this._lightColor = ThemeColor.parse('#fff');
/** Store the light color as a ThemeColor object */
this._darkColor = ThemeColor.parse('#000');
}
/**
* Define the background color for contrast comparison.
* This can be a CSS color value or the name of a
* color from the color palette.
*/
set uxColorContrast(backgroundColor) {
this._backgroundColor = ThemeColor.parse(this._colorService.resolve(backgroundColor));
}
/**
* Define the light color for contrast comparison.
* This can be a CSS color value or the name of a
* color from the color palette.
*/
set lightColor(lightColor) {
this._lightColor = ThemeColor.parse(this._colorService.resolve(lightColor));
}
/**
* Define the dark color for contrast comparison.
* This can be a CSS color value or the name of a
* color from the color palette.
*/
set darkColor(darkColor) {
this._darkColor = ThemeColor.parse(this._colorService.resolve(darkColor));
}
/** Determine the color to set based on the supplied parameters */
get _color() {
return this._backgroundColor
? this._contrastService
.getContrastColor(this._backgroundColor, this._lightColor, this._darkColor)
.toRgba()
: null;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ColorContrastDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: ColorContrastDirective, isStandalone: true, selector: "[uxColorContrast]", inputs: { uxColorContrast: "uxColorContrast", lightColor: "lightColor", darkColor: "darkColor" }, host: { properties: { "style.color": "this._color" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: ColorContrastDirective, decorators: [{
type: Directive,
args: [{ selector: '[uxColorContrast]' }]
}], propDecorators: { uxColorContrast: [{
type: Input
}], lightColor: [{
type: Input
}], darkColor: [{
type: Input
}], _color: [{
type: HostBinding,
args: ['style.color']
}] } });
/**
* This directive can be used to target specific elements based on their CSS
* class so we can control when the focus shows. This will help prevent us
* polluting the FocusIndicatorDirective with an lot of selectors.
*
* If the button has a uxFocusIndicator, uxMenuTriggerFor or uxMenuNavigationToggle directive applied we should skip this
*/
class DefaultFocusIndicatorDirective extends FocusIndicatorDirective {
constructor() {
super();
// Enable programmatic focus by default
this.programmaticFocusIndicator = true;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: DefaultFocusIndicatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: DefaultFocusIndicatorDirective, isStandalone: true, selector: ".btn:not([uxFocusIndicator]):not([uxMenuNavigationToggle]):not([uxMenuTriggerFor]), a[href]:not([uxFocusIndicator]):not([uxMenuNavigationToggle]):not([uxMenuTriggerFor])", usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: DefaultFocusIndicatorDirective, decorators: [{
type: Directive,
args: [{
selector: '.btn:not([uxFocusIndicator]):not([uxMenuNavigationToggle]):not([uxMenuTriggerFor]), a[href]:not([uxFocusIndicator]):not([uxMenuNavigationToggle]):not([uxMenuTriggerFor])',
}]
}], ctorParameters: () => [] });
class FocusIndicatorOptionsDirective {
constructor() {
this._options = inject(LocalFocusIndicatorOptions, { self: true });
}
/** If `true`, this element will receive a focus indicator when the element is clicked on. */
set mouseFocusIndicator(mouseFocusIndicator) {
this._options.mouseFocusIndicator = mouseFocusIndicator;
}
/** If `true`, this element will receive a focus indicator when the element is touched. */
set touchFocusIndicator(touchFocusIndicator) {
this._options.touchFocusIndicator = touchFocusIndicator;
}
/** If `true`, this element will receive a focus indicator when the element is focused using the keyboard. */
set keyboardFocusIndicator(keyboardFocusIndicator) {
this._options.keyboardFocusIndicator = keyboardFocusIndicator;
}
/** If `true`, this element will receive a focus indicator when the element is programmatically focused. */
set programmaticFocusIndicator(programmaticFocusIndicator) {
this._options.programmaticFocusIndicator = programmaticFocusIndicator;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorOptionsDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.9", type: FocusIndicatorOptionsDirective, isStandalone: true, selector: "[uxFocusIndicatorOptions]", inputs: { mouseFocusIndicator: "mouseFocusIndicator", touchFocusIndicator: "touchFocusIndicator", keyboardFocusIndicator: "keyboardFocusIndicator", programmaticFocusIndicator: "programmaticFocusIndicator" }, providers: [LocalFocusIndicatorOptions], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: FocusIndicatorOptionsDirective, decorators: [{
type: Directive,
args: [{
selector: '[uxFocusIndicatorOptions]',
providers: [LocalFocusIndicatorOptions],
}]
}], propDecorators: { mouseFocusIndicator: [{
type: Input
}], touchFocusIndicator: [{
type: Input
}], keyboardFocusIndicator: [{
type: Input
}], programmaticFocusIndicator: [{
type: Input
}] } });
/**
* When working with component host elements
* we cannot apply directives, eg. FocusIndicatorOriginDirective
* however we may still want the functionality to be applied to
* the host element. This class allows the host element to become
* a focus indicator origin
*/
class FocusIndicatorOrigin {
constructor(_focusIndicatorOrigin, elementRef, renderer) {
this._focusIndicatorOrigin = _focusIndicatorOrigin;
/** Store all event handlers */
this._handlers = [];
// add event handlers
this._handlers = [
renderer.listen(elementRef.nativeElement, 'click', () => th