@ng-matero/extensions
Version:
Angular Material Extensions
748 lines (741 loc) • 40.6 kB
JavaScript
import { A11yModule } from '@angular/cdk/a11y';
import { Overlay, OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
import { ComponentPortal, PortalModule } from '@angular/cdk/portal';
import { NgTemplateOutlet, CommonModule } from '@angular/common';
import * as i0 from '@angular/core';
import { InjectionToken, inject, ElementRef, ChangeDetectorRef, NgZone, Renderer2, Input, ChangeDetectionStrategy, ViewEncapsulation, Component, ViewContainerRef, DOCUMENT, EventEmitter, Injector, afterNextRender, booleanAttribute, Output, forwardRef, Directive, HostAttributeToken, ViewChild, ContentChild, NgModule } from '@angular/core';
import { MatIconButton, MatButtonModule } from '@angular/material/button';
import { ColorPicker } from '@acrodata/color-picker';
import { Directionality } from '@angular/cdk/bidi';
import { hasModifierKey, ESCAPE, UP_ARROW, DOWN_ARROW } from '@angular/cdk/keycodes';
import { _animationsDisabled } from '@angular/material/core';
import { Subject, Subscription, merge, of } from 'rxjs';
import { take, filter } from 'rxjs/operators';
import { NG_VALUE_ACCESSOR, NG_VALIDATORS, Validators } from '@angular/forms';
import { MatFormField } from '@angular/material/form-field';
import { MAT_INPUT_VALUE_ACCESSOR } from '@angular/material/input';
/** Used to generate a unique ID for each colorpicker instance. */
let colorpickerUid = 0;
/** Injection token that determines the scroll handling while the panel is open. */
const MTX_COLORPICKER_SCROLL_STRATEGY = new InjectionToken('mtx-colorpicker-scroll-strategy', {
providedIn: 'root',
factory: () => {
const overlay = inject(Overlay);
return () => overlay.scrollStrategies.reposition();
},
});
class MtxColorpickerContent {
constructor() {
this._elementRef = inject(ElementRef);
this._animationsDisabled = _animationsDisabled();
this._changeDetectorRef = inject(ChangeDetectorRef);
this._ngZone = inject(NgZone);
/** Emits when an animation has finished. */
this._animationDone = new Subject();
/** Whether there is an in-progress animation. */
this._isAnimating = false;
this._handleAnimationEvent = (event) => {
const element = this._elementRef.nativeElement;
if (event.target !== element || !event.animationName.startsWith('_mtx-colorpicker-content')) {
return;
}
clearTimeout(this._animationFallback);
this._isAnimating = event.type === 'animationstart';
element.classList.toggle('mtx-colorpicker-content-animating', this._isAnimating);
if (!this._isAnimating) {
this._animationDone.next();
}
};
if (!this._animationsDisabled) {
const element = this._elementRef.nativeElement;
const renderer = inject(Renderer2);
this._eventCleanups = this._ngZone.runOutsideAngular(() => [
renderer.listen(element, 'animationstart', this._handleAnimationEvent),
renderer.listen(element, 'animationend', this._handleAnimationEvent),
renderer.listen(element, 'animationcancel', this._handleAnimationEvent),
]);
}
}
ngOnDestroy() {
clearTimeout(this._animationFallback);
this._eventCleanups?.forEach(cleanup => cleanup());
this._animationDone.complete();
}
_startExitAnimation() {
this._elementRef.nativeElement.classList.add('mtx-colorpicker-content-exit');
if (this._animationsDisabled) {
this._animationDone.next();
}
else {
// Some internal apps disable animations in tests using `* {animation: none !important}`.
// If that happens, the animation events won't fire and we'll never clean up the overlay.
// Add a fallback that will fire if the animation doesn't run in a certain amount of time.
clearTimeout(this._animationFallback);
this._animationFallback = setTimeout(() => {
if (!this._isAnimating) {
this._animationDone.next();
}
}, 200);
}
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerContent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MtxColorpickerContent, isStandalone: true, selector: "mtx-colorpicker-content", inputs: { color: "color" }, host: { properties: { "class": "color ? \"mat-\" + color : \"\"", "class.mtx-colorpicker-content-animations-enabled": "!_animationsDisabled" }, classAttribute: "mtx-colorpicker-content" }, exportAs: ["mtxColorpickerContent"], ngImport: i0, template: "@if (picker.content) {\n <ng-template [ngTemplateOutlet]=\"picker.content\"></ng-template>\n} @else {\n <color-picker\n [format]=\"picker.format\"\n [value]=\"picker.selected\"\n (valueChange)=\"picker.select($event)\"\n />\n}\n", styles: ["@keyframes _mtx-colorpicker-content-dropdown-enter{0%{opacity:0;transform:scaleY(.8)}to{opacity:1;transform:none}}@keyframes _mtx-colorpicker-content-exit{0%{opacity:1}to{opacity:0}}.mtx-colorpicker-content{display:block;border-radius:4px}.mtx-colorpicker-content.mtx-colorpicker-content-animations-enabled{animation:_mtx-colorpicker-content-dropdown-enter .12s cubic-bezier(0,0,.2,1)}.mtx-colorpicker-content-exit.mtx-colorpicker-content-animations-enabled{animation:_mtx-colorpicker-content-exit .1s linear}\n"], dependencies: [{ kind: "component", type: ColorPicker, selector: "color-picker", inputs: ["format", "value", "hideAlpha", "disabled"], outputs: ["formatChange", "valueChange", "colorChange"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerContent, decorators: [{
type: Component,
args: [{ selector: 'mtx-colorpicker-content', host: {
'class': 'mtx-colorpicker-content',
'[class]': 'color ? "mat-" + color : ""',
'[class.mtx-colorpicker-content-animations-enabled]': '!_animationsDisabled',
}, exportAs: 'mtxColorpickerContent', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [ColorPicker, NgTemplateOutlet], template: "@if (picker.content) {\n <ng-template [ngTemplateOutlet]=\"picker.content\"></ng-template>\n} @else {\n <color-picker\n [format]=\"picker.format\"\n [value]=\"picker.selected\"\n (valueChange)=\"picker.select($event)\"\n />\n}\n", styles: ["@keyframes _mtx-colorpicker-content-dropdown-enter{0%{opacity:0;transform:scaleY(.8)}to{opacity:1;transform:none}}@keyframes _mtx-colorpicker-content-exit{0%{opacity:1}to{opacity:0}}.mtx-colorpicker-content{display:block;border-radius:4px}.mtx-colorpicker-content.mtx-colorpicker-content-animations-enabled{animation:_mtx-colorpicker-content-dropdown-enter .12s cubic-bezier(0,0,.2,1)}.mtx-colorpicker-content-exit.mtx-colorpicker-content-animations-enabled{animation:_mtx-colorpicker-content-exit .1s linear}\n"] }]
}], ctorParameters: () => [], propDecorators: { color: [{
type: Input
}] } });
class MtxColorpicker {
constructor() {
this._overlay = inject(Overlay);
this._viewContainerRef = inject(ViewContainerRef);
this._dir = inject(Directionality, { optional: true });
this._document = inject(DOCUMENT, { optional: true });
this._scrollStrategy = inject(MTX_COLORPICKER_SCROLL_STRATEGY);
this._inputStateChanges = Subscription.EMPTY;
/** Emits when the colorpicker has been opened. */
this.openedStream = new EventEmitter();
/** Emits when the colorpicker has been closed. */
this.closedStream = new EventEmitter();
/** Preferred position of the colorpicker in the X axis. */
this.xPosition = 'start';
/** Preferred position of the colorpicker in the Y axis. */
this.yPosition = 'below';
/**
* Whether to restore focus to the previously-focused element when the panel is closed.
* Note that automatic focus restoration is an accessibility feature and it is recommended that
* you provide your own equivalent, if you decide to turn it off.
*/
this.restoreFocus = true;
this._opened = false;
/** The id for the colorpicker panel. */
this.id = `mtx-colorpicker-${colorpickerUid++}`;
this._validSelected = '';
/** The element that was focused before the colorpicker was opened. */
this._focusedElementBeforeOpen = null;
/** Unique class that will be added to the backdrop so that the test harnesses can look it up. */
this._backdropHarnessClass = `${this.id}-backdrop`;
/** Emits when the colorpicker is disabled. */
this._disabledChange = new Subject();
/** Emits new selected color when selected color changes. */
this._selectedChanged = new Subject();
this._injector = inject(Injector);
}
get disabled() {
return this._disabled === undefined && this.pickerInput
? this.pickerInput.disabled
: !!this._disabled;
}
set disabled(value) {
if (value !== this._disabled) {
this._disabled = value;
this._disabledChange.next(value);
}
}
/** Whether the panel is open. */
get opened() {
return this._opened;
}
set opened(value) {
value ? this.open() : this.close();
}
/** Color palette to use on the colorpicker's panel. */
get color() {
return this._color || (this.pickerInput ? this.pickerInput.getThemePalette() : undefined);
}
set color(value) {
this._color = value;
}
/** The input and output color format. */
get format() {
return this._format || this.pickerInput?.format;
}
set format(value) {
this._format = value;
}
/** The currently selected color. */
get selected() {
return this._validSelected;
}
set selected(value) {
this._validSelected = value;
}
ngOnChanges() { }
ngOnDestroy() {
this._destroyOverlay();
this.close();
this._inputStateChanges.unsubscribe();
this._disabledChange.complete();
}
/** Selects the given color. */
select(nextVal) {
const oldValue = this.selected;
this.selected = nextVal;
// TODO: `nextVal` should compare with `oldValue`
this._selectedChanged.next(nextVal);
}
/**
* Register an input with this colorpicker.
* @param input The colorpicker input to register with this colorpicker.
*/
registerInput(input) {
if (this.pickerInput) {
throw Error('A Colorpicker can only be associated with a single input.');
}
this.pickerInput = input;
this._inputStateChanges = input._valueChange.subscribe((value) => (this.selected = value));
}
/** Open the panel. */
open() {
if (this._opened || this.disabled) {
return;
}
if (!this.pickerInput) {
throw Error('Attempted to open an Colorpicker with no associated input.');
}
if (this._document) {
this._focusedElementBeforeOpen = this._document.activeElement;
}
this._openOverlay();
this._opened = true;
this.openedStream.emit();
}
/** Close the panel. */
close() {
if (!this._opened) {
return;
}
if (this._componentRef) {
const { instance } = this._componentRef;
instance._animationDone.pipe(take(1)).subscribe(() => this._destroyOverlay());
instance._startExitAnimation();
}
const completeClose = () => {
// The `_opened` could've been reset already if
// we got two events in quick succession.
if (this._opened) {
this._opened = false;
this.closedStream.emit();
this._focusedElementBeforeOpen = null;
}
};
if (this.restoreFocus &&
this._focusedElementBeforeOpen &&
typeof this._focusedElementBeforeOpen.focus === 'function') {
// Because IE moves focus asynchronously, we can't count on it being restored before we've
// marked the colorpicker as closed. If the event fires out of sequence and the element that
// we're refocusing opens the colorpicker on focus, the user could be stuck with not being
// able to close the panel at all. We work around it by making the logic, that marks
// the colorpicker as closed, async as well.
this._focusedElementBeforeOpen.focus();
setTimeout(completeClose);
}
else {
completeClose();
}
}
/** Forwards relevant values from the colorpicker to the colorpicker content inside the overlay. */
_forwardContentValues(instance) {
instance.picker = this;
instance.color = this.color;
}
/** Open the colopicker as a popup. */
_openOverlay() {
this._destroyOverlay();
const labelId = this.pickerInput.getOverlayLabelId();
const portal = new ComponentPortal(MtxColorpickerContent, this._viewContainerRef);
const overlayRef = (this._overlayRef = this._overlay.create(new OverlayConfig({
positionStrategy: this._getDropdownStrategy(),
hasBackdrop: true,
backdropClass: ['mat-overlay-transparent-backdrop', this._backdropHarnessClass],
direction: this._dir || undefined,
scrollStrategy: this._scrollStrategy(),
panelClass: `mtx-colorpicker-popup`,
})));
const overlayElement = overlayRef.overlayElement;
overlayElement.setAttribute('role', 'dialog');
if (labelId) {
overlayElement.setAttribute('aria-labelledby', labelId);
}
this._getCloseStream(overlayRef).subscribe(event => {
if (event) {
event.preventDefault();
}
this.close();
});
this._componentRef = overlayRef.attach(portal);
this._forwardContentValues(this._componentRef.instance);
// Update the position once the panel has rendered. Only relevant in dropdown mode.
afterNextRender(() => {
overlayRef.updatePosition();
}, { injector: this._injector });
}
/** Destroys the current overlay. */
_destroyOverlay() {
if (this._overlayRef) {
this._overlayRef.dispose();
this._overlayRef = this._componentRef = null;
}
}
/** Gets a position strategy that will open the panel as a dropdown. */
_getDropdownStrategy() {
const strategy = this._overlay
.position()
.flexibleConnectedTo(this.pickerInput.getConnectedOverlayOrigin())
.withTransformOriginOn('.mtx-colorpicker-content')
.withFlexibleDimensions(false)
.withViewportMargin(8)
.withLockedPosition();
return this._setConnectedPositions(strategy);
}
/** Sets the positions of the colorpicker in dropdown mode based on the current configuration. */
_setConnectedPositions(strategy) {
const primaryX = this.xPosition === 'end' ? 'end' : 'start';
const secondaryX = primaryX === 'start' ? 'end' : 'start';
const primaryY = this.yPosition === 'above' ? 'bottom' : 'top';
const secondaryY = primaryY === 'top' ? 'bottom' : 'top';
return strategy.withPositions([
{
originX: primaryX,
originY: secondaryY,
overlayX: primaryX,
overlayY: primaryY,
},
{
originX: primaryX,
originY: primaryY,
overlayX: primaryX,
overlayY: secondaryY,
},
{
originX: secondaryX,
originY: secondaryY,
overlayX: secondaryX,
overlayY: primaryY,
},
{
originX: secondaryX,
originY: primaryY,
overlayX: secondaryX,
overlayY: secondaryY,
},
]);
}
/** Gets an observable that will emit when the overlay is supposed to be closed. */
_getCloseStream(overlayRef) {
return merge(overlayRef.backdropClick(), overlayRef.detachments(), overlayRef.keydownEvents().pipe(filter(event => {
// Closing on alt + up is only valid when there's an input associated with the colorpicker.
return ((event.keyCode === ESCAPE && !hasModifierKey(event)) ||
(this.pickerInput && hasModifierKey(event, 'altKey') && event.keyCode === UP_ARROW));
})));
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpicker, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.2.5", type: MtxColorpicker, isStandalone: true, selector: "mtx-colorpicker", inputs: { content: "content", disabled: ["disabled", "disabled", booleanAttribute], xPosition: "xPosition", yPosition: "yPosition", restoreFocus: ["restoreFocus", "restoreFocus", booleanAttribute], opened: ["opened", "opened", booleanAttribute], color: "color", format: "format" }, outputs: { openedStream: "opened", closedStream: "closed" }, exportAs: ["mtxColorpicker"], usesOnChanges: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpicker, decorators: [{
type: Component,
args: [{
selector: 'mtx-colorpicker',
template: '',
exportAs: 'mtxColorpicker',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
}]
}], propDecorators: { content: [{
type: Input
}], openedStream: [{
type: Output,
args: ['opened']
}], closedStream: [{
type: Output,
args: ['closed']
}], disabled: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], xPosition: [{
type: Input
}], yPosition: [{
type: Input
}], restoreFocus: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], opened: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], color: [{
type: Input
}], format: [{
type: Input
}] } });
class MtxColorPickerInputEvent {
constructor(
/** Reference to the colorpicker input component that emitted the event. */
target,
/** Reference to the native input element associated with the colorpicker input. */
targetElement) {
this.target = target;
this.targetElement = targetElement;
this.value = this.target.value;
}
}
const MTX_COLORPICKER_VALUE_ACCESSOR = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MtxColorpickerInput),
multi: true,
};
const MTX_COLORPICKER_VALIDATORS = {
provide: NG_VALIDATORS,
useExisting: forwardRef(() => MtxColorpickerInput),
multi: true,
};
class MtxColorpickerInput {
constructor() {
this._elementRef = inject(ElementRef);
this._formField = inject(MatFormField, { optional: true });
/** Emits when a `change` event is fired on this `<input>`. */
this.colorChange = new EventEmitter();
/** Emits when an `input` event is fired on this `<input>`. */
this.colorInput = new EventEmitter();
/** Emits when the disabled state has changed */
this._disabledChange = new EventEmitter();
/** Emits when the value changes (either due to user input or programmatic change). */
this._valueChange = new EventEmitter();
this._onTouched = () => { };
this._validatorOnChange = () => { };
this._cvaOnChange = () => { };
this._pickerSubscription = Subscription.EMPTY;
/** The combined form control validator for this input. */
this._validator = Validators.compose([]);
/** Whether the last value set on the input was valid. */
this._lastValueValid = false;
}
set mtxColorpicker(value) {
if (!value) {
return;
}
this._picker = value;
this._picker.registerInput(this);
this._pickerSubscription.unsubscribe();
this._pickerSubscription = this._picker._selectedChanged.subscribe((selected) => {
this.value = selected;
this._cvaOnChange(selected);
this._onTouched();
this.colorInput.emit(new MtxColorPickerInputEvent(this, this._elementRef.nativeElement));
this.colorChange.emit(new MtxColorPickerInputEvent(this, this._elementRef.nativeElement));
});
}
/** Whether the colorpicker-input is disabled. */
get disabled() {
return !!this._disabled;
}
set disabled(value) {
const element = this._elementRef.nativeElement;
if (this._disabled !== value) {
this._disabled = value;
this._disabledChange.emit(value);
}
// We need to null check the `blur` method, because it's undefined during SSR.
// In Ivy static bindings are invoked earlier, before the element is attached to the DOM.
// This can cause an error to be thrown in some browsers (IE/Edge) which assert that the
// element has been inserted.
if (value && this._isInitialized && element.blur) {
// Normally, native input elements automatically blur if they turn disabled. This behavior
// is problematic, because it would mean that it triggers another change detection cycle,
// which then causes a changed after checked error if the input element was focused before.
element.blur();
}
}
/** The value of the input. */
get value() {
return this._value;
}
set value(value) {
const oldValue = this.value;
this._value = value;
this._formatValue(value);
this._valueChange.emit(value);
}
ngAfterViewInit() {
this._isInitialized = true;
}
ngOnDestroy() {
this._pickerSubscription.unsubscribe();
this._valueChange.complete();
this._disabledChange.complete();
}
registerOnValidatorChange(fn) {
this._validatorOnChange = fn;
}
/** @docs-private */
validate(c) {
return this._validator ? this._validator(c) : null;
}
/**
* @deprecated
* @breaking-change 8.0.0 Use `getConnectedOverlayOrigin` instead
*/
getPopupConnectionElementRef() {
return this.getConnectedOverlayOrigin();
}
/**
* Gets the element that the colorpicker popup should be connected to.
* @return The element to connect the popup to.
*/
getConnectedOverlayOrigin() {
return this._formField ? this._formField.getConnectedOverlayOrigin() : this._elementRef;
}
/** Gets the ID of an element that should be used a description for the overlay. */
getOverlayLabelId() {
if (this._formField) {
return this._formField.getLabelId();
}
return this._elementRef.nativeElement.getAttribute('aria-labelledby');
}
// Implemented as part of ControlValueAccessor.
writeValue(value) {
this.value = value;
}
// Implemented as part of ControlValueAccessor.
registerOnChange(fn) {
this._cvaOnChange = fn;
}
// Implemented as part of ControlValueAccessor.
registerOnTouched(fn) {
this._onTouched = fn;
}
// Implemented as part of ControlValueAccessor.
setDisabledState(isDisabled) {
this.disabled = isDisabled;
}
_onKeydown(event) {
const isAltDownArrow = event.altKey && event.keyCode === DOWN_ARROW;
if (this._picker && isAltDownArrow && !this._elementRef.nativeElement.readOnly) {
this._picker.open();
event.preventDefault();
}
}
/** Handles blur events on the input. */
_onBlur() {
// Reformat the input only if we have a valid value.
if (this.value) {
this._formatValue(this.value);
}
this._onTouched();
}
_onInput(event) {
const value = event.target.value;
const nextValue = value;
this._value = nextValue;
this._cvaOnChange(nextValue);
this._valueChange.emit(nextValue);
this.colorInput.emit(new MtxColorPickerInputEvent(this, this._elementRef.nativeElement));
}
_onChange() {
this.colorChange.emit(new MtxColorPickerInputEvent(this, this._elementRef.nativeElement));
}
/** Returns the palette used by the input's form field, if any. */
getThemePalette() {
return this._formField ? this._formField.color : undefined;
}
/** TODO: Formats a value and sets it on the input element. */
_formatValue(value) {
this._elementRef.nativeElement.value = value ? value : '';
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerInput, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.5", type: MtxColorpickerInput, isStandalone: true, selector: "input[mtxColorpicker]", inputs: { mtxColorpicker: "mtxColorpicker", disabled: ["disabled", "disabled", booleanAttribute], value: "value", format: "format" }, outputs: { colorChange: "colorChange", colorInput: "colorInput" }, host: { listeners: { "input": "_onInput($event)", "change": "_onChange()", "blur": "_onBlur()", "keydown": "_onKeydown($event)" }, properties: { "attr.aria-haspopup": "_picker ? \"dialog\" : null", "attr.aria-owns": "(_picker?.opened && _picker.id) || null", "disabled": "disabled" }, classAttribute: "mtx-colorpicker-input" }, providers: [
MTX_COLORPICKER_VALUE_ACCESSOR,
MTX_COLORPICKER_VALIDATORS,
{ provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: MtxColorpickerInput },
], exportAs: ["mtxColorpickerInput"], ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerInput, decorators: [{
type: Directive,
args: [{
selector: 'input[mtxColorpicker]',
providers: [
MTX_COLORPICKER_VALUE_ACCESSOR,
MTX_COLORPICKER_VALIDATORS,
{ provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: MtxColorpickerInput },
],
host: {
'class': 'mtx-colorpicker-input',
'[attr.aria-haspopup]': '_picker ? "dialog" : null',
'[attr.aria-owns]': '(_picker?.opened && _picker.id) || null',
'[disabled]': 'disabled',
'(input)': '_onInput($event)',
'(change)': '_onChange()',
'(blur)': '_onBlur()',
'(keydown)': '_onKeydown($event)',
},
exportAs: 'mtxColorpickerInput',
}]
}], propDecorators: { mtxColorpicker: [{
type: Input
}], disabled: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], value: [{
type: Input
}], format: [{
type: Input
}], colorChange: [{
type: Output
}], colorInput: [{
type: Output
}] } });
/** Can be used to override the icon of a `mtxColorpickerToggle`. */
class MtxColorpickerToggleIcon {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerToggleIcon, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
/** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.5", type: MtxColorpickerToggleIcon, isStandalone: true, selector: "[mtxColorpickerToggleIcon]", ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerToggleIcon, decorators: [{
type: Directive,
args: [{
selector: '[mtxColorpickerToggleIcon]',
}]
}] });
class MtxColorpickerToggle {
/** Whether the toggle button is disabled. */
get disabled() {
if (this._disabled == null && this.picker) {
return this.picker.disabled;
}
return !!this._disabled;
}
set disabled(value) {
this._disabled = value;
}
constructor() {
this._changeDetectorRef = inject(ChangeDetectorRef);
this._stateChanges = Subscription.EMPTY;
const defaultTabIndex = inject(new HostAttributeToken('tabindex'), { optional: true });
const parsedTabIndex = Number(defaultTabIndex);
this.tabIndex = parsedTabIndex || parsedTabIndex === 0 ? parsedTabIndex : null;
}
ngOnChanges(changes) {
if (changes.picker) {
this._watchStateChanges();
}
}
ngOnDestroy() {
this._stateChanges.unsubscribe();
}
ngAfterContentInit() {
this._watchStateChanges();
}
_open(event) {
if (this.picker && !this.disabled) {
this.picker.open();
event.stopPropagation();
}
}
_watchStateChanges() {
const pickerDisabled = this.picker ? this.picker._disabledChange : of();
const inputDisabled = this.picker && this.picker.pickerInput
? this.picker.pickerInput._disabledChange
: of();
const pickerToggled = this.picker
? merge(this.picker.openedStream, this.picker.closedStream)
: of();
this._stateChanges.unsubscribe();
this._stateChanges = merge(pickerDisabled, inputDisabled, pickerToggled).subscribe(() => this._changeDetectorRef.markForCheck());
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerToggle, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.5", type: MtxColorpickerToggle, isStandalone: true, selector: "mtx-colorpicker-toggle", inputs: { picker: ["for", "picker"], tabIndex: "tabIndex", ariaLabel: ["aria-label", "ariaLabel"], disabled: ["disabled", "disabled", booleanAttribute], disableRipple: ["disableRipple", "disableRipple", booleanAttribute] }, host: { listeners: { "click": "_open($event)" }, properties: { "attr.tabindex": "null", "class.mtx-colorpicker-toggle-active": "picker && picker.opened", "class.mat-accent": "picker && picker.color === \"accent\"", "class.mat-warn": "picker && picker.color === \"warn\"" }, classAttribute: "mtx-colorpicker-toggle" }, queries: [{ propertyName: "_customIcon", first: true, predicate: MtxColorpickerToggleIcon, descendants: true }], viewQueries: [{ propertyName: "_button", first: true, predicate: ["button"], descendants: true }], exportAs: ["mtxColorpickerToggle"], usesOnChanges: true, ngImport: i0, template: "<button\n #button\n matIconButton\n type=\"button\"\n [attr.aria-haspopup]=\"picker ? 'dialog' : null\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\n [disabled]=\"disabled\"\n [disableRipple]=\"disableRipple\"\n>\n @if (!_customIcon) {\n <svg\n class=\"mtx-colorpicker-toggle-default-icon\"\n viewBox=\"0 0 24 24\"\n width=\"24px\"\n height=\"24px\"\n fill=\"currentColor\"\n focusable=\"false\"\n >\n <path\n d=\"M17.5,12A1.5,1.5 0 0,1 16,10.5A1.5,1.5 0 0,1 17.5,9A1.5,1.5 0 0,1 19,10.5A1.5,1.5 0 0,1 17.5,12M14.5,8A1.5,1.5 0 0,1 13,6.5A1.5,1.5 0 0,1 14.5,5A1.5,1.5 0 0,1 16,6.5A1.5,1.5 0 0,1 14.5,8M9.5,8A1.5,1.5 0 0,1 8,6.5A1.5,1.5 0 0,1 9.5,5A1.5,1.5 0 0,1 11,6.5A1.5,1.5 0 0,1 9.5,8M6.5,12A1.5,1.5 0 0,1 5,10.5A1.5,1.5 0 0,1 6.5,9A1.5,1.5 0 0,1 8,10.5A1.5,1.5 0 0,1 6.5,12M12,3A9,9 0 0,0 3,12A9,9 0 0,0 12,21A1.5,1.5 0 0,0 13.5,19.5C13.5,19.11 13.35,18.76 13.11,18.5C12.88,18.23 12.73,17.88 12.73,17.5A1.5,1.5 0 0,1 14.23,16H16A5,5 0 0,0 21,11C21,6.58 16.97,3 12,3Z\"\n />\n </svg>\n }\n\n <ng-content select=\"[mtxColorpickerToggleIcon]\"></ng-content>\n</button>\n", styles: [".mtx-colorpicker-toggle{pointer-events:auto;color:var(--mtx-colorpicker-toggle-icon-color, var(--mat-sys-on-surface-variant))}.mtx-colorpicker-toggle-active{color:var(--mtx-colorpicker-toggle-active-state-icon-color, var(--mat-sys-on-surface-variant))}@media(forced-colors:active){.mtx-colorpicker-toggle-default-icon{color:CanvasText}}\n"], dependencies: [{ kind: "component", type: MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerToggle, decorators: [{
type: Component,
args: [{ selector: 'mtx-colorpicker-toggle', host: {
'class': 'mtx-colorpicker-toggle',
'[attr.tabindex]': 'null',
'[class.mtx-colorpicker-toggle-active]': 'picker && picker.opened',
'[class.mat-accent]': 'picker && picker.color === "accent"',
'[class.mat-warn]': 'picker && picker.color === "warn"',
// Bind the `click` on the host, rather than the inner `button`, so that we can call
// `stopPropagation` on it without affecting the user's `click` handlers. We need to stop
// it so that the input doesn't get focused automatically by the form field (See #21836).
'(click)': '_open($event)',
}, exportAs: 'mtxColorpickerToggle', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatIconButton], template: "<button\n #button\n matIconButton\n type=\"button\"\n [attr.aria-haspopup]=\"picker ? 'dialog' : null\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.tabindex]=\"disabled ? -1 : tabIndex\"\n [disabled]=\"disabled\"\n [disableRipple]=\"disableRipple\"\n>\n @if (!_customIcon) {\n <svg\n class=\"mtx-colorpicker-toggle-default-icon\"\n viewBox=\"0 0 24 24\"\n width=\"24px\"\n height=\"24px\"\n fill=\"currentColor\"\n focusable=\"false\"\n >\n <path\n d=\"M17.5,12A1.5,1.5 0 0,1 16,10.5A1.5,1.5 0 0,1 17.5,9A1.5,1.5 0 0,1 19,10.5A1.5,1.5 0 0,1 17.5,12M14.5,8A1.5,1.5 0 0,1 13,6.5A1.5,1.5 0 0,1 14.5,5A1.5,1.5 0 0,1 16,6.5A1.5,1.5 0 0,1 14.5,8M9.5,8A1.5,1.5 0 0,1 8,6.5A1.5,1.5 0 0,1 9.5,5A1.5,1.5 0 0,1 11,6.5A1.5,1.5 0 0,1 9.5,8M6.5,12A1.5,1.5 0 0,1 5,10.5A1.5,1.5 0 0,1 6.5,9A1.5,1.5 0 0,1 8,10.5A1.5,1.5 0 0,1 6.5,12M12,3A9,9 0 0,0 3,12A9,9 0 0,0 12,21A1.5,1.5 0 0,0 13.5,19.5C13.5,19.11 13.35,18.76 13.11,18.5C12.88,18.23 12.73,17.88 12.73,17.5A1.5,1.5 0 0,1 14.23,16H16A5,5 0 0,0 21,11C21,6.58 16.97,3 12,3Z\"\n />\n </svg>\n }\n\n <ng-content select=\"[mtxColorpickerToggleIcon]\"></ng-content>\n</button>\n", styles: [".mtx-colorpicker-toggle{pointer-events:auto;color:var(--mtx-colorpicker-toggle-icon-color, var(--mat-sys-on-surface-variant))}.mtx-colorpicker-toggle-active{color:var(--mtx-colorpicker-toggle-active-state-icon-color, var(--mat-sys-on-surface-variant))}@media(forced-colors:active){.mtx-colorpicker-toggle-default-icon{color:CanvasText}}\n"] }]
}], ctorParameters: () => [], propDecorators: { picker: [{
type: Input,
args: ['for']
}], tabIndex: [{
type: Input
}], ariaLabel: [{
type: Input,
args: ['aria-label']
}], disabled: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], disableRipple: [{
type: Input,
args: [{ transform: booleanAttribute }]
}], _customIcon: [{
type: ContentChild,
args: [MtxColorpickerToggleIcon]
}], _button: [{
type: ViewChild,
args: ['button']
}] } });
class MtxColorpickerModule {
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
/** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerModule, imports: [CommonModule,
OverlayModule,
A11yModule,
PortalModule,
MatButtonModule,
MtxColorpicker,
MtxColorpickerContent,
MtxColorpickerInput,
MtxColorpickerToggle,
MtxColorpickerToggleIcon,
ColorPicker], exports: [MtxColorpicker,
MtxColorpickerContent,
MtxColorpickerInput,
MtxColorpickerToggle,
MtxColorpickerToggleIcon] }); }
/** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerModule, imports: [CommonModule,
OverlayModule,
A11yModule,
PortalModule,
MatButtonModule,
MtxColorpickerContent,
MtxColorpickerToggle,
ColorPicker] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.5", ngImport: i0, type: MtxColorpickerModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule,
OverlayModule,
A11yModule,
PortalModule,
MatButtonModule,
MtxColorpicker,
MtxColorpickerContent,
MtxColorpickerInput,
MtxColorpickerToggle,
MtxColorpickerToggleIcon,
ColorPicker,
],
exports: [
MtxColorpicker,
MtxColorpickerContent,
MtxColorpickerInput,
MtxColorpickerToggle,
MtxColorpickerToggleIcon,
],
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { MTX_COLORPICKER_SCROLL_STRATEGY, MTX_COLORPICKER_VALIDATORS, MTX_COLORPICKER_VALUE_ACCESSOR, MtxColorPickerInputEvent, MtxColorpicker, MtxColorpickerContent, MtxColorpickerInput, MtxColorpickerModule, MtxColorpickerToggle, MtxColorpickerToggleIcon };
//# sourceMappingURL=mtxColorpicker.mjs.map