@snabcentr/client-ui 4.16.12-profstroy → 4.16.13-profstroy

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/esm2022/feedback/feedback-form/sc-feedback-form.component.mjs +21 -11
  2. package/esm2022/providers/cleanup-recaptcha-artifacts.mjs +30 -0
  3. package/esm2022/providers/index.mjs +2 -1
  4. package/esm2022/public-api.mjs +1 -2
  5. package/esm2022/samples/sc-sample.module.mjs +10 -3
  6. package/esm2022/services/index.mjs +1 -2
  7. package/feedback/feedback-form/sc-feedback-form.component.d.ts +1 -1
  8. package/fesm2022/snabcentr-client-ui.mjs +64 -367
  9. package/fesm2022/snabcentr-client-ui.mjs.map +1 -1
  10. package/package.json +2 -1
  11. package/providers/cleanup-recaptcha-artifacts.d.ts +7 -0
  12. package/providers/index.d.ts +1 -0
  13. package/public-api.d.ts +0 -1
  14. package/release_notes.tmp +2 -5
  15. package/samples/sc-sample.module.d.ts +2 -1
  16. package/services/index.d.ts +0 -1
  17. package/styles/tailwind/tailwind.scss +2 -40
  18. package/esm2022/services/sc-scripts.service.mjs +0 -106
  19. package/esm2022/smart-captcha/index.mjs +0 -5
  20. package/esm2022/smart-captcha/interfaces/index.mjs +0 -6
  21. package/esm2022/smart-captcha/interfaces/sc-smart-captcha-api.mjs +0 -2
  22. package/esm2022/smart-captcha/interfaces/sc-smart-captcha-event.mjs +0 -2
  23. package/esm2022/smart-captcha/interfaces/sc-smart-captcha-language.mjs +0 -2
  24. package/esm2022/smart-captcha/interfaces/sc-smart-captcha-render-params.mjs +0 -2
  25. package/esm2022/smart-captcha/interfaces/sc-smart-captcha-settings.mjs +0 -2
  26. package/esm2022/smart-captcha/interfaces/sc-smart-captcha-window.mjs +0 -2
  27. package/esm2022/smart-captcha/sc-smart-captcha.component.mjs +0 -167
  28. package/esm2022/smart-captcha/services/index.mjs +0 -2
  29. package/esm2022/smart-captcha/services/sc-smart-captcha-loader.service.mjs +0 -87
  30. package/esm2022/smart-captcha/tokens/index.mjs +0 -3
  31. package/esm2022/smart-captcha/tokens/sc-smart-captcha-load-timeout.token.mjs +0 -8
  32. package/esm2022/smart-captcha/tokens/sc-smart-captcha-settings.token.mjs +0 -6
  33. package/services/sc-scripts.service.d.ts +0 -51
  34. package/smart-captcha/index.d.ts +0 -4
  35. package/smart-captcha/interfaces/index.d.ts +0 -5
  36. package/smart-captcha/interfaces/sc-smart-captcha-api.d.ts +0 -36
  37. package/smart-captcha/interfaces/sc-smart-captcha-event.d.ts +0 -4
  38. package/smart-captcha/interfaces/sc-smart-captcha-language.d.ts +0 -4
  39. package/smart-captcha/interfaces/sc-smart-captcha-render-params.d.ts +0 -16
  40. package/smart-captcha/interfaces/sc-smart-captcha-settings.d.ts +0 -16
  41. package/smart-captcha/interfaces/sc-smart-captcha-window.d.ts +0 -14
  42. package/smart-captcha/sc-smart-captcha.component.d.ts +0 -92
  43. package/smart-captcha/services/index.d.ts +0 -1
  44. package/smart-captcha/services/sc-smart-captcha-loader.service.d.ts +0 -50
  45. package/smart-captcha/tokens/index.d.ts +0 -2
  46. package/smart-captcha/tokens/sc-smart-captcha-load-timeout.token.d.ts +0 -5
  47. package/smart-captcha/tokens/sc-smart-captcha-settings.token.d.ts +0 -6
@@ -1,20 +1,18 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, Injectable, NgZone, RendererFactory2, signal, EventEmitter, ChangeDetectorRef, Directive, Input, Output, untracked, Pipe, ElementRef, HostListener, Renderer2, ContentChildren, NgModule, input, computed, Component, ChangeDetectionStrategy, Inject, HostBinding, model, output, SkipSelf, DestroyRef, effect, ContentChild, ViewChild, viewChild, Optional, contentChild, TemplateRef, forwardRef, ViewEncapsulation, Injector, viewChildren, afterNextRender } from '@angular/core';
2
+ import { InjectionToken, inject, Injectable, NgZone, signal, EventEmitter, ChangeDetectorRef, Directive, Input, Output, untracked, Pipe, ElementRef, HostListener, Renderer2, ContentChildren, NgModule, input, computed, Component, ChangeDetectionStrategy, Inject, HostBinding, model, output, SkipSelf, DestroyRef, effect, ContentChild, ViewChild, viewChild, Optional, contentChild, TemplateRef, forwardRef, ViewEncapsulation, Injector, viewChildren, afterNextRender } from '@angular/core';
3
3
  import * as i1 from '@snabcentr/client-core';
4
- import { ScContactsService, ScUserService, ScLocationsService, IS_BROWSER, ScAuthService, SEARCH_TERM, ScUnitsHelper, ScImageHelper, SC_PATH_IMAGE_NOT_FOUND, ScImage, ScSuggestionAddressQuality, ScPhoneService, ScUserMetrikaService, ScUserMetrikaGoalsEnum, IS_RUNNING_ON_TERMINAL, ScVCardService, ScVerificationService, ScISuggestionType, SC_MIN_LENGTH_SEARCH_TERM, ScConvertersService, ScNumberHelper, ScOpfList, ScReferencesService, ScContragentService, ScBannerService, ScMediaImageTransformerPipe, ScUploadedFile, ScCartService, loadingPlaceholder, SC_ORDER_LOADER, ScMimeTypes, ScCatalogService, SC_URLS, ScWarehouseService, SEARCH_TERM_PROVIDERS, ScPaginationService, SC_NEXT_PAGE_PAGINATION_CLICK, SC_PRODUCT_PAGINATION_OPTIONS, ScCatalogFilterService, ScIdOrSlugPipe, SC_CATEGORY_INFO, ScConfiguratorService, IS_SERVER, RESPONSE, ScIconTypesEnum, ScDocumentInfoTypesEnum, ScOrderItemsGroup, ScOrderItem, ScDeliveryAddressService, ScOrdersService, ScUIService, SC_USER_INFO as SC_USER_INFO$1, ScPaymentType, ScDeliveryType, TERMINAL_PROVIDERS, ScOrderDraft, SC_UPDATE_INTERVAL, ScOrderDraftsService, ScOrderDraftActualizationStatus, ScRouteKeys, ScSeoService, scOrderIsLoaded, SC_PAGE_QUERY_PARAM, ScFrequentlyAskedQuestionsService, SchemaOrgFactory, scGetPageQueryParamChanges, ScNewsService, SC_COMPANY_INFO, ScFeedbackService } from '@snabcentr/client-core';
4
+ import { ScContactsService, ScUserService, ScLocationsService, ScAuthService, SEARCH_TERM, ScUnitsHelper, ScImageHelper, SC_PATH_IMAGE_NOT_FOUND, ScImage, ScSuggestionAddressQuality, ScPhoneService, ScUserMetrikaService, ScUserMetrikaGoalsEnum, IS_RUNNING_ON_TERMINAL, ScVCardService, ScVerificationService, ScISuggestionType, SC_MIN_LENGTH_SEARCH_TERM, ScConvertersService, ScNumberHelper, ScOpfList, ScReferencesService, ScContragentService, ScBannerService, ScMediaImageTransformerPipe, ScUploadedFile, ScCartService, loadingPlaceholder, SC_ORDER_LOADER, ScMimeTypes, ScCatalogService, SC_URLS, ScWarehouseService, SEARCH_TERM_PROVIDERS, ScPaginationService, SC_NEXT_PAGE_PAGINATION_CLICK, SC_PRODUCT_PAGINATION_OPTIONS, ScCatalogFilterService, ScIdOrSlugPipe, SC_CATEGORY_INFO, ScConfiguratorService, IS_SERVER, RESPONSE, ScIconTypesEnum, ScDocumentInfoTypesEnum, ScOrderItemsGroup, ScOrderItem, ScDeliveryAddressService, ScOrdersService, ScUIService, SC_USER_INFO as SC_USER_INFO$1, ScPaymentType, ScDeliveryType, TERMINAL_PROVIDERS, ScOrderDraft, SC_UPDATE_INTERVAL, ScOrderDraftsService, ScOrderDraftActualizationStatus, ScRouteKeys, ScSeoService, scOrderIsLoaded, SC_PAGE_QUERY_PARAM, ScFrequentlyAskedQuestionsService, SchemaOrgFactory, scGetPageQueryParamChanges, ScNewsService, SC_COMPANY_INFO, ScFeedbackService } from '@snabcentr/client-core';
5
5
  import * as i5$1 from 'rxjs';
6
- import { EMPTY, BehaviorSubject, switchMap, of, shareReplay, map, Observable, Subject, filter, tap, catchError, finalize, startWith, share, timer, scan, takeWhile, endWith, distinctUntilChanged, debounceTime, throwError, combineLatest, pairwise, Subscription, merge, skip, from, concatMap, noop, first, retry, defaultIfEmpty, exhaustMap, fromEvent, animationFrames, take, takeUntil, defer, timeout, ignoreElements } from 'rxjs';
6
+ import { EMPTY, BehaviorSubject, switchMap, of, shareReplay, map, Subject, filter, tap, catchError, finalize, startWith, share, timer, scan, takeWhile, endWith, distinctUntilChanged, debounceTime, throwError, combineLatest, pairwise, Observable, Subscription, merge, skip, from, concatMap, noop, first, retry, defaultIfEmpty, exhaustMap, fromEvent, animationFrames, take, takeUntil } from 'rxjs';
7
7
  import { WA_WINDOW } from '@ng-web-apis/common';
8
8
  import { takeUntilDestroyed, toSignal, outputFromObservable, toObservable } from '@angular/core/rxjs-interop';
9
9
  import * as i4$1 from '@taiga-ui/cdk';
10
- import { TuiDay, TuiTime, TuiValueTransformer, TUI_IS_MOBILE, TuiValidationError, tuiControlValue, tuiIsPresent, tuiMarkControlAsTouchedAndValidate, tuiIsFalsy, TuiAutoFocus, TuiRepeatTimes, TuiSwipeService, TUI_SWIPE_OPTIONS, TuiHovered, TuiDayRange, TuiMonth, tuiPure, tuiProvide, TUI_WINDOW_SIZE, tuiClamp, tuiZonefree, TUI_TRUE_HANDLER } from '@taiga-ui/cdk';
10
+ import { TuiDay, TuiTime, TuiValueTransformer, TUI_IS_MOBILE, TuiValidationError, tuiControlValue, tuiIsPresent, tuiMarkControlAsTouchedAndValidate, tuiIsFalsy, TuiAutoFocus, TuiRepeatTimes, TuiSwipeService, TUI_SWIPE_OPTIONS, TuiHovered, TuiDayRange, TuiMonth, tuiPure, tuiProvide, TUI_WINDOW_SIZE, tuiClamp, TUI_TRUE_HANDLER } from '@taiga-ui/cdk';
11
11
  import * as i2$1 from '@taiga-ui/kit';
12
12
  import { TUI_DATE_VALUE_TRANSFORMER, TuiPreview, TuiAvatar, TuiAccordionItem, TuiElasticContainer, TuiAccordion, TuiFieldErrorPipe, TuiFilterByInputPipe, TuiStringifyContentPipe, TuiDataListWrapper, TuiButtonLoading, TuiSortCountriesPipe, TuiStepper, TuiCarousel, TuiPush, TuiCheckbox, TUI_CONFIRM_WORDS, TuiFiles, TuiChip, TuiInputNumber, TuiBadge, TuiTooltip, TuiHighlight, TuiLineClamp, TuiFade, TuiRange, TuiBlock, tuiInputNumberOptionsProvider, TuiDataListWrapperComponent, TuiChevron, TuiSelect, TuiInputSlider, TuiTreeService, TuiTreeItemContent, TUI_TREE_START, TUI_TREE_CONTENT, TUI_TREE_LOADING, TUI_TREE_LOADER, TuiTree, TuiPreviewDialogService, TUI_CONFIRM, tuiFilesAccepted, TuiInputFiles, TuiInputFilesDirective, TuiFilesComponent, TuiFile, TuiFileRejectedPipe, TUI_INPUT_FILES_OPTIONS, tuiCreateFileFormatValidator, tuiCreateFileSizeValidator, TUI_INPUT_FILE_TEXTS, tuiItemsHandlersProvider as tuiItemsHandlersProvider$1, TUI_PAGINATION_TEXTS, TuiAccordionDirective, TuiAccordionItemContent } from '@taiga-ui/kit';
13
- import * as i2$2 from '@angular/common';
14
- import { DOCUMENT, CommonModule, NgIf, AsyncPipe, NgTemplateOutlet, NgFor, NgClass } from '@angular/common';
15
13
  import { HttpClient, HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
16
14
  import * as i1$1 from '@angular/forms';
17
- import { FormControl, NgControl, FormGroupDirective, FormGroup, Validators, FormArray, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
15
+ import { FormControl, NgControl, FormGroupDirective, FormGroup, Validators, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
18
16
  import * as i1$2 from '@taiga-ui/core';
19
17
  import { TuiButton, TuiDialog, TuiDialogService, TuiLink, TuiFallbackSrcPipe, TuiInitialsPipe, TuiIcon, TuiAppearance, TuiWithAppearance, TuiIcons, TuiWithIcons, TUI_DATA_LIST_HOST, tuiDropdownOptionsProvider, TuiLabel, TuiError, TuiLoader, TuiDataList, TuiNotification, TuiTextfield, TuiTitle, TuiFormatNumberPipe, TuiNumberFormat, TuiHint, TUI_MONTHS, TuiScrollbar, tuiNumberFormatProvider, tuiItemsHandlersProvider, tuiTextfieldOptionsProvider, tuiHintOptionsProvider, TuiHintDriver, TuiHintHover, TuiHintPosition, TuiHintDirective, TuiAlertService, TuiDataListComponent, TuiOption, TuiIconPipe, TUI_BUTTON_OPTIONS, TUI_BUTTON_DEFAULT_OPTIONS, TUI_SPIN_ICONS, TuiSurface, tuiFadeIn } from '@taiga-ui/core';
20
18
  import { isValidPhoneNumber } from 'libphonenumber-js/max';
@@ -26,6 +24,8 @@ import { isNil, isUndefined, isObject, isArray, isString } from 'lodash-es';
26
24
  import * as i5 from '@taiga-ui/core/components/label';
27
25
  import * as i8 from '@maskito/angular';
28
26
  import { MaskitoDirective } from '@maskito/angular';
27
+ import * as i2$2 from '@angular/common';
28
+ import { DOCUMENT, CommonModule, NgIf, AsyncPipe, NgTemplateOutlet, NgFor, NgClass } from '@angular/common';
29
29
  import * as i2$3 from '@taiga-ui/polymorpheus';
30
30
  import { POLYMORPHEUS_CONTEXT, PolymorpheusComponent, PolymorpheusTemplate, PolymorpheusOutlet, injectContext } from '@taiga-ui/polymorpheus';
31
31
  import * as i2 from 'angularx-qrcode';
@@ -55,6 +55,8 @@ import { Clipboard } from '@angular/cdk/clipboard';
55
55
  import * as i2$5 from '@taiga-ui/experimental/components/expand';
56
56
  import * as i3$3 from '@taiga-ui/kit/components/data-list-wrapper';
57
57
  import { TuiGroup } from '@taiga-ui/core/directives/group';
58
+ import * as i4$3 from 'ng-recaptcha-2';
59
+ import { RecaptchaFormsModule, RecaptchaModule, RecaptchaComponent } from 'ng-recaptcha-2';
58
60
 
59
61
  /**
60
62
  * Поток для закрытия уведомлений помощи.
@@ -354,6 +356,36 @@ const SC_HIDDEN_PRINT_ELEMENTS = new InjectionToken('SC_HIDDEN_PRINT_ELEMENTS',
354
356
  providedIn: 'root',
355
357
  });
356
358
 
359
+ /**
360
+ * Селектор iframe reCAPTCHA.
361
+ */
362
+ const RECAPTCHA_IFRAME_SELECTOR = 'iframe[src*="recaptcha"]';
363
+ /**
364
+ * Селектор хоста reCAPTCHA.
365
+ */
366
+ const RECAPTCHA_HOST_SELECTOR = 're-captcha';
367
+ /**
368
+ * Освобождает ресурсы reCAPTCHA и удаляет осиротевшие iframe после смены маршрута.
369
+ *
370
+ * @param documentReference Объект документа.
371
+ * @param windowReference Объект окна браузера.
372
+ */
373
+ function cleanupRecaptchaArtifacts(documentReference, windowReference) {
374
+ const windowWithRecaptcha = windowReference;
375
+ try {
376
+ windowWithRecaptcha.grecaptcha?.reset();
377
+ }
378
+ catch {
379
+ // Ошибки reCAPTCHA не должны блокировать навигацию.
380
+ }
381
+ documentReference.querySelectorAll(RECAPTCHA_IFRAME_SELECTOR).forEach((iframe) => {
382
+ if (iframe.closest(RECAPTCHA_HOST_SELECTOR)) {
383
+ return;
384
+ }
385
+ iframe.remove();
386
+ });
387
+ }
388
+
357
389
  /**
358
390
  * Сервис по работе с печатью страницы.
359
391
  */
@@ -399,107 +431,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
399
431
  }]
400
432
  }] });
401
433
 
402
- /**
403
- * Сервис для вставки в {@link Document} внешних и дополнительных скриптов.
404
- */
405
- class ScScriptsService {
406
- constructor() {
407
- /**
408
- * Объект {@link Document}, предоставляющий доступ к DOM страницы.
409
- */
410
- this.document = inject(DOCUMENT);
411
- /**
412
- * Объект {@link Renderer2}, предоставляющий доступ к DOM страницы.
413
- */
414
- this.renderer = inject(RendererFactory2).createRenderer(null, null);
415
- /**
416
- * Признак того, что скрипт выполняется в браузере.
417
- */
418
- this.isBrowser = inject(IS_BROWSER);
419
- /**
420
- * {@link NgZone} для вставки скриптов вне зоны Angular.
421
- */
422
- this.ngZone = inject(NgZone);
423
- }
424
- /**
425
- * Вставляет в конец {@link Document.body} скрипты, заданные строками HTML, вне зоны Angular. Из каждой строки берётся первый `<script>`. На сервере ничего не делает.
426
- * Принимает только доверенные строки из конфигурации приложения: строка разбирается как HTML и может выполнить код.
427
- *
428
- * @param scriptStrings Строки HTML скриптов.
429
- */
430
- appendScripts(scriptStrings) {
431
- if (!this.isBrowser) {
432
- return;
433
- }
434
- this.ngZone.runOutsideAngular(() => {
435
- scriptStrings.forEach((scriptString) => {
436
- const script = this.createScript(scriptString);
437
- if (script) {
438
- this.renderer.appendChild(this.document.body, script);
439
- }
440
- });
441
- });
442
- }
443
- /**
444
- * Загружает внешний скрипт: при подписке добавляет его в {@link Document.head}, после загрузки выдаёт элемент скрипта и завершается.
445
- * Если скрипт не загрузился или подписка отменена раньше, удаляет его со страницы; удаление не отменяет загрузку и выполнение уже вставленного скрипта. На сервере завершается без загрузки.
446
- *
447
- * @param url Адрес скрипта.
448
- */
449
- loadScript$(url) {
450
- if (!this.isBrowser) {
451
- return EMPTY;
452
- }
453
- return new Observable((subscriber) => {
454
- const script = this.renderer.createElement('script');
455
- let isLoaded = false;
456
- const unlistenLoad = this.renderer.listen(script, 'load', () => {
457
- isLoaded = true;
458
- subscriber.next(script);
459
- subscriber.complete();
460
- });
461
- const unlistenError = this.renderer.listen(script, 'error', () => {
462
- subscriber.error(new Error(`Failed to load script ${url}`));
463
- });
464
- this.renderer.setProperty(script, 'src', url);
465
- this.renderer.appendChild(this.document.head, script);
466
- return () => {
467
- unlistenLoad();
468
- unlistenError();
469
- if (!isLoaded) {
470
- this.removeScript(script);
471
- }
472
- };
473
- });
474
- }
475
- /**
476
- * Удаляет скрипт со страницы. При подключённых анимациях Angular узел удаляется при ближайшей проверке изменений.
477
- *
478
- * @param script Элемент скрипта.
479
- */
480
- removeScript(script) {
481
- this.renderer.removeChild(script.parentNode, script);
482
- }
483
- /**
484
- * Создаёт {@link HTMLScriptElement} из строки HTML скрипта.
485
- *
486
- * @param scriptString Строка HTML скрипта.
487
- */
488
- createScript(scriptString) {
489
- const range = this.document.createRange();
490
- const fragment = range.createContextualFragment(scriptString);
491
- return fragment.querySelector('script');
492
- }
493
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
494
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, providedIn: 'root' }); }
495
- }
496
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, decorators: [{
497
- type: Injectable,
498
- args: [{
499
- providedIn: 'root',
500
- }]
501
- }] });
502
-
503
434
  /**
504
435
  * Проверяет корректность введенного номера телефона.
505
436
  */
@@ -12346,14 +12277,18 @@ class ScPreviewSampleModule {
12346
12277
  TuiHovered,
12347
12278
  TuiButton,
12348
12279
  TuiButtonLoading,
12349
- TuiLabel], exports: [ScPreviewSampleComponent] }); }
12280
+ TuiLabel,
12281
+ RecaptchaFormsModule,
12282
+ RecaptchaModule], exports: [ScPreviewSampleComponent] }); }
12350
12283
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScPreviewSampleModule, imports: [CommonModule,
12351
12284
  ReactiveFormsModule,
12352
12285
  TuiError,
12353
12286
  ScFormFieldsModule,
12354
12287
  TuiInputModule,
12355
12288
  TuiInputPhoneModule, i2$1.TuiCarouselComponent, TuiAvatar,
12356
- TuiButtonLoading] }); }
12289
+ TuiButtonLoading,
12290
+ RecaptchaFormsModule,
12291
+ RecaptchaModule] }); }
12357
12292
  }
12358
12293
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScPreviewSampleModule, decorators: [{
12359
12294
  type: NgModule,
@@ -12373,6 +12308,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
12373
12308
  TuiButton,
12374
12309
  TuiButtonLoading,
12375
12310
  TuiLabel,
12311
+ RecaptchaFormsModule,
12312
+ RecaptchaModule,
12376
12313
  ],
12377
12314
  exports: [ScPreviewSampleComponent],
12378
12315
  }]
@@ -12392,255 +12329,6 @@ const scGetCurrentRoute = (route) => {
12392
12329
  return currentRoute;
12393
12330
  };
12394
12331
 
12395
- /**
12396
- * Токен времени ожидания загрузки скрипта Yandex SmartCaptcha в миллисекундах.
12397
- */
12398
- const SC_SMART_CAPTCHA_LOAD_TIMEOUT = new InjectionToken('SC_SMART_CAPTCHA_LOAD_TIMEOUT', {
12399
- factory: () => 20_000,
12400
- });
12401
-
12402
- /**
12403
- * Сервис загрузки скрипта Yandex SmartCaptcha.
12404
- */
12405
- class ScSmartCaptchaLoaderService {
12406
- constructor() {
12407
- /**
12408
- * Сервис для вставки внешних скриптов.
12409
- */
12410
- this.scriptsService = inject(ScScriptsService);
12411
- /**
12412
- * Окно браузера с API Yandex SmartCaptcha.
12413
- */
12414
- this.window = inject(WA_WINDOW);
12415
- /**
12416
- * Признак того, что приложение запущено в браузере.
12417
- */
12418
- this.isBrowser = inject(IS_BROWSER);
12419
- /**
12420
- * Время ожидания загрузки скрипта в миллисекундах.
12421
- */
12422
- this.loadTimeout = inject(SC_SMART_CAPTCHA_LOAD_TIMEOUT);
12423
- /**
12424
- * Имя функции окна, которую скрипт вызывает после загрузки.
12425
- */
12426
- this.onloadCallbackName = 'scSmartCaptchaOnload';
12427
- /**
12428
- * Адрес скрипта.
12429
- */
12430
- this.scriptUrl = `https://smartcaptcha.cloud.yandex.ru/captcha.js?render=onload&onload=${this.onloadCallbackName}`;
12431
- /**
12432
- * Загрузка API, общая для всех виджетов. Скрипт загружается один раз; отписка и истечение ожидания у подписчика загрузку не прерывают, после ошибки следующая подписка загружает скрипт заново.
12433
- */
12434
- this.loading$ = defer(() => this.load$()).pipe(shareReplay(1));
12435
- /**
12436
- * {@link Observable} API Yandex SmartCaptcha. Значения и ошибки приходят вне зоны Angular, ожидание первого значения ограничено {@link SC_SMART_CAPTCHA_LOAD_TIMEOUT}.
12437
- */
12438
- this.api$ = this.loading$.pipe(timeout({ first: this.loadTimeout }), tuiZonefree());
12439
- }
12440
- /**
12441
- * Возвращает API Yandex SmartCaptcha, при необходимости загружая скрипт. На сервере ничего не возвращает.
12442
- */
12443
- load$() {
12444
- if (!this.isBrowser) {
12445
- return EMPTY;
12446
- }
12447
- if (this.window.smartCaptcha) {
12448
- return of(this.window.smartCaptcha);
12449
- }
12450
- return merge(this.onload$(), this.scriptsService.loadScript$(this.scriptUrl).pipe(ignoreElements()));
12451
- }
12452
- /**
12453
- * Ждёт вызова функции из параметра `onload` адреса скрипта и возвращает API, которое скрипт к этому моменту создал.
12454
- */
12455
- onload$() {
12456
- return new Observable((subscriber) => {
12457
- this.window[this.onloadCallbackName] = () => {
12458
- if (this.window.smartCaptcha) {
12459
- subscriber.next(this.window.smartCaptcha);
12460
- subscriber.complete();
12461
- }
12462
- else {
12463
- subscriber.error(new Error('Yandex SmartCaptcha API is unavailable'));
12464
- }
12465
- };
12466
- return () => {
12467
- this.window[this.onloadCallbackName] = undefined;
12468
- };
12469
- });
12470
- }
12471
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
12472
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, providedIn: 'root' }); }
12473
- }
12474
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, decorators: [{
12475
- type: Injectable,
12476
- args: [{
12477
- providedIn: 'root',
12478
- }]
12479
- }] });
12480
-
12481
- /**
12482
- * Токен настроек Yandex SmartCaptcha. Задаётся приложением.
12483
- */
12484
- const SC_SMART_CAPTCHA_SETTINGS = new InjectionToken('SC_SMART_CAPTCHA_SETTINGS');
12485
-
12486
- /* eslint-disable no-use-before-define */
12487
- /**
12488
- * Виджет Yandex SmartCaptcha. Значение поля ввода - токен прохождения проверки, `null` пока проверка не пройдена или токен истёк.
12489
- */
12490
- class ScSmartCaptchaComponent {
12491
- /**
12492
- * Инициализирует экземпляр класса {@link ScSmartCaptchaComponent}.
12493
- */
12494
- constructor() {
12495
- /**
12496
- * Контейнер, в котором отрисовывается виджет.
12497
- */
12498
- this.container = viewChild.required('container');
12499
- /**
12500
- * Настройки Yandex SmartCaptcha.
12501
- */
12502
- this.settings = inject(SC_SMART_CAPTCHA_SETTINGS);
12503
- /**
12504
- * Сервис загрузки скрипта Yandex SmartCaptcha.
12505
- */
12506
- this.loader = inject(ScSmartCaptchaLoaderService);
12507
- /**
12508
- * {@link NgZone} для отрисовки виджета вне зоны Angular и возврата его событий в зону.
12509
- */
12510
- this.ngZone = inject(NgZone);
12511
- /**
12512
- * Ссылка для автоматического управления уничтожением зависимостей.
12513
- */
12514
- this.destroyRef = inject(DestroyRef);
12515
- /**
12516
- * Признак того, что капчу не удалось загрузить.
12517
- */
12518
- this.hasError = signal(false);
12519
- /**
12520
- * Функции отписки от событий виджета.
12521
- */
12522
- this.unsubscribers = [];
12523
- /**
12524
- * Обработчик изменения значения поля ввода.
12525
- */
12526
- this.onChange = noop;
12527
- /**
12528
- * Обработчик касания поля ввода.
12529
- */
12530
- this.onTouched = noop;
12531
- afterNextRender(() => {
12532
- this.load();
12533
- });
12534
- this.destroyRef.onDestroy(() => {
12535
- this.destroyWidget();
12536
- });
12537
- }
12538
- /** @inheritDoc */
12539
- writeValue(token) {
12540
- const { api, widgetId } = this;
12541
- if (!token && api && widgetId !== undefined) {
12542
- this.ngZone.runOutsideAngular(() => {
12543
- api.reset(widgetId);
12544
- });
12545
- }
12546
- }
12547
- /** @inheritDoc */
12548
- registerOnChange(onChange) {
12549
- this.onChange = onChange;
12550
- }
12551
- /** @inheritDoc */
12552
- registerOnTouched(onTouched) {
12553
- this.onTouched = onTouched;
12554
- }
12555
- /**
12556
- * Повторяет загрузку капчи после ошибки.
12557
- */
12558
- retry() {
12559
- this.hasError.set(false);
12560
- this.load();
12561
- }
12562
- /**
12563
- * Загружает API Yandex SmartCaptcha и отрисовывает виджет (API приходит вне зоны Angular). При ошибке загрузки или отрисовки показывает сообщение.
12564
- */
12565
- load() {
12566
- this.loader.api$
12567
- .pipe(tap((api) => {
12568
- this.render(api);
12569
- }), takeUntilDestroyed(this.destroyRef))
12570
- .subscribe({
12571
- error: () => {
12572
- this.showError();
12573
- },
12574
- });
12575
- }
12576
- /**
12577
- * Отрисовывает виджет и подписывается на его события.
12578
- *
12579
- * @param api API Yandex SmartCaptcha.
12580
- */
12581
- render(api) {
12582
- const widgetId = api.render(this.container().nativeElement, { sitekey: this.settings.sitekey, hl: this.settings.language });
12583
- this.api = api;
12584
- this.widgetId = widgetId;
12585
- this.unsubscribers = [
12586
- api.subscribe(widgetId, 'success', (token) => {
12587
- this.updateValue(typeof token === 'string' ? token : null);
12588
- }),
12589
- api.subscribe(widgetId, 'token-expired', () => {
12590
- this.updateValue(null);
12591
- api.reset(widgetId);
12592
- }),
12593
- api.subscribe(widgetId, 'javascript-error', () => {
12594
- this.showError();
12595
- }),
12596
- ];
12597
- }
12598
- /**
12599
- * Передаёт форме новое значение токена.
12600
- *
12601
- * @param token Токен прохождения проверки.
12602
- */
12603
- updateValue(token) {
12604
- this.ngZone.run(() => {
12605
- this.onChange(token);
12606
- this.onTouched();
12607
- });
12608
- }
12609
- /**
12610
- * Удаляет виджет, очищает токен и показывает сообщение об ошибке.
12611
- */
12612
- showError() {
12613
- this.destroyWidget();
12614
- this.ngZone.run(() => {
12615
- this.hasError.set(true);
12616
- this.onChange(null);
12617
- });
12618
- }
12619
- /**
12620
- * Удаляет виджет вместе с созданными им элементами и обработчиками.
12621
- */
12622
- destroyWidget() {
12623
- this.unsubscribers.forEach((unsubscribe) => {
12624
- unsubscribe();
12625
- });
12626
- this.unsubscribers = [];
12627
- const { api, widgetId } = this;
12628
- if (api && widgetId !== undefined) {
12629
- this.ngZone.runOutsideAngular(() => {
12630
- api.destroy(widgetId);
12631
- });
12632
- }
12633
- this.api = undefined;
12634
- this.widgetId = undefined;
12635
- }
12636
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12637
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScSmartCaptchaComponent, isStandalone: true, selector: "sc-smart-captcha", providers: [tuiProvide(NG_VALUE_ACCESSOR, ScSmartCaptchaComponent, true)], viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n #container\n class=\"min-h-[7.375rem]\"\n [class.hidden]=\"hasError()\"\n></div>\n@if (hasError()) {\n <p\n role=\"alert\"\n class=\"text-body-s text-tui-text-negative\"\n >\n \u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u00AB\u042F \u043D\u0435 \u0440\u043E\u0431\u043E\u0442\u00BB.\n <button\n tuiLink\n type=\"button\"\n (click)=\"retry()\"\n >\n \u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C\n </button>\n </p>\n}\n", dependencies: [{ kind: "directive", type: TuiLink, selector: "a[tuiLink], button[tuiLink]", inputs: ["pseudo"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12638
- }
12639
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaComponent, decorators: [{
12640
- type: Component,
12641
- args: [{ standalone: true, selector: 'sc-smart-captcha', imports: [TuiLink], providers: [tuiProvide(NG_VALUE_ACCESSOR, ScSmartCaptchaComponent, true)], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n #container\n class=\"min-h-[7.375rem]\"\n [class.hidden]=\"hasError()\"\n></div>\n@if (hasError()) {\n <p\n role=\"alert\"\n class=\"text-body-s text-tui-text-negative\"\n >\n \u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 \u00AB\u042F \u043D\u0435 \u0440\u043E\u0431\u043E\u0442\u00BB.\n <button\n tuiLink\n type=\"button\"\n (click)=\"retry()\"\n >\n \u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C\n </button>\n </p>\n}\n" }]
12642
- }], ctorParameters: () => [] });
12643
-
12644
12332
  /**
12645
12333
  * Компонент формы обратной связи.
12646
12334
  */
@@ -12712,7 +12400,7 @@ class ScFeedbackFormComponent {
12712
12400
  }
12713
12401
  }));
12714
12402
  /**
12715
- * Поле ввода токена капчи, имя `recaptcha` задано API.
12403
+ * Поле ввода для recaptcha.
12716
12404
  */
12717
12405
  this.recaptchaControl = new FormControl(null, Validators.required);
12718
12406
  /**
@@ -12754,10 +12442,8 @@ class ScFeedbackFormComponent {
12754
12442
  }),
12755
12443
  // eslint-disable-next-line rxjs/no-implicit-any-catch
12756
12444
  catchError((error) => {
12757
- // Токен капчи одноразовый: для повторной отправки нужна новая проверка.
12758
- this.recaptchaControl.reset();
12759
12445
  this.form.markAllAsTouched();
12760
- const { errors, message } = (error.error ?? {});
12446
+ const { errors, message } = error.error;
12761
12447
  if (errors) {
12762
12448
  Object.keys(errors).forEach((key) => {
12763
12449
  const control = this.form.get(key);
@@ -12794,6 +12480,16 @@ class ScFeedbackFormComponent {
12794
12480
  * Список стран.
12795
12481
  */
12796
12482
  this.countries = getCountries();
12483
+ /**
12484
+ * Это решение ошибки #4940, было @see [предложено](https://github.com/DethAriel/ng-recaptcha/issues/123#issuecomment-426112101) автором {@link RecaptchaComponent}.
12485
+ */
12486
+ RecaptchaComponent.prototype.ngOnDestroy = function () {
12487
+ // eslint-disable-next-line @typescript-eslint/dot-notation
12488
+ if (this['subscription']) {
12489
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/dot-notation
12490
+ this['subscription'].unsubscribe();
12491
+ }
12492
+ };
12797
12493
  merge(this.user$, this.accepted$.pipe(tap((files) => {
12798
12494
  this.form.controls.files.reset([]);
12799
12495
  this.onUploadFile(files);
@@ -12917,7 +12613,7 @@ class ScFeedbackFormComponent {
12917
12613
  return ScPhoneService.isValidPhoneNumberForMessenger(value);
12918
12614
  }
12919
12615
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScFeedbackFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12920
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScFeedbackFormComponent, isStandalone: true, selector: "sc-feedback-form", inputs: { slugInput: { classPropertyName: "slugInput", publicName: "slug", isSignal: true, isRequired: false, transformFunction: null }, fieldsInput: { classPropertyName: "fieldsInput", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickOffer: "clickOffer", sendSuccess: "sendSuccess" }, ngImport: i0, template: "@let fieldsList = fields();\n<form\n *ngIf=\"fieldsList.length > 0\"\n [formGroup]=\"form\"\n (ngSubmit)=\"onSubmit.next()\"\n class=\"flex flex-col justify-between gap-4\"\n>\n <!-- \u0424\u0418\u041E -->\n <label\n *ngIf=\"fieldsList.includes('name')\"\n tuiLabel\n >\n \u0424\u0418\u041E\n <tui-input formControlName=\"name\"> \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0424.\u0418.\u041E. </tui-input>\n <tui-error\n formControlName=\"name\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0422\u0435\u043B\u0435\u0444\u043E\u043D -->\n @if (fieldsList.includes('phone')) {\n <label tuiLabel>\n \u0422\u0435\u043B\u0435\u0444\u043E\u043D\n <tui-textfield>\n <input\n formControlName=\"phone\"\n tuiInputPhoneInternational\n [countrySearch]=\"true\"\n [countries]=\"(countries | tuiSortCountries | async) || []\"\n autocomplete=\"phone\"\n />\n </tui-textfield>\n <tui-error\n formControlName=\"phone\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <label\n *ngIf=\"fieldsList.includes('isShouldUseMessenger') && form.controls.phone.value && isValidPhoneNumberForMessenger(form.controls.phone.value)\"\n tuiLabel\n >\n <input\n formControlName=\"isShouldUseMessenger\"\n tuiCheckbox\n type=\"checkbox\"\n />\n <span tuiTitle> \u041D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043C\u0435\u0441\u0441\u0435\u043D\u0434\u0436\u0435\u0440\u0430\u0445, \u0430 \u043D\u0435 \u0437\u0432\u043E\u043D\u0438\u0442\u044C </span>\n </label>\n }\n <!-- \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B -->\n <label\n *ngIf=\"fieldsList.includes('email')\"\n tuiLabel\n >\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <tui-input formControlName=\"email\">\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <sc-suggestion-field\n *tuiDataList\n [type]=\"suggestionType.email\"\n />\n </tui-input>\n <tui-error\n formControlName=\"email\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 -->\n <label\n *ngIf=\"fieldsList.includes('message')\"\n tuiLabel\n >\n \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439\n <tui-textarea formControlName=\"message\"> \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 </tui-textarea>\n <tui-error\n formControlName=\"message\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0424\u0430\u0439\u043B\u044B -->\n <div\n *ngIf=\"fieldsList.includes('files')\"\n class=\"flex flex-col gap-1\"\n >\n <label tuiInputFiles>\n <input\n #validator=\"tuiInputFilesValidator\"\n accept=\".doc,.docx,.pdf,image/*\"\n tuiInputFiles\n [formControl]=\"loadedFile\"\n [multiple]=\"true\"\n (reject)=\"onReject($event)\"\n />\n </label>\n\n <tui-error\n *ngIf=\"loadedFile.invalid\"\n [error]=\"['maxLength'] | tuiFieldError | async\"\n [formControl]=\"loadedFile\"\n />\n\n @let accepted = accepted$ | async;\n <tui-files\n *ngIf=\"accepted?.length || rejected.length\"\n class=\"tui-space_top-1\"\n >\n <tui-file\n *ngFor=\"let file of accepted\"\n [file]=\"file\"\n (remove)=\"onRemove(file)\"\n />\n <tui-file\n *ngFor=\"let file of rejected\"\n state=\"error\"\n [file]=\"(file | tuiFileRejected: validator | async) || file\"\n (remove)=\"onRemove(file)\"\n />\n </tui-files>\n </div>\n\n <!-- \u041A\u0430\u043F\u0447\u0430 -->\n @if (form.get('recaptcha'); as recaptcha) {\n <div\n class=\"mb-3 max-h-[7.5rem] overflow-hidden duration-500\"\n [ngClass]=\"{ '!max-h-0 !-m-2': recaptcha.valid }\"\n [attr.inert]=\"recaptcha.valid ? '' : null\"\n >\n <sc-smart-captcha formControlName=\"recaptcha\" />\n </div>\n @if (recaptcha.getError('serverResponse'); as serverErrors) {\n <tui-error [error]=\"serverErrors.join(' ')\" />\n }\n }\n\n <!-- \u042D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F -->\n <div class=\"flex flex-wrap items-center gap-3\">\n <button\n tuiButton\n [disabled]=\"form.invalid\"\n [loading]=\"!!(loading$ | async)\"\n type=\"submit\"\n iconStart=\"@tui.sc.send\"\n class=\"self-center\"\n >\n \u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C\n </button>\n <div class=\"grow basis-60 text-body-s\">\n \u041D\u0430\u0436\u0438\u043C\u0430\u044F \u043D\u0430 \u043A\u043D\u043E\u043F\u043A\u0443, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441\n <button\n tuiLink\n [pseudo]=\"true\"\n type=\"button\"\n (click)=\"context?.data?.onClickOfferHandler(); clickOffer.emit()\"\n >\n \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438\n </button>\n </div>\n </div>\n</form>\n", dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: TuiError, selector: "tui-error", inputs: ["error"] }, { kind: "pipe", type: TuiFieldErrorPipe, name: "tuiFieldError" }, { kind: "ngmodule", type: ScFormFieldsModule }, { kind: "component", type: ScSuggestionFieldComponent, selector: "sc-suggestion-field", inputs: ["type"], outputs: ["selectedClick"] }, { kind: "ngmodule", type: TuiInputModule }, { kind: "component", type: i3.TuiInputComponent, selector: "tui-input" }, { kind: "directive", type: i3.TuiInputDirective, selector: "tui-input" }, { kind: "ngmodule", type: TuiInputPhoneModule }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "component", type: TuiButtonLoading, selector: "[tuiButton][loading],[tuiIconButton][loading]", inputs: ["size", "loading"] }, { kind: "directive", type: TuiLabel, selector: "label[tuiLabel]" }, { kind: "component", type: ScSmartCaptchaComponent, selector: "sc-smart-captcha" }, { kind: "directive", type: TuiLink, selector: "a[tuiLink], button[tuiLink]", inputs: ["pseudo"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: TuiTextareaModule }, { kind: "component", type: i3.TuiTextareaComponent, selector: "tui-textarea", inputs: ["rows", "maxLength", "expandable"] }, { kind: "directive", type: i3.TuiTextareaDirective, selector: "tui-textarea" }, { kind: "component", type: TuiCheckbox, selector: "input[type=\"checkbox\"][tuiCheckbox]", inputs: ["size"] }, { kind: "directive", type: TuiTitle, selector: "[tuiTitle]", inputs: ["tuiTitle"] }, { kind: "component", type: i2$1.TuiFile, selector: "tui-file,a[tuiFile],button[tuiFile]", inputs: ["file", "state", "size", "showDelete", "showSize", "leftContent"], outputs: ["remove"] }, { kind: "component", type: i2$1.TuiInputFiles, selector: "label[tuiInputFiles]" }, { kind: "component", type: i2$1.TuiFilesComponent, selector: "tui-files", inputs: ["max", "expanded"], outputs: ["expandedChange"] }, { kind: "pipe", type: i2$1.TuiFileRejectedPipe, name: "tuiFileRejected" }, { kind: "directive", type: i2$1.TuiInputFilesDirective, selector: "input[tuiInputFiles]", outputs: ["reject"] }, { kind: "component", type: TuiInputPhoneInternational, selector: "input[tuiInputPhoneInternational]", inputs: ["countrySearch", "countries", "countryIsoCode"], outputs: ["countryIsoCodeChange"] }, { kind: "component", type: i1$2.TuiTextfieldComponent, selector: "tui-textfield:not([multi])" }, { kind: "pipe", type: TuiSortCountriesPipe, name: "tuiSortCountries" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12616
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScFeedbackFormComponent, isStandalone: true, selector: "sc-feedback-form", inputs: { slugInput: { classPropertyName: "slugInput", publicName: "slug", isSignal: true, isRequired: false, transformFunction: null }, fieldsInput: { classPropertyName: "fieldsInput", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clickOffer: "clickOffer", sendSuccess: "sendSuccess" }, ngImport: i0, template: "@let fieldsList = fields();\n<form\n *ngIf=\"fieldsList.length > 0\"\n [formGroup]=\"form\"\n (ngSubmit)=\"onSubmit.next()\"\n class=\"flex flex-col justify-between gap-4\"\n>\n <!-- \u0424\u0418\u041E -->\n <label\n *ngIf=\"fieldsList.includes('name')\"\n tuiLabel\n >\n \u0424\u0418\u041E\n <tui-input formControlName=\"name\"> \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0424.\u0418.\u041E. </tui-input>\n <tui-error\n formControlName=\"name\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0422\u0435\u043B\u0435\u0444\u043E\u043D -->\n @if (fieldsList.includes('phone')) {\n <label tuiLabel>\n \u0422\u0435\u043B\u0435\u0444\u043E\u043D\n <tui-textfield>\n <input\n formControlName=\"phone\"\n tuiInputPhoneInternational\n [countrySearch]=\"true\"\n [countries]=\"(countries | tuiSortCountries | async) || []\"\n autocomplete=\"phone\"\n />\n </tui-textfield>\n <tui-error\n formControlName=\"phone\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <label\n *ngIf=\"fieldsList.includes('isShouldUseMessenger') && form.controls.phone.value && isValidPhoneNumberForMessenger(form.controls.phone.value)\"\n tuiLabel\n >\n <input\n formControlName=\"isShouldUseMessenger\"\n tuiCheckbox\n type=\"checkbox\"\n />\n <span tuiTitle> \u041D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043C\u0435\u0441\u0441\u0435\u043D\u0434\u0436\u0435\u0440\u0430\u0445, \u0430 \u043D\u0435 \u0437\u0432\u043E\u043D\u0438\u0442\u044C </span>\n </label>\n }\n <!-- \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B -->\n <label\n *ngIf=\"fieldsList.includes('email')\"\n tuiLabel\n >\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <tui-input formControlName=\"email\">\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <sc-suggestion-field\n *tuiDataList\n [type]=\"suggestionType.email\"\n />\n </tui-input>\n <tui-error\n formControlName=\"email\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 -->\n <label\n *ngIf=\"fieldsList.includes('message')\"\n tuiLabel\n >\n \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439\n <tui-textarea formControlName=\"message\"> \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 </tui-textarea>\n <tui-error\n formControlName=\"message\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0424\u0430\u0439\u043B\u044B -->\n <div\n *ngIf=\"fieldsList.includes('files')\"\n class=\"flex flex-col gap-1\"\n >\n <label tuiInputFiles>\n <input\n #validator=\"tuiInputFilesValidator\"\n accept=\".doc,.docx,.pdf,image/*\"\n tuiInputFiles\n [formControl]=\"loadedFile\"\n [multiple]=\"true\"\n (reject)=\"onReject($event)\"\n />\n </label>\n\n <tui-error\n *ngIf=\"loadedFile.invalid\"\n [error]=\"['maxLength'] | tuiFieldError | async\"\n [formControl]=\"loadedFile\"\n />\n\n @let accepted = accepted$ | async;\n <tui-files\n *ngIf=\"accepted?.length || rejected.length\"\n class=\"tui-space_top-1\"\n >\n <tui-file\n *ngFor=\"let file of accepted\"\n [file]=\"file\"\n (remove)=\"onRemove(file)\"\n />\n <tui-file\n *ngFor=\"let file of rejected\"\n state=\"error\"\n [file]=\"(file | tuiFileRejected: validator | async) || file\"\n (remove)=\"onRemove(file)\"\n />\n </tui-files>\n </div>\n\n <!-- recaptcha -->\n @if (form.get('recaptcha')) {\n <div\n class=\"mb-3 max-h-20 overflow-hidden duration-500\"\n [ngClass]=\"{ '!max-h-0 !-m-2': form.get('recaptcha')?.valid }\"\n >\n <re-captcha formControlName=\"recaptcha\" />\n </div>\n }\n\n <!-- \u042D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F -->\n <div class=\"flex flex-wrap items-center gap-3\">\n <button\n tuiButton\n [disabled]=\"form.invalid\"\n [loading]=\"!!(loading$ | async)\"\n type=\"submit\"\n iconStart=\"@tui.sc.send\"\n class=\"self-center\"\n >\n \u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C\n </button>\n <div class=\"grow basis-60 text-body-s\">\n \u041D\u0430\u0436\u0438\u043C\u0430\u044F \u043D\u0430 \u043A\u043D\u043E\u043F\u043A\u0443, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441\n <button\n tuiLink\n [pseudo]=\"true\"\n type=\"button\"\n (click)=\"context?.data?.onClickOfferHandler(); clickOffer.emit()\"\n >\n \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438\n </button>\n </div>\n </div>\n</form>\n", dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: TuiError, selector: "tui-error", inputs: ["error"] }, { kind: "pipe", type: TuiFieldErrorPipe, name: "tuiFieldError" }, { kind: "ngmodule", type: ScFormFieldsModule }, { kind: "component", type: ScSuggestionFieldComponent, selector: "sc-suggestion-field", inputs: ["type"], outputs: ["selectedClick"] }, { kind: "ngmodule", type: TuiInputModule }, { kind: "component", type: i3.TuiInputComponent, selector: "tui-input" }, { kind: "directive", type: i3.TuiInputDirective, selector: "tui-input" }, { kind: "ngmodule", type: TuiInputPhoneModule }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "component", type: TuiButtonLoading, selector: "[tuiButton][loading],[tuiIconButton][loading]", inputs: ["size", "loading"] }, { kind: "directive", type: TuiLabel, selector: "label[tuiLabel]" }, { kind: "ngmodule", type: RecaptchaFormsModule }, { kind: "directive", type: i4$3.RecaptchaValueAccessorDirective, selector: "re-captcha[formControlName],re-captcha[formControl],re-captcha[ngModel]" }, { kind: "ngmodule", type: RecaptchaModule }, { kind: "component", type: i4$3.RecaptchaComponent, selector: "re-captcha", inputs: ["id", "siteKey", "theme", "type", "size", "tabIndex", "badge", "errorMode"], outputs: ["resolved", "error", "errored"], exportAs: ["reCaptcha"] }, { kind: "directive", type: TuiLink, selector: "a[tuiLink], button[tuiLink]", inputs: ["pseudo"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: TuiTextareaModule }, { kind: "component", type: i3.TuiTextareaComponent, selector: "tui-textarea", inputs: ["rows", "maxLength", "expandable"] }, { kind: "directive", type: i3.TuiTextareaDirective, selector: "tui-textarea" }, { kind: "component", type: TuiCheckbox, selector: "input[type=\"checkbox\"][tuiCheckbox]", inputs: ["size"] }, { kind: "directive", type: TuiTitle, selector: "[tuiTitle]", inputs: ["tuiTitle"] }, { kind: "component", type: i2$1.TuiFile, selector: "tui-file,a[tuiFile],button[tuiFile]", inputs: ["file", "state", "size", "showDelete", "showSize", "leftContent"], outputs: ["remove"] }, { kind: "component", type: i2$1.TuiInputFiles, selector: "label[tuiInputFiles]" }, { kind: "component", type: i2$1.TuiFilesComponent, selector: "tui-files", inputs: ["max", "expanded"], outputs: ["expandedChange"] }, { kind: "pipe", type: i2$1.TuiFileRejectedPipe, name: "tuiFileRejected" }, { kind: "directive", type: i2$1.TuiInputFilesDirective, selector: "input[tuiInputFiles]", outputs: ["reject"] }, { kind: "component", type: TuiInputPhoneInternational, selector: "input[tuiInputPhoneInternational]", inputs: ["countrySearch", "countries", "countryIsoCode"], outputs: ["countryIsoCodeChange"] }, { kind: "component", type: i1$2.TuiTextfieldComponent, selector: "tui-textfield:not([multi])" }, { kind: "pipe", type: TuiSortCountriesPipe, name: "tuiSortCountries" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
12921
12617
  }
12922
12618
  __decorate([
12923
12619
  tuiPure
@@ -12937,7 +12633,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
12937
12633
  TuiButton,
12938
12634
  TuiButtonLoading,
12939
12635
  TuiLabel,
12940
- ScSmartCaptchaComponent,
12636
+ RecaptchaFormsModule,
12637
+ RecaptchaModule,
12941
12638
  TuiLink,
12942
12639
  NgIf,
12943
12640
  TuiTextareaModule,
@@ -12947,7 +12644,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
12947
12644
  TuiInputPhoneInternational,
12948
12645
  ...TuiTextfield,
12949
12646
  TuiSortCountriesPipe,
12950
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let fieldsList = fields();\n<form\n *ngIf=\"fieldsList.length > 0\"\n [formGroup]=\"form\"\n (ngSubmit)=\"onSubmit.next()\"\n class=\"flex flex-col justify-between gap-4\"\n>\n <!-- \u0424\u0418\u041E -->\n <label\n *ngIf=\"fieldsList.includes('name')\"\n tuiLabel\n >\n \u0424\u0418\u041E\n <tui-input formControlName=\"name\"> \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0424.\u0418.\u041E. </tui-input>\n <tui-error\n formControlName=\"name\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0422\u0435\u043B\u0435\u0444\u043E\u043D -->\n @if (fieldsList.includes('phone')) {\n <label tuiLabel>\n \u0422\u0435\u043B\u0435\u0444\u043E\u043D\n <tui-textfield>\n <input\n formControlName=\"phone\"\n tuiInputPhoneInternational\n [countrySearch]=\"true\"\n [countries]=\"(countries | tuiSortCountries | async) || []\"\n autocomplete=\"phone\"\n />\n </tui-textfield>\n <tui-error\n formControlName=\"phone\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <label\n *ngIf=\"fieldsList.includes('isShouldUseMessenger') && form.controls.phone.value && isValidPhoneNumberForMessenger(form.controls.phone.value)\"\n tuiLabel\n >\n <input\n formControlName=\"isShouldUseMessenger\"\n tuiCheckbox\n type=\"checkbox\"\n />\n <span tuiTitle> \u041D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043C\u0435\u0441\u0441\u0435\u043D\u0434\u0436\u0435\u0440\u0430\u0445, \u0430 \u043D\u0435 \u0437\u0432\u043E\u043D\u0438\u0442\u044C </span>\n </label>\n }\n <!-- \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B -->\n <label\n *ngIf=\"fieldsList.includes('email')\"\n tuiLabel\n >\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <tui-input formControlName=\"email\">\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <sc-suggestion-field\n *tuiDataList\n [type]=\"suggestionType.email\"\n />\n </tui-input>\n <tui-error\n formControlName=\"email\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 -->\n <label\n *ngIf=\"fieldsList.includes('message')\"\n tuiLabel\n >\n \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439\n <tui-textarea formControlName=\"message\"> \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 </tui-textarea>\n <tui-error\n formControlName=\"message\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0424\u0430\u0439\u043B\u044B -->\n <div\n *ngIf=\"fieldsList.includes('files')\"\n class=\"flex flex-col gap-1\"\n >\n <label tuiInputFiles>\n <input\n #validator=\"tuiInputFilesValidator\"\n accept=\".doc,.docx,.pdf,image/*\"\n tuiInputFiles\n [formControl]=\"loadedFile\"\n [multiple]=\"true\"\n (reject)=\"onReject($event)\"\n />\n </label>\n\n <tui-error\n *ngIf=\"loadedFile.invalid\"\n [error]=\"['maxLength'] | tuiFieldError | async\"\n [formControl]=\"loadedFile\"\n />\n\n @let accepted = accepted$ | async;\n <tui-files\n *ngIf=\"accepted?.length || rejected.length\"\n class=\"tui-space_top-1\"\n >\n <tui-file\n *ngFor=\"let file of accepted\"\n [file]=\"file\"\n (remove)=\"onRemove(file)\"\n />\n <tui-file\n *ngFor=\"let file of rejected\"\n state=\"error\"\n [file]=\"(file | tuiFileRejected: validator | async) || file\"\n (remove)=\"onRemove(file)\"\n />\n </tui-files>\n </div>\n\n <!-- \u041A\u0430\u043F\u0447\u0430 -->\n @if (form.get('recaptcha'); as recaptcha) {\n <div\n class=\"mb-3 max-h-[7.5rem] overflow-hidden duration-500\"\n [ngClass]=\"{ '!max-h-0 !-m-2': recaptcha.valid }\"\n [attr.inert]=\"recaptcha.valid ? '' : null\"\n >\n <sc-smart-captcha formControlName=\"recaptcha\" />\n </div>\n @if (recaptcha.getError('serverResponse'); as serverErrors) {\n <tui-error [error]=\"serverErrors.join(' ')\" />\n }\n }\n\n <!-- \u042D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F -->\n <div class=\"flex flex-wrap items-center gap-3\">\n <button\n tuiButton\n [disabled]=\"form.invalid\"\n [loading]=\"!!(loading$ | async)\"\n type=\"submit\"\n iconStart=\"@tui.sc.send\"\n class=\"self-center\"\n >\n \u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C\n </button>\n <div class=\"grow basis-60 text-body-s\">\n \u041D\u0430\u0436\u0438\u043C\u0430\u044F \u043D\u0430 \u043A\u043D\u043E\u043F\u043A\u0443, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441\n <button\n tuiLink\n [pseudo]=\"true\"\n type=\"button\"\n (click)=\"context?.data?.onClickOfferHandler(); clickOffer.emit()\"\n >\n \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438\n </button>\n </div>\n </div>\n</form>\n" }]
12647
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let fieldsList = fields();\n<form\n *ngIf=\"fieldsList.length > 0\"\n [formGroup]=\"form\"\n (ngSubmit)=\"onSubmit.next()\"\n class=\"flex flex-col justify-between gap-4\"\n>\n <!-- \u0424\u0418\u041E -->\n <label\n *ngIf=\"fieldsList.includes('name')\"\n tuiLabel\n >\n \u0424\u0418\u041E\n <tui-input formControlName=\"name\"> \u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u0412\u0430\u0448\u0438 \u0424.\u0418.\u041E. </tui-input>\n <tui-error\n formControlName=\"name\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0422\u0435\u043B\u0435\u0444\u043E\u043D -->\n @if (fieldsList.includes('phone')) {\n <label tuiLabel>\n \u0422\u0435\u043B\u0435\u0444\u043E\u043D\n <tui-textfield>\n <input\n formControlName=\"phone\"\n tuiInputPhoneInternational\n [countrySearch]=\"true\"\n [countries]=\"(countries | tuiSortCountries | async) || []\"\n autocomplete=\"phone\"\n />\n </tui-textfield>\n <tui-error\n formControlName=\"phone\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <label\n *ngIf=\"fieldsList.includes('isShouldUseMessenger') && form.controls.phone.value && isValidPhoneNumberForMessenger(form.controls.phone.value)\"\n tuiLabel\n >\n <input\n formControlName=\"isShouldUseMessenger\"\n tuiCheckbox\n type=\"checkbox\"\n />\n <span tuiTitle> \u041D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0432 \u043C\u0435\u0441\u0441\u0435\u043D\u0434\u0436\u0435\u0440\u0430\u0445, \u0430 \u043D\u0435 \u0437\u0432\u043E\u043D\u0438\u0442\u044C </span>\n </label>\n }\n <!-- \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B -->\n <label\n *ngIf=\"fieldsList.includes('email')\"\n tuiLabel\n >\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <tui-input formControlName=\"email\">\n \u0410\u0434\u0440\u0435\u0441 \u044D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u043E\u0439 \u043F\u043E\u0447\u0442\u044B\n <sc-suggestion-field\n *tuiDataList\n [type]=\"suggestionType.email\"\n />\n </tui-input>\n <tui-error\n formControlName=\"email\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 -->\n <label\n *ngIf=\"fieldsList.includes('message')\"\n tuiLabel\n >\n \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439\n <tui-textarea formControlName=\"message\"> \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 </tui-textarea>\n <tui-error\n formControlName=\"message\"\n [error]=\"[] | tuiFieldError | async\"\n />\n </label>\n\n <!-- \u0424\u0430\u0439\u043B\u044B -->\n <div\n *ngIf=\"fieldsList.includes('files')\"\n class=\"flex flex-col gap-1\"\n >\n <label tuiInputFiles>\n <input\n #validator=\"tuiInputFilesValidator\"\n accept=\".doc,.docx,.pdf,image/*\"\n tuiInputFiles\n [formControl]=\"loadedFile\"\n [multiple]=\"true\"\n (reject)=\"onReject($event)\"\n />\n </label>\n\n <tui-error\n *ngIf=\"loadedFile.invalid\"\n [error]=\"['maxLength'] | tuiFieldError | async\"\n [formControl]=\"loadedFile\"\n />\n\n @let accepted = accepted$ | async;\n <tui-files\n *ngIf=\"accepted?.length || rejected.length\"\n class=\"tui-space_top-1\"\n >\n <tui-file\n *ngFor=\"let file of accepted\"\n [file]=\"file\"\n (remove)=\"onRemove(file)\"\n />\n <tui-file\n *ngFor=\"let file of rejected\"\n state=\"error\"\n [file]=\"(file | tuiFileRejected: validator | async) || file\"\n (remove)=\"onRemove(file)\"\n />\n </tui-files>\n </div>\n\n <!-- recaptcha -->\n @if (form.get('recaptcha')) {\n <div\n class=\"mb-3 max-h-20 overflow-hidden duration-500\"\n [ngClass]=\"{ '!max-h-0 !-m-2': form.get('recaptcha')?.valid }\"\n >\n <re-captcha formControlName=\"recaptcha\" />\n </div>\n }\n\n <!-- \u042D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u044F -->\n <div class=\"flex flex-wrap items-center gap-3\">\n <button\n tuiButton\n [disabled]=\"form.invalid\"\n [loading]=\"!!(loading$ | async)\"\n type=\"submit\"\n iconStart=\"@tui.sc.send\"\n class=\"self-center\"\n >\n \u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C\n </button>\n <div class=\"grow basis-60 text-body-s\">\n \u041D\u0430\u0436\u0438\u043C\u0430\u044F \u043D\u0430 \u043A\u043D\u043E\u043F\u043A\u0443, \u0432\u044B \u0441\u043E\u0433\u043B\u0430\u0448\u0430\u0435\u0442\u0435\u0441\u044C \u0441\n <button\n tuiLink\n [pseudo]=\"true\"\n type=\"button\"\n (click)=\"context?.data?.onClickOfferHandler(); clickOffer.emit()\"\n >\n \u041F\u043E\u043B\u0438\u0442\u0438\u043A\u043E\u0439 \u043A\u043E\u043D\u0444\u0438\u0434\u0435\u043D\u0446\u0438\u0430\u043B\u044C\u043D\u043E\u0441\u0442\u0438\n </button>\n </div>\n </div>\n</form>\n" }]
12951
12648
  }], ctorParameters: () => [], propDecorators: { isValidPhoneNumberForMessenger: [] } });
12952
12649
 
12953
12650
  /**
@@ -13534,5 +13231,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
13534
13231
  * Generated bundle index. Do not edit.
13535
13232
  */
13536
13233
 
13537
- export { AbstractScPriceCard, AuthMethod, CURRENT_COUNTRY_ID, CostWithDiscountComponent, FilesAndDocumentsComponent, FilesAndDocumentsModule, FinishDateTimeTransformerDirective, IDLE_ITEM_STATE, IS_DEFAULT_COUNTRY, MAX_FILES_IN_FORM_INPUT, SC_ALLOW_SELECT_TERMINATED, SC_BANNER_DURATION, SC_BLOCK_INCOMPLETE_ADDRESS, SC_CATALOG_FILTER_PREVIEWS, SC_CATALOG_PRODUCTS_FILTERS, SC_CATALOG_SHOW_PRODUCTS_RECURSIVELY, SC_DATE_FORMATTER, SC_DEBOUNCE_TIME_DEFAULT, SC_DIALOG_SERVICE_TOKEN, SC_ERROR_CHANGE_HANDLER, SC_FAQ_GROUP_QUERY_PARAM, SC_FAQ_QUESTION_ANCHOR_PREFIX, SC_HELP_NOTIFICATION_CLOSE, SC_HELP_NOTIFICATION_LIMIT, SC_HIDDEN_PRINT_ELEMENTS, SC_MANAGER_QR_HANDLER, SC_NOTIFY_WHEN_IN_STOCK_REQUIRED_FIELDS, SC_ORDER_FORM_CONFIG, SC_ORDER_OPTIONS, SC_PAGE_SIZE_OPTIONS$1 as SC_PAGE_SIZE_OPTIONS, SC_SHOW_HELP_NOTIFICATION_IN_PHONE_INPUT, SC_SMART_CAPTCHA_LOAD_TIMEOUT, SC_SMART_CAPTCHA_SETTINGS, SC_USER_CITY_INFO, SC_USER_INFO, SC_USER_PROVIDERS, SC_VERIFICATION_CODE_TIMEOUT, ScAccordionComponent, ScAccordionContentDirective, ScAccordionModule, ScAddContactDialogComponent, ScAddContragentBankAccountsDialogComponent, ScAddContragentDialogComponent, ScAddDeliveryAddressDialogComponent, ScAddOrEditingCartItemDialogComponent, ScAddOrEditingCartItemFormComponent, ScAddressQualityDirective, ScAddressQualityService, ScAddressesSelectionFieldComponent, ScAuthModule, ScBannerComponent, ScBannerModule, ScBrandsListComponent, ScBrandsListModule, ScCartAddProductsFromCsvDialogComponent, ScCatalogFilterCollapsibleComponent, ScCatalogFiltersComponent, ScCatalogModule, ScCategoryCardComponent, ScConfirmAlertComponent, ScContactsAccordionComponent, ScContactsModule, ScContragentsAccordionComponent, ScContragentsAccordionItemComponent, ScContragentsModule, ScDeliveryAddressAccordionComponent, ScDeliveryAddressAccordionItemComponent, ScDeliveryAddressModule, ScDownloadPriceListComponent, ScDraftComponent, ScDraftExpirationClockService, ScDraftListHelper, ScDraftListUpdatesService, ScEmailLinkDirective, ScErrorBlockStatusComponent, ScErrorHandlerComponent, ScFavoriteButtonComponent, ScFeedbackFormComponent, ScFocusFirstInvalidFieldDirective, ScFormFieldsModule, ScFormatDatePipe, ScFrequentlyAskedQuestionsComponent, ScFrequentlyAskedQuestionsGroupSelectorComponent, ScFrequentlyAskedQuestionsWithGroupsComponent, ScGratitudeComponent, ScHelpNotificationService, ScHoverImageCarouselComponent, ScInputQuantityComponent, ScLinks, ScManagerCardComponent, ScManagerCardPushComponent, ScNewContactFormComponent, ScNewContragentBankAccountsFormComponent, ScNewContragentFormComponent, ScNewOrderItemsComponent, ScNewsCardComponent, ScNewsCardSkeletonComponent, ScNewsListComponent, ScNewsModule, ScNextInputFocusDirective, ScNextInputFocusModule, ScNoindexDirective, ScNoindexWrapperComponent, ScNotifyWhenInStockDialogComponent, ScOrderAccessorDirective, ScOrderFormComponent, ScOrderItemComponent, ScOrderItemsListByStockComponent, ScOrderItemsListComponent, ScOrderItemsListWithActionsComponent, ScOrderModule, ScPaginationLinksComponent, ScPaymentStatusComponent, ScPersonalDataProcessingPolicyComponent, ScPhoneFormatPipe, ScPreviewSampleComponent, ScPreviewSampleModule, ScPreviewSamplesMosquitoComponent, ScPriceCardComponent, ScPriceCardInlineComponent, ScPriceHistoryComponent, ScPriceListPaginationComponent, ScPriceWarehouseStockComponent, ScPrintDirective, ScPrintService, ScPrivacyPolicyComponent, ScProductInAllWarehousesPipe, ScProfileAccordionsContentComponent, ScProfileModule, ScProfstroyActualizationPanelComponent, ScProfstroyBadgeComponent, ScProfstroyDraftBadgesComponent, ScProfstroyDraftCreateDialogComponent, ScProfstroyDraftHelper, ScProfstroyDraftState, ScPublicOfferComponent, ScQRCodeDialogComponent, ScQRCodeModule, ScResetUserPasswordComponent, ScResourcePreviewComponent, ScSandwichComponent, ScSandwichM2Component, ScSandwichM2SkeletonComponent, ScSandwichSkeletonComponent, ScScriptsService, ScSelectOnFocusinDirective, ScSeoTagsComponent, ScShareButtonComponent, ScShareDialogComponent, ScShareMessengersLinksComponent, ScShareService, ScSignInFormByEmailComponent, ScSignInFormByPhoneComponent, ScSignInFormComponent, ScSignUpFormComponent, ScSimpleSignUpFormComponent, ScSmartCaptchaComponent, ScSmartCaptchaLoaderService, ScSuggestionFieldComponent, ScTelLinkDirective, ScTerminalLinkDirective, ScUpdateUserInfoDialogComponent, ScUserManagersComponent, ScUserModule, ScUserPhoneApproveDialogComponent, ScVerificationModule, ScVerificationPhoneCheckFormComponent, TreeDirective, TreeIconService, TreeLoaderService, TreeTopDirective, phoneValidator, scAtLeastOneRequiredValidator, scBicValidator, scClientUiIconsName, scCorrespondentAccountValidator, scGetCurrentRoute, scGetFaqGroupQueryParams, scGetFaqQuestionAnchor, scGetFaqQuestionIdFromAnchor, scPasswordConfirmMatchingValidator, stepValidator, tuiDateValueTransformerDefaultProvider };
13234
+ export { AbstractScPriceCard, AuthMethod, CURRENT_COUNTRY_ID, CostWithDiscountComponent, FilesAndDocumentsComponent, FilesAndDocumentsModule, FinishDateTimeTransformerDirective, IDLE_ITEM_STATE, IS_DEFAULT_COUNTRY, MAX_FILES_IN_FORM_INPUT, SC_ALLOW_SELECT_TERMINATED, SC_BANNER_DURATION, SC_BLOCK_INCOMPLETE_ADDRESS, SC_CATALOG_FILTER_PREVIEWS, SC_CATALOG_PRODUCTS_FILTERS, SC_CATALOG_SHOW_PRODUCTS_RECURSIVELY, SC_DATE_FORMATTER, SC_DEBOUNCE_TIME_DEFAULT, SC_DIALOG_SERVICE_TOKEN, SC_ERROR_CHANGE_HANDLER, SC_FAQ_GROUP_QUERY_PARAM, SC_FAQ_QUESTION_ANCHOR_PREFIX, SC_HELP_NOTIFICATION_CLOSE, SC_HELP_NOTIFICATION_LIMIT, SC_HIDDEN_PRINT_ELEMENTS, SC_MANAGER_QR_HANDLER, SC_NOTIFY_WHEN_IN_STOCK_REQUIRED_FIELDS, SC_ORDER_FORM_CONFIG, SC_ORDER_OPTIONS, SC_PAGE_SIZE_OPTIONS$1 as SC_PAGE_SIZE_OPTIONS, SC_SHOW_HELP_NOTIFICATION_IN_PHONE_INPUT, SC_USER_CITY_INFO, SC_USER_INFO, SC_USER_PROVIDERS, SC_VERIFICATION_CODE_TIMEOUT, ScAccordionComponent, ScAccordionContentDirective, ScAccordionModule, ScAddContactDialogComponent, ScAddContragentBankAccountsDialogComponent, ScAddContragentDialogComponent, ScAddDeliveryAddressDialogComponent, ScAddOrEditingCartItemDialogComponent, ScAddOrEditingCartItemFormComponent, ScAddressQualityDirective, ScAddressQualityService, ScAddressesSelectionFieldComponent, ScAuthModule, ScBannerComponent, ScBannerModule, ScBrandsListComponent, ScBrandsListModule, ScCartAddProductsFromCsvDialogComponent, ScCatalogFilterCollapsibleComponent, ScCatalogFiltersComponent, ScCatalogModule, ScCategoryCardComponent, ScConfirmAlertComponent, ScContactsAccordionComponent, ScContactsModule, ScContragentsAccordionComponent, ScContragentsAccordionItemComponent, ScContragentsModule, ScDeliveryAddressAccordionComponent, ScDeliveryAddressAccordionItemComponent, ScDeliveryAddressModule, ScDownloadPriceListComponent, ScDraftComponent, ScDraftExpirationClockService, ScDraftListHelper, ScDraftListUpdatesService, ScEmailLinkDirective, ScErrorBlockStatusComponent, ScErrorHandlerComponent, ScFavoriteButtonComponent, ScFeedbackFormComponent, ScFocusFirstInvalidFieldDirective, ScFormFieldsModule, ScFormatDatePipe, ScFrequentlyAskedQuestionsComponent, ScFrequentlyAskedQuestionsGroupSelectorComponent, ScFrequentlyAskedQuestionsWithGroupsComponent, ScGratitudeComponent, ScHelpNotificationService, ScHoverImageCarouselComponent, ScInputQuantityComponent, ScLinks, ScManagerCardComponent, ScManagerCardPushComponent, ScNewContactFormComponent, ScNewContragentBankAccountsFormComponent, ScNewContragentFormComponent, ScNewOrderItemsComponent, ScNewsCardComponent, ScNewsCardSkeletonComponent, ScNewsListComponent, ScNewsModule, ScNextInputFocusDirective, ScNextInputFocusModule, ScNoindexDirective, ScNoindexWrapperComponent, ScNotifyWhenInStockDialogComponent, ScOrderAccessorDirective, ScOrderFormComponent, ScOrderItemComponent, ScOrderItemsListByStockComponent, ScOrderItemsListComponent, ScOrderItemsListWithActionsComponent, ScOrderModule, ScPaginationLinksComponent, ScPaymentStatusComponent, ScPersonalDataProcessingPolicyComponent, ScPhoneFormatPipe, ScPreviewSampleComponent, ScPreviewSampleModule, ScPreviewSamplesMosquitoComponent, ScPriceCardComponent, ScPriceCardInlineComponent, ScPriceHistoryComponent, ScPriceListPaginationComponent, ScPriceWarehouseStockComponent, ScPrintDirective, ScPrintService, ScPrivacyPolicyComponent, ScProductInAllWarehousesPipe, ScProfileAccordionsContentComponent, ScProfileModule, ScProfstroyActualizationPanelComponent, ScProfstroyBadgeComponent, ScProfstroyDraftBadgesComponent, ScProfstroyDraftCreateDialogComponent, ScProfstroyDraftHelper, ScProfstroyDraftState, ScPublicOfferComponent, ScQRCodeDialogComponent, ScQRCodeModule, ScResetUserPasswordComponent, ScResourcePreviewComponent, ScSandwichComponent, ScSandwichM2Component, ScSandwichM2SkeletonComponent, ScSandwichSkeletonComponent, ScSelectOnFocusinDirective, ScSeoTagsComponent, ScShareButtonComponent, ScShareDialogComponent, ScShareMessengersLinksComponent, ScShareService, ScSignInFormByEmailComponent, ScSignInFormByPhoneComponent, ScSignInFormComponent, ScSignUpFormComponent, ScSimpleSignUpFormComponent, ScSuggestionFieldComponent, ScTelLinkDirective, ScTerminalLinkDirective, ScUpdateUserInfoDialogComponent, ScUserManagersComponent, ScUserModule, ScUserPhoneApproveDialogComponent, ScVerificationModule, ScVerificationPhoneCheckFormComponent, TreeDirective, TreeIconService, TreeLoaderService, TreeTopDirective, cleanupRecaptchaArtifacts, phoneValidator, scAtLeastOneRequiredValidator, scBicValidator, scClientUiIconsName, scCorrespondentAccountValidator, scGetCurrentRoute, scGetFaqGroupQueryParams, scGetFaqQuestionAnchor, scGetFaqQuestionIdFromAnchor, scPasswordConfirmMatchingValidator, stepValidator, tuiDateValueTransformerDefaultProvider };
13538
13235
  //# sourceMappingURL=snabcentr-client-ui.mjs.map