text-field.mjs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. import * as i0 from '@angular/core';
  2. import { Component, ChangeDetectionStrategy, ViewEncapsulation, inject, NgZone, RendererFactory2, Injectable, ElementRef, EventEmitter, Directive, Output, Renderer2, booleanAttribute, Input, NgModule } from '@angular/core';
  3. import { EMPTY, Subject } from 'rxjs';
  4. import { P as Platform } from './platform-DmdVEw_C.mjs';
  5. import { _ as _CdkPrivateStyleLoader } from './style-loader-Cu9AvjH9.mjs';
  6. import { _ as _bindEventWithOptions } from './backwards-compatibility-DHR38MsD.mjs';
  7. import { a as coerceElement, c as coerceNumberProperty } from './element-x4z00URv.mjs';
  8. import { DOCUMENT } from '@angular/common';
  9. import { auditTime } from 'rxjs/operators';
  10. /** Component used to load the structural styles of the text field. */
  11. class _CdkTextFieldStyleLoader {
  12. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: _CdkTextFieldStyleLoader, deps: [], target: i0.ɵɵFactoryTarget.Component });
  13. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", 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 });
  14. }
  15. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: _CdkTextFieldStyleLoader, decorators: [{
  16. type: Component,
  17. 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"] }]
  18. }] });
  19. /** Options to pass to the animationstart listener. */
  20. const listenerOptions = { passive: true };
  21. /**
  22. * An injectable service that can be used to monitor the autofill state of an input.
  23. * Based on the following blog post:
  24. * https://medium.com/@brunn/detecting-autofilled-fields-in-javascript-aed598d25da7
  25. */
  26. class AutofillMonitor {
  27. _platform = inject(Platform);
  28. _ngZone = inject(NgZone);
  29. _renderer = inject(RendererFactory2).createRenderer(null, null);
  30. _styleLoader = inject(_CdkPrivateStyleLoader);
  31. _monitoredElements = new Map();
  32. constructor() { }
  33. monitor(elementOrRef) {
  34. if (!this._platform.isBrowser) {
  35. return EMPTY;
  36. }
  37. this._styleLoader.load(_CdkTextFieldStyleLoader);
  38. const element = coerceElement(elementOrRef);
  39. const info = this._monitoredElements.get(element);
  40. if (info) {
  41. return info.subject;
  42. }
  43. const subject = new Subject();
  44. const cssClass = 'cdk-text-field-autofilled';
  45. const listener = (event) => {
  46. // Animation events fire on initial element render, we check for the presence of the autofill
  47. // CSS class to make sure this is a real change in state, not just the initial render before
  48. // we fire off events.
  49. if (event.animationName === 'cdk-text-field-autofill-start' &&
  50. !element.classList.contains(cssClass)) {
  51. element.classList.add(cssClass);
  52. this._ngZone.run(() => subject.next({ target: event.target, isAutofilled: true }));
  53. }
  54. else if (event.animationName === 'cdk-text-field-autofill-end' &&
  55. element.classList.contains(cssClass)) {
  56. element.classList.remove(cssClass);
  57. this._ngZone.run(() => subject.next({ target: event.target, isAutofilled: false }));
  58. }
  59. };
  60. const unlisten = this._ngZone.runOutsideAngular(() => {
  61. element.classList.add('cdk-text-field-autofill-monitored');
  62. return _bindEventWithOptions(this._renderer, element, 'animationstart', listener, listenerOptions);
  63. });
  64. this._monitoredElements.set(element, { subject, unlisten });
  65. return subject;
  66. }
  67. stopMonitoring(elementOrRef) {
  68. const element = coerceElement(elementOrRef);
  69. const info = this._monitoredElements.get(element);
  70. if (info) {
  71. info.unlisten();
  72. info.subject.complete();
  73. element.classList.remove('cdk-text-field-autofill-monitored');
  74. element.classList.remove('cdk-text-field-autofilled');
  75. this._monitoredElements.delete(element);
  76. }
  77. }
  78. ngOnDestroy() {
  79. this._monitoredElements.forEach((_info, element) => this.stopMonitoring(element));
  80. }
  81. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: AutofillMonitor, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
  82. static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: AutofillMonitor, providedIn: 'root' });
  83. }
  84. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: AutofillMonitor, decorators: [{
  85. type: Injectable,
  86. args: [{ providedIn: 'root' }]
  87. }], ctorParameters: () => [] });
  88. /** A directive that can be used to monitor the autofill state of an input. */
  89. class CdkAutofill {
  90. _elementRef = inject(ElementRef);
  91. _autofillMonitor = inject(AutofillMonitor);
  92. /** Emits when the autofill state of the element changes. */
  93. cdkAutofill = new EventEmitter();
  94. constructor() { }
  95. ngOnInit() {
  96. this._autofillMonitor
  97. .monitor(this._elementRef)
  98. .subscribe(event => this.cdkAutofill.emit(event));
  99. }
  100. ngOnDestroy() {
  101. this._autofillMonitor.stopMonitoring(this._elementRef);
  102. }
  103. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkAutofill, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  104. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: CdkAutofill, isStandalone: true, selector: "[cdkAutofill]", outputs: { cdkAutofill: "cdkAutofill" }, ngImport: i0 });
  105. }
  106. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkAutofill, decorators: [{
  107. type: Directive,
  108. args: [{
  109. selector: '[cdkAutofill]',
  110. }]
  111. }], ctorParameters: () => [], propDecorators: { cdkAutofill: [{
  112. type: Output
  113. }] } });
  114. /** Directive to automatically resize a textarea to fit its content. */
  115. class CdkTextareaAutosize {
  116. _elementRef = inject(ElementRef);
  117. _platform = inject(Platform);
  118. _ngZone = inject(NgZone);
  119. _renderer = inject(Renderer2);
  120. _resizeEvents = new Subject();
  121. /** Keep track of the previous textarea value to avoid resizing when the value hasn't changed. */
  122. _previousValue;
  123. _initialHeight;
  124. _destroyed = new Subject();
  125. _listenerCleanups;
  126. _minRows;
  127. _maxRows;
  128. _enabled = true;
  129. /**
  130. * Value of minRows as of last resize. If the minRows has decreased, the
  131. * height of the textarea needs to be recomputed to reflect the new minimum. The maxHeight
  132. * does not have the same problem because it does not affect the textarea's scrollHeight.
  133. */
  134. _previousMinRows = -1;
  135. _textareaElement;
  136. /** Minimum amount of rows in the textarea. */
  137. get minRows() {
  138. return this._minRows;
  139. }
  140. set minRows(value) {
  141. this._minRows = coerceNumberProperty(value);
  142. this._setMinHeight();
  143. }
  144. /** Maximum amount of rows in the textarea. */
  145. get maxRows() {
  146. return this._maxRows;
  147. }
  148. set maxRows(value) {
  149. this._maxRows = coerceNumberProperty(value);
  150. this._setMaxHeight();
  151. }
  152. /** Whether autosizing is enabled or not */
  153. get enabled() {
  154. return this._enabled;
  155. }
  156. set enabled(value) {
  157. // Only act if the actual value changed. This specifically helps to not run
  158. // resizeToFitContent too early (i.e. before ngAfterViewInit)
  159. if (this._enabled !== value) {
  160. (this._enabled = value) ? this.resizeToFitContent(true) : this.reset();
  161. }
  162. }
  163. get placeholder() {
  164. return this._textareaElement.placeholder;
  165. }
  166. set placeholder(value) {
  167. this._cachedPlaceholderHeight = undefined;
  168. if (value) {
  169. this._textareaElement.setAttribute('placeholder', value);
  170. }
  171. else {
  172. this._textareaElement.removeAttribute('placeholder');
  173. }
  174. this._cacheTextareaPlaceholderHeight();
  175. }
  176. /** Cached height of a textarea with a single row. */
  177. _cachedLineHeight;
  178. /** Cached height of a textarea with only the placeholder. */
  179. _cachedPlaceholderHeight;
  180. /** Cached scroll top of a textarea */
  181. _cachedScrollTop;
  182. /** Used to reference correct document/window */
  183. _document = inject(DOCUMENT, { optional: true });
  184. _hasFocus;
  185. _isViewInited = false;
  186. constructor() {
  187. const styleLoader = inject(_CdkPrivateStyleLoader);
  188. styleLoader.load(_CdkTextFieldStyleLoader);
  189. this._textareaElement = this._elementRef.nativeElement;
  190. }
  191. /** Sets the minimum height of the textarea as determined by minRows. */
  192. _setMinHeight() {
  193. const minHeight = this.minRows && this._cachedLineHeight ? `${this.minRows * this._cachedLineHeight}px` : null;
  194. if (minHeight) {
  195. this._textareaElement.style.minHeight = minHeight;
  196. }
  197. }
  198. /** Sets the maximum height of the textarea as determined by maxRows. */
  199. _setMaxHeight() {
  200. const maxHeight = this.maxRows && this._cachedLineHeight ? `${this.maxRows * this._cachedLineHeight}px` : null;
  201. if (maxHeight) {
  202. this._textareaElement.style.maxHeight = maxHeight;
  203. }
  204. }
  205. ngAfterViewInit() {
  206. if (this._platform.isBrowser) {
  207. // Remember the height which we started with in case autosizing is disabled
  208. this._initialHeight = this._textareaElement.style.height;
  209. this.resizeToFitContent();
  210. this._ngZone.runOutsideAngular(() => {
  211. this._listenerCleanups = [
  212. this._renderer.listen('window', 'resize', () => this._resizeEvents.next()),
  213. this._renderer.listen(this._textareaElement, 'focus', this._handleFocusEvent),
  214. this._renderer.listen(this._textareaElement, 'blur', this._handleFocusEvent),
  215. ];
  216. this._resizeEvents.pipe(auditTime(16)).subscribe(() => {
  217. // Clear the cached heights since the styles can change
  218. // when the window is resized (e.g. by media queries).
  219. this._cachedLineHeight = this._cachedPlaceholderHeight = undefined;
  220. this.resizeToFitContent(true);
  221. });
  222. });
  223. this._isViewInited = true;
  224. this.resizeToFitContent(true);
  225. }
  226. }
  227. ngOnDestroy() {
  228. this._listenerCleanups?.forEach(cleanup => cleanup());
  229. this._resizeEvents.complete();
  230. this._destroyed.next();
  231. this._destroyed.complete();
  232. }
  233. /**
  234. * Cache the height of a single-row textarea if it has not already been cached.
  235. *
  236. * We need to know how large a single "row" of a textarea is in order to apply minRows and
  237. * maxRows. For the initial version, we will assume that the height of a single line in the
  238. * textarea does not ever change.
  239. */
  240. _cacheTextareaLineHeight() {
  241. if (this._cachedLineHeight) {
  242. return;
  243. }
  244. // Use a clone element because we have to override some styles.
  245. const textareaClone = this._textareaElement.cloneNode(false);
  246. const cloneStyles = textareaClone.style;
  247. textareaClone.rows = 1;
  248. // Use `position: absolute` so that this doesn't cause a browser layout and use
  249. // `visibility: hidden` so that nothing is rendered. Clear any other styles that
  250. // would affect the height.
  251. cloneStyles.position = 'absolute';
  252. cloneStyles.visibility = 'hidden';
  253. cloneStyles.border = 'none';
  254. cloneStyles.padding = '0';
  255. cloneStyles.height = '';
  256. cloneStyles.minHeight = '';
  257. cloneStyles.maxHeight = '';
  258. // App styles might be messing with the height through the positioning properties.
  259. cloneStyles.top = cloneStyles.bottom = cloneStyles.left = cloneStyles.right = 'auto';
  260. // In Firefox it happens that textarea elements are always bigger than the specified amount
  261. // of rows. This is because Firefox tries to add extra space for the horizontal scrollbar.
  262. // As a workaround that removes the extra space for the scrollbar, we can just set overflow
  263. // to hidden. This ensures that there is no invalid calculation of the line height.
  264. // See Firefox bug report: https://bugzilla.mozilla.org/show_bug.cgi?id=33654
  265. cloneStyles.overflow = 'hidden';
  266. this._textareaElement.parentNode.appendChild(textareaClone);
  267. this._cachedLineHeight = textareaClone.clientHeight;
  268. textareaClone.remove();
  269. // Min and max heights have to be re-calculated if the cached line height changes
  270. this._setMinHeight();
  271. this._setMaxHeight();
  272. }
  273. _measureScrollHeight() {
  274. const element = this._textareaElement;
  275. const previousMargin = element.style.marginBottom || '';
  276. const isFirefox = this._platform.FIREFOX;
  277. const needsMarginFiller = isFirefox && this._hasFocus;
  278. const measuringClass = isFirefox
  279. ? 'cdk-textarea-autosize-measuring-firefox'
  280. : 'cdk-textarea-autosize-measuring';
  281. // In some cases the page might move around while we're measuring the `textarea` on Firefox. We
  282. // work around it by assigning a temporary margin with the same height as the `textarea` so that
  283. // it occupies the same amount of space. See #23233.
  284. if (needsMarginFiller) {
  285. element.style.marginBottom = `${element.clientHeight}px`;
  286. }
  287. // Reset the textarea height to auto in order to shrink back to its default size.
  288. // Also temporarily force overflow:hidden, so scroll bars do not interfere with calculations.
  289. element.classList.add(measuringClass);
  290. // The measuring class includes a 2px padding to workaround an issue with Chrome,
  291. // so we account for that extra space here by subtracting 4 (2px top + 2px bottom).
  292. const scrollHeight = element.scrollHeight - 4;
  293. element.classList.remove(measuringClass);
  294. if (needsMarginFiller) {
  295. element.style.marginBottom = previousMargin;
  296. }
  297. return scrollHeight;
  298. }
  299. _cacheTextareaPlaceholderHeight() {
  300. if (!this._isViewInited || this._cachedPlaceholderHeight != undefined) {
  301. return;
  302. }
  303. if (!this.placeholder) {
  304. this._cachedPlaceholderHeight = 0;
  305. return;
  306. }
  307. const value = this._textareaElement.value;
  308. this._textareaElement.value = this._textareaElement.placeholder;
  309. this._cachedPlaceholderHeight = this._measureScrollHeight();
  310. this._textareaElement.value = value;
  311. }
  312. /** Handles `focus` and `blur` events. */
  313. _handleFocusEvent = (event) => {
  314. this._hasFocus = event.type === 'focus';
  315. };
  316. ngDoCheck() {
  317. if (this._platform.isBrowser) {
  318. this.resizeToFitContent();
  319. }
  320. }
  321. /**
  322. * Resize the textarea to fit its content.
  323. * @param force Whether to force a height recalculation. By default the height will be
  324. * recalculated only if the value changed since the last call.
  325. */
  326. resizeToFitContent(force = false) {
  327. // If autosizing is disabled, just skip everything else
  328. if (!this._enabled) {
  329. return;
  330. }
  331. this._cacheTextareaLineHeight();
  332. this._cacheTextareaPlaceholderHeight();
  333. this._cachedScrollTop = this._textareaElement.scrollTop;
  334. // If we haven't determined the line-height yet, we know we're still hidden and there's no point
  335. // in checking the height of the textarea.
  336. if (!this._cachedLineHeight) {
  337. return;
  338. }
  339. const textarea = this._elementRef.nativeElement;
  340. const value = textarea.value;
  341. // Only resize if the value or minRows have changed since these calculations can be expensive.
  342. if (!force && this._minRows === this._previousMinRows && value === this._previousValue) {
  343. return;
  344. }
  345. const scrollHeight = this._measureScrollHeight();
  346. const height = Math.max(scrollHeight, this._cachedPlaceholderHeight || 0);
  347. // Use the scrollHeight to know how large the textarea *would* be if fit its entire value.
  348. textarea.style.height = `${height}px`;
  349. this._ngZone.runOutsideAngular(() => {
  350. if (typeof requestAnimationFrame !== 'undefined') {
  351. requestAnimationFrame(() => this._scrollToCaretPosition(textarea));
  352. }
  353. else {
  354. setTimeout(() => this._scrollToCaretPosition(textarea));
  355. }
  356. });
  357. this._previousValue = value;
  358. this._previousMinRows = this._minRows;
  359. }
  360. /**
  361. * Resets the textarea to its original size
  362. */
  363. reset() {
  364. // Do not try to change the textarea, if the initialHeight has not been determined yet
  365. // This might potentially remove styles when reset() is called before ngAfterViewInit
  366. if (this._initialHeight !== undefined) {
  367. this._textareaElement.style.height = this._initialHeight;
  368. }
  369. }
  370. _noopInputHandler() {
  371. // no-op handler that ensures we're running change detection on input events.
  372. }
  373. /**
  374. * Scrolls a textarea to the caret position. On Firefox resizing the textarea will
  375. * prevent it from scrolling to the caret position. We need to re-set the selection
  376. * in order for it to scroll to the proper position.
  377. */
  378. _scrollToCaretPosition(textarea) {
  379. const { selectionStart, selectionEnd } = textarea;
  380. // IE will throw an "Unspecified error" if we try to set the selection range after the
  381. // element has been removed from the DOM. Assert that the directive hasn't been destroyed
  382. // between the time we requested the animation frame and when it was executed.
  383. // Also note that we have to assert that the textarea is focused before we set the
  384. // selection range. Setting the selection range on a non-focused textarea will cause
  385. // it to receive focus on IE and Edge.
  386. if (!this._destroyed.isStopped && this._hasFocus) {
  387. textarea.setSelectionRange(selectionStart, selectionEnd);
  388. textarea.scrollTop = this._cachedScrollTop;
  389. }
  390. }
  391. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTextareaAutosize, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  392. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.6", 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 });
  393. }
  394. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: CdkTextareaAutosize, decorators: [{
  395. type: Directive,
  396. args: [{
  397. selector: 'textarea[cdkTextareaAutosize]',
  398. exportAs: 'cdkTextareaAutosize',
  399. host: {
  400. 'class': 'cdk-textarea-autosize',
  401. // Textarea elements that have the directive applied should have a single row by default.
  402. // Browsers normally show two rows by default and therefore this limits the minRows binding.
  403. 'rows': '1',
  404. '(input)': '_noopInputHandler()',
  405. },
  406. }]
  407. }], ctorParameters: () => [], propDecorators: { minRows: [{
  408. type: Input,
  409. args: ['cdkAutosizeMinRows']
  410. }], maxRows: [{
  411. type: Input,
  412. args: ['cdkAutosizeMaxRows']
  413. }], enabled: [{
  414. type: Input,
  415. args: [{ alias: 'cdkTextareaAutosize', transform: booleanAttribute }]
  416. }], placeholder: [{
  417. type: Input
  418. }] } });
  419. class TextFieldModule {
  420. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TextFieldModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  421. static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.6", ngImport: i0, type: TextFieldModule, imports: [CdkAutofill, CdkTextareaAutosize], exports: [CdkAutofill, CdkTextareaAutosize] });
  422. static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TextFieldModule });
  423. }
  424. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: TextFieldModule, decorators: [{
  425. type: NgModule,
  426. args: [{
  427. imports: [CdkAutofill, CdkTextareaAutosize],
  428. exports: [CdkAutofill, CdkTextareaAutosize],
  429. }]
  430. }] });
  431. export { AutofillMonitor, CdkAutofill, CdkTextareaAutosize, TextFieldModule };
  432. //# sourceMappingURL=text-field.mjs.map