@snabcentr/client-ui 4.16.0 → 4.17.0
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.
- package/esm2022/feedback/feedback-form/sc-feedback-form.component.mjs +11 -21
- package/esm2022/providers/index.mjs +1 -2
- package/esm2022/public-api.mjs +2 -1
- package/esm2022/samples/sc-sample.module.mjs +3 -10
- package/esm2022/services/index.mjs +2 -1
- package/esm2022/services/sc-scripts.service.mjs +106 -0
- package/esm2022/smart-captcha/index.mjs +5 -0
- package/esm2022/smart-captcha/interfaces/index.mjs +6 -0
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-api.mjs +2 -0
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-event.mjs +2 -0
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-language.mjs +2 -0
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-render-params.mjs +2 -0
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-settings.mjs +2 -0
- package/esm2022/smart-captcha/interfaces/sc-smart-captcha-window.mjs +2 -0
- package/esm2022/smart-captcha/sc-smart-captcha.component.mjs +167 -0
- package/esm2022/smart-captcha/services/index.mjs +2 -0
- package/esm2022/smart-captcha/services/sc-smart-captcha-loader.service.mjs +87 -0
- package/esm2022/smart-captcha/tokens/index.mjs +3 -0
- package/esm2022/smart-captcha/tokens/sc-smart-captcha-load-timeout.token.mjs +8 -0
- package/esm2022/smart-captcha/tokens/sc-smart-captcha-settings.token.mjs +6 -0
- package/feedback/feedback-form/sc-feedback-form.component.d.ts +1 -1
- package/fesm2022/snabcentr-client-ui.mjs +367 -64
- package/fesm2022/snabcentr-client-ui.mjs.map +1 -1
- package/package.json +1 -2
- package/providers/index.d.ts +0 -1
- package/public-api.d.ts +1 -0
- package/release_notes.tmp +3 -3
- package/samples/sc-sample.module.d.ts +1 -2
- package/services/index.d.ts +1 -0
- package/services/sc-scripts.service.d.ts +51 -0
- package/smart-captcha/index.d.ts +4 -0
- package/smart-captcha/interfaces/index.d.ts +5 -0
- package/smart-captcha/interfaces/sc-smart-captcha-api.d.ts +36 -0
- package/smart-captcha/interfaces/sc-smart-captcha-event.d.ts +4 -0
- package/smart-captcha/interfaces/sc-smart-captcha-language.d.ts +4 -0
- package/smart-captcha/interfaces/sc-smart-captcha-render-params.d.ts +16 -0
- package/smart-captcha/interfaces/sc-smart-captcha-settings.d.ts +16 -0
- package/smart-captcha/interfaces/sc-smart-captcha-window.d.ts +14 -0
- package/smart-captcha/sc-smart-captcha.component.d.ts +92 -0
- package/smart-captcha/services/index.d.ts +1 -0
- package/smart-captcha/services/sc-smart-captcha-loader.service.d.ts +50 -0
- package/smart-captcha/tokens/index.d.ts +2 -0
- package/smart-captcha/tokens/sc-smart-captcha-load-timeout.token.d.ts +5 -0
- package/smart-captcha/tokens/sc-smart-captcha-settings.token.d.ts +6 -0
- package/styles/tailwind/tailwind.scss +40 -2
- package/esm2022/providers/cleanup-recaptcha-artifacts.mjs +0 -30
- package/providers/cleanup-recaptcha-artifacts.d.ts +0 -7
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, inject, Injectable, NgZone, signal, EventEmitter, ChangeDetectorRef, Directive, Input, Output, 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, RendererFactory2, signal, EventEmitter, ChangeDetectorRef, Directive, Input, Output, 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, ScAuthService, SEARCH_TERM, ScUnitsHelper, ScImageHelper, SC_PATH_IMAGE_NOT_FOUND, ScImage, ScPhoneService, ScUserMetrikaService, ScUserMetrikaGoalsEnum, IS_RUNNING_ON_TERMINAL, ScVCardService, ScVerificationService, ScISuggestionType, SC_MIN_LENGTH_SEARCH_TERM, ScConvertersService, ScNumberHelper, ScOpfList, ScReferencesService, ScContragentService, ScBannerService, ScMediaImageTransformerPipe, ScCartService, ScUploadedFile, 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, ScDeliveryAddressService, ScOrdersService, ScUIService, SC_USER_INFO as SC_USER_INFO$1, ScPaymentType, ScDeliveryType, TERMINAL_PROVIDERS, ScOrderDraftsService, ScRouteKeys, ScSeoService, scOrderIsLoaded, SC_PAGE_QUERY_PARAM, ScFrequentlyAskedQuestionsService, SchemaOrgFactory, scGetPageQueryParamChanges, ScNewsService, SC_COMPANY_INFO, ScFeedbackService } from '@snabcentr/client-core';
|
|
4
|
+
import { ScContactsService, ScUserService, ScLocationsService, IS_BROWSER, ScAuthService, SEARCH_TERM, ScUnitsHelper, ScImageHelper, SC_PATH_IMAGE_NOT_FOUND, ScImage, ScPhoneService, ScUserMetrikaService, ScUserMetrikaGoalsEnum, IS_RUNNING_ON_TERMINAL, ScVCardService, ScVerificationService, ScISuggestionType, SC_MIN_LENGTH_SEARCH_TERM, ScConvertersService, ScNumberHelper, ScOpfList, ScReferencesService, ScContragentService, ScBannerService, ScMediaImageTransformerPipe, ScCartService, ScUploadedFile, 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, ScDeliveryAddressService, ScOrdersService, ScUIService, SC_USER_INFO as SC_USER_INFO$1, ScPaymentType, ScDeliveryType, TERMINAL_PROVIDERS, ScOrderDraftsService, 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, Subject, filter, tap, catchError, finalize, startWith, share, timer, scan, takeWhile, endWith, distinctUntilChanged, debounceTime, throwError, combineLatest,
|
|
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, fromEvent, animationFrames, take, takeUntil, defer, timeout, ignoreElements } 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, tuiControlValue, tuiIsPresent, tuiMarkControlAsTouchedAndValidate, tuiIsFalsy, TuiAutoFocus, TuiRepeatTimes, TuiSwipeService, TUI_SWIPE_OPTIONS, TuiHovered, TuiDayRange, TuiMonth, tuiPure, tuiProvide, TuiValidationError, TUI_WINDOW_SIZE, tuiClamp, TUI_TRUE_HANDLER } from '@taiga-ui/cdk';
|
|
10
|
+
import { TuiDay, TuiTime, TuiValueTransformer, TUI_IS_MOBILE, tuiControlValue, tuiIsPresent, tuiMarkControlAsTouchedAndValidate, tuiIsFalsy, TuiAutoFocus, TuiRepeatTimes, TuiSwipeService, TUI_SWIPE_OPTIONS, TuiHovered, TuiDayRange, TuiMonth, tuiPure, tuiProvide, TuiValidationError, TUI_WINDOW_SIZE, tuiClamp, tuiZonefree, 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, TuiFiles, TuiChip, TuiInputNumber, TuiBadge, TuiTooltip, TuiHighlight, TuiLineClamp, TuiFade, TuiRange, tuiInputNumberOptionsProvider, TuiDataListWrapperComponent, TuiChevron, TuiSelect, TuiInputSlider, TuiTreeService, TuiTreeItemContent, TUI_TREE_START, TUI_TREE_CONTENT, TUI_TREE_LOADING, TUI_TREE_LOADER, TuiTree, TuiPreviewDialogService, tuiFilesAccepted, TuiInputFiles, TuiInputFilesDirective, TuiFilesComponent, TuiFile, TuiFileRejectedPipe, TUI_CONFIRM, 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';
|
|
13
15
|
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
|
14
16
|
import * as i1$1 from '@angular/forms';
|
|
15
|
-
import { FormControl, FormGroupDirective, NgControl, FormGroup, Validators, FormArray, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
17
|
+
import { FormControl, FormGroupDirective, NgControl, FormGroup, Validators, FormArray, FormsModule, ReactiveFormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
|
|
16
18
|
import * as i1$2 from '@taiga-ui/core';
|
|
17
19
|
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, TuiDataListComponent, TuiOption, TuiAlertService, TuiIconPipe, TUI_BUTTON_OPTIONS, TUI_BUTTON_DEFAULT_OPTIONS, TUI_SPIN_ICONS, TuiSurface, tuiFadeIn } from '@taiga-ui/core';
|
|
18
20
|
import { isValidPhoneNumber } from 'libphonenumber-js/max';
|
|
@@ -24,8 +26,6 @@ import { isNil, isUndefined, isObject, isArray, isString } from 'lodash-es';
|
|
|
24
26
|
import * as i5 from '@taiga-ui/core/components/label';
|
|
25
27
|
import * as i8 from '@maskito/angular';
|
|
26
28
|
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,8 +55,6 @@ 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';
|
|
60
58
|
|
|
61
59
|
/**
|
|
62
60
|
* Поток для закрытия уведомлений помощи.
|
|
@@ -349,36 +347,6 @@ const SC_HIDDEN_PRINT_ELEMENTS = new InjectionToken('SC_HIDDEN_PRINT_ELEMENTS',
|
|
|
349
347
|
providedIn: 'root',
|
|
350
348
|
});
|
|
351
349
|
|
|
352
|
-
/**
|
|
353
|
-
* Селектор iframe reCAPTCHA.
|
|
354
|
-
*/
|
|
355
|
-
const RECAPTCHA_IFRAME_SELECTOR = 'iframe[src*="recaptcha"]';
|
|
356
|
-
/**
|
|
357
|
-
* Селектор хоста reCAPTCHA.
|
|
358
|
-
*/
|
|
359
|
-
const RECAPTCHA_HOST_SELECTOR = 're-captcha';
|
|
360
|
-
/**
|
|
361
|
-
* Освобождает ресурсы reCAPTCHA и удаляет осиротевшие iframe после смены маршрута.
|
|
362
|
-
*
|
|
363
|
-
* @param documentReference Объект документа.
|
|
364
|
-
* @param windowReference Объект окна браузера.
|
|
365
|
-
*/
|
|
366
|
-
function cleanupRecaptchaArtifacts(documentReference, windowReference) {
|
|
367
|
-
const windowWithRecaptcha = windowReference;
|
|
368
|
-
try {
|
|
369
|
-
windowWithRecaptcha.grecaptcha?.reset();
|
|
370
|
-
}
|
|
371
|
-
catch {
|
|
372
|
-
// Ошибки reCAPTCHA не должны блокировать навигацию.
|
|
373
|
-
}
|
|
374
|
-
documentReference.querySelectorAll(RECAPTCHA_IFRAME_SELECTOR).forEach((iframe) => {
|
|
375
|
-
if (iframe.closest(RECAPTCHA_HOST_SELECTOR)) {
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
iframe.remove();
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
|
|
382
350
|
/**
|
|
383
351
|
* Сервис по работе с печатью страницы.
|
|
384
352
|
*/
|
|
@@ -424,6 +392,107 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
424
392
|
}]
|
|
425
393
|
}] });
|
|
426
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Сервис для вставки в {@link Document} внешних и дополнительных скриптов.
|
|
397
|
+
*/
|
|
398
|
+
class ScScriptsService {
|
|
399
|
+
constructor() {
|
|
400
|
+
/**
|
|
401
|
+
* Объект {@link Document}, предоставляющий доступ к DOM страницы.
|
|
402
|
+
*/
|
|
403
|
+
this.document = inject(DOCUMENT);
|
|
404
|
+
/**
|
|
405
|
+
* Объект {@link Renderer2}, предоставляющий доступ к DOM страницы.
|
|
406
|
+
*/
|
|
407
|
+
this.renderer = inject(RendererFactory2).createRenderer(null, null);
|
|
408
|
+
/**
|
|
409
|
+
* Признак того, что скрипт выполняется в браузере.
|
|
410
|
+
*/
|
|
411
|
+
this.isBrowser = inject(IS_BROWSER);
|
|
412
|
+
/**
|
|
413
|
+
* {@link NgZone} для вставки скриптов вне зоны Angular.
|
|
414
|
+
*/
|
|
415
|
+
this.ngZone = inject(NgZone);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Вставляет в конец {@link Document.body} скрипты, заданные строками HTML, вне зоны Angular. Из каждой строки берётся первый `<script>`. На сервере ничего не делает.
|
|
419
|
+
* Принимает только доверенные строки из конфигурации приложения: строка разбирается как HTML и может выполнить код.
|
|
420
|
+
*
|
|
421
|
+
* @param scriptStrings Строки HTML скриптов.
|
|
422
|
+
*/
|
|
423
|
+
appendScripts(scriptStrings) {
|
|
424
|
+
if (!this.isBrowser) {
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
this.ngZone.runOutsideAngular(() => {
|
|
428
|
+
scriptStrings.forEach((scriptString) => {
|
|
429
|
+
const script = this.createScript(scriptString);
|
|
430
|
+
if (script) {
|
|
431
|
+
this.renderer.appendChild(this.document.body, script);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Загружает внешний скрипт: при подписке добавляет его в {@link Document.head}, после загрузки выдаёт элемент скрипта и завершается.
|
|
438
|
+
* Если скрипт не загрузился или подписка отменена раньше, удаляет его со страницы; удаление не отменяет загрузку и выполнение уже вставленного скрипта. На сервере завершается без загрузки.
|
|
439
|
+
*
|
|
440
|
+
* @param url Адрес скрипта.
|
|
441
|
+
*/
|
|
442
|
+
loadScript$(url) {
|
|
443
|
+
if (!this.isBrowser) {
|
|
444
|
+
return EMPTY;
|
|
445
|
+
}
|
|
446
|
+
return new Observable((subscriber) => {
|
|
447
|
+
const script = this.renderer.createElement('script');
|
|
448
|
+
let isLoaded = false;
|
|
449
|
+
const unlistenLoad = this.renderer.listen(script, 'load', () => {
|
|
450
|
+
isLoaded = true;
|
|
451
|
+
subscriber.next(script);
|
|
452
|
+
subscriber.complete();
|
|
453
|
+
});
|
|
454
|
+
const unlistenError = this.renderer.listen(script, 'error', () => {
|
|
455
|
+
subscriber.error(new Error(`Failed to load script ${url}`));
|
|
456
|
+
});
|
|
457
|
+
this.renderer.setProperty(script, 'src', url);
|
|
458
|
+
this.renderer.appendChild(this.document.head, script);
|
|
459
|
+
return () => {
|
|
460
|
+
unlistenLoad();
|
|
461
|
+
unlistenError();
|
|
462
|
+
if (!isLoaded) {
|
|
463
|
+
this.removeScript(script);
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Удаляет скрипт со страницы. При подключённых анимациях Angular узел удаляется при ближайшей проверке изменений.
|
|
470
|
+
*
|
|
471
|
+
* @param script Элемент скрипта.
|
|
472
|
+
*/
|
|
473
|
+
removeScript(script) {
|
|
474
|
+
this.renderer.removeChild(script.parentNode, script);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Создаёт {@link HTMLScriptElement} из строки HTML скрипта.
|
|
478
|
+
*
|
|
479
|
+
* @param scriptString Строка HTML скрипта.
|
|
480
|
+
*/
|
|
481
|
+
createScript(scriptString) {
|
|
482
|
+
const range = this.document.createRange();
|
|
483
|
+
const fragment = range.createContextualFragment(scriptString);
|
|
484
|
+
return fragment.querySelector('script');
|
|
485
|
+
}
|
|
486
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
487
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, providedIn: 'root' }); }
|
|
488
|
+
}
|
|
489
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScScriptsService, decorators: [{
|
|
490
|
+
type: Injectable,
|
|
491
|
+
args: [{
|
|
492
|
+
providedIn: 'root',
|
|
493
|
+
}]
|
|
494
|
+
}] });
|
|
495
|
+
|
|
427
496
|
/**
|
|
428
497
|
* Проверяет корректность введенного номера телефона.
|
|
429
498
|
*/
|
|
@@ -10548,18 +10617,14 @@ class ScPreviewSampleModule {
|
|
|
10548
10617
|
TuiHovered,
|
|
10549
10618
|
TuiButton,
|
|
10550
10619
|
TuiButtonLoading,
|
|
10551
|
-
TuiLabel,
|
|
10552
|
-
RecaptchaFormsModule,
|
|
10553
|
-
RecaptchaModule], exports: [ScPreviewSampleComponent] }); }
|
|
10620
|
+
TuiLabel], exports: [ScPreviewSampleComponent] }); }
|
|
10554
10621
|
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScPreviewSampleModule, imports: [CommonModule,
|
|
10555
10622
|
ReactiveFormsModule,
|
|
10556
10623
|
TuiError,
|
|
10557
10624
|
ScFormFieldsModule,
|
|
10558
10625
|
TuiInputModule,
|
|
10559
10626
|
TuiInputPhoneModule, i2$1.TuiCarouselComponent, TuiAvatar,
|
|
10560
|
-
TuiButtonLoading
|
|
10561
|
-
RecaptchaFormsModule,
|
|
10562
|
-
RecaptchaModule] }); }
|
|
10627
|
+
TuiButtonLoading] }); }
|
|
10563
10628
|
}
|
|
10564
10629
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScPreviewSampleModule, decorators: [{
|
|
10565
10630
|
type: NgModule,
|
|
@@ -10579,8 +10644,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
10579
10644
|
TuiButton,
|
|
10580
10645
|
TuiButtonLoading,
|
|
10581
10646
|
TuiLabel,
|
|
10582
|
-
RecaptchaFormsModule,
|
|
10583
|
-
RecaptchaModule,
|
|
10584
10647
|
],
|
|
10585
10648
|
exports: [ScPreviewSampleComponent],
|
|
10586
10649
|
}]
|
|
@@ -10600,6 +10663,255 @@ const scGetCurrentRoute = (route) => {
|
|
|
10600
10663
|
return currentRoute;
|
|
10601
10664
|
};
|
|
10602
10665
|
|
|
10666
|
+
/**
|
|
10667
|
+
* Токен времени ожидания загрузки скрипта Yandex SmartCaptcha в миллисекундах.
|
|
10668
|
+
*/
|
|
10669
|
+
const SC_SMART_CAPTCHA_LOAD_TIMEOUT = new InjectionToken('SC_SMART_CAPTCHA_LOAD_TIMEOUT', {
|
|
10670
|
+
factory: () => 20_000,
|
|
10671
|
+
});
|
|
10672
|
+
|
|
10673
|
+
/**
|
|
10674
|
+
* Сервис загрузки скрипта Yandex SmartCaptcha.
|
|
10675
|
+
*/
|
|
10676
|
+
class ScSmartCaptchaLoaderService {
|
|
10677
|
+
constructor() {
|
|
10678
|
+
/**
|
|
10679
|
+
* Сервис для вставки внешних скриптов.
|
|
10680
|
+
*/
|
|
10681
|
+
this.scriptsService = inject(ScScriptsService);
|
|
10682
|
+
/**
|
|
10683
|
+
* Окно браузера с API Yandex SmartCaptcha.
|
|
10684
|
+
*/
|
|
10685
|
+
this.window = inject(WA_WINDOW);
|
|
10686
|
+
/**
|
|
10687
|
+
* Признак того, что приложение запущено в браузере.
|
|
10688
|
+
*/
|
|
10689
|
+
this.isBrowser = inject(IS_BROWSER);
|
|
10690
|
+
/**
|
|
10691
|
+
* Время ожидания загрузки скрипта в миллисекундах.
|
|
10692
|
+
*/
|
|
10693
|
+
this.loadTimeout = inject(SC_SMART_CAPTCHA_LOAD_TIMEOUT);
|
|
10694
|
+
/**
|
|
10695
|
+
* Имя функции окна, которую скрипт вызывает после загрузки.
|
|
10696
|
+
*/
|
|
10697
|
+
this.onloadCallbackName = 'scSmartCaptchaOnload';
|
|
10698
|
+
/**
|
|
10699
|
+
* Адрес скрипта.
|
|
10700
|
+
*/
|
|
10701
|
+
this.scriptUrl = `https://smartcaptcha.cloud.yandex.ru/captcha.js?render=onload&onload=${this.onloadCallbackName}`;
|
|
10702
|
+
/**
|
|
10703
|
+
* Загрузка API, общая для всех виджетов. Скрипт загружается один раз; отписка и истечение ожидания у подписчика загрузку не прерывают, после ошибки следующая подписка загружает скрипт заново.
|
|
10704
|
+
*/
|
|
10705
|
+
this.loading$ = defer(() => this.load$()).pipe(shareReplay(1));
|
|
10706
|
+
/**
|
|
10707
|
+
* {@link Observable} API Yandex SmartCaptcha. Значения и ошибки приходят вне зоны Angular, ожидание первого значения ограничено {@link SC_SMART_CAPTCHA_LOAD_TIMEOUT}.
|
|
10708
|
+
*/
|
|
10709
|
+
this.api$ = this.loading$.pipe(timeout({ first: this.loadTimeout }), tuiZonefree());
|
|
10710
|
+
}
|
|
10711
|
+
/**
|
|
10712
|
+
* Возвращает API Yandex SmartCaptcha, при необходимости загружая скрипт. На сервере ничего не возвращает.
|
|
10713
|
+
*/
|
|
10714
|
+
load$() {
|
|
10715
|
+
if (!this.isBrowser) {
|
|
10716
|
+
return EMPTY;
|
|
10717
|
+
}
|
|
10718
|
+
if (this.window.smartCaptcha) {
|
|
10719
|
+
return of(this.window.smartCaptcha);
|
|
10720
|
+
}
|
|
10721
|
+
return merge(this.onload$(), this.scriptsService.loadScript$(this.scriptUrl).pipe(ignoreElements()));
|
|
10722
|
+
}
|
|
10723
|
+
/**
|
|
10724
|
+
* Ждёт вызова функции из параметра `onload` адреса скрипта и возвращает API, которое скрипт к этому моменту создал.
|
|
10725
|
+
*/
|
|
10726
|
+
onload$() {
|
|
10727
|
+
return new Observable((subscriber) => {
|
|
10728
|
+
this.window[this.onloadCallbackName] = () => {
|
|
10729
|
+
if (this.window.smartCaptcha) {
|
|
10730
|
+
subscriber.next(this.window.smartCaptcha);
|
|
10731
|
+
subscriber.complete();
|
|
10732
|
+
}
|
|
10733
|
+
else {
|
|
10734
|
+
subscriber.error(new Error('Yandex SmartCaptcha API is unavailable'));
|
|
10735
|
+
}
|
|
10736
|
+
};
|
|
10737
|
+
return () => {
|
|
10738
|
+
this.window[this.onloadCallbackName] = undefined;
|
|
10739
|
+
};
|
|
10740
|
+
});
|
|
10741
|
+
}
|
|
10742
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
10743
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, providedIn: 'root' }); }
|
|
10744
|
+
}
|
|
10745
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaLoaderService, decorators: [{
|
|
10746
|
+
type: Injectable,
|
|
10747
|
+
args: [{
|
|
10748
|
+
providedIn: 'root',
|
|
10749
|
+
}]
|
|
10750
|
+
}] });
|
|
10751
|
+
|
|
10752
|
+
/**
|
|
10753
|
+
* Токен настроек Yandex SmartCaptcha. Задаётся приложением.
|
|
10754
|
+
*/
|
|
10755
|
+
const SC_SMART_CAPTCHA_SETTINGS = new InjectionToken('SC_SMART_CAPTCHA_SETTINGS');
|
|
10756
|
+
|
|
10757
|
+
/* eslint-disable no-use-before-define */
|
|
10758
|
+
/**
|
|
10759
|
+
* Виджет Yandex SmartCaptcha. Значение поля ввода - токен прохождения проверки, `null` пока проверка не пройдена или токен истёк.
|
|
10760
|
+
*/
|
|
10761
|
+
class ScSmartCaptchaComponent {
|
|
10762
|
+
/**
|
|
10763
|
+
* Инициализирует экземпляр класса {@link ScSmartCaptchaComponent}.
|
|
10764
|
+
*/
|
|
10765
|
+
constructor() {
|
|
10766
|
+
/**
|
|
10767
|
+
* Контейнер, в котором отрисовывается виджет.
|
|
10768
|
+
*/
|
|
10769
|
+
this.container = viewChild.required('container');
|
|
10770
|
+
/**
|
|
10771
|
+
* Настройки Yandex SmartCaptcha.
|
|
10772
|
+
*/
|
|
10773
|
+
this.settings = inject(SC_SMART_CAPTCHA_SETTINGS);
|
|
10774
|
+
/**
|
|
10775
|
+
* Сервис загрузки скрипта Yandex SmartCaptcha.
|
|
10776
|
+
*/
|
|
10777
|
+
this.loader = inject(ScSmartCaptchaLoaderService);
|
|
10778
|
+
/**
|
|
10779
|
+
* {@link NgZone} для отрисовки виджета вне зоны Angular и возврата его событий в зону.
|
|
10780
|
+
*/
|
|
10781
|
+
this.ngZone = inject(NgZone);
|
|
10782
|
+
/**
|
|
10783
|
+
* Ссылка для автоматического управления уничтожением зависимостей.
|
|
10784
|
+
*/
|
|
10785
|
+
this.destroyRef = inject(DestroyRef);
|
|
10786
|
+
/**
|
|
10787
|
+
* Признак того, что капчу не удалось загрузить.
|
|
10788
|
+
*/
|
|
10789
|
+
this.hasError = signal(false);
|
|
10790
|
+
/**
|
|
10791
|
+
* Функции отписки от событий виджета.
|
|
10792
|
+
*/
|
|
10793
|
+
this.unsubscribers = [];
|
|
10794
|
+
/**
|
|
10795
|
+
* Обработчик изменения значения поля ввода.
|
|
10796
|
+
*/
|
|
10797
|
+
this.onChange = noop;
|
|
10798
|
+
/**
|
|
10799
|
+
* Обработчик касания поля ввода.
|
|
10800
|
+
*/
|
|
10801
|
+
this.onTouched = noop;
|
|
10802
|
+
afterNextRender(() => {
|
|
10803
|
+
this.load();
|
|
10804
|
+
});
|
|
10805
|
+
this.destroyRef.onDestroy(() => {
|
|
10806
|
+
this.destroyWidget();
|
|
10807
|
+
});
|
|
10808
|
+
}
|
|
10809
|
+
/** @inheritDoc */
|
|
10810
|
+
writeValue(token) {
|
|
10811
|
+
const { api, widgetId } = this;
|
|
10812
|
+
if (!token && api && widgetId !== undefined) {
|
|
10813
|
+
this.ngZone.runOutsideAngular(() => {
|
|
10814
|
+
api.reset(widgetId);
|
|
10815
|
+
});
|
|
10816
|
+
}
|
|
10817
|
+
}
|
|
10818
|
+
/** @inheritDoc */
|
|
10819
|
+
registerOnChange(onChange) {
|
|
10820
|
+
this.onChange = onChange;
|
|
10821
|
+
}
|
|
10822
|
+
/** @inheritDoc */
|
|
10823
|
+
registerOnTouched(onTouched) {
|
|
10824
|
+
this.onTouched = onTouched;
|
|
10825
|
+
}
|
|
10826
|
+
/**
|
|
10827
|
+
* Повторяет загрузку капчи после ошибки.
|
|
10828
|
+
*/
|
|
10829
|
+
retry() {
|
|
10830
|
+
this.hasError.set(false);
|
|
10831
|
+
this.load();
|
|
10832
|
+
}
|
|
10833
|
+
/**
|
|
10834
|
+
* Загружает API Yandex SmartCaptcha и отрисовывает виджет (API приходит вне зоны Angular). При ошибке загрузки или отрисовки показывает сообщение.
|
|
10835
|
+
*/
|
|
10836
|
+
load() {
|
|
10837
|
+
this.loader.api$
|
|
10838
|
+
.pipe(tap((api) => {
|
|
10839
|
+
this.render(api);
|
|
10840
|
+
}), takeUntilDestroyed(this.destroyRef))
|
|
10841
|
+
.subscribe({
|
|
10842
|
+
error: () => {
|
|
10843
|
+
this.showError();
|
|
10844
|
+
},
|
|
10845
|
+
});
|
|
10846
|
+
}
|
|
10847
|
+
/**
|
|
10848
|
+
* Отрисовывает виджет и подписывается на его события.
|
|
10849
|
+
*
|
|
10850
|
+
* @param api API Yandex SmartCaptcha.
|
|
10851
|
+
*/
|
|
10852
|
+
render(api) {
|
|
10853
|
+
const widgetId = api.render(this.container().nativeElement, { sitekey: this.settings.sitekey, hl: this.settings.language });
|
|
10854
|
+
this.api = api;
|
|
10855
|
+
this.widgetId = widgetId;
|
|
10856
|
+
this.unsubscribers = [
|
|
10857
|
+
api.subscribe(widgetId, 'success', (token) => {
|
|
10858
|
+
this.updateValue(typeof token === 'string' ? token : null);
|
|
10859
|
+
}),
|
|
10860
|
+
api.subscribe(widgetId, 'token-expired', () => {
|
|
10861
|
+
this.updateValue(null);
|
|
10862
|
+
api.reset(widgetId);
|
|
10863
|
+
}),
|
|
10864
|
+
api.subscribe(widgetId, 'javascript-error', () => {
|
|
10865
|
+
this.showError();
|
|
10866
|
+
}),
|
|
10867
|
+
];
|
|
10868
|
+
}
|
|
10869
|
+
/**
|
|
10870
|
+
* Передаёт форме новое значение токена.
|
|
10871
|
+
*
|
|
10872
|
+
* @param token Токен прохождения проверки.
|
|
10873
|
+
*/
|
|
10874
|
+
updateValue(token) {
|
|
10875
|
+
this.ngZone.run(() => {
|
|
10876
|
+
this.onChange(token);
|
|
10877
|
+
this.onTouched();
|
|
10878
|
+
});
|
|
10879
|
+
}
|
|
10880
|
+
/**
|
|
10881
|
+
* Удаляет виджет, очищает токен и показывает сообщение об ошибке.
|
|
10882
|
+
*/
|
|
10883
|
+
showError() {
|
|
10884
|
+
this.destroyWidget();
|
|
10885
|
+
this.ngZone.run(() => {
|
|
10886
|
+
this.hasError.set(true);
|
|
10887
|
+
this.onChange(null);
|
|
10888
|
+
});
|
|
10889
|
+
}
|
|
10890
|
+
/**
|
|
10891
|
+
* Удаляет виджет вместе с созданными им элементами и обработчиками.
|
|
10892
|
+
*/
|
|
10893
|
+
destroyWidget() {
|
|
10894
|
+
this.unsubscribers.forEach((unsubscribe) => {
|
|
10895
|
+
unsubscribe();
|
|
10896
|
+
});
|
|
10897
|
+
this.unsubscribers = [];
|
|
10898
|
+
const { api, widgetId } = this;
|
|
10899
|
+
if (api && widgetId !== undefined) {
|
|
10900
|
+
this.ngZone.runOutsideAngular(() => {
|
|
10901
|
+
api.destroy(widgetId);
|
|
10902
|
+
});
|
|
10903
|
+
}
|
|
10904
|
+
this.api = undefined;
|
|
10905
|
+
this.widgetId = undefined;
|
|
10906
|
+
}
|
|
10907
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10908
|
+
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 }); }
|
|
10909
|
+
}
|
|
10910
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScSmartCaptchaComponent, decorators: [{
|
|
10911
|
+
type: Component,
|
|
10912
|
+
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" }]
|
|
10913
|
+
}], ctorParameters: () => [] });
|
|
10914
|
+
|
|
10603
10915
|
/**
|
|
10604
10916
|
* Компонент формы обратной связи.
|
|
10605
10917
|
*/
|
|
@@ -10671,7 +10983,7 @@ class ScFeedbackFormComponent {
|
|
|
10671
10983
|
}
|
|
10672
10984
|
}));
|
|
10673
10985
|
/**
|
|
10674
|
-
* Поле ввода
|
|
10986
|
+
* Поле ввода токена капчи, имя `recaptcha` задано API.
|
|
10675
10987
|
*/
|
|
10676
10988
|
this.recaptchaControl = new FormControl(null, Validators.required);
|
|
10677
10989
|
/**
|
|
@@ -10713,8 +11025,10 @@ class ScFeedbackFormComponent {
|
|
|
10713
11025
|
}),
|
|
10714
11026
|
// eslint-disable-next-line rxjs/no-implicit-any-catch
|
|
10715
11027
|
catchError((error) => {
|
|
11028
|
+
// Токен капчи одноразовый: для повторной отправки нужна новая проверка.
|
|
11029
|
+
this.recaptchaControl.reset();
|
|
10716
11030
|
this.form.markAllAsTouched();
|
|
10717
|
-
const { errors, message } = error.error;
|
|
11031
|
+
const { errors, message } = (error.error ?? {});
|
|
10718
11032
|
if (errors) {
|
|
10719
11033
|
Object.keys(errors).forEach((key) => {
|
|
10720
11034
|
const control = this.form.get(key);
|
|
@@ -10751,16 +11065,6 @@ class ScFeedbackFormComponent {
|
|
|
10751
11065
|
* Список стран.
|
|
10752
11066
|
*/
|
|
10753
11067
|
this.countries = getCountries();
|
|
10754
|
-
/**
|
|
10755
|
-
* Это решение ошибки #4940, было @see [предложено](https://github.com/DethAriel/ng-recaptcha/issues/123#issuecomment-426112101) автором {@link RecaptchaComponent}.
|
|
10756
|
-
*/
|
|
10757
|
-
RecaptchaComponent.prototype.ngOnDestroy = function () {
|
|
10758
|
-
// eslint-disable-next-line @typescript-eslint/dot-notation
|
|
10759
|
-
if (this['subscription']) {
|
|
10760
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/dot-notation
|
|
10761
|
-
this['subscription'].unsubscribe();
|
|
10762
|
-
}
|
|
10763
|
-
};
|
|
10764
11068
|
merge(this.accepted$, this.user$, this.loadedFile.valueChanges.pipe(tap((files) => {
|
|
10765
11069
|
this.form.controls.files.reset([]);
|
|
10766
11070
|
this.onUploadFile(files);
|
|
@@ -10884,7 +11188,7 @@ class ScFeedbackFormComponent {
|
|
|
10884
11188
|
return ScPhoneService.isValidPhoneNumberForMessenger(value);
|
|
10885
11189
|
}
|
|
10886
11190
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScFeedbackFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10887
|
-
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 }); }
|
|
11191
|
+
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 }); }
|
|
10888
11192
|
}
|
|
10889
11193
|
__decorate([
|
|
10890
11194
|
tuiPure
|
|
@@ -10904,8 +11208,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
10904
11208
|
TuiButton,
|
|
10905
11209
|
TuiButtonLoading,
|
|
10906
11210
|
TuiLabel,
|
|
10907
|
-
|
|
10908
|
-
RecaptchaModule,
|
|
11211
|
+
ScSmartCaptchaComponent,
|
|
10909
11212
|
TuiLink,
|
|
10910
11213
|
NgIf,
|
|
10911
11214
|
TuiTextareaModule,
|
|
@@ -10915,7 +11218,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
10915
11218
|
TuiInputPhoneInternational,
|
|
10916
11219
|
...TuiTextfield,
|
|
10917
11220
|
TuiSortCountriesPipe,
|
|
10918
|
-
], 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 <!--
|
|
11221
|
+
], 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" }]
|
|
10919
11222
|
}], ctorParameters: () => [], propDecorators: { isValidPhoneNumberForMessenger: [] } });
|
|
10920
11223
|
|
|
10921
11224
|
/**
|
|
@@ -11502,5 +11805,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
11502
11805
|
* Generated bundle index. Do not edit.
|
|
11503
11806
|
*/
|
|
11504
11807
|
|
|
11505
|
-
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_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, ScAddressesSelectionFieldComponent, ScAuthModule, ScBannerComponent, ScBannerModule, ScBrandsListComponent, ScBrandsListModule, ScCartAddProductsFromCsvDialogComponent, ScCatalogFilterCollapsibleComponent, ScCatalogFiltersComponent, ScCatalogModule, ScCategoryCardComponent, ScContactsAccordionComponent, ScContactsModule, ScContragentsAccordionComponent, ScContragentsAccordionItemComponent, ScContragentsModule, ScDeliveryAddressAccordionComponent, ScDeliveryAddressAccordionItemComponent, ScDeliveryAddressModule, ScDownloadPriceListComponent, ScDraftComponent, 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, 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,
|
|
11808
|
+
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_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, ScAddressesSelectionFieldComponent, ScAuthModule, ScBannerComponent, ScBannerModule, ScBrandsListComponent, ScBrandsListModule, ScCartAddProductsFromCsvDialogComponent, ScCatalogFilterCollapsibleComponent, ScCatalogFiltersComponent, ScCatalogModule, ScCategoryCardComponent, ScContactsAccordionComponent, ScContactsModule, ScContragentsAccordionComponent, ScContragentsAccordionItemComponent, ScContragentsModule, ScDeliveryAddressAccordionComponent, ScDeliveryAddressAccordionItemComponent, ScDeliveryAddressModule, ScDownloadPriceListComponent, ScDraftComponent, 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, 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 };
|
|
11506
11809
|
//# sourceMappingURL=snabcentr-client-ui.mjs.map
|