@sima-land/moleculas 16.0.0-alpha.6 → 16.0.0-alpha.7
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/modifier/index.d.ts +2 -48
- package/common/components/modifier/index.js +3 -114
- package/common/components/modifier/modifier.d.ts +14 -0
- package/common/components/modifier/modifier.js +117 -0
- package/common/components/modifier/types.d.ts +35 -0
- package/common/components/modifier/types.js +2 -0
- package/common/components/product-info/types.d.ts +2 -2
- package/common/hooks/index.d.ts +1 -0
- package/common/hooks/index.js +1 -0
- package/desktop/components/product-carousel/index.d.ts +11 -6
- package/desktop/components/product-carousel/index.js +19 -18
- package/mobile/components/select-screen/index.d.ts +4 -4
- package/mobile/components/select-screen/index.js +5 -5
- package/package.json +1 -1
- /package/common/components/modifier/{modifiers.module.scss → modifier.module.scss} +0 -0
|
@@ -1,48 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
type: 'text';
|
|
4
|
-
text: string;
|
|
5
|
-
}
|
|
6
|
-
interface ColorContent {
|
|
7
|
-
type: 'color';
|
|
8
|
-
color: string;
|
|
9
|
-
}
|
|
10
|
-
interface ImageContent {
|
|
11
|
-
type: 'image';
|
|
12
|
-
src: string;
|
|
13
|
-
}
|
|
14
|
-
export type ModifierContent = TextContent | ColorContent | ImageContent;
|
|
15
|
-
export interface ModifierProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
16
|
-
/** Вывести выбранным. */
|
|
17
|
-
active?: boolean;
|
|
18
|
-
/** Вывести отключенным. */
|
|
19
|
-
disabled?: boolean;
|
|
20
|
-
/** Вывести зачеркнутым. */
|
|
21
|
-
crossedOut?: boolean;
|
|
22
|
-
/** Содержимое. */
|
|
23
|
-
content: ModifierContent;
|
|
24
|
-
/** Высота по дизайн-гайдам. */
|
|
25
|
-
size?: 's' | 'm';
|
|
26
|
-
/** Кол-во. */
|
|
27
|
-
count?: number;
|
|
28
|
-
/** Выводить ли ярлык уценки. */
|
|
29
|
-
markdown?: boolean;
|
|
30
|
-
/** Идентификатор для систем автоматизированного тестирования. */
|
|
31
|
-
'data-testid'?: string;
|
|
32
|
-
}
|
|
33
|
-
export type MoreButtonProps = Omit<ModifierProps, 'content' | 'crossedOut' | 'active' | 'count'> & {
|
|
34
|
-
count: number;
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Кнопка модификатора (аналога товара).
|
|
38
|
-
* @param props Свойства.
|
|
39
|
-
* @return Элемент.
|
|
40
|
-
*/
|
|
41
|
-
export declare function Modifier({ size, active, crossedOut, disabled, content, count, className, markdown, 'data-testid': testId, ...props }: ModifierProps): JSX.Element;
|
|
42
|
-
/**
|
|
43
|
-
* Кнопка "+N" для показа полного списка модификаторов.
|
|
44
|
-
* @param props Свойства.
|
|
45
|
-
* @return Элемент.
|
|
46
|
-
*/
|
|
47
|
-
export declare function MoreButton({ count, className, 'data-testid': testId, ...rest }: MoreButtonProps): JSX.Element;
|
|
48
|
-
export {};
|
|
1
|
+
export type { TextContent, ImageContent, ColorContent, ModifierContent, ModifierProps, MoreButtonProps, } from './types';
|
|
2
|
+
export { Modifier, MoreButton } from './modifier';
|
|
@@ -1,117 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
24
|
-
};
|
|
25
|
-
var __rest = (this && this.__rest) || function (s, e) {
|
|
26
|
-
var t = {};
|
|
27
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
28
|
-
t[p] = s[p];
|
|
29
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
30
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
31
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
32
|
-
t[p[i]] = s[p[i]];
|
|
33
|
-
}
|
|
34
|
-
return t;
|
|
35
|
-
};
|
|
36
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
-
};
|
|
39
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
3
|
exports.MoreButton = exports.Modifier = void 0;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const bind_1 = __importDefault(require("classnames/bind"));
|
|
45
|
-
const modifiers_module_scss_1 = __importDefault(require("./modifiers.module.scss"));
|
|
46
|
-
const hooks_1 = require("../../hooks");
|
|
47
|
-
const cx = bind_1.default.bind(modifiers_module_scss_1.default);
|
|
48
|
-
/**
|
|
49
|
-
* Кнопка модификатора (аналога товара).
|
|
50
|
-
* @param props Свойства.
|
|
51
|
-
* @return Элемент.
|
|
52
|
-
*/
|
|
53
|
-
function Modifier(_a) {
|
|
54
|
-
var { size = 'm', active, crossedOut, disabled, content, count, className, markdown, 'data-testid': testId = 'modifier' } = _a, props = __rest(_a, ["size", "active", "crossedOut", "disabled", "content", "count", "className", "markdown", 'data-testid']);
|
|
55
|
-
// текст хинта
|
|
56
|
-
const [hint, setHint] = (0, react_1.useState)('');
|
|
57
|
-
// состояние хинта
|
|
58
|
-
const [open, setOpen] = (0, react_1.useState)(false);
|
|
59
|
-
// позиционирование хинта
|
|
60
|
-
const _b = (0, hint_1.useHintFloating)({ open, onOpenChange: setOpen }), { refs } = _b, floating = __rest(_b, ["refs"]);
|
|
61
|
-
// пользовательское взаимодействие для хинта
|
|
62
|
-
const { getReferenceProps, getFloatingProps } = (0, hint_1.useHintOnHover)(floating);
|
|
63
|
-
// определение необходимости активации хинта
|
|
64
|
-
(0, react_1.useEffect)(() => {
|
|
65
|
-
const textElement = refs.reference.current;
|
|
66
|
-
if (!(textElement instanceof HTMLElement) || content.type !== 'text') {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
// eslint-disable-next-line require-jsdoc
|
|
70
|
-
const defineHint = () => setHint(isTruncated(textElement) ? content.text : '');
|
|
71
|
-
defineHint();
|
|
72
|
-
const observer = new ResizeObserver(defineHint);
|
|
73
|
-
observer.observe(textElement);
|
|
74
|
-
return () => observer.disconnect();
|
|
75
|
-
}, [content.text]);
|
|
76
|
-
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
77
|
-
react_1.default.createElement("a", Object.assign({}, props, { className: cx('root', `size-${size}`, { active, disabled }, className), "data-testid": testId }),
|
|
78
|
-
content.type === 'color' && (react_1.default.createElement("span", { className: cx('color'), role: 'banner', style: { background: content.color } })),
|
|
79
|
-
content.type === 'image' && react_1.default.createElement(Image, { src: content.src }),
|
|
80
|
-
content.type === 'text' && (react_1.default.createElement("span", Object.assign({ ref: refs.setReference, className: cx('text') }, getReferenceProps()), content.text)),
|
|
81
|
-
typeof count === 'number' && (react_1.default.createElement("span", { className: cx('counter') }, count > 99 ? '99+' : count)),
|
|
82
|
-
crossedOut && (react_1.default.createElement("svg", { width: '100%', height: '100%', className: cx('diagonal') },
|
|
83
|
-
react_1.default.createElement("line", { x1: '0', y1: '100%', x2: '100%', y2: '0', stroke: 'var(--modifier-border-color)' }))),
|
|
84
|
-
markdown && react_1.default.createElement("span", { className: modifiers_module_scss_1.default.corner }, "\u0423")),
|
|
85
|
-
hint && (react_1.default.createElement(hint_1.Hint, Object.assign({ open: open, hintRef: refs.setFloating, arrowRef: refs.setArrow }, getFloatingProps()), hint))));
|
|
86
|
-
}
|
|
87
|
-
exports.Modifier = Modifier;
|
|
88
|
-
/**
|
|
89
|
-
* Картинка с заглушкой в случае ошибки загрузки.
|
|
90
|
-
* @param props Свойства.
|
|
91
|
-
* @return Элемент.
|
|
92
|
-
*/
|
|
93
|
-
function Image(_a) {
|
|
94
|
-
var { src, onError } = _a, rest = __rest(_a, ["src", "onError"]);
|
|
95
|
-
const { failed, handleError } = (0, hooks_1.useImageStub)(src, onError);
|
|
96
|
-
return (react_1.default.createElement("span", { className: cx('image-wrapper', { fail: failed }) },
|
|
97
|
-
failed && react_1.default.createElement(ImageBroken_1.default, null),
|
|
98
|
-
react_1.default.createElement("img", Object.assign({ className: cx('image') }, rest, { src: src, onError: handleError }))));
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Кнопка "+N" для показа полного списка модификаторов.
|
|
102
|
-
* @param props Свойства.
|
|
103
|
-
* @return Элемент.
|
|
104
|
-
*/
|
|
105
|
-
function MoreButton(_a) {
|
|
106
|
-
var { count, className, 'data-testid': testId = 'more-modifiers' } = _a, rest = __rest(_a, ["count", "className", 'data-testid']);
|
|
107
|
-
return (react_1.default.createElement(Modifier, Object.assign({ role: 'button', "aria-label": '\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0432\u0441\u0435 \u0430\u043D\u0430\u043B\u043E\u0433\u0438' }, rest, { className: cx('more', className), content: { type: 'text', text: `+${count}` }, "data-testid": testId })));
|
|
108
|
-
}
|
|
109
|
-
exports.MoreButton = MoreButton;
|
|
110
|
-
/**
|
|
111
|
-
* Определяет, обрезан ли текст в элементе.
|
|
112
|
-
* @param el Элемент.
|
|
113
|
-
* @return Обрезан ли текст в элементе.
|
|
114
|
-
*/
|
|
115
|
-
function isTruncated(el) {
|
|
116
|
-
return el.scrollWidth > el.clientWidth;
|
|
117
|
-
}
|
|
4
|
+
var modifier_1 = require("./modifier");
|
|
5
|
+
Object.defineProperty(exports, "Modifier", { enumerable: true, get: function () { return modifier_1.Modifier; } });
|
|
6
|
+
Object.defineProperty(exports, "MoreButton", { enumerable: true, get: function () { return modifier_1.MoreButton; } });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { ModifierProps, MoreButtonProps } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Кнопка модификатора (аналога товара).
|
|
5
|
+
* @param props Свойства.
|
|
6
|
+
* @return Элемент.
|
|
7
|
+
*/
|
|
8
|
+
export declare function Modifier({ size, active, crossedOut, disabled, content, count, className, markdown, 'data-testid': testId, ...props }: ModifierProps): JSX.Element;
|
|
9
|
+
/**
|
|
10
|
+
* Кнопка "+N" для показа полного списка модификаторов.
|
|
11
|
+
* @param props Свойства.
|
|
12
|
+
* @return Элемент.
|
|
13
|
+
*/
|
|
14
|
+
export declare function MoreButton({ count, className, 'data-testid': testId, ...rest }: MoreButtonProps): JSX.Element;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
26
|
+
var t = {};
|
|
27
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
28
|
+
t[p] = s[p];
|
|
29
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
30
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
31
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
32
|
+
t[p[i]] = s[p[i]];
|
|
33
|
+
}
|
|
34
|
+
return t;
|
|
35
|
+
};
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.MoreButton = exports.Modifier = void 0;
|
|
41
|
+
const react_1 = __importStar(require("react"));
|
|
42
|
+
const hint_1 = require("@sima-land/ui-nucleons/hint");
|
|
43
|
+
const hooks_1 = require("../../hooks");
|
|
44
|
+
const ImageBroken_1 = __importDefault(require("@sima-land/ui-quarks/icons/40x40/Stroked/ImageBroken"));
|
|
45
|
+
const bind_1 = __importDefault(require("classnames/bind"));
|
|
46
|
+
const modifier_module_scss_1 = __importDefault(require("./modifier.module.scss"));
|
|
47
|
+
const cx = bind_1.default.bind(modifier_module_scss_1.default);
|
|
48
|
+
/**
|
|
49
|
+
* Кнопка модификатора (аналога товара).
|
|
50
|
+
* @param props Свойства.
|
|
51
|
+
* @return Элемент.
|
|
52
|
+
*/
|
|
53
|
+
function Modifier(_a) {
|
|
54
|
+
var { size = 'm', active, crossedOut, disabled, content, count, className, markdown, 'data-testid': testId = 'modifier' } = _a, props = __rest(_a, ["size", "active", "crossedOut", "disabled", "content", "count", "className", "markdown", 'data-testid']);
|
|
55
|
+
// текст хинта
|
|
56
|
+
const [hint, setHint] = (0, react_1.useState)('');
|
|
57
|
+
// состояние хинта
|
|
58
|
+
const [open, setOpen] = (0, react_1.useState)(false);
|
|
59
|
+
// позиционирование хинта
|
|
60
|
+
const _b = (0, hint_1.useHintFloating)({ open, onOpenChange: setOpen }), { refs } = _b, floating = __rest(_b, ["refs"]);
|
|
61
|
+
// пользовательское взаимодействие для хинта
|
|
62
|
+
const { getReferenceProps, getFloatingProps } = (0, hint_1.useHintOnHover)(floating);
|
|
63
|
+
// определение необходимости активации хинта
|
|
64
|
+
(0, react_1.useEffect)(() => {
|
|
65
|
+
const textElement = refs.reference.current;
|
|
66
|
+
if (!(textElement instanceof HTMLElement) || content.type !== 'text') {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// eslint-disable-next-line require-jsdoc
|
|
70
|
+
const defineHint = () => setHint(isTruncated(textElement) ? content.text : '');
|
|
71
|
+
defineHint();
|
|
72
|
+
const observer = new ResizeObserver(defineHint);
|
|
73
|
+
observer.observe(textElement);
|
|
74
|
+
return () => observer.disconnect();
|
|
75
|
+
}, [content.text]);
|
|
76
|
+
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
77
|
+
react_1.default.createElement("a", Object.assign({}, props, { className: cx('root', `size-${size}`, { active, disabled }, className), "data-testid": testId }),
|
|
78
|
+
content.type === 'color' && (react_1.default.createElement("span", { className: cx('color'), role: 'banner', style: { background: content.color } })),
|
|
79
|
+
content.type === 'image' && react_1.default.createElement(Image, { src: content.src }),
|
|
80
|
+
content.type === 'text' && (react_1.default.createElement("span", Object.assign({ ref: refs.setReference, className: cx('text') }, getReferenceProps()), content.text)),
|
|
81
|
+
typeof count === 'number' && (react_1.default.createElement("span", { className: cx('counter') }, count > 99 ? '99+' : count)),
|
|
82
|
+
crossedOut && (react_1.default.createElement("svg", { width: '100%', height: '100%', className: cx('diagonal') },
|
|
83
|
+
react_1.default.createElement("line", { x1: '0', y1: '100%', x2: '100%', y2: '0', stroke: 'var(--modifier-border-color)' }))),
|
|
84
|
+
markdown && react_1.default.createElement("span", { className: modifier_module_scss_1.default.corner }, "\u0423")),
|
|
85
|
+
hint && (react_1.default.createElement(hint_1.Hint, Object.assign({ open: open, hintRef: refs.setFloating, arrowRef: refs.setArrow }, getFloatingProps()), hint))));
|
|
86
|
+
}
|
|
87
|
+
exports.Modifier = Modifier;
|
|
88
|
+
/**
|
|
89
|
+
* Картинка с заглушкой в случае ошибки загрузки.
|
|
90
|
+
* @param props Свойства.
|
|
91
|
+
* @return Элемент.
|
|
92
|
+
*/
|
|
93
|
+
function Image(_a) {
|
|
94
|
+
var { src, onError } = _a, rest = __rest(_a, ["src", "onError"]);
|
|
95
|
+
const { failed, handleError } = (0, hooks_1.useImageStub)(src, onError);
|
|
96
|
+
return (react_1.default.createElement("span", { className: cx('image-wrapper', { fail: failed }) },
|
|
97
|
+
failed && react_1.default.createElement(ImageBroken_1.default, null),
|
|
98
|
+
react_1.default.createElement("img", Object.assign({ className: cx('image') }, rest, { src: src, onError: handleError }))));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Кнопка "+N" для показа полного списка модификаторов.
|
|
102
|
+
* @param props Свойства.
|
|
103
|
+
* @return Элемент.
|
|
104
|
+
*/
|
|
105
|
+
function MoreButton(_a) {
|
|
106
|
+
var { count, className, 'data-testid': testId = 'more-modifiers' } = _a, rest = __rest(_a, ["count", "className", 'data-testid']);
|
|
107
|
+
return (react_1.default.createElement(Modifier, Object.assign({ role: 'button', "aria-label": '\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0432\u0441\u0435 \u0430\u043D\u0430\u043B\u043E\u0433\u0438' }, rest, { className: cx('more', className), content: { type: 'text', text: `+${count}` }, "data-testid": testId })));
|
|
108
|
+
}
|
|
109
|
+
exports.MoreButton = MoreButton;
|
|
110
|
+
/**
|
|
111
|
+
* Определяет, обрезан ли текст в элементе.
|
|
112
|
+
* @param el Элемент.
|
|
113
|
+
* @return Обрезан ли текст в элементе.
|
|
114
|
+
*/
|
|
115
|
+
function isTruncated(el) {
|
|
116
|
+
return el.scrollWidth > el.clientWidth;
|
|
117
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AnchorHTMLAttributes } from 'react';
|
|
2
|
+
export interface TextContent {
|
|
3
|
+
type: 'text';
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ColorContent {
|
|
7
|
+
type: 'color';
|
|
8
|
+
color: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ImageContent {
|
|
11
|
+
type: 'image';
|
|
12
|
+
src: string;
|
|
13
|
+
}
|
|
14
|
+
export type ModifierContent = TextContent | ColorContent | ImageContent;
|
|
15
|
+
export interface ModifierProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
16
|
+
/** Вывести выбранным. */
|
|
17
|
+
active?: boolean;
|
|
18
|
+
/** Вывести отключенным. */
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
/** Вывести зачеркнутым. */
|
|
21
|
+
crossedOut?: boolean;
|
|
22
|
+
/** Содержимое. */
|
|
23
|
+
content: ModifierContent;
|
|
24
|
+
/** Высота по дизайн-гайдам. */
|
|
25
|
+
size?: 's' | 'm';
|
|
26
|
+
/** Кол-во. */
|
|
27
|
+
count?: number;
|
|
28
|
+
/** Выводить ли ярлык уценки. */
|
|
29
|
+
markdown?: boolean;
|
|
30
|
+
/** Идентификатор для систем автоматизированного тестирования. */
|
|
31
|
+
'data-testid'?: string;
|
|
32
|
+
}
|
|
33
|
+
export type MoreButtonProps = Omit<ModifierProps, 'content' | 'crossedOut' | 'active' | 'count'> & {
|
|
34
|
+
count: number;
|
|
35
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
2
|
export interface ProductInfoProps {
|
|
3
3
|
/** Ограничение товара. Влияет на отображение информации. */
|
|
4
4
|
restriction?: 'adult' | 'unavailable';
|
|
5
5
|
/** Содержимое. */
|
|
6
|
-
children?:
|
|
6
|
+
children?: ReactNode;
|
|
7
7
|
}
|
package/common/hooks/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { ReactEventHandler } from 'react';
|
|
|
4
4
|
* @param src Ссылка на картинку.
|
|
5
5
|
* @param onError Обработчик ошибки.
|
|
6
6
|
* @return Управление состоянием.
|
|
7
|
+
* @todo Переименовать в useImageError?
|
|
7
8
|
*/
|
|
8
9
|
export declare function useImageStub(src?: string, onError?: ReactEventHandler<HTMLImageElement>): {
|
|
9
10
|
failed: boolean;
|
package/common/hooks/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const react_1 = require("react");
|
|
|
8
8
|
* @param src Ссылка на картинку.
|
|
9
9
|
* @param onError Обработчик ошибки.
|
|
10
10
|
* @return Управление состоянием.
|
|
11
|
+
* @todo Переименовать в useImageError?
|
|
11
12
|
*/
|
|
12
13
|
function useImageStub(src, onError) {
|
|
13
14
|
const [failed, setFailed] = (0, react_1.useState)(false);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import { ReactElement, ReactNode, CSSProperties } from 'react';
|
|
2
|
+
import { ProductInfoProps } from '../../../common/components/product-info';
|
|
3
3
|
interface ItemSize {
|
|
4
4
|
xs?: 2 | 3 | 4;
|
|
5
5
|
s?: 2 | 3 | 4;
|
|
@@ -7,25 +7,30 @@ interface ItemSize {
|
|
|
7
7
|
l?: 2 | 3 | 4;
|
|
8
8
|
xl?: 2 | 3 | 4;
|
|
9
9
|
}
|
|
10
|
-
export type ItemElement =
|
|
10
|
+
export type ItemElement = ReactElement<ProductInfoProps>;
|
|
11
11
|
export interface ProductCarouselProps {
|
|
12
12
|
/** CSS-класс для корневого элемента. */
|
|
13
13
|
className?: string;
|
|
14
14
|
/** Элементы карусели. */
|
|
15
|
-
children?:
|
|
15
|
+
children?: ReactNode;
|
|
16
16
|
/** Настройки размера элемента карусели. */
|
|
17
|
-
itemSize?: ItemSize;
|
|
17
|
+
itemSize?: ItemSize | 'unset';
|
|
18
18
|
/** Сработает при попадании карусели во viewport. */
|
|
19
19
|
onInViewport?: () => void;
|
|
20
20
|
/** Сработает при попадании карусели в область достаточно близкую к viewport'у. */
|
|
21
21
|
onNeedRequest?: () => void;
|
|
22
22
|
/** Нужно ли показывать всплывающую карточку при наведении на элемент карусели. */
|
|
23
23
|
withHoverCard?: boolean;
|
|
24
|
+
/** Предоставит свойства для элемента карусели. */
|
|
25
|
+
itemProps?: {
|
|
26
|
+
style?: CSSProperties;
|
|
27
|
+
className?: string;
|
|
28
|
+
};
|
|
24
29
|
}
|
|
25
30
|
/**
|
|
26
31
|
* Карусель рекомендованных товаров.
|
|
27
32
|
* @param props Свойства.
|
|
28
33
|
* @return Элемент.
|
|
29
34
|
*/
|
|
30
|
-
export declare function ProductCarousel({ className, itemSize, onInViewport, onNeedRequest, withHoverCard, children, }: ProductCarouselProps): JSX.Element;
|
|
35
|
+
export declare function ProductCarousel({ className, itemSize, itemProps, onInViewport, onNeedRequest, withHoverCard, children, }: ProductCarouselProps): JSX.Element;
|
|
31
36
|
export {};
|
|
@@ -39,32 +39,33 @@ const product_carousel_module_scss_1 = __importDefault(require("./product-carous
|
|
|
39
39
|
const layer_1 = require("@sima-land/ui-nucleons/helpers/layer");
|
|
40
40
|
const cx = bind_1.default.bind(product_carousel_module_scss_1.default);
|
|
41
41
|
// eslint-disable-next-line require-jsdoc
|
|
42
|
-
const getSizeClasses = (size
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
const getSizeClasses = (size) => size && size !== 'unset'
|
|
43
|
+
? [
|
|
44
|
+
`size-xs-${size.xs || 4}`,
|
|
45
|
+
`size-s-${size.s || 3}`,
|
|
46
|
+
`size-m-${size.m || 2}`,
|
|
47
|
+
`size-l-${size.l || 2}`,
|
|
48
|
+
`size-xl-${size.xl || 2}`,
|
|
49
|
+
]
|
|
50
|
+
: [];
|
|
49
51
|
/**
|
|
50
52
|
* Карусель рекомендованных товаров.
|
|
51
53
|
* @param props Свойства.
|
|
52
54
|
* @return Элемент.
|
|
53
55
|
*/
|
|
54
|
-
function ProductCarousel({ className, itemSize, onInViewport, onNeedRequest, withHoverCard, children, }) {
|
|
56
|
+
function ProductCarousel({ className, itemSize = { xs: 4, s: 3, m: 2, l: 2, xl: 2 }, itemProps, onInViewport, onNeedRequest, withHoverCard, children, }) {
|
|
55
57
|
const layer = (0, layer_1.useLayer)();
|
|
56
58
|
const [activeItemIndex, setActiveItemIndex] = (0, react_1.useState)(null);
|
|
57
59
|
const cardShow = (0, utils_1.useAllowFlag)();
|
|
58
60
|
const needBigArrows = (0, media_1.useMedia)('(min-width: 1600px)');
|
|
59
61
|
const rootRef = (0, react_1.useRef)(null);
|
|
60
62
|
const targetItemRef = (0, react_1.useRef)(null);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
63
|
+
const items = react_1.Children.toArray(children).reduce((acc, item) => {
|
|
64
|
+
if ((0, react_1.isValidElement)(item) && item.type === product_info_1.ProductInfo) {
|
|
65
|
+
acc.push(item);
|
|
66
|
+
}
|
|
67
|
+
return acc;
|
|
68
|
+
}, []);
|
|
68
69
|
// вычисляем ширину элемента карусели для позиционирования стрелок
|
|
69
70
|
const firstItemRef = (0, react_1.useRef)(null);
|
|
70
71
|
const itemWidth = (0, utils_1.useClientWidth)(firstItemRef, [items.length]);
|
|
@@ -89,7 +90,7 @@ function ProductCarousel({ className, itemSize, onInViewport, onNeedRequest, wit
|
|
|
89
90
|
top: `${itemWidth / 2}px`,
|
|
90
91
|
},
|
|
91
92
|
},
|
|
92
|
-
}), { renderItem: ([item, index], realIndex) => (react_1.default.createElement(
|
|
93
|
+
}), { renderItem: ([item, index], realIndex) => (react_1.default.createElement(Item, { rootRef: realIndex === 0 ? firstItemRef : undefined, withHoverCard: withHoverCard, className: cx(getSizeClasses(itemSize), itemProps === null || itemProps === void 0 ? void 0 : itemProps.className), style: itemProps === null || itemProps === void 0 ? void 0 : itemProps.style, onMouseEnter: e => {
|
|
93
94
|
if (cardShow.allowed()) {
|
|
94
95
|
targetItemRef.current = e.currentTarget;
|
|
95
96
|
setActiveItemIndex(index);
|
|
@@ -109,8 +110,8 @@ exports.ProductCarousel = ProductCarousel;
|
|
|
109
110
|
* Полное содержимое будет выведено во всплывающей карточке.
|
|
110
111
|
* @inheritdoc
|
|
111
112
|
*/
|
|
112
|
-
function
|
|
113
|
-
return (react_1.default.createElement("div", { ref: rootRef, "data-testid": 'product-carousel:item', className: cx('item', className), onMouseEnter: onMouseEnter }, (0, react_1.cloneElement)(children, {
|
|
113
|
+
function Item({ rootRef, className, onMouseEnter, withHoverCard, children, style, }) {
|
|
114
|
+
return (react_1.default.createElement("div", { ref: rootRef, "data-testid": 'product-carousel:item', className: cx('item', className), onMouseEnter: onMouseEnter, style: style }, (0, react_1.cloneElement)(children, {
|
|
114
115
|
children: react_1.Children.toArray(children.props.children).reduce((list, child) => {
|
|
115
116
|
if ((0, react_1.isValidElement)(child)) {
|
|
116
117
|
switch (child.type) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ButtonHTMLAttributes } from 'react';
|
|
2
2
|
import { LayoutProps } from '@sima-land/ui-nucleons/layout';
|
|
3
3
|
export type OptionSize = 's' | 'm' | 'l' | 'xl';
|
|
4
|
-
export interface SelectScreenOptionProps extends
|
|
4
|
+
export interface SelectScreenOptionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
5
5
|
size?: OptionSize;
|
|
6
6
|
selected?: boolean;
|
|
7
7
|
withSelectedIcon?: boolean;
|
|
@@ -11,10 +11,10 @@ export interface SelectScreenOptionProps extends React.ButtonHTMLAttributes<HTML
|
|
|
11
11
|
* @param props Свойства.
|
|
12
12
|
* @return Элемент.
|
|
13
13
|
*/
|
|
14
|
-
export declare
|
|
14
|
+
export declare function SelectScreenLayout({ children, ...props }: LayoutProps): JSX.Element;
|
|
15
15
|
/**
|
|
16
16
|
* Опция.
|
|
17
17
|
* @param props Свойства.
|
|
18
18
|
* @return Элемент.
|
|
19
19
|
*/
|
|
20
|
-
export declare
|
|
20
|
+
export declare function SelectScreenOption({ children, className, selected, withSelectedIcon, size, ...props }: SelectScreenOptionProps): JSX.Element;
|
|
@@ -48,21 +48,21 @@ const select_screen_module_scss_1 = __importDefault(require("./select-screen.mod
|
|
|
48
48
|
* @param props Свойства.
|
|
49
49
|
* @return Элемент.
|
|
50
50
|
*/
|
|
51
|
-
|
|
51
|
+
function SelectScreenLayout(_a) {
|
|
52
52
|
var { children } = _a, props = __rest(_a, ["children"]);
|
|
53
53
|
return (react_1.default.createElement(layout_1.MobileLayout, Object.assign({}, props, { disabledOn: ['mxs', 'ms'] }),
|
|
54
|
-
react_1.default.createElement("div", { className: select_screen_module_scss_1.default.container }, react_1.Children.toArray(children).filter(x => (0, react_1.isValidElement)(x) && x.type ===
|
|
55
|
-
}
|
|
54
|
+
react_1.default.createElement("div", { className: select_screen_module_scss_1.default.container }, react_1.Children.toArray(children).filter(x => (0, react_1.isValidElement)(x) && x.type === SelectScreenOption))));
|
|
55
|
+
}
|
|
56
56
|
exports.SelectScreenLayout = SelectScreenLayout;
|
|
57
57
|
/**
|
|
58
58
|
* Опция.
|
|
59
59
|
* @param props Свойства.
|
|
60
60
|
* @return Элемент.
|
|
61
61
|
*/
|
|
62
|
-
|
|
62
|
+
function SelectScreenOption(_a) {
|
|
63
63
|
var { children, className, selected, withSelectedIcon = selected, size = 'm' } = _a, props = __rest(_a, ["children", "className", "selected", "withSelectedIcon", "size"]);
|
|
64
64
|
return (react_1.default.createElement("button", Object.assign({}, props, { type: 'button', className: (0, classnames_1.default)(select_screen_module_scss_1.default.item, className, select_screen_module_scss_1.default[`size-${size}`]), "data-testid": 'select-screen:option' }),
|
|
65
65
|
children,
|
|
66
66
|
selected && withSelectedIcon && react_1.default.createElement(Check_1.default, { role: 'presentation', className: select_screen_module_scss_1.default.icon })));
|
|
67
|
-
}
|
|
67
|
+
}
|
|
68
68
|
exports.SelectScreenOption = SelectScreenOption;
|
package/package.json
CHANGED
|
File without changes
|