@snabcentr/client-ui 4.14.1 → 4.14.3
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/pages/frequently-asked-questions/sc-frequently-asked-questions.component.mjs +57 -12
- package/esm2022/pages/frequently-asked-questions-with-groups/sc-frequently-asked-questions-with-groups.component.mjs +2 -2
- package/esm2022/share/share-dialog/sc-share-dialog.component.mjs +12 -7
- package/fesm2022/snabcentr-client-ui.mjs +65 -18
- package/fesm2022/snabcentr-client-ui.mjs.map +1 -1
- package/package.json +2 -1
- package/pages/frequently-asked-questions/sc-frequently-asked-questions.component.d.ts +23 -3
- package/release_notes.tmp +2 -2
- package/share/share-dialog/sc-share-dialog.component.d.ts +2 -2
|
@@ -1,10 +1,10 @@
|
|
|
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, viewChildren, afterNextRender } 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';
|
|
3
3
|
import * as i1 from '@snabcentr/client-core';
|
|
4
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, 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, Observable, pairwise, Subscription, merge, skip, from, concatMap, noop, first, retry } from 'rxjs';
|
|
7
|
-
import { WA_WINDOW
|
|
6
|
+
import { EMPTY, BehaviorSubject, switchMap, of, shareReplay, map, Subject, filter, tap, catchError, finalize, startWith, share, timer, scan, takeWhile, endWith, distinctUntilChanged, debounceTime, throwError, combineLatest, Observable, pairwise, Subscription, merge, skip, from, concatMap, noop, first, retry, fromEvent, animationFrames, take, takeUntil } from 'rxjs';
|
|
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
10
|
import { TuiDay, TuiTime, TuiValueTransformer, TUI_IS_MOBILE, tuiControlValue, tuiIsPresent, tuiMarkControlAsTouchedAndValidate, tuiIsFalsy, TuiAutoFocus, TuiRepeatTimes, TuiHovered, TuiDayRange, TuiMonth, tuiPure, tuiProvide, TuiValidationError, TUI_WINDOW_SIZE, tuiClamp, TUI_TRUE_HANDLER } from '@taiga-ui/cdk';
|
|
@@ -51,6 +51,7 @@ import * as i5$2 from '@taiga-ui/kit/components/slider';
|
|
|
51
51
|
import * as i9 from 'angular8-yandex-maps';
|
|
52
52
|
import { AngularYandexMapsModule } from 'angular8-yandex-maps';
|
|
53
53
|
import { isValid, parse, format } from 'date-fns';
|
|
54
|
+
import { Clipboard } from '@angular/cdk/clipboard';
|
|
54
55
|
import * as i2$5 from '@taiga-ui/experimental/components/expand';
|
|
55
56
|
import * as i3$3 from '@taiga-ui/kit/components/data-list-wrapper';
|
|
56
57
|
import { TuiGroup } from '@taiga-ui/core/directives/group';
|
|
@@ -9483,9 +9484,9 @@ class ScShareDialogComponent {
|
|
|
9483
9484
|
*/
|
|
9484
9485
|
this.context = inject(POLYMORPHEUS_CONTEXT);
|
|
9485
9486
|
/**
|
|
9486
|
-
*
|
|
9487
|
+
* Сервис копирования текста в буфер обмена.
|
|
9487
9488
|
*/
|
|
9488
|
-
this.
|
|
9489
|
+
this.clipboard = inject(Clipboard);
|
|
9489
9490
|
/**
|
|
9490
9491
|
* Ссылка на объект окна браузера.
|
|
9491
9492
|
*/
|
|
@@ -9548,8 +9549,12 @@ class ScShareDialogComponent {
|
|
|
9548
9549
|
*/
|
|
9549
9550
|
copyShareLink() {
|
|
9550
9551
|
this.emitShareClick('copy_to_clipboard');
|
|
9551
|
-
this.
|
|
9552
|
-
|
|
9552
|
+
if (this.clipboard.copy(this.shareUrl)) {
|
|
9553
|
+
this.alerts.open('Ссылка скопирована в буфер обмена.', { appearance: 'positive' }).subscribe();
|
|
9554
|
+
}
|
|
9555
|
+
else {
|
|
9556
|
+
this.alerts.open('Не удалось скопировать ссылку в буфер обмена.', { appearance: 'negative' }).subscribe();
|
|
9557
|
+
}
|
|
9553
9558
|
}
|
|
9554
9559
|
/**
|
|
9555
9560
|
* Открывает диалоговое окно с QR-кодом ссылки.
|
|
@@ -9798,8 +9803,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
9798
9803
|
class ScFrequentlyAskedQuestionsComponent {
|
|
9799
9804
|
/**
|
|
9800
9805
|
* Инициализирует экземпляр класса {@link ScFrequentlyAskedQuestionsComponent}.
|
|
9801
|
-
*
|
|
9802
|
-
* Вопрос из якоря адреса раскрывается, а после отрисовки списка к нему выполняется прокрутка (в браузере).
|
|
9803
9806
|
*/
|
|
9804
9807
|
constructor() {
|
|
9805
9808
|
/**
|
|
@@ -9810,6 +9813,14 @@ class ScFrequentlyAskedQuestionsComponent {
|
|
|
9810
9813
|
* {@link InputSignal} отображения загрузки.
|
|
9811
9814
|
*/
|
|
9812
9815
|
this.showLoading = input(false);
|
|
9816
|
+
/**
|
|
9817
|
+
* {@link InputSignal} параметров прокрутки к вопросу из якоря.
|
|
9818
|
+
*/
|
|
9819
|
+
this.scrollOptions = input({ behavior: 'instant', block: 'center' });
|
|
9820
|
+
/**
|
|
9821
|
+
* {@link InputSignal} количества кадров удержания вопроса из якоря в поле зрения (около 5 секунд).
|
|
9822
|
+
*/
|
|
9823
|
+
this.scrollHoldFrames = input(300);
|
|
9813
9824
|
/**
|
|
9814
9825
|
* Признак, что приложение запущено на сервере.
|
|
9815
9826
|
*/
|
|
@@ -9826,20 +9837,37 @@ class ScFrequentlyAskedQuestionsComponent {
|
|
|
9826
9837
|
* Активный маршрут.
|
|
9827
9838
|
*/
|
|
9828
9839
|
this.route = inject(ActivatedRoute);
|
|
9840
|
+
/**
|
|
9841
|
+
* Инжектор компонента.
|
|
9842
|
+
*/
|
|
9843
|
+
this.injector = inject(Injector);
|
|
9844
|
+
/**
|
|
9845
|
+
* Ссылка на уничтожение компонента.
|
|
9846
|
+
*/
|
|
9847
|
+
this.destroyRef = inject(DestroyRef);
|
|
9829
9848
|
/**
|
|
9830
9849
|
* {@link Signal} ссылок на заголовки вопросов.
|
|
9831
9850
|
*/
|
|
9832
9851
|
this.questionHeaders = viewChildren('questionHeader');
|
|
9833
|
-
|
|
9834
|
-
if (
|
|
9852
|
+
// На сервере все вопросы раскрыты.
|
|
9853
|
+
if (this.isServer) {
|
|
9835
9854
|
return;
|
|
9836
9855
|
}
|
|
9837
|
-
|
|
9838
|
-
|
|
9856
|
+
// Раскрываем вопрос из якоря и прокручиваем к нему: якорь может смениться на открытой странице, список загрузиться позже.
|
|
9857
|
+
combineLatest([this.route.fragment, toObservable(this.items)])
|
|
9858
|
+
.pipe(map(([fragment, items]) => {
|
|
9859
|
+
const questionId = scGetFaqQuestionIdFromAnchor(fragment);
|
|
9860
|
+
return questionId !== null && items.some((item) => item.id === questionId) ? questionId : null;
|
|
9861
|
+
}), filter(tuiIsPresent), takeUntilDestroyed())
|
|
9862
|
+
.subscribe((questionId) => {
|
|
9863
|
+
this.onOpenedChange(questionId, true);
|
|
9839
9864
|
afterNextRender(() => {
|
|
9840
|
-
this.getQuestionHeader(questionId)
|
|
9841
|
-
|
|
9842
|
-
|
|
9865
|
+
const header = this.getQuestionHeader(questionId);
|
|
9866
|
+
if (header) {
|
|
9867
|
+
this.scrollToHeader(header);
|
|
9868
|
+
}
|
|
9869
|
+
}, { injector: this.injector });
|
|
9870
|
+
});
|
|
9843
9871
|
}
|
|
9844
9872
|
/**
|
|
9845
9873
|
* Возвращает параметры формирования ссылки на вопрос: текущая страница с её query-параметрами и якорем вопроса.
|
|
@@ -9880,8 +9908,27 @@ class ScFrequentlyAskedQuestionsComponent {
|
|
|
9880
9908
|
const anchor = scGetFaqQuestionAnchor(questionId);
|
|
9881
9909
|
return this.questionHeaders().find((header) => header.nativeElement.id === anchor)?.nativeElement;
|
|
9882
9910
|
}
|
|
9911
|
+
/**
|
|
9912
|
+
* Прокручивает страницу к заголовку вопроса и удерживает его в поле зрения.
|
|
9913
|
+
*
|
|
9914
|
+
* @param header Элемент заголовка вопроса.
|
|
9915
|
+
*/
|
|
9916
|
+
scrollToHeader(header) {
|
|
9917
|
+
const getTop = () => Math.round(header.getBoundingClientRect().top);
|
|
9918
|
+
const userScroll$ = merge(fromEvent(globalThis, 'wheel'), fromEvent(globalThis, 'touchstart'), fromEvent(globalThis, 'keydown'), fromEvent(globalThis, 'mousedown'));
|
|
9919
|
+
// Мгновенно: плавная прокрутка не выполняется в скрытой вкладке.
|
|
9920
|
+
header.scrollIntoView(this.scrollOptions());
|
|
9921
|
+
let expectedTop = getTop();
|
|
9922
|
+
// Повторяем прокрутку, если вопрос сдвинула догрузка страницы или чужая прокрутка, пока пользователь не начнёт прокручивать сам.
|
|
9923
|
+
animationFrames()
|
|
9924
|
+
.pipe(take(this.scrollHoldFrames()), map(getTop), filter((top) => top !== expectedTop), takeUntilDestroyed(this.destroyRef), takeUntil(userScroll$))
|
|
9925
|
+
.subscribe(() => {
|
|
9926
|
+
header.scrollIntoView(this.scrollOptions());
|
|
9927
|
+
expectedTop = getTop();
|
|
9928
|
+
});
|
|
9929
|
+
}
|
|
9883
9930
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScFrequentlyAskedQuestionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9884
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScFrequentlyAskedQuestionsComponent, isStandalone: true, selector: "sc-frequently-asked-questions", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, showLoading: { classPropertyName: "showLoading", publicName: "showLoading", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "ngSkipHydration": "true" } }, providers: [
|
|
9931
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScFrequentlyAskedQuestionsComponent, isStandalone: true, selector: "sc-frequently-asked-questions", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, showLoading: { classPropertyName: "showLoading", publicName: "showLoading", isSignal: true, isRequired: false, transformFunction: null }, scrollOptions: { classPropertyName: "scrollOptions", publicName: "scrollOptions", isSignal: true, isRequired: false, transformFunction: null }, scrollHoldFrames: { classPropertyName: "scrollHoldFrames", publicName: "scrollHoldFrames", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "ngSkipHydration": "true" } }, providers: [
|
|
9885
9932
|
{
|
|
9886
9933
|
provide: TUI_BUTTON_OPTIONS,
|
|
9887
9934
|
useValue: {
|
|
@@ -10188,7 +10235,7 @@ class ScFrequentlyAskedQuestionsWithGroupsComponent {
|
|
|
10188
10235
|
this.pageQueryParam = SC_PAGE_QUERY_PARAM;
|
|
10189
10236
|
}
|
|
10190
10237
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScFrequentlyAskedQuestionsWithGroupsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10191
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScFrequentlyAskedQuestionsWithGroupsComponent, isStandalone: true, selector: "sc-frequently-asked-questions-with-groups", outputs: { clickSendQuestion: "clickSendQuestion" }, host: { attributes: { "ngSkipHydration": "true" } }, ngImport: i0, template: "@let items = data$ | async;\n@let pageCount = pageCount$ | async;\n@let viewMode = viewMode$ | async;\n\n<div\n *ngIf=\"viewMode\"\n class=\"flex gap-6\"\n [class.flex-col]=\"viewMode === 'select'\"\n>\n <div class=\"flex flex-col gap-7\">\n <sc-frequently-asked-questions-group-selector\n [selectedGroupId]=\"groupId$ | async\"\n [viewMode]=\"viewMode\"\n class=\"shrink-0\"\n [class.w-64]=\"viewMode !== 'select'\"\n />\n\n <button\n *ngIf=\"viewMode === 'list'\"\n tuiButton\n size=\"m\"\n type=\"button\"\n iconStart=\"@tui.circle-help\"\n appearance=\"secondary\"\n (click)=\"clickSendQuestion.emit()\"\n class=\"self-center\"\n >\n \u0417\u0430\u0434\u0430\u0442\u044C \u0432\u043E\u043F\u0440\u043E\u0441\n </button>\n </div>\n\n <div class=\"grow\">\n @if (items && items.length) {\n <sc-frequently-asked-questions\n [items]=\"items\"\n [showLoading]=\"isLoading()\"\n />\n\n <sc-pagination-links\n *ngIf=\"pageCount && pageCount > 1\"\n [length]=\"pageCount\"\n [index]=\"(currentPage$ | async) ?? 1\"\n [queryParam]=\"pageQueryParam\"\n class=\"mt-4\"\n />\n } @else {\n <p class=\"text-body-s-bold\">\u0421\u043F\u0438\u0441\u043E\u043A \u0432\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u043F\u0443\u0441\u0442</p>\n }\n </div>\n</div>\n", dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ScFrequentlyAskedQuestionsGroupSelectorComponent, selector: "sc-frequently-asked-questions-group-selector", inputs: ["selectedGroupId", "viewMode"] }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "component", type: ScFrequentlyAskedQuestionsComponent, selector: "sc-frequently-asked-questions", inputs: ["items", "showLoading"] }, { kind: "component", type: ScPaginationLinksComponent, selector: "sc-pagination-links", inputs: ["length", "index", "queryParam", "activePadding", "sidePadding"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10238
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ScFrequentlyAskedQuestionsWithGroupsComponent, isStandalone: true, selector: "sc-frequently-asked-questions-with-groups", outputs: { clickSendQuestion: "clickSendQuestion" }, host: { attributes: { "ngSkipHydration": "true" } }, ngImport: i0, template: "@let items = data$ | async;\n@let pageCount = pageCount$ | async;\n@let viewMode = viewMode$ | async;\n\n<div\n *ngIf=\"viewMode\"\n class=\"flex gap-6\"\n [class.flex-col]=\"viewMode === 'select'\"\n>\n <div class=\"flex flex-col gap-7\">\n <sc-frequently-asked-questions-group-selector\n [selectedGroupId]=\"groupId$ | async\"\n [viewMode]=\"viewMode\"\n class=\"shrink-0\"\n [class.w-64]=\"viewMode !== 'select'\"\n />\n\n <button\n *ngIf=\"viewMode === 'list'\"\n tuiButton\n size=\"m\"\n type=\"button\"\n iconStart=\"@tui.circle-help\"\n appearance=\"secondary\"\n (click)=\"clickSendQuestion.emit()\"\n class=\"self-center\"\n >\n \u0417\u0430\u0434\u0430\u0442\u044C \u0432\u043E\u043F\u0440\u043E\u0441\n </button>\n </div>\n\n <div class=\"grow\">\n @if (items && items.length) {\n <sc-frequently-asked-questions\n [items]=\"items\"\n [showLoading]=\"isLoading()\"\n />\n\n <sc-pagination-links\n *ngIf=\"pageCount && pageCount > 1\"\n [length]=\"pageCount\"\n [index]=\"(currentPage$ | async) ?? 1\"\n [queryParam]=\"pageQueryParam\"\n class=\"mt-4\"\n />\n } @else {\n <p class=\"text-body-s-bold\">\u0421\u043F\u0438\u0441\u043E\u043A \u0432\u043E\u043F\u0440\u043E\u0441\u043E\u0432 \u043F\u0443\u0441\u0442</p>\n }\n </div>\n</div>\n", dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ScFrequentlyAskedQuestionsGroupSelectorComponent, selector: "sc-frequently-asked-questions-group-selector", inputs: ["selectedGroupId", "viewMode"] }, { kind: "directive", type: TuiButton, selector: "a[tuiButton],button[tuiButton],a[tuiIconButton],button[tuiIconButton]", inputs: ["size"] }, { kind: "component", type: ScFrequentlyAskedQuestionsComponent, selector: "sc-frequently-asked-questions", inputs: ["items", "showLoading", "scrollOptions", "scrollHoldFrames"] }, { kind: "component", type: ScPaginationLinksComponent, selector: "sc-pagination-links", inputs: ["length", "index", "queryParam", "activePadding", "sidePadding"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
10192
10239
|
}
|
|
10193
10240
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ScFrequentlyAskedQuestionsWithGroupsComponent, decorators: [{
|
|
10194
10241
|
type: Component,
|