@sima-land/moleculas 12.1.0 → 12.3.1
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/common/components/adult-block/adult-block.d.ts +2 -2
- package/common/components/adult-block/adult-block.js +2 -2
- package/common/components/badge/badge.module.scss +1 -1
- package/common/components/badge/index.d.ts +4 -0
- package/common/components/badge/index.js +2 -6
- package/common/components/badge-list/badge-list.module.scss +0 -1
- package/common/components/badge-list/index.d.ts +6 -2
- package/common/components/badge-list/index.js +4 -2
- package/common/components/product-info/index.d.ts +5 -0
- package/common/components/product-info/index.js +5 -4
- package/common/components/product-info/product-info.module.scss +10 -0
- package/common/components/quick-view-button/index.js +1 -1
- package/common/components/wish-button/index.js +1 -1
- package/common/helpers/format-qty-string.js +1 -3
- package/common/helpers/get-contained-items.js +2 -1
- package/desktop/components/breadcrumbs/breadcrumbs.module.scss +2 -2
- package/desktop/components/breadcrumbs/index.d.ts +4 -0
- package/desktop/components/breadcrumbs/index.js +5 -5
- package/desktop/components/gallery-modal/components/all-round-view.js +13 -13
- package/desktop/components/gallery-modal/components/all-round-view.module.scss +1 -1
- package/desktop/components/gallery-modal/components/gallery-modal.d.ts +7 -0
- package/desktop/components/gallery-modal/components/gallery-modal.js +13 -12
- package/desktop/components/gallery-modal/components/image-overlay.js +1 -1
- package/desktop/components/gallery-modal/components/image-overlay.module.scss +1 -1
- package/desktop/components/gallery-modal/components/review-info.d.ts +1 -1
- package/desktop/components/gallery-modal/components/review-info.js +1 -1
- package/desktop/components/gallery-modal/components/thumbnail.d.ts +1 -1
- package/desktop/components/gallery-modal/components/thumbnail.js +3 -3
- package/desktop/components/gallery-modal/utils.d.ts +1 -1
- package/desktop/components/gallery-modal/utils.js +6 -6
- package/desktop/components/item-image/index.d.ts +1 -1
- package/desktop/components/item-image/index.js +8 -9
- package/desktop/components/item-image/item-image.module.scss +4 -4
- package/desktop/components/modifiers/button/index.js +4 -4
- package/desktop/components/modifiers/group/index.js +19 -18
- package/desktop/components/modifiers/widget/index.js +2 -2
- package/desktop/components/person-modal/index.d.ts +16 -14
- package/desktop/components/person-modal/index.js +5 -16
- package/desktop/components/product-card/index.d.ts +5 -2
- package/desktop/components/product-card/index.js +7 -7
- package/desktop/components/product-card/product-card.module.scss +14 -0
- package/desktop/components/product-carousel/hover-card.js +4 -4
- package/desktop/components/product-carousel/index.d.ts +6 -0
- package/desktop/components/product-carousel/index.js +35 -34
- package/desktop/components/product-carousel/product-carousel.module.scss +1 -1
- package/desktop/components/product-carousel/utils.js +11 -11
- package/desktop/components/promotion-card/banner-title.js +7 -7
- package/desktop/components/promotion-card/estimate.js +4 -6
- package/desktop/components/promotion-card/index.d.ts +11 -1
- package/desktop/components/promotion-card/index.js +7 -7
- package/desktop/components/promotion-card/index.module.scss +2 -2
- package/desktop/components/promotion-card/placeholder.js +4 -4
- package/mobile/components/garland-calculator-button/garland-calculator-button.module.scss +1 -1
- package/mobile/components/item-image/index.d.ts +1 -1
- package/mobile/components/item-image/index.js +5 -7
- package/mobile/components/item-image/item-image.module.scss +3 -3
- package/mobile/components/modifiers-list/index.d.ts +1 -1
- package/mobile/components/modifiers-list/index.js +1 -1
- package/mobile/components/modifiers-list/modifier-item/index.js +7 -7
- package/mobile/components/modifiers-list/modifiers-list.module.scss +0 -1
- package/mobile/components/person-screen/index.d.ts +1 -1
- package/mobile/components/person-screen/index.js +3 -3
- package/mobile/components/person-screen/person-screen.module.scss +0 -1
- package/mobile/components/product-actions-alert/index.js +6 -5
- package/mobile/components/product-row/index.d.ts +1 -1
- package/mobile/components/product-row/index.js +19 -24
- package/mobile/components/product-row/product-row.module.scss +0 -1
- package/mobile/components/product-slider/index.d.ts +1 -1
- package/mobile/components/product-slider/index.js +7 -7
- package/mobile/components/product-slider/item.js +2 -2
- package/mobile/components/product-slider/utils.js +1 -1
- package/mobile/components/search-bar/index.d.ts +1 -1
- package/mobile/components/search-bar/index.js +31 -31
- package/mobile/components/search-bar/search-bar.module.scss +9 -3
- package/mobile/components/select-screen/index.js +5 -6
- package/package.json +39 -31
- package/README.md +0 -86
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
height: 2px;
|
|
55
55
|
right: 2px;
|
|
56
56
|
background: #9e9e9e;
|
|
57
|
-
opacity: .32;
|
|
57
|
+
opacity: 0.32;
|
|
58
58
|
border-radius: 4px;
|
|
59
59
|
}
|
|
60
60
|
&.selected {
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
left: 0;
|
|
84
84
|
right: 0;
|
|
85
85
|
bottom: 0;
|
|
86
|
-
background-color: rgba(0, 0, 0, .04);
|
|
86
|
+
background-color: rgba(0, 0, 0, 0.04);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -108,13 +108,13 @@
|
|
|
108
108
|
left: -5px;
|
|
109
109
|
width: calc(100% + 10px);
|
|
110
110
|
height: calc(100% + 10px);
|
|
111
|
-
background: rgba(255, 255, 255, .5);
|
|
111
|
+
background: rgba(255, 255, 255, 0.5);
|
|
112
112
|
z-index: 4;
|
|
113
113
|
display: flex;
|
|
114
114
|
justify-content: center;
|
|
115
115
|
align-items: center;
|
|
116
116
|
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
|
|
117
|
-
background: rgba(255, 255, 255, .95);
|
|
117
|
+
background: rgba(255, 255, 255, 0.95);
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
@@ -24,7 +24,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.ModifierButton = void 0;
|
|
26
26
|
const react_1 = __importStar(require("react"));
|
|
27
|
-
const
|
|
27
|
+
const lodash_1 = require("lodash");
|
|
28
28
|
const modifier_button_module_scss_1 = __importDefault(require("./modifier-button.module.scss"));
|
|
29
29
|
const bind_1 = __importDefault(require("classnames/bind"));
|
|
30
30
|
const constants_1 = require("../../../../common/constants");
|
|
@@ -33,14 +33,14 @@ const typesList = Object.values(constants_1.MODIFIERS_TYPES);
|
|
|
33
33
|
/**
|
|
34
34
|
* Компонент модификатора.
|
|
35
35
|
*/
|
|
36
|
-
exports.ModifierButton = react_1.forwardRef(function ModifierButton({ count = null, content, selected, color, image, type: typeProp = 'text', className, onClick, isMarkdown: hasMarkdown, squared = [constants_1.MODIFIERS_TYPES.color, constants_1.MODIFIERS_TYPES.image].includes(typeProp), 'data-testid': testId = 'modifier-button', }, ref) {
|
|
36
|
+
exports.ModifierButton = (0, react_1.forwardRef)(function ModifierButton({ count = null, content, selected, color, image, type: typeProp = 'text', className, onClick, isMarkdown: hasMarkdown, squared = [constants_1.MODIFIERS_TYPES.color, constants_1.MODIFIERS_TYPES.image].includes(typeProp), 'data-testid': testId = 'modifier-button', }, ref) {
|
|
37
37
|
const type = typesList.includes(typeProp) ? typeProp : 'text';
|
|
38
|
-
const hasCount =
|
|
38
|
+
const hasCount = (0, lodash_1.isNumber)(count) && count >= 0;
|
|
39
39
|
return (react_1.default.createElement("div", { ref: ref, className: cx('modifier-button', squared && 'squared', selected && 'selected', className), style: color ? { background: color } : undefined, onClick: onClick, "data-testid": testId },
|
|
40
40
|
(hasCount || hasMarkdown) && (react_1.default.createElement("span", { className: cx('label', hasCount && 'with-count'), "data-testid": 'modifier-button:badge' },
|
|
41
41
|
hasCount && (count > 99 ? '99+' : count),
|
|
42
42
|
hasMarkdown && (hasCount ? '(У)' : 'У'))),
|
|
43
43
|
[constants_1.MODIFIERS_TYPES.text, constants_1.MODIFIERS_TYPES.image].includes(type) && (react_1.default.createElement("div", { className: cx('content') },
|
|
44
44
|
type === constants_1.MODIFIERS_TYPES.text && (react_1.default.createElement("span", { className: cx('text', !squared && 'guttered') }, String(content || ''))),
|
|
45
|
-
type === constants_1.MODIFIERS_TYPES.image &&
|
|
45
|
+
type === constants_1.MODIFIERS_TYPES.image && react_1.default.createElement("img", { src: image, alt: content, className: cx('image') })))));
|
|
46
46
|
});
|
|
@@ -24,7 +24,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
25
|
exports.ModifiersGroup = exports.createHiddenNodeIndexFinder = void 0;
|
|
26
26
|
const react_1 = __importStar(require("react"));
|
|
27
|
-
const
|
|
27
|
+
const lodash_1 = require("lodash");
|
|
28
28
|
const prop_1 = __importDefault(require("lodash/fp/prop"));
|
|
29
29
|
const button_1 = require("../button");
|
|
30
30
|
const on_1 = __importDefault(require("@sima-land/ui-nucleons/helpers/on"));
|
|
@@ -48,13 +48,13 @@ const createHiddenNodeIndexFinder = (container) => (childNode) => {
|
|
|
48
48
|
return childOffsetTop - container.offsetTop >= container.clientHeight;
|
|
49
49
|
};
|
|
50
50
|
exports.createHiddenNodeIndexFinder = createHiddenNodeIndexFinder;
|
|
51
|
-
const defaultGetItemType = prop_1.default('type');
|
|
52
|
-
const defaultGetItemCount = prop_1.default('count');
|
|
53
|
-
const defaultGetItemColor = prop_1.default('color');
|
|
54
|
-
const defaultGetItemContent = prop_1.default('content');
|
|
55
|
-
const defaultIsSelectedItem = prop_1.default('selected');
|
|
56
|
-
const defaultGetItemImage = prop_1.default('image');
|
|
57
|
-
const defaultGetIsMarkdown = prop_1.default('isMarkdown');
|
|
51
|
+
const defaultGetItemType = (0, prop_1.default)('type');
|
|
52
|
+
const defaultGetItemCount = (0, prop_1.default)('count');
|
|
53
|
+
const defaultGetItemColor = (0, prop_1.default)('color');
|
|
54
|
+
const defaultGetItemContent = (0, prop_1.default)('content');
|
|
55
|
+
const defaultIsSelectedItem = (0, prop_1.default)('selected');
|
|
56
|
+
const defaultGetItemImage = (0, prop_1.default)('image');
|
|
57
|
+
const defaultGetIsMarkdown = (0, prop_1.default)('isMarkdown');
|
|
58
58
|
/**
|
|
59
59
|
* Возвращает компонент списка модификаторов.
|
|
60
60
|
* @param {Object} props Свойства компонента.
|
|
@@ -82,12 +82,12 @@ class ModifiersGroup extends react_1.Component {
|
|
|
82
82
|
lastVisibleChildIndex: null,
|
|
83
83
|
};
|
|
84
84
|
this.windowWidth = 0;
|
|
85
|
-
this.containerRef = react_1.createRef();
|
|
86
|
-
this.showingButtonRef = react_1.createRef();
|
|
85
|
+
this.containerRef = (0, react_1.createRef)();
|
|
86
|
+
this.showingButtonRef = (0, react_1.createRef)();
|
|
87
87
|
/**
|
|
88
88
|
* Сбрасывает информацию о видимых и невидимых дочерних узлах контейнера.
|
|
89
89
|
*/
|
|
90
|
-
this.resetVisibleNodesData =
|
|
90
|
+
this.resetVisibleNodesData = (0, lodash_1.debounce)(() => {
|
|
91
91
|
if (document.documentElement.offsetWidth !== this.windowWidth) {
|
|
92
92
|
this.windowWidth = document.documentElement.offsetWidth;
|
|
93
93
|
this.setState({
|
|
@@ -107,7 +107,7 @@ class ModifiersGroup extends react_1.Component {
|
|
|
107
107
|
const showingButtonEl = this.showingButtonRef.current;
|
|
108
108
|
if (containerEl && showingButtonEl) {
|
|
109
109
|
const childList = [...containerEl.children];
|
|
110
|
-
const firstHiddenNodeIndex = childList.findIndex(exports.createHiddenNodeIndexFinder(containerEl));
|
|
110
|
+
const firstHiddenNodeIndex = childList.findIndex((0, exports.createHiddenNodeIndexFinder)(containerEl));
|
|
111
111
|
if (firstHiddenNodeIndex !== -1) {
|
|
112
112
|
const lastVisibleElIndex = firstHiddenNodeIndex - 1;
|
|
113
113
|
const lastVisibleNode = childList[lastVisibleElIndex];
|
|
@@ -115,7 +115,7 @@ class ModifiersGroup extends react_1.Component {
|
|
|
115
115
|
const rightBound = lastVisibleNode.getBoundingClientRect().right;
|
|
116
116
|
const rightContainerBound = containerEl.getBoundingClientRect().right;
|
|
117
117
|
// проверяем, хватает ли кнопке места (с запасом в половину) после последнего видимого дочернего элемента
|
|
118
|
-
const isShowingButtonFit = rightContainerBound - rightBound >=
|
|
118
|
+
const isShowingButtonFit = rightContainerBound - rightBound >= showingButtonEl.clientWidth * 1.5;
|
|
119
119
|
this.setState({
|
|
120
120
|
// если хватает места - ставим кнопку после последнего, иначе - вместо
|
|
121
121
|
lastVisibleChildIndex: lastVisibleElIndex + (isShowingButtonFit ? 1 : 0),
|
|
@@ -143,7 +143,7 @@ class ModifiersGroup extends react_1.Component {
|
|
|
143
143
|
*/
|
|
144
144
|
componentDidMount() {
|
|
145
145
|
this.windowWidth = document.documentElement.offsetWidth;
|
|
146
|
-
this.removeGlobalListener = on_1.default(window, 'resize', this.resetVisibleNodesData);
|
|
146
|
+
this.removeGlobalListener = (0, on_1.default)(window, 'resize', this.resetVisibleNodesData);
|
|
147
147
|
this.checkVisibleNodes();
|
|
148
148
|
}
|
|
149
149
|
/**
|
|
@@ -166,10 +166,11 @@ class ModifiersGroup extends react_1.Component {
|
|
|
166
166
|
const { needShowAll, hasHiddenNodes, lastVisibleChildIndex } = this.state;
|
|
167
167
|
const needHideModifiers = !needShowAll && lastVisibleChildIndex !== null;
|
|
168
168
|
return (react_1.default.createElement("div", { className: cx('modifiers-group', !needShowAll && 'height-limited'), ref: this.containerRef, "data-testid": testId },
|
|
169
|
-
Array.isArray(items) &&
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
Array.isArray(items) &&
|
|
170
|
+
items.map((item, index) => {
|
|
171
|
+
const isDisplayed = !needHideModifiers || index < lastVisibleChildIndex;
|
|
172
|
+
return (react_1.default.createElement(button_1.ModifierButton, { key: index, type: getItemType(item), count: getItemCount(item), color: getItemColor(item), content: getItemContent(item), selected: isSelectedItem(item), image: getItemImage(item), onClick: () => onSelectItem && onSelectItem(item, isSelectedItem(item)), className: cx('guttered', !isDisplayed && 'not-display'), isMarkdown: isMarkdown(item) }));
|
|
173
|
+
}),
|
|
173
174
|
Array.isArray(items) && hasHiddenNodes && !needShowAll && (react_1.default.createElement(button_1.ModifierButton, { squared: true, ref: this.showingButtonRef, content: `+${items.length - lastVisibleChildIndex}`, className: cx('show-all-button', 'guttered', lastVisibleChildIndex === null && 'invisible'), onClick: this.handleShowAllClick, "data-testid": 'modifier-group:show-all-button' }))));
|
|
174
175
|
}
|
|
175
176
|
}
|
|
@@ -27,9 +27,9 @@ const ModifiersWidget = ({ title, items, sizesTableUrl, onSelectItem, }) => (rea
|
|
|
27
27
|
" (",
|
|
28
28
|
items.length,
|
|
29
29
|
"\u00A0",
|
|
30
|
-
get_declination_1.default(items.length, ['вариант', 'варианта', 'вариантов']),
|
|
30
|
+
(0, get_declination_1.default)(items.length, ['вариант', 'варианта', 'вариантов']),
|
|
31
31
|
"):")),
|
|
32
|
-
react_1.default.createElement(group_1.ModifiersGroup, { items: items, getItemContent: prop_1.default('name'), getItemCount: prop_1.default('inCartQty'), onSelectItem: (item, selected) => {
|
|
32
|
+
react_1.default.createElement(group_1.ModifiersGroup, { items: items, getItemContent: (0, prop_1.default)('name'), getItemCount: (0, prop_1.default)('inCartQty'), onSelectItem: (item, selected) => {
|
|
33
33
|
!selected && onSelectItem && onSelectItem(item);
|
|
34
34
|
} }),
|
|
35
35
|
Boolean(sizesTableUrl) && (react_1.default.createElement(link_1.Link, { href: sizesTableUrl, className: cx('modifiers-link') }, "\u0422\u0430\u0431\u043B\u0438\u0446\u0430 \u0440\u0430\u0437\u043C\u0435\u0440\u043E\u0432"))));
|
|
@@ -1,37 +1,39 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import { ModalProps } from '@sima-land/ui-nucleons/modal';
|
|
3
3
|
export interface PersonModalProps {
|
|
4
|
+
/** Имя. */
|
|
4
5
|
name: string;
|
|
6
|
+
/** Должность. */
|
|
5
7
|
appointment: string;
|
|
8
|
+
/** Ссылка на фото. */
|
|
6
9
|
photoUrl?: string;
|
|
10
|
+
/** Почта. */
|
|
7
11
|
email?: string;
|
|
12
|
+
/** Skype. */
|
|
8
13
|
skype?: string;
|
|
14
|
+
/** Социальные сети. */
|
|
9
15
|
social?: any[];
|
|
16
|
+
/** Ссылка на рабочий номер телефона. */
|
|
10
17
|
phoneHref?: string;
|
|
18
|
+
/** Рабочий номер телефона. */
|
|
11
19
|
phoneText?: string;
|
|
20
|
+
/** Ссылка на сотовый номер телефона. */
|
|
12
21
|
secondPhoneHref?: string;
|
|
22
|
+
/** Сотовый номер телефона. */
|
|
13
23
|
secondPhoneText?: string;
|
|
24
|
+
/** Свойства ссылки под именем. */
|
|
14
25
|
arbitraryLinkProps?: any;
|
|
26
|
+
/** Сработает при нажатии на кнопку "Закрыть". */
|
|
15
27
|
onClose: () => void;
|
|
28
|
+
/** Нужно ли блокировать прокрутку пока открыто окно. */
|
|
16
29
|
withScrollDisable?: ModalProps['withScrollDisable'];
|
|
30
|
+
/** Опции блокировки прокрутки. */
|
|
17
31
|
scrollDisableOptions?: ModalProps['scrollDisableOptions'];
|
|
18
32
|
}
|
|
19
33
|
/**
|
|
20
|
-
* Компонент
|
|
34
|
+
* Компонент модального окна сотрудника.
|
|
21
35
|
* @param props Свойства.
|
|
22
|
-
* @
|
|
23
|
-
* @param props.appointment Должность.
|
|
24
|
-
* @param props.photoUrl Ссылка на фото.
|
|
25
|
-
* @param props.email Почта.
|
|
26
|
-
* @param props.skype Skype.
|
|
27
|
-
* @param props.social Социальные сети.
|
|
28
|
-
* @param props.phoneHref Ссылка на рабочий номер телефона.
|
|
29
|
-
* @param props.phoneText Рабочий номер телефона.
|
|
30
|
-
* @param props.secondPhoneHref Ссылка на сотовый номер телефона.
|
|
31
|
-
* @param props.secondPhoneText Сотовый номер телефона.
|
|
32
|
-
* @param props.arbitraryLinkProps Свойства ссылки под именем.
|
|
33
|
-
* @param props.onClose Сработает при нажатии на кнопку "Закрыть".
|
|
34
|
-
* @return Компонент.
|
|
36
|
+
* @return Элемент.
|
|
35
37
|
*/
|
|
36
38
|
export declare const PersonModal: ({ name, appointment, photoUrl, email, skype, social, phoneHref, phoneText, secondPhoneHref, secondPhoneText, arbitraryLinkProps, onClose, withScrollDisable, scrollDisableOptions, }: PersonModalProps) => JSX.Element;
|
|
37
39
|
export default PersonModal;
|
|
@@ -16,24 +16,12 @@ const modal_1 = require("@sima-land/ui-nucleons/modal");
|
|
|
16
16
|
const keydown_1 = require("@sima-land/ui-nucleons/hooks/keydown");
|
|
17
17
|
const cx = bind_1.default.bind(person_modal_module_scss_1.default);
|
|
18
18
|
/**
|
|
19
|
-
* Компонент
|
|
19
|
+
* Компонент модального окна сотрудника.
|
|
20
20
|
* @param props Свойства.
|
|
21
|
-
* @
|
|
22
|
-
* @param props.appointment Должность.
|
|
23
|
-
* @param props.photoUrl Ссылка на фото.
|
|
24
|
-
* @param props.email Почта.
|
|
25
|
-
* @param props.skype Skype.
|
|
26
|
-
* @param props.social Социальные сети.
|
|
27
|
-
* @param props.phoneHref Ссылка на рабочий номер телефона.
|
|
28
|
-
* @param props.phoneText Рабочий номер телефона.
|
|
29
|
-
* @param props.secondPhoneHref Ссылка на сотовый номер телефона.
|
|
30
|
-
* @param props.secondPhoneText Сотовый номер телефона.
|
|
31
|
-
* @param props.arbitraryLinkProps Свойства ссылки под именем.
|
|
32
|
-
* @param props.onClose Сработает при нажатии на кнопку "Закрыть".
|
|
33
|
-
* @return Компонент.
|
|
21
|
+
* @return Элемент.
|
|
34
22
|
*/
|
|
35
23
|
const PersonModal = ({ name, appointment, photoUrl, email, skype, social, phoneHref, phoneText, secondPhoneHref, secondPhoneText, arbitraryLinkProps, onClose, withScrollDisable, scrollDisableOptions, }) => {
|
|
36
|
-
keydown_1.useKeydown('Escape', onClose);
|
|
24
|
+
(0, keydown_1.useKeydown)('Escape', onClose);
|
|
37
25
|
return (react_1.default.createElement(modal_1.Modal, { size: 's', withScrollDisable: withScrollDisable, scrollDisableOptions: scrollDisableOptions, onClose: onClose },
|
|
38
26
|
react_1.default.createElement(modal_1.Modal.Body, null,
|
|
39
27
|
react_1.default.createElement("div", { className: cx('main') },
|
|
@@ -50,7 +38,8 @@ const PersonModal = ({ name, appointment, photoUrl, email, skype, social, phoneH
|
|
|
50
38
|
'Email: ',
|
|
51
39
|
react_1.default.createElement(link_1.Link, { color: 'gray87', href: `mailto:${email}`, children: email }))),
|
|
52
40
|
Array.isArray(social) && social.length > 0 && (react_1.default.createElement("span", { className: cx('contacts-item') },
|
|
53
|
-
"\u0421\u043E\u0446. \u0441\u0435\u0442\u0438:
|
|
41
|
+
"\u0421\u043E\u0446. \u0441\u0435\u0442\u0438:",
|
|
42
|
+
' ',
|
|
54
43
|
social.map((props, key) => (react_1.default.createElement(link_1.Link, Object.assign({ className: cx('inline'), key: key, color: 'gray87', target: '_blank', rel: 'nofollow' }, props)))))),
|
|
55
44
|
skype && (react_1.default.createElement("span", { className: cx('contacts-item') },
|
|
56
45
|
'Skype: ',
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { ProductInfoProps } from '../../../common/components/product-info';
|
|
3
3
|
export interface ProductCardProps extends ProductInfoProps, React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** Будет вызвана при уходе курсора с элемента. */
|
|
4
5
|
onMouseLeave?: () => void;
|
|
6
|
+
/** Будет вызвана при нажатии на кнопку-иконку быстрого просмотра. */
|
|
5
7
|
onQuickViewClick?: () => void;
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
@@ -9,10 +11,11 @@ export interface ProductCardProps extends ProductInfoProps, React.HTMLAttributes
|
|
|
9
11
|
* @param props Свойства.
|
|
10
12
|
* @return Элемент.
|
|
11
13
|
*/
|
|
12
|
-
declare const CartControlSlot: ({ children, stepText, markupText, }: {
|
|
13
|
-
children
|
|
14
|
+
declare const CartControlSlot: ({ children, stepText, markupText, loading, }: {
|
|
15
|
+
children?: React.ReactNode;
|
|
14
16
|
stepText?: string | undefined;
|
|
15
17
|
markupText?: string | undefined;
|
|
18
|
+
loading?: boolean | undefined;
|
|
16
19
|
}) => JSX.Element;
|
|
17
20
|
export interface ProductCardComponent extends React.ForwardRefExoticComponent<React.PropsWithoutRef<ProductCardProps> & React.RefAttributes<HTMLDivElement>> {
|
|
18
21
|
CartControl: typeof CartControlSlot;
|
|
@@ -50,24 +50,24 @@ const cx = bind_1.default.bind(product_card_module_scss_1.default);
|
|
|
50
50
|
* @param props Свойства.
|
|
51
51
|
* @return Элемент.
|
|
52
52
|
*/
|
|
53
|
-
const CartControlSlot = ({ children, stepText, markupText, }) => (react_1.default.createElement("div", { className: cx('control-wrapper') },
|
|
54
|
-
react_1.default.createElement("div", { className: cx('control') }, children),
|
|
55
|
-
stepText &&
|
|
56
|
-
markupText &&
|
|
53
|
+
const CartControlSlot = ({ children, stepText, markupText, loading, }) => (react_1.default.createElement("div", { className: cx('control-wrapper', { loading }) },
|
|
54
|
+
react_1.default.createElement("div", { className: cx('control') }, !loading && children),
|
|
55
|
+
(loading || stepText) && react_1.default.createElement("div", { className: cx('unit-text') }, !loading && stepText),
|
|
56
|
+
!loading && markupText && react_1.default.createElement("div", { className: cx('bottom-text') }, markupText)));
|
|
57
57
|
/**
|
|
58
58
|
* Карточка товара, появляющаяся над элементом карусели.
|
|
59
59
|
* @param props Свойства компонента.
|
|
60
60
|
* @return Элемент.
|
|
61
61
|
*/
|
|
62
|
-
exports.ProductCard = react_1.forwardRef((_a, rootRef) => {
|
|
62
|
+
exports.ProductCard = (0, react_1.forwardRef)((_a, rootRef) => {
|
|
63
63
|
var { data, onLinkClick, onQuickViewClick, children,
|
|
64
64
|
// div props
|
|
65
65
|
className } = _a, rootProps = __rest(_a, ["data", "onLinkClick", "onQuickViewClick", "children", "className"]);
|
|
66
|
-
const { cartControl } = define_slots_1.defineSlots(children, { cartControl: CartControlSlot });
|
|
66
|
+
const { cartControl } = (0, define_slots_1.defineSlots)(children, { cartControl: CartControlSlot });
|
|
67
67
|
return (react_1.default.createElement("div", Object.assign({ ref: rootRef, className: cx('root', shapes_1.SmallRounds.all, shadows_1.BoxShadow.z4, className) }, rootProps),
|
|
68
68
|
react_1.default.createElement(product_info_1.ProductInfo, { data: data, onLinkClick: onLinkClick },
|
|
69
69
|
react_1.default.createElement(product_info_1.ProductInfo.OnImage, null,
|
|
70
|
-
react_1.default.createElement(with_hint_1.WithHint, { hint: '\u0411\u044B\u0441\u0442\u0440\u044B\u0439 \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440', direction: 'left' }, (ref, toggle) => (react_1.default.createElement(quick_view_button_1.QuickViewButton, { ref: ref, onMouseEnter: () => toggle(true), onMouseLeave: () => toggle(false), className: cx('quick-view-button'), onClick: with_prevent_1.default(onQuickViewClick) }))))),
|
|
70
|
+
react_1.default.createElement(with_hint_1.WithHint, { hint: '\u0411\u044B\u0441\u0442\u0440\u044B\u0439 \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440', direction: 'left' }, (ref, toggle) => (react_1.default.createElement(quick_view_button_1.QuickViewButton, { ref: ref, onMouseEnter: () => toggle(true), onMouseLeave: () => toggle(false), className: cx('quick-view-button'), onClick: (0, with_prevent_1.default)(onQuickViewClick) }))))),
|
|
71
71
|
cartControl));
|
|
72
72
|
});
|
|
73
73
|
exports.ProductCard.CartControl = CartControlSlot;
|
|
@@ -16,6 +16,20 @@
|
|
|
16
16
|
display: flex;
|
|
17
17
|
flex-wrap: wrap;
|
|
18
18
|
margin-top: 16px;
|
|
19
|
+
&.loading {
|
|
20
|
+
.control {
|
|
21
|
+
background: colors.$gray4;
|
|
22
|
+
border-radius: 4px;
|
|
23
|
+
}
|
|
24
|
+
.unit-text::before {
|
|
25
|
+
content: '';
|
|
26
|
+
display: block;
|
|
27
|
+
background: colors.$gray4;
|
|
28
|
+
border-radius: 4px;
|
|
29
|
+
width: 48px;
|
|
30
|
+
height: 16px;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
19
33
|
}
|
|
20
34
|
|
|
21
35
|
.control {
|
|
@@ -37,13 +37,13 @@ const cx = bind_1.default.bind(hover_card_module_scss_1.default);
|
|
|
37
37
|
* @return Элемент.
|
|
38
38
|
*/
|
|
39
39
|
const HoverCard = ({ data, targetRef, onMouseLeave, onQuickViewClick, onLinkClick, renderCartControl, }) => {
|
|
40
|
-
const rootRef = react_1.useRef(null);
|
|
41
|
-
const [ready, setReady] = react_1.useState(false);
|
|
42
|
-
react_1.useLayoutEffect(() => {
|
|
40
|
+
const rootRef = (0, react_1.useRef)(null);
|
|
41
|
+
const [ready, setReady] = (0, react_1.useState)(false);
|
|
42
|
+
(0, react_1.useLayoutEffect)(() => {
|
|
43
43
|
if (targetRef.current && rootRef.current) {
|
|
44
44
|
const element = rootRef.current;
|
|
45
45
|
const rect = targetRef.current.getBoundingClientRect();
|
|
46
|
-
const correction = utils_1.getOriginCorrection(rootRef.current);
|
|
46
|
+
const correction = (0, utils_1.getOriginCorrection)(rootRef.current);
|
|
47
47
|
element.style.left = `${correction.x + rect.left - 16}px`;
|
|
48
48
|
element.style.top = `${correction.y + rect.top - 16}px`;
|
|
49
49
|
element.style.width = `${rect.width + 32}px`;
|
|
@@ -9,11 +9,17 @@ interface ItemSize {
|
|
|
9
9
|
xl?: 2 | 3 | 4;
|
|
10
10
|
}
|
|
11
11
|
export interface ProductCarouselProps {
|
|
12
|
+
/** CSS-класс для корневого элемента. */
|
|
12
13
|
className?: string;
|
|
14
|
+
/** Элементы карусели. */
|
|
13
15
|
children?: React.ReactNode;
|
|
16
|
+
/** Найстройки размера элемента карусели. */
|
|
14
17
|
itemSize?: ItemSize;
|
|
18
|
+
/** Сработает при попадании карусели во viewport. */
|
|
15
19
|
onInViewport?: () => void;
|
|
20
|
+
/** Сработает при попадании карусели в область достаточно близкую к viewport'у. */
|
|
16
21
|
onNeedRequest?: () => void;
|
|
22
|
+
/** Нужно ли показывать всплывающую карточку при наведении на элемент карусели. */
|
|
17
23
|
withHoverCard?: boolean;
|
|
18
24
|
}
|
|
19
25
|
declare type CarouselItemProps = ProductInfoProps & Pick<HoverCardProps, 'renderCartControl' | 'onQuickViewClick'>;
|
|
@@ -51,50 +51,51 @@ const Item = () => null;
|
|
|
51
51
|
* @return Элемент.
|
|
52
52
|
*/
|
|
53
53
|
const ProductCarousel = ({ className, itemSize, onInViewport, onNeedRequest, withHoverCard, children, }) => {
|
|
54
|
-
const [activeItemIndex, setActiveItemIndex] = react_1.useState(null);
|
|
55
|
-
const cardShow = utils_1.useAllowFlag();
|
|
56
|
-
const needBigArrows = media_1.useMedia('(min-width: 1600px)');
|
|
57
|
-
const sectionRef = react_1.useRef(null);
|
|
58
|
-
const stubRef = react_1.useRef(null);
|
|
59
|
-
const targetItemRef = react_1.useRef(null);
|
|
54
|
+
const [activeItemIndex, setActiveItemIndex] = (0, react_1.useState)(null);
|
|
55
|
+
const cardShow = (0, utils_1.useAllowFlag)();
|
|
56
|
+
const needBigArrows = (0, media_1.useMedia)('(min-width: 1600px)');
|
|
57
|
+
const sectionRef = (0, react_1.useRef)(null);
|
|
58
|
+
const stubRef = (0, react_1.useRef)(null);
|
|
59
|
+
const targetItemRef = (0, react_1.useRef)(null);
|
|
60
60
|
const items = react_1.Children.toArray(children).reduce((acc, item) => {
|
|
61
|
-
react_1.isValidElement(item) && item.type === Item && acc.push(item.props);
|
|
61
|
+
(0, react_1.isValidElement)(item) && item.type === Item && acc.push(item.props);
|
|
62
62
|
return acc;
|
|
63
63
|
}, []);
|
|
64
64
|
// вычисляем ширину элемента карусели для позиционирования стрелок
|
|
65
|
-
const itemWidth = utils_1.useChildWidth(sectionRef, `.${cx('item')}`, []);
|
|
65
|
+
const itemWidth = (0, utils_1.useChildWidth)(sectionRef, `.${cx('item')}`, [items.length]);
|
|
66
66
|
// инициируем загрузку данных, когда компонент почти попал в зону видимости
|
|
67
|
-
utils_1.useViewport(stubRef, onNeedRequest, {
|
|
67
|
+
(0, utils_1.useViewport)(stubRef, onNeedRequest, {
|
|
68
68
|
rootMargin: '200px 0px 200px 0px',
|
|
69
69
|
});
|
|
70
70
|
// отправляем статистку, когда компонент попадает в зону видимости
|
|
71
|
-
utils_1.useViewport(sectionRef, onInViewport);
|
|
72
|
-
return Array.isArray(items) && items.length > 0
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
top: `${itemWidth / 2}px`,
|
|
83
|
-
},
|
|
71
|
+
(0, utils_1.useViewport)(sectionRef, onInViewport);
|
|
72
|
+
return Array.isArray(items) && items.length > 0 ? (react_1.default.createElement("div", { ref: sectionRef, className: cx('root', className) },
|
|
73
|
+
react_1.default.createElement(carousel_1.Carousel, Object.assign({ step: 3, draggable: false,
|
|
74
|
+
// докидываем индекс чтобы позже брать актуальные данные из списка по нему
|
|
75
|
+
items: items.map((item, index) => [item, index]) }, (itemWidth !== null && {
|
|
76
|
+
withControls: true,
|
|
77
|
+
controlProps: {
|
|
78
|
+
size: needBigArrows ? 'l' : 's',
|
|
79
|
+
style: {
|
|
80
|
+
zIndex: 1,
|
|
81
|
+
top: `${itemWidth / 2}px`,
|
|
84
82
|
},
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
83
|
+
},
|
|
84
|
+
}), { renderItem: ([item, index]) => (react_1.default.createElement("div", { "data-testid": 'product-carousel:item', className: cx('item', getSizeClasses(itemSize)), onMouseEnter: e => {
|
|
85
|
+
if (cardShow.allowed()) {
|
|
86
|
+
targetItemRef.current = e.currentTarget;
|
|
87
|
+
setActiveItemIndex(index);
|
|
88
|
+
}
|
|
89
|
+
} },
|
|
90
|
+
react_1.default.createElement(product_info_1.ProductInfo, { data: item.data, onLinkClick: item.onLinkClick }))),
|
|
91
|
+
// длительность прокрутки в Carousel - 320, делаем слегка с запасом
|
|
92
|
+
// @todo после восстановления проверить позицию курсора чтобы показать карточку (если будет критично)
|
|
93
|
+
onChangeTargetIndex: () => cardShow.disallowFor(360) })),
|
|
94
|
+
withHoverCard &&
|
|
95
|
+
activeItemIndex !== null &&
|
|
96
|
+
[items[activeItemIndex]].map(item => (react_1.default.createElement(hover_card_1.HoverCard, { key: activeItemIndex, targetRef: targetItemRef, onMouseLeave: () => setActiveItemIndex(null),
|
|
96
97
|
// данные элемента карусели
|
|
97
|
-
data:
|
|
98
|
+
data: item.data, onLinkClick: item.onLinkClick, onQuickViewClick: item.onQuickViewClick, renderCartControl: item.renderCartControl }))))) : (react_1.default.createElement("div", { ref: stubRef }));
|
|
98
99
|
};
|
|
99
100
|
exports.ProductCarousel = ProductCarousel;
|
|
100
101
|
exports.ProductCarousel.Item = Item;
|
|
@@ -13,7 +13,7 @@ const on_1 = __importDefault(require("@sima-land/ui-nucleons/helpers/on"));
|
|
|
13
13
|
* @param options Опции IntersectionObserver.
|
|
14
14
|
*/
|
|
15
15
|
const useViewport = (ref, callback, options) => {
|
|
16
|
-
react_1.useEffect(() => {
|
|
16
|
+
(0, react_1.useEffect)(() => {
|
|
17
17
|
const element = ref.current;
|
|
18
18
|
if (element) {
|
|
19
19
|
const observer = new IntersectionObserver(entries => {
|
|
@@ -33,15 +33,15 @@ exports.useViewport = useViewport;
|
|
|
33
33
|
* @return Объект работы с флагом.
|
|
34
34
|
*/
|
|
35
35
|
const useAllowFlag = () => {
|
|
36
|
-
const ref = react_1.useRef(true);
|
|
37
|
-
const timerIdRef = react_1.useRef();
|
|
38
|
-
const allowed = react_1.useCallback(() => ref.current, []);
|
|
39
|
-
const disallowFor = react_1.useCallback(timeout => {
|
|
36
|
+
const ref = (0, react_1.useRef)(true);
|
|
37
|
+
const timerIdRef = (0, react_1.useRef)();
|
|
38
|
+
const allowed = (0, react_1.useCallback)(() => ref.current, []);
|
|
39
|
+
const disallowFor = (0, react_1.useCallback)(timeout => {
|
|
40
40
|
window.clearTimeout(timerIdRef.current);
|
|
41
41
|
ref.current = false;
|
|
42
|
-
timerIdRef.current = window.setTimeout(() => ref.current = true, timeout);
|
|
42
|
+
timerIdRef.current = window.setTimeout(() => (ref.current = true), timeout);
|
|
43
43
|
}, []);
|
|
44
|
-
const controlRef = react_1.useRef({ allowed, disallowFor });
|
|
44
|
+
const controlRef = (0, react_1.useRef)({ allowed, disallowFor });
|
|
45
45
|
return controlRef.current;
|
|
46
46
|
};
|
|
47
47
|
exports.useAllowFlag = useAllowFlag;
|
|
@@ -53,16 +53,16 @@ exports.useAllowFlag = useAllowFlag;
|
|
|
53
53
|
* @return Ширина.
|
|
54
54
|
*/
|
|
55
55
|
const useChildWidth = (ref, selector, deps) => {
|
|
56
|
-
const [itemWidth, setItemWidth] = react_1.useState(null);
|
|
57
|
-
const update = react_1.useCallback(() => {
|
|
56
|
+
const [itemWidth, setItemWidth] = (0, react_1.useState)(null);
|
|
57
|
+
const update = (0, react_1.useCallback)(() => {
|
|
58
58
|
if (ref.current) {
|
|
59
59
|
const child = ref.current.querySelector(selector);
|
|
60
60
|
child && setItemWidth(child.clientWidth);
|
|
61
61
|
}
|
|
62
62
|
}, [ref]);
|
|
63
|
-
react_1.useEffect(() => {
|
|
63
|
+
(0, react_1.useEffect)(() => {
|
|
64
64
|
ref.current && update();
|
|
65
|
-
return on_1.default(window, 'resize', update);
|
|
65
|
+
return (0, on_1.default)(window, 'resize', update);
|
|
66
66
|
}, deps);
|
|
67
67
|
return itemWidth;
|
|
68
68
|
};
|
|
@@ -16,12 +16,12 @@ const BannerTitle = ({ promotionType, volumeDiscount, dueDate }) => {
|
|
|
16
16
|
break;
|
|
17
17
|
case 'special':
|
|
18
18
|
if (dueDate) {
|
|
19
|
-
content =
|
|
19
|
+
content = react_1.default.createElement(exports.CustomTimer, { dueDate: dueDate });
|
|
20
20
|
}
|
|
21
21
|
break;
|
|
22
22
|
case 'volume-discount':
|
|
23
23
|
if (volumeDiscount) {
|
|
24
|
-
content = (react_1.default.createElement("div", { className: banner_title_module_scss_1.default.discount },
|
|
24
|
+
content = (react_1.default.createElement("div", { className: banner_title_module_scss_1.default.discount, "data-testid": 'promotion-card:banner-discount' },
|
|
25
25
|
"\u0441\u043A\u0438\u0434\u043A\u0438 \u0434\u043E",
|
|
26
26
|
react_1.default.createElement("div", { className: banner_title_module_scss_1.default.percent },
|
|
27
27
|
volumeDiscount,
|
|
@@ -29,17 +29,17 @@ const BannerTitle = ({ promotionType, volumeDiscount, dueDate }) => {
|
|
|
29
29
|
}
|
|
30
30
|
break;
|
|
31
31
|
}
|
|
32
|
-
return
|
|
32
|
+
return react_1.default.createElement(react_1.default.Fragment, null, content);
|
|
33
33
|
};
|
|
34
34
|
exports.BannerTitle = BannerTitle;
|
|
35
|
-
const CustomTimer = ({ dueDate }) => (react_1.default.createElement(timer_1.Timer, { date: date_fns_1.formatISO(dueDate), timeout: 1000 * 60, format: ({ days, hours, minutes }) => (react_1.default.createElement("div", { className: banner_title_module_scss_1.default.timer },
|
|
35
|
+
const CustomTimer = ({ dueDate }) => (react_1.default.createElement(timer_1.Timer, { date: (0, date_fns_1.formatISO)(dueDate), timeout: 1000 * 60, format: ({ days, hours, minutes }) => (react_1.default.createElement("div", { className: banner_title_module_scss_1.default.timer, "data-testid": 'promotion-card:banner-timer' },
|
|
36
36
|
react_1.default.createElement(TimerPart, { label: '\u0434\u043D\u0435\u0439', value: Math.min(99, days) }),
|
|
37
|
-
react_1.default.createElement(
|
|
37
|
+
react_1.default.createElement(TimerDivider, null),
|
|
38
38
|
react_1.default.createElement(TimerPart, { label: '\u0447\u0430\u0441\u043E\u0432', value: hours % 24 }),
|
|
39
|
-
react_1.default.createElement(
|
|
39
|
+
react_1.default.createElement(TimerDivider, null),
|
|
40
40
|
react_1.default.createElement(TimerPart, { label: '\u043C\u0438\u043D\u0443\u0442', value: minutes % 60 }))) }));
|
|
41
41
|
exports.CustomTimer = CustomTimer;
|
|
42
42
|
const TimerPart = ({ label, value }) => (react_1.default.createElement("div", { className: banner_title_module_scss_1.default.part },
|
|
43
43
|
react_1.default.createElement("div", null, `${value}`.padStart(2, '0')),
|
|
44
44
|
react_1.default.createElement("div", { className: banner_title_module_scss_1.default.label }, label)));
|
|
45
|
-
const
|
|
45
|
+
const TimerDivider = () => react_1.default.createElement("div", { className: banner_title_module_scss_1.default.divider }, ":");
|
|
@@ -24,15 +24,13 @@ const toTimePart = (n) => `${n}`.padStart(2, '0');
|
|
|
24
24
|
const Estimate = ({ dueDate }) => {
|
|
25
25
|
const now = new Date();
|
|
26
26
|
let content = null;
|
|
27
|
-
if (date_fns_1.getYear(dueDate) !== date_fns_1.getYear(now)) {
|
|
28
|
-
const text = [date_fns_1.getDate, date_fns_1.getMonth, date_fns_1.getYear]
|
|
29
|
-
.map(fn => toTimePart(fn(dueDate)))
|
|
30
|
-
.join('.');
|
|
27
|
+
if ((0, date_fns_1.getYear)(dueDate) !== (0, date_fns_1.getYear)(now)) {
|
|
28
|
+
const text = [date_fns_1.getDate, date_fns_1.getMonth, date_fns_1.getYear].map(fn => toTimePart(fn(dueDate))).join('.');
|
|
31
29
|
content = `До ${text}`;
|
|
32
30
|
}
|
|
33
31
|
else {
|
|
34
|
-
content = `До ${date_fns_1.getDate(dueDate)} ${MONTH_SHORT_NAME[date_fns_1.getMonth(dueDate)]}`;
|
|
32
|
+
content = `До ${(0, date_fns_1.getDate)(dueDate)} ${MONTH_SHORT_NAME[(0, date_fns_1.getMonth)(dueDate)]}`;
|
|
35
33
|
}
|
|
36
|
-
return
|
|
34
|
+
return react_1.default.createElement(react_1.default.Fragment, null, content);
|
|
37
35
|
};
|
|
38
36
|
exports.Estimate = Estimate;
|
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { PromotionType } from './types';
|
|
3
3
|
export interface PromotionCardProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
/** Ссылка, переход по которой будет произведён при нажатии на карточку. */
|
|
4
5
|
href?: string;
|
|
6
|
+
/** Заголовок, выводится под баннером. */
|
|
5
7
|
title: string;
|
|
8
|
+
/** Подзаголовок. */
|
|
6
9
|
subtitle?: string;
|
|
10
|
+
/** Дополнительный текст, выводится в правом нижнем углу. */
|
|
7
11
|
postfix?: string;
|
|
12
|
+
/** Путь к изображению для баннера. */
|
|
8
13
|
imageSrc: string;
|
|
14
|
+
/** Дата окончания акции. */
|
|
9
15
|
dueDate: Date;
|
|
16
|
+
/** Тип акции. */
|
|
10
17
|
promotionType?: PromotionType;
|
|
18
|
+
/** Скидка за объем, указывается при соответствующем типе акции. */
|
|
11
19
|
volumeDiscount?: number;
|
|
20
|
+
/** Идентификатор для систем автоматизированного тестирования. */
|
|
21
|
+
'data-testid'?: string;
|
|
12
22
|
}
|
|
13
23
|
/**
|
|
14
24
|
* Карточка акции.
|
|
@@ -16,6 +26,6 @@ export interface PromotionCardProps extends React.HTMLAttributes<HTMLDivElement>
|
|
|
16
26
|
* @return Элемент.
|
|
17
27
|
*/
|
|
18
28
|
export declare const PromotionCard: {
|
|
19
|
-
({ promotionType, href, imageSrc, title, subtitle, dueDate, volumeDiscount, postfix, className, ...restProps }: PromotionCardProps): JSX.Element;
|
|
29
|
+
({ promotionType, href, imageSrc, title, subtitle, dueDate, volumeDiscount, postfix, className, "data-testid": testId, ...restProps }: PromotionCardProps): JSX.Element;
|
|
20
30
|
Placeholder: (props: React.HTMLAttributes<HTMLDivElement>) => JSX.Element;
|
|
21
31
|
};
|