@sima-land/moleculas 13.2.3 → 14.0.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/common/components/badge/index.d.ts +1 -3
- package/common/components/badge/index.js +1 -2
- package/common/components/intractive-image/index.d.ts +18 -0
- package/common/components/intractive-image/index.js +53 -0
- package/common/components/intractive-image/interactive-image.module.scss +50 -0
- package/common/constants.d.ts +2 -5
- package/common/constants.js +2 -2
- package/common/types.d.ts +1 -0
- package/common/types.js +2 -0
- package/desktop/components/modifiers/button/index.d.ts +5 -3
- package/desktop/components/modifiers/button/index.js +5 -7
- package/desktop/components/modifiers/button/modifier-button.module.scss +4 -0
- package/desktop/components/modifiers/group/index.d.ts +11 -81
- package/desktop/components/modifiers/group/index.js +29 -133
- package/desktop/components/modifiers/group/modifiers-group.module.scss +19 -31
- package/desktop/components/modifiers/group/utils.d.ts +20 -0
- package/desktop/components/modifiers/group/utils.js +73 -0
- package/desktop/components/modifiers/modifiers.scss +5 -0
- package/desktop/components/product-carousel/index.js +1 -1
- package/mobile/components/modifiers-list/modifier-item/index.d.ts +2 -1
- package/mobile/components/modifiers-list/modifier-item/index.js +3 -3
- package/package.json +1 -1
- package/desktop/components/item-image/index.d.ts +0 -88
- package/desktop/components/item-image/index.js +0 -135
- package/desktop/components/item-image/item-image.module.scss +0 -158
- package/desktop/components/modifiers/widget/index.d.ts +0 -18
- package/desktop/components/modifiers/widget/index.js +0 -36
- package/desktop/components/modifiers/widget/modifiers-widget.module.scss +0 -10
- package/desktop/components/modifiers/widget/readme.md +0 -53
- package/mobile/components/item-image/index.d.ts +0 -56
- package/mobile/components/item-image/index.js +0 -88
- package/mobile/components/item-image/item-image.module.scss +0 -79
|
@@ -3,13 +3,11 @@ export interface BadgeField {
|
|
|
3
3
|
type: 'text' | 'timer' | 'svg-url';
|
|
4
4
|
value: string;
|
|
5
5
|
}
|
|
6
|
-
export interface BadgeProps extends React.
|
|
6
|
+
export interface BadgeProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'color'> {
|
|
7
7
|
/** Основной цвет, используется как цвет обводки, иконок и текста. */
|
|
8
8
|
color?: string;
|
|
9
9
|
/** Содержимое шильдика. */
|
|
10
10
|
fields: Array<BadgeField>;
|
|
11
|
-
/** Ссылка, переход по которой будет произведён по нажатию на шильдик. */
|
|
12
|
-
href?: string;
|
|
13
11
|
/** Идентификатор для систем автоматизированного тестирования. */
|
|
14
12
|
'data-testid'?: string;
|
|
15
13
|
}
|
|
@@ -30,9 +30,8 @@ const cx = bind_1.default.bind(badge_module_scss_1.default);
|
|
|
30
30
|
*/
|
|
31
31
|
const Badge = (_a) => {
|
|
32
32
|
var { className, color, fields, href, style, 'data-testid': testId = 'badge' } = _a, restProps = __rest(_a, ["className", "color", "fields", "href", "style", 'data-testid']);
|
|
33
|
-
const Element = href ? 'a' : 'span';
|
|
34
33
|
const iconOnly = fields.length === 1 && fields[0].type === 'svg-url';
|
|
35
|
-
return (react_1.default.createElement(
|
|
34
|
+
return (react_1.default.createElement("a", Object.assign({}, restProps, { "data-testid": testId, href: href, style: Object.assign(Object.assign({}, style), { '--badge-color': color }), className: cx('root', iconOnly && 'icon-only', href && 'interactive', className), children: iconOnly ? (react_1.default.createElement("img", { className: cx('icon'), src: fields[0].value })) : (
|
|
36
35
|
// вложенный span нужен для того чтобы объединить `display: inline-flex` и `text-overflow: ellipsis`
|
|
37
36
|
react_1.default.createElement("span", { className: cx('content') }, fields.reduce((acc, item, i) => {
|
|
38
37
|
let result = null;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface InteractiveImageProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
children?: React.ReactNode;
|
|
4
|
+
'data-testid'?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface InteractiveImageImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
|
|
7
|
+
'data-testid'?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface InteractiveImagePointProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
'data-testid'?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const InteractiveImage: ({ children, "data-testid": testId, className, ...rest }: InteractiveImageProps) => JSX.Element;
|
|
15
|
+
export declare const Parts: {
|
|
16
|
+
readonly Image: React.ForwardRefExoticComponent<InteractiveImageImageProps & React.RefAttributes<HTMLImageElement>>;
|
|
17
|
+
readonly Point: React.ForwardRefExoticComponent<InteractiveImagePointProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
18
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
22
|
+
var t = {};
|
|
23
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
24
|
+
t[p] = s[p];
|
|
25
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
26
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
27
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
28
|
+
t[p[i]] = s[p[i]];
|
|
29
|
+
}
|
|
30
|
+
return t;
|
|
31
|
+
};
|
|
32
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
33
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
34
|
+
};
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.Parts = exports.InteractiveImage = void 0;
|
|
37
|
+
const react_1 = __importStar(require("react"));
|
|
38
|
+
const classnames_1 = __importDefault(require("classnames"));
|
|
39
|
+
const interactive_image_module_scss_1 = __importDefault(require("./interactive-image.module.scss"));
|
|
40
|
+
const InteractiveImage = (_a) => {
|
|
41
|
+
var { children, 'data-testid': testId, className } = _a, rest = __rest(_a, ["children", 'data-testid', "className"]);
|
|
42
|
+
return (react_1.default.createElement("div", Object.assign({ className: (0, classnames_1.default)(interactive_image_module_scss_1.default.root, className) }, rest, { "data-testid": testId }), react_1.Children.toArray(children).filter(child => (0, react_1.isValidElement)(child) && (child.type === Image || child.type === Point))));
|
|
43
|
+
};
|
|
44
|
+
exports.InteractiveImage = InteractiveImage;
|
|
45
|
+
const Image = (0, react_1.forwardRef)((_a, ref) => {
|
|
46
|
+
var { className, 'data-testid': testId = 'interactive-image:image' } = _a, rest = __rest(_a, ["className", 'data-testid']);
|
|
47
|
+
return (react_1.default.createElement("img", Object.assign({ ref: ref, className: (0, classnames_1.default)(interactive_image_module_scss_1.default.image, className), "data-testid": testId }, rest)));
|
|
48
|
+
});
|
|
49
|
+
const Point = (0, react_1.forwardRef)((_a, ref) => {
|
|
50
|
+
var { x, y, className, style, 'data-testid': testId = 'interactive-image:point' } = _a, rest = __rest(_a, ["x", "y", "className", "style", 'data-testid']);
|
|
51
|
+
return (react_1.default.createElement("a", Object.assign({ ref: ref, "aria-label": '\u0422\u043E\u0447\u043A\u0430 \u043D\u0430 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0438', "data-testid": testId, className: (0, classnames_1.default)(interactive_image_module_scss_1.default.point, className), style: Object.assign(Object.assign({}, style), { top: `${y}%`, left: `${x}%` }) }, rest)));
|
|
52
|
+
});
|
|
53
|
+
exports.Parts = { Image, Point };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
@use 'node_modules/@sima-land/ui-nucleons/colors';
|
|
2
|
+
@use 'node_modules/@sima-land/ui-nucleons/breakpoints';
|
|
3
|
+
|
|
4
|
+
.root {
|
|
5
|
+
display: inline-block;
|
|
6
|
+
font-size: 0;
|
|
7
|
+
position: relative;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
background: colors.$basic-gray4;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.image {
|
|
13
|
+
display: block;
|
|
14
|
+
max-width: 100%;
|
|
15
|
+
max-height: 100%;
|
|
16
|
+
min-width: 100%;
|
|
17
|
+
min-height: 100%;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.point {
|
|
21
|
+
position: absolute;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
align-items: center;
|
|
25
|
+
width: 64px;
|
|
26
|
+
height: 64px;
|
|
27
|
+
background: rgba(colors.$basic-gray87, 0.4);
|
|
28
|
+
border-radius: 50%;
|
|
29
|
+
transform: translate(-50%, -50%);
|
|
30
|
+
&:hover {
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
background: rgba(colors.$basic-gray87, 0.64);
|
|
33
|
+
}
|
|
34
|
+
&::after {
|
|
35
|
+
content: '';
|
|
36
|
+
display: block;
|
|
37
|
+
width: 24px;
|
|
38
|
+
height: 24px;
|
|
39
|
+
background: #fff;
|
|
40
|
+
border-radius: 50%;
|
|
41
|
+
}
|
|
42
|
+
@include breakpoints.down('xs') {
|
|
43
|
+
width: 40px;
|
|
44
|
+
height: 40px;
|
|
45
|
+
&::after {
|
|
46
|
+
width: 16px;
|
|
47
|
+
height: 16px;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
package/common/constants.d.ts
CHANGED
package/common/constants.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare type ModifierType = 'text' | 'image' | 'color';
|
package/common/types.js
ADDED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { CSSProperties } from 'react';
|
|
2
|
+
import { ModifierType } from '../../../../common/types';
|
|
2
3
|
export interface Modifier {
|
|
3
4
|
count?: number;
|
|
4
5
|
content: string;
|
|
5
6
|
color?: string;
|
|
6
7
|
image?: string;
|
|
7
|
-
type?:
|
|
8
|
+
type?: ModifierType;
|
|
8
9
|
isMarkdown?: boolean;
|
|
9
10
|
selected?: boolean;
|
|
10
11
|
}
|
|
11
12
|
export interface ModifierButtonProps extends Modifier {
|
|
12
13
|
className?: string;
|
|
14
|
+
style?: CSSProperties;
|
|
13
15
|
onClick?: React.MouseEventHandler<HTMLDivElement>;
|
|
14
16
|
squared?: boolean;
|
|
15
17
|
'data-testid'?: string;
|
|
@@ -17,4 +19,4 @@ export interface ModifierButtonProps extends Modifier {
|
|
|
17
19
|
/**
|
|
18
20
|
* Компонент модификатора.
|
|
19
21
|
*/
|
|
20
|
-
export declare const ModifierButton: React.ForwardRefExoticComponent<ModifierButtonProps & React.RefAttributes<HTMLDivElement
|
|
22
|
+
export declare const ModifierButton: React.ForwardRefExoticComponent<ModifierButtonProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -29,18 +29,16 @@ const modifier_button_module_scss_1 = __importDefault(require("./modifier-button
|
|
|
29
29
|
const bind_1 = __importDefault(require("classnames/bind"));
|
|
30
30
|
const constants_1 = require("../../../../common/constants");
|
|
31
31
|
const cx = bind_1.default.bind(modifier_button_module_scss_1.default);
|
|
32
|
-
const typesList = Object.values(constants_1.MODIFIERS_TYPES);
|
|
33
32
|
/**
|
|
34
33
|
* Компонент модификатора.
|
|
35
34
|
*/
|
|
36
|
-
exports.ModifierButton = (0, react_1.forwardRef)(function ModifierButton({ count = null, content, selected, color, image, type
|
|
37
|
-
const type = typesList.includes(typeProp) ? typeProp : 'text';
|
|
35
|
+
exports.ModifierButton = (0, react_1.forwardRef)(function ModifierButton({ count = null, content, selected, color, image, type = 'text', className, style, onClick, isMarkdown: hasMarkdown, squared = [constants_1.MODIFIER_TYPE.color, constants_1.MODIFIER_TYPE.image].includes(type), 'data-testid': testId = 'modifier-button', }, ref) {
|
|
38
36
|
const hasCount = (0, lodash_1.isNumber)(count) && count >= 0;
|
|
39
|
-
return (react_1.default.createElement("div", { ref: ref, className: cx('modifier-button', squared && 'squared', selected && 'selected', className), style: color ? { background: color } :
|
|
37
|
+
return (react_1.default.createElement("div", { ref: ref, className: cx('modifier-button', squared && 'squared', selected && 'selected', className), style: color ? Object.assign(Object.assign({}, style), { background: color }) : style, onClick: onClick, "data-testid": testId },
|
|
40
38
|
(hasCount || hasMarkdown) && (react_1.default.createElement("span", { className: cx('label', hasCount && 'with-count'), "data-testid": 'modifier-button:badge' },
|
|
41
39
|
hasCount && (count > 99 ? '99+' : count),
|
|
42
40
|
hasMarkdown && (hasCount ? '(У)' : 'У'))),
|
|
43
|
-
[constants_1.
|
|
44
|
-
type === constants_1.
|
|
45
|
-
type === constants_1.
|
|
41
|
+
[constants_1.MODIFIER_TYPE.text, constants_1.MODIFIER_TYPE.image].includes(type) && (react_1.default.createElement("div", { className: cx('content') },
|
|
42
|
+
type === constants_1.MODIFIER_TYPE.text && (react_1.default.createElement("span", { className: cx('text', !squared && 'guttered') }, String(content || ''))),
|
|
43
|
+
type === constants_1.MODIFIER_TYPE.image && react_1.default.createElement("img", { src: image, alt: content, className: cx('image') })))));
|
|
46
44
|
});
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
max-width: 100%;
|
|
7
7
|
position: relative;
|
|
8
8
|
display: inline-block;
|
|
9
|
+
font-size: 0;
|
|
10
|
+
line-height: 0;
|
|
9
11
|
border-radius: 4px;
|
|
10
12
|
min-width: $minSize;
|
|
11
13
|
height: $minSize;
|
|
@@ -47,6 +49,8 @@
|
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
.text {
|
|
52
|
+
font-size: 14px;
|
|
53
|
+
line-height: 20px;
|
|
50
54
|
text-overflow: ellipsis;
|
|
51
55
|
white-space: nowrap;
|
|
52
56
|
overflow: hidden;
|
|
@@ -1,85 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
import React, { Component } from 'react';
|
|
3
|
-
import { ModifierButtonProps, Modifier } from '../button';
|
|
4
|
-
declare type ModifierPredicate<T> = (item: Modifier) => T;
|
|
5
|
-
interface ModifiersGroupState {
|
|
6
|
-
needShowAll: boolean;
|
|
7
|
-
hasHiddenNodes: boolean;
|
|
8
|
-
lastVisibleChildIndex: number | null;
|
|
9
|
-
}
|
|
1
|
+
import { MouseEventHandler, ReactNode } from 'react';
|
|
10
2
|
export interface ModifiersGroupProps {
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
/** Будет вызвана
|
|
16
|
-
|
|
17
|
-
/** Возвращает тип модификатора ("text" или "image", по умолчанию "text"). */
|
|
18
|
-
getItemType?: ModifierPredicate<ModifierButtonProps['type']>;
|
|
19
|
-
/** Возвращает число с количеством модификатора (по умолчанию свойство "count"). */
|
|
20
|
-
getItemCount?: ModifierPredicate<number>;
|
|
21
|
-
/** Возвращает цвет модификатора (по умолчанию свойство "color"). */
|
|
22
|
-
getItemColor?: ModifierPredicate<string>;
|
|
23
|
-
/** Возвращает содержимое модификатора (по умолчанию свойство "content"). */
|
|
24
|
-
getItemContent?: ModifierPredicate<string>;
|
|
25
|
-
/** Показывает, выбран ли модификатор (по умолчанию свойство "selected"). */
|
|
26
|
-
isSelectedItem?: ModifierPredicate<boolean>;
|
|
27
|
-
/** Возвращает URL изображения модификатора (по умолчанию свойство "image"). */
|
|
28
|
-
getItemImage?: ModifierPredicate<string>;
|
|
29
|
-
/** Имеет ли товар уценку. */
|
|
30
|
-
isMarkdown?: ModifierPredicate<boolean>;
|
|
31
|
-
/** Сработает при нажатии на кнопку отображения всех модификаторов. */
|
|
32
|
-
onClickShowAll?: () => void;
|
|
33
|
-
/** Идентификатор для систем автоматизированного тестирования. */
|
|
34
|
-
'data-testid'?: string;
|
|
3
|
+
/** Кнопки модификаторов. */
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
/** Надо ли сразу показывать весь список не ограничивая двумя строками. */
|
|
6
|
+
defaultOpened?: boolean;
|
|
7
|
+
/** Будет вызвана после нажатия на кнопку показа всех модификаторов. */
|
|
8
|
+
onShowAll?: MouseEventHandler<HTMLDivElement>;
|
|
35
9
|
}
|
|
36
10
|
/**
|
|
37
|
-
*
|
|
38
|
-
* @param
|
|
39
|
-
* @return
|
|
40
|
-
*/
|
|
41
|
-
export declare const createHiddenNodeIndexFinder: (container: HTMLElement) => (childNode: HTMLElement) => boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Компонент списка модификаторов.
|
|
11
|
+
* Блок списка кнопок модификаторов.
|
|
12
|
+
* @param props Свойства.
|
|
13
|
+
* @return Элемент.
|
|
44
14
|
*/
|
|
45
|
-
export declare
|
|
46
|
-
removeGlobalListener: any;
|
|
47
|
-
state: {
|
|
48
|
-
needShowAll: boolean;
|
|
49
|
-
hasHiddenNodes: boolean;
|
|
50
|
-
lastVisibleChildIndex: null;
|
|
51
|
-
};
|
|
52
|
-
windowWidth: number;
|
|
53
|
-
containerRef: React.RefObject<HTMLDivElement>;
|
|
54
|
-
showingButtonRef: React.RefObject<HTMLDivElement>;
|
|
55
|
-
/**
|
|
56
|
-
* @inheritdoc
|
|
57
|
-
*/
|
|
58
|
-
componentDidMount(): void;
|
|
59
|
-
/**
|
|
60
|
-
* @inheritdoc
|
|
61
|
-
*/
|
|
62
|
-
componentDidUpdate(): void;
|
|
63
|
-
/**
|
|
64
|
-
* @inheritdoc
|
|
65
|
-
*/
|
|
66
|
-
componentWillUnmount(): void;
|
|
67
|
-
/**
|
|
68
|
-
* Сбрасывает информацию о видимых и невидимых дочерних узлах контейнера.
|
|
69
|
-
*/
|
|
70
|
-
resetVisibleNodesData: import("lodash").DebouncedFunc<() => void>;
|
|
71
|
-
/**
|
|
72
|
-
* Обновляет информацию о видимых и невидимых дочерних узлах контейнера,
|
|
73
|
-
* необходимую для показа кнопки раскрытия полного списка модификаторов.
|
|
74
|
-
*/
|
|
75
|
-
checkVisibleNodes: () => void;
|
|
76
|
-
/**
|
|
77
|
-
* Обработчик нажатия на кнопку отображения всех модификаторов.
|
|
78
|
-
*/
|
|
79
|
-
handleShowAllClick: () => void;
|
|
80
|
-
/**
|
|
81
|
-
* @inheritdoc
|
|
82
|
-
*/
|
|
83
|
-
render(): JSX.Element;
|
|
84
|
-
}
|
|
85
|
-
export {};
|
|
15
|
+
export declare const ModifiersGroup: ({ children, defaultOpened, onShowAll, }: ModifiersGroupProps) => JSX.Element;
|
|
@@ -22,144 +22,40 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.ModifiersGroup =
|
|
25
|
+
exports.ModifiersGroup = void 0;
|
|
26
26
|
const react_1 = __importStar(require("react"));
|
|
27
|
-
const lodash_1 = require("lodash");
|
|
28
|
-
const prop_1 = __importDefault(require("lodash/fp/prop"));
|
|
29
27
|
const button_1 = require("../button");
|
|
30
|
-
const
|
|
31
|
-
const modifiers_group_module_scss_1 = __importDefault(require("./modifiers-group.module.scss"));
|
|
28
|
+
const utils_1 = require("./utils");
|
|
32
29
|
const bind_1 = __importDefault(require("classnames/bind"));
|
|
30
|
+
const modifiers_group_module_scss_1 = __importDefault(require("./modifiers-group.module.scss"));
|
|
33
31
|
const cx = bind_1.default.bind(modifiers_group_module_scss_1.default);
|
|
34
32
|
/**
|
|
35
|
-
*
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Создает функцию, находящую индекс элемента, который не должен быть виден.
|
|
40
|
-
* @param container Контейнер.
|
|
41
|
-
* @return Функция.
|
|
33
|
+
* Блок списка кнопок модификаторов.
|
|
34
|
+
* @param props Свойства.
|
|
35
|
+
* @return Элемент.
|
|
42
36
|
*/
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
const ModifiersGroup = ({ children, defaultOpened = false, onShowAll, }) => {
|
|
38
|
+
const [opened, setOpened] = (0, react_1.useState)(defaultOpened);
|
|
39
|
+
const rootRef = (0, react_1.useRef)(null);
|
|
40
|
+
const openerRef = (0, react_1.useRef)(null);
|
|
41
|
+
const showAll = (0, react_1.useCallback)(event => {
|
|
42
|
+
setOpened(true);
|
|
43
|
+
onShowAll === null || onShowAll === void 0 ? void 0 : onShowAll(event);
|
|
44
|
+
}, [onShowAll]);
|
|
45
|
+
const viewState = (0, utils_1.useViewState)(rootRef, openerRef);
|
|
46
|
+
const items = react_1.Children.toArray(children).reduce((result, child, index) => {
|
|
47
|
+
if ((0, react_1.isValidElement)(child) && child.type === button_1.ModifierButton) {
|
|
48
|
+
const needHideItems = viewState.lastVisibleIndex !== -1 && !opened;
|
|
49
|
+
const isDisplayed = !needHideItems || index < viewState.lastVisibleIndex;
|
|
50
|
+
result.push(react_1.default.createElement(GroupItem, { key: index, hidden: !isDisplayed }, child));
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}, []);
|
|
54
|
+
return (react_1.default.createElement("div", { ref: rootRef, className: cx('root', { opened }) },
|
|
55
|
+
items,
|
|
56
|
+
!opened && (react_1.default.createElement(GroupItem, { ref: openerRef, invisible: viewState.lastVisibleIndex === -1 },
|
|
57
|
+
react_1.default.createElement(OpenButton, { count: items.length - viewState.lastVisibleIndex, onClick: showAll })))));
|
|
49
58
|
};
|
|
50
|
-
exports.createHiddenNodeIndexFinder = createHiddenNodeIndexFinder;
|
|
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
|
-
/**
|
|
59
|
-
* Компонент списка модификаторов.
|
|
60
|
-
*/
|
|
61
|
-
class ModifiersGroup extends react_1.Component {
|
|
62
|
-
constructor() {
|
|
63
|
-
super(...arguments);
|
|
64
|
-
this.state = {
|
|
65
|
-
// нажата ли кнопка показа всех модификаторов
|
|
66
|
-
needShowAll: this.props.needShowAll || false,
|
|
67
|
-
// есть ли дочерние узлы контейнера, которые скрыты из за ограничения его высоты
|
|
68
|
-
hasHiddenNodes: true,
|
|
69
|
-
// индекс последнего видимого элемента в ограниченном по высоте контейнере
|
|
70
|
-
lastVisibleChildIndex: null,
|
|
71
|
-
};
|
|
72
|
-
this.windowWidth = 0;
|
|
73
|
-
this.containerRef = (0, react_1.createRef)();
|
|
74
|
-
this.showingButtonRef = (0, react_1.createRef)();
|
|
75
|
-
/**
|
|
76
|
-
* Сбрасывает информацию о видимых и невидимых дочерних узлах контейнера.
|
|
77
|
-
*/
|
|
78
|
-
this.resetVisibleNodesData = (0, lodash_1.debounce)(() => {
|
|
79
|
-
if (document.documentElement.offsetWidth !== this.windowWidth) {
|
|
80
|
-
this.windowWidth = document.documentElement.offsetWidth;
|
|
81
|
-
this.setState({
|
|
82
|
-
hasHiddenNodes: true,
|
|
83
|
-
lastVisibleChildIndex: null,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
}, 250, { leading: true });
|
|
87
|
-
/**
|
|
88
|
-
* Обновляет информацию о видимых и невидимых дочерних узлах контейнера,
|
|
89
|
-
* необходимую для показа кнопки раскрытия полного списка модификаторов.
|
|
90
|
-
*/
|
|
91
|
-
this.checkVisibleNodes = () => {
|
|
92
|
-
// если не указан индекс последнего видимого узла
|
|
93
|
-
if (this.state.lastVisibleChildIndex === null) {
|
|
94
|
-
const containerEl = this.containerRef.current;
|
|
95
|
-
const showingButtonEl = this.showingButtonRef.current;
|
|
96
|
-
if (containerEl && showingButtonEl) {
|
|
97
|
-
const childList = [...containerEl.children];
|
|
98
|
-
const firstHiddenNodeIndex = childList.findIndex((0, exports.createHiddenNodeIndexFinder)(containerEl));
|
|
99
|
-
if (firstHiddenNodeIndex !== -1) {
|
|
100
|
-
const lastVisibleElIndex = firstHiddenNodeIndex - 1;
|
|
101
|
-
const lastVisibleNode = childList[lastVisibleElIndex];
|
|
102
|
-
if (lastVisibleNode) {
|
|
103
|
-
const rightBound = lastVisibleNode.getBoundingClientRect().right;
|
|
104
|
-
const rightContainerBound = containerEl.getBoundingClientRect().right;
|
|
105
|
-
// проверяем, хватает ли кнопке места (с запасом в половину) после последнего видимого дочернего элемента
|
|
106
|
-
const isShowingButtonFit = rightContainerBound - rightBound >= showingButtonEl.clientWidth * 1.5;
|
|
107
|
-
this.setState({
|
|
108
|
-
// если хватает места - ставим кнопку после последнего, иначе - вместо
|
|
109
|
-
lastVisibleChildIndex: lastVisibleElIndex + (isShowingButtonFit ? 1 : 0),
|
|
110
|
-
hasHiddenNodes: true,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
this.setState({ hasHiddenNodes: false });
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
/**
|
|
121
|
-
* Обработчик нажатия на кнопку отображения всех модификаторов.
|
|
122
|
-
*/
|
|
123
|
-
this.handleShowAllClick = () => {
|
|
124
|
-
const { onClickShowAll } = this.props;
|
|
125
|
-
this.setState({ needShowAll: true });
|
|
126
|
-
onClickShowAll && onClickShowAll();
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* @inheritdoc
|
|
131
|
-
*/
|
|
132
|
-
componentDidMount() {
|
|
133
|
-
this.windowWidth = document.documentElement.offsetWidth;
|
|
134
|
-
this.removeGlobalListener = (0, on_1.default)(window, 'resize', this.resetVisibleNodesData);
|
|
135
|
-
this.checkVisibleNodes();
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* @inheritdoc
|
|
139
|
-
*/
|
|
140
|
-
componentDidUpdate() {
|
|
141
|
-
this.checkVisibleNodes();
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* @inheritdoc
|
|
145
|
-
*/
|
|
146
|
-
componentWillUnmount() {
|
|
147
|
-
this.removeGlobalListener();
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* @inheritdoc
|
|
151
|
-
*/
|
|
152
|
-
render() {
|
|
153
|
-
const { items, onSelectItem, getItemType = defaultGetItemType, getItemCount = defaultGetItemCount, getItemColor = defaultGetItemColor, getItemContent = defaultGetItemContent, isSelectedItem = defaultIsSelectedItem, getItemImage = defaultGetItemImage, isMarkdown = defaultGetIsMarkdown, 'data-testid': testId = 'modifiers-group', } = this.props;
|
|
154
|
-
const { needShowAll, hasHiddenNodes, lastVisibleChildIndex } = this.state;
|
|
155
|
-
const needHideModifiers = !needShowAll && lastVisibleChildIndex !== null;
|
|
156
|
-
return (react_1.default.createElement("div", { className: cx('modifiers-group', !needShowAll && 'height-limited'), ref: this.containerRef, "data-testid": testId },
|
|
157
|
-
Array.isArray(items) &&
|
|
158
|
-
items.map((item, index) => {
|
|
159
|
-
const isDisplayed = !needHideModifiers || index < lastVisibleChildIndex;
|
|
160
|
-
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) }));
|
|
161
|
-
}),
|
|
162
|
-
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' }))));
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
59
|
exports.ModifiersGroup = ModifiersGroup;
|
|
60
|
+
const GroupItem = (0, react_1.forwardRef)(({ children, hidden, invisible }, ref) => (react_1.default.createElement("div", { ref: ref, className: cx('item', { hidden, invisible }), "data-testid": 'modifier-group:item' }, children)));
|
|
61
|
+
const OpenButton = ({ count, onClick }) => (react_1.default.createElement(button_1.ModifierButton, { squared: true, onClick: onClick, content: `+${count}`, className: cx('opener'), "data-testid": 'modifier-group:show-all-button' }));
|
|
@@ -1,43 +1,31 @@
|
|
|
1
1
|
@use 'node_modules/@sima-land/ui-nucleons/colors';
|
|
2
|
-
@
|
|
2
|
+
@use '../modifiers';
|
|
3
3
|
|
|
4
|
-
.
|
|
4
|
+
.root {
|
|
5
|
+
position: relative;
|
|
5
6
|
display: flex;
|
|
6
7
|
flex-wrap: wrap;
|
|
7
|
-
|
|
8
|
+
flex-direction: row;
|
|
9
|
+
margin: -#{modifiers.$gutter};
|
|
10
|
+
font-size: 0;
|
|
8
11
|
overflow: hidden;
|
|
9
|
-
|
|
10
|
-
max-height:
|
|
12
|
+
&:not(.opened) {
|
|
13
|
+
max-height: modifiers.$groupMaxHeight;
|
|
11
14
|
}
|
|
12
15
|
}
|
|
13
16
|
|
|
14
|
-
.
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.guttered {
|
|
26
|
-
margin: $gutter;
|
|
17
|
+
.item {
|
|
18
|
+
height: modifiers.$minSize;
|
|
19
|
+
margin: modifiers.$gutter;
|
|
20
|
+
max-width: 100%;
|
|
21
|
+
&.hidden {
|
|
22
|
+
display: none;
|
|
23
|
+
}
|
|
24
|
+
&.invisible {
|
|
25
|
+
opacity: 0;
|
|
26
|
+
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
.
|
|
30
|
-
width: $minSize;
|
|
29
|
+
.opener {
|
|
31
30
|
color: colors.$basic-blue;
|
|
32
31
|
}
|
|
33
|
-
|
|
34
|
-
.not-display {
|
|
35
|
-
display: none;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
.invisible {
|
|
39
|
-
opacity: 0;
|
|
40
|
-
height: 0;
|
|
41
|
-
margin-top: 0;
|
|
42
|
-
margin-bottom: 0;
|
|
43
|
-
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export interface ViewState {
|
|
3
|
+
phase: 'default' | 'ready';
|
|
4
|
+
lastVisibleIndex: number;
|
|
5
|
+
}
|
|
6
|
+
export declare const initialViewState: ViewState;
|
|
7
|
+
/**
|
|
8
|
+
* Хук состояния отображения блока модификаторов.
|
|
9
|
+
* @param containerRef Ref элемента-контейнера.
|
|
10
|
+
* @param openerRef Ref элемента кнопки, показывающей весь список модификаторов.
|
|
11
|
+
* @return Состояние.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useViewState(containerRef: RefObject<HTMLElement>, openerRef: RefObject<HTMLElement>): ViewState;
|
|
14
|
+
/**
|
|
15
|
+
* Определяет индекс последней видимой кнопки-модификатора для свернутого списка модификаторов.
|
|
16
|
+
* @param containerRef Ref элемента-контейнера.
|
|
17
|
+
* @param openerRef Ref элемента кнопки, показывающей весь список модификаторов.
|
|
18
|
+
* @return Состояние.
|
|
19
|
+
*/
|
|
20
|
+
export declare function defineViewState(containerRef: RefObject<HTMLElement>, openerRef: RefObject<HTMLElement>): ViewState;
|