@angular/cdk
Version:
Angular Material Component Development Kit
504 lines (498 loc) • 15.8 kB
JavaScript
import * as i0 from '@angular/core';
import { Component, ChangeDetectionStrategy, ViewEncapsulation, inject, NgZone, RendererFactory2, Injectable, ElementRef, EventEmitter, Directive, Output, Renderer2, DOCUMENT, booleanAttribute, Input, NgModule } from '@angular/core';
import { EMPTY, Subject } from 'rxjs';
import { Platform } from './_platform-chunk.mjs';
import { _CdkPrivateStyleLoader } from './_style-loader-chunk.mjs';
import { coerceElement, coerceNumberProperty } from './_element-chunk.mjs';
import { auditTime } from 'rxjs/operators';
import '@angular/common';
class _CdkTextFieldStyleLoader {
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: _CdkTextFieldStyleLoader,
deps: [],
target: i0.ɵɵFactoryTarget.Component
});
static ɵcmp = i0.ɵɵngDeclareComponent({
minVersion: "14.0.0",
version: "21.0.0",
type: _CdkTextFieldStyleLoader,
isStandalone: true,
selector: "ng-component",
host: {
attributes: {
"cdk-text-field-style-loader": ""
}
},
ngImport: i0,
template: '',
isInline: true,
styles: ["textarea.cdk-textarea-autosize{resize:none}textarea.cdk-textarea-autosize-measuring{padding:2px 0 !important;box-sizing:content-box !important;height:auto !important;overflow:hidden !important}textarea.cdk-textarea-autosize-measuring-firefox{padding:2px 0 !important;box-sizing:content-box !important;height:0 !important}@keyframes cdk-text-field-autofill-start{/*!*/}@keyframes cdk-text-field-autofill-end{/*!*/}.cdk-text-field-autofill-monitored:-webkit-autofill{animation:cdk-text-field-autofill-start 0s 1ms}.cdk-text-field-autofill-monitored:not(:-webkit-autofill){animation:cdk-text-field-autofill-end 0s 1ms}\n"],
changeDetection: i0.ChangeDetectionStrategy.OnPush,
encapsulation: i0.ViewEncapsulation.None
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: _CdkTextFieldStyleLoader,
decorators: [{
type: Component,
args: [{
template: '',
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
host: {
'cdk-text-field-style-loader': ''
},
styles: ["textarea.cdk-textarea-autosize{resize:none}textarea.cdk-textarea-autosize-measuring{padding:2px 0 !important;box-sizing:content-box !important;height:auto !important;overflow:hidden !important}textarea.cdk-textarea-autosize-measuring-firefox{padding:2px 0 !important;box-sizing:content-box !important;height:0 !important}@keyframes cdk-text-field-autofill-start{/*!*/}@keyframes cdk-text-field-autofill-end{/*!*/}.cdk-text-field-autofill-monitored:-webkit-autofill{animation:cdk-text-field-autofill-start 0s 1ms}.cdk-text-field-autofill-monitored:not(:-webkit-autofill){animation:cdk-text-field-autofill-end 0s 1ms}\n"]
}]
}]
});
const listenerOptions = {
passive: true
};
class AutofillMonitor {
_platform = inject(Platform);
_ngZone = inject(NgZone);
_renderer = inject(RendererFactory2).createRenderer(null, null);
_styleLoader = inject(_CdkPrivateStyleLoader);
_monitoredElements = new Map();
constructor() {}
monitor(elementOrRef) {
if (!this._platform.isBrowser) {
return EMPTY;
}
this._styleLoader.load(_CdkTextFieldStyleLoader);
const element = coerceElement(elementOrRef);
const info = this._monitoredElements.get(element);
if (info) {
return info.subject;
}
const subject = new Subject();
const cssClass = 'cdk-text-field-autofilled';
const listener = event => {
if (event.animationName === 'cdk-text-field-autofill-start' && !element.classList.contains(cssClass)) {
element.classList.add(cssClass);
this._ngZone.run(() => subject.next({
target: event.target,
isAutofilled: true
}));
} else if (event.animationName === 'cdk-text-field-autofill-end' && element.classList.contains(cssClass)) {
element.classList.remove(cssClass);
this._ngZone.run(() => subject.next({
target: event.target,
isAutofilled: false
}));
}
};
const unlisten = this._ngZone.runOutsideAngular(() => {
element.classList.add('cdk-text-field-autofill-monitored');
return this._renderer.listen(element, 'animationstart', listener, listenerOptions);
});
this._monitoredElements.set(element, {
subject,
unlisten
});
return subject;
}
stopMonitoring(elementOrRef) {
const element = coerceElement(elementOrRef);
const info = this._monitoredElements.get(element);
if (info) {
info.unlisten();
info.subject.complete();
element.classList.remove('cdk-text-field-autofill-monitored');
element.classList.remove('cdk-text-field-autofilled');
this._monitoredElements.delete(element);
}
}
ngOnDestroy() {
this._monitoredElements.forEach((_info, element) => this.stopMonitoring(element));
}
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: AutofillMonitor,
deps: [],
target: i0.ɵɵFactoryTarget.Injectable
});
static ɵprov = i0.ɵɵngDeclareInjectable({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: AutofillMonitor,
providedIn: 'root'
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: AutofillMonitor,
decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}],
ctorParameters: () => []
});
class CdkAutofill {
_elementRef = inject(ElementRef);
_autofillMonitor = inject(AutofillMonitor);
cdkAutofill = new EventEmitter();
constructor() {}
ngOnInit() {
this._autofillMonitor.monitor(this._elementRef).subscribe(event => this.cdkAutofill.emit(event));
}
ngOnDestroy() {
this._autofillMonitor.stopMonitoring(this._elementRef);
}
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: CdkAutofill,
deps: [],
target: i0.ɵɵFactoryTarget.Directive
});
static ɵdir = i0.ɵɵngDeclareDirective({
minVersion: "14.0.0",
version: "21.0.0",
type: CdkAutofill,
isStandalone: true,
selector: "[cdkAutofill]",
outputs: {
cdkAutofill: "cdkAutofill"
},
ngImport: i0
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: CdkAutofill,
decorators: [{
type: Directive,
args: [{
selector: '[cdkAutofill]'
}]
}],
ctorParameters: () => [],
propDecorators: {
cdkAutofill: [{
type: Output
}]
}
});
class CdkTextareaAutosize {
_elementRef = inject(ElementRef);
_platform = inject(Platform);
_ngZone = inject(NgZone);
_renderer = inject(Renderer2);
_resizeEvents = new Subject();
_previousValue;
_initialHeight;
_destroyed = new Subject();
_listenerCleanups;
_minRows;
_maxRows;
_enabled = true;
_previousMinRows = -1;
_textareaElement;
get minRows() {
return this._minRows;
}
set minRows(value) {
this._minRows = coerceNumberProperty(value);
this._setMinHeight();
}
get maxRows() {
return this._maxRows;
}
set maxRows(value) {
this._maxRows = coerceNumberProperty(value);
this._setMaxHeight();
}
get enabled() {
return this._enabled;
}
set enabled(value) {
if (this._enabled !== value) {
(this._enabled = value) ? this.resizeToFitContent(true) : this.reset();
}
}
get placeholder() {
return this._textareaElement.placeholder;
}
set placeholder(value) {
this._cachedPlaceholderHeight = undefined;
if (value) {
this._textareaElement.setAttribute('placeholder', value);
} else {
this._textareaElement.removeAttribute('placeholder');
}
this._cacheTextareaPlaceholderHeight();
}
_cachedLineHeight;
_cachedPlaceholderHeight;
_document = inject(DOCUMENT);
_hasFocus;
_isViewInited = false;
constructor() {
const styleLoader = inject(_CdkPrivateStyleLoader);
styleLoader.load(_CdkTextFieldStyleLoader);
this._textareaElement = this._elementRef.nativeElement;
}
_setMinHeight() {
const minHeight = this.minRows && this._cachedLineHeight ? `${this.minRows * this._cachedLineHeight}px` : null;
if (minHeight) {
this._textareaElement.style.minHeight = minHeight;
}
}
_setMaxHeight() {
const maxHeight = this.maxRows && this._cachedLineHeight ? `${this.maxRows * this._cachedLineHeight}px` : null;
if (maxHeight) {
this._textareaElement.style.maxHeight = maxHeight;
}
}
ngAfterViewInit() {
if (this._platform.isBrowser) {
this._initialHeight = this._textareaElement.style.height;
this.resizeToFitContent();
this._ngZone.runOutsideAngular(() => {
this._listenerCleanups = [this._renderer.listen('window', 'resize', () => this._resizeEvents.next()), this._renderer.listen(this._textareaElement, 'focus', this._handleFocusEvent), this._renderer.listen(this._textareaElement, 'blur', this._handleFocusEvent)];
this._resizeEvents.pipe(auditTime(16)).subscribe(() => {
this._cachedLineHeight = this._cachedPlaceholderHeight = undefined;
this.resizeToFitContent(true);
});
});
this._isViewInited = true;
this.resizeToFitContent(true);
}
}
ngOnDestroy() {
this._listenerCleanups?.forEach(cleanup => cleanup());
this._resizeEvents.complete();
this._destroyed.next();
this._destroyed.complete();
}
_cacheTextareaLineHeight() {
if (this._cachedLineHeight) {
return;
}
const textareaClone = this._textareaElement.cloneNode(false);
const cloneStyles = textareaClone.style;
textareaClone.rows = 1;
cloneStyles.position = 'absolute';
cloneStyles.visibility = 'hidden';
cloneStyles.border = 'none';
cloneStyles.padding = '0';
cloneStyles.height = '';
cloneStyles.minHeight = '';
cloneStyles.maxHeight = '';
cloneStyles.top = cloneStyles.bottom = cloneStyles.left = cloneStyles.right = 'auto';
cloneStyles.overflow = 'hidden';
this._textareaElement.parentNode.appendChild(textareaClone);
this._cachedLineHeight = textareaClone.clientHeight;
textareaClone.remove();
this._setMinHeight();
this._setMaxHeight();
}
_measureScrollHeight() {
const element = this._textareaElement;
const previousMargin = element.style.marginBottom || '';
const isFirefox = this._platform.FIREFOX;
const needsMarginFiller = isFirefox && this._hasFocus;
const measuringClass = isFirefox ? 'cdk-textarea-autosize-measuring-firefox' : 'cdk-textarea-autosize-measuring';
if (needsMarginFiller) {
element.style.marginBottom = `${element.clientHeight}px`;
}
element.classList.add(measuringClass);
const scrollHeight = element.scrollHeight - 4;
element.classList.remove(measuringClass);
if (needsMarginFiller) {
element.style.marginBottom = previousMargin;
}
return scrollHeight;
}
_cacheTextareaPlaceholderHeight() {
if (!this._isViewInited || this._cachedPlaceholderHeight != undefined) {
return;
}
if (!this.placeholder) {
this._cachedPlaceholderHeight = 0;
return;
}
const value = this._textareaElement.value;
this._textareaElement.value = this._textareaElement.placeholder;
this._cachedPlaceholderHeight = this._measureScrollHeight();
this._textareaElement.value = value;
}
_handleFocusEvent = event => {
this._hasFocus = event.type === 'focus';
};
ngDoCheck() {
if (this._platform.isBrowser) {
this.resizeToFitContent();
}
}
resizeToFitContent(force = false) {
if (!this._enabled) {
return;
}
this._cacheTextareaLineHeight();
this._cacheTextareaPlaceholderHeight();
if (!this._cachedLineHeight) {
return;
}
const textarea = this._elementRef.nativeElement;
const value = textarea.value;
if (!force && this._minRows === this._previousMinRows && value === this._previousValue) {
return;
}
const scrollHeight = this._measureScrollHeight();
const height = Math.max(scrollHeight, this._cachedPlaceholderHeight || 0);
textarea.style.height = `${height}px`;
this._ngZone.runOutsideAngular(() => {
if (typeof requestAnimationFrame !== 'undefined') {
requestAnimationFrame(() => this._scrollToCaretPosition(textarea));
} else {
setTimeout(() => this._scrollToCaretPosition(textarea));
}
});
this._previousValue = value;
this._previousMinRows = this._minRows;
}
reset() {
if (this._initialHeight !== undefined) {
this._textareaElement.style.height = this._initialHeight;
}
}
_noopInputHandler() {}
_scrollToCaretPosition(textarea) {
const {
selectionStart,
selectionEnd
} = textarea;
if (!this._destroyed.isStopped && this._hasFocus) {
textarea.setSelectionRange(selectionStart, selectionEnd);
}
}
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: CdkTextareaAutosize,
deps: [],
target: i0.ɵɵFactoryTarget.Directive
});
static ɵdir = i0.ɵɵngDeclareDirective({
minVersion: "16.1.0",
version: "21.0.0",
type: CdkTextareaAutosize,
isStandalone: true,
selector: "textarea[cdkTextareaAutosize]",
inputs: {
minRows: ["cdkAutosizeMinRows", "minRows"],
maxRows: ["cdkAutosizeMaxRows", "maxRows"],
enabled: ["cdkTextareaAutosize", "enabled", booleanAttribute],
placeholder: "placeholder"
},
host: {
attributes: {
"rows": "1"
},
listeners: {
"input": "_noopInputHandler()"
},
classAttribute: "cdk-textarea-autosize"
},
exportAs: ["cdkTextareaAutosize"],
ngImport: i0
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: CdkTextareaAutosize,
decorators: [{
type: Directive,
args: [{
selector: 'textarea[cdkTextareaAutosize]',
exportAs: 'cdkTextareaAutosize',
host: {
'class': 'cdk-textarea-autosize',
'rows': '1',
'(input)': '_noopInputHandler()'
}
}]
}],
ctorParameters: () => [],
propDecorators: {
minRows: [{
type: Input,
args: ['cdkAutosizeMinRows']
}],
maxRows: [{
type: Input,
args: ['cdkAutosizeMaxRows']
}],
enabled: [{
type: Input,
args: [{
alias: 'cdkTextareaAutosize',
transform: booleanAttribute
}]
}],
placeholder: [{
type: Input
}]
}
});
class TextFieldModule {
static ɵfac = i0.ɵɵngDeclareFactory({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: TextFieldModule,
deps: [],
target: i0.ɵɵFactoryTarget.NgModule
});
static ɵmod = i0.ɵɵngDeclareNgModule({
minVersion: "14.0.0",
version: "21.0.0",
ngImport: i0,
type: TextFieldModule,
imports: [CdkAutofill, CdkTextareaAutosize],
exports: [CdkAutofill, CdkTextareaAutosize]
});
static ɵinj = i0.ɵɵngDeclareInjector({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: TextFieldModule
});
}
i0.ɵɵngDeclareClassMetadata({
minVersion: "12.0.0",
version: "21.0.0",
ngImport: i0,
type: TextFieldModule,
decorators: [{
type: NgModule,
args: [{
imports: [CdkAutofill, CdkTextareaAutosize],
exports: [CdkAutofill, CdkTextareaAutosize]
}]
}]
});
export { AutofillMonitor, CdkAutofill, CdkTextareaAutosize, TextFieldModule };
//# sourceMappingURL=text-field.mjs.map