@snack-uikit/tag 0.4.10-preview-104ad22c.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/CHANGELOG.md +256 -0
- package/LICENSE +201 -0
- package/README.md +31 -0
- package/dist/components/Tag/Tag.d.ts +20 -0
- package/dist/components/Tag/Tag.js +24 -0
- package/dist/components/Tag/constants.d.ts +4 -0
- package/dist/components/Tag/constants.js +5 -0
- package/dist/components/Tag/index.d.ts +1 -0
- package/dist/components/Tag/index.js +1 -0
- package/dist/components/Tag/styles.module.css +270 -0
- package/dist/components/TagRow/TagRow.d.ts +22 -0
- package/dist/components/TagRow/TagRow.js +25 -0
- package/dist/components/TagRow/constants.d.ts +5 -0
- package/dist/components/TagRow/constants.js +5 -0
- package/dist/components/TagRow/index.d.ts +1 -0
- package/dist/components/TagRow/index.js +1 -0
- package/dist/components/TagRow/utils.d.ts +2 -0
- package/dist/components/TagRow/utils.js +13 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/constants.d.ts +15 -0
- package/dist/constants.js +17 -0
- package/dist/helperComponents/TagList/TagList.d.ts +12 -0
- package/dist/helperComponents/TagList/TagList.js +12 -0
- package/dist/helperComponents/TagList/index.d.ts +1 -0
- package/dist/helperComponents/TagList/index.js +1 -0
- package/dist/helperComponents/TagMore/TagMore.d.ts +12 -0
- package/dist/helperComponents/TagMore/TagMore.js +10 -0
- package/dist/helperComponents/TagMore/index.d.ts +1 -0
- package/dist/helperComponents/TagMore/index.js +1 -0
- package/dist/helperComponents/TagMore/styles.module.css +69 -0
- package/dist/helperComponents/TagRowSimple/TagRowSimple.d.ts +12 -0
- package/dist/helperComponents/TagRowSimple/TagRowSimple.js +20 -0
- package/dist/helperComponents/TagRowSimple/index.d.ts +1 -0
- package/dist/helperComponents/TagRowSimple/index.js +1 -0
- package/dist/helperComponents/TagRowSimple/styles.module.css +10 -0
- package/dist/helperComponents/TagRowTruncated/TagRowTruncated.d.ts +13 -0
- package/dist/helperComponents/TagRowTruncated/TagRowTruncated.js +87 -0
- package/dist/helperComponents/TagRowTruncated/hooks.d.ts +3 -0
- package/dist/helperComponents/TagRowTruncated/hooks.js +17 -0
- package/dist/helperComponents/TagRowTruncated/index.d.ts +1 -0
- package/dist/helperComponents/TagRowTruncated/index.js +1 -0
- package/dist/helperComponents/TagRowTruncated/styles.module.css +47 -0
- package/dist/helperComponents/TagRowTruncated/utils.d.ts +2 -0
- package/dist/helperComponents/TagRowTruncated/utils.js +4 -0
- package/dist/helperComponents/index.d.ts +2 -0
- package/dist/helperComponents/index.js +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.js +1 -0
- package/package.json +42 -0
- package/src/components/Tag/Tag.tsx +55 -0
- package/src/components/Tag/constants.ts +6 -0
- package/src/components/Tag/index.ts +1 -0
- package/src/components/Tag/styles.module.scss +175 -0
- package/src/components/TagRow/TagRow.tsx +34 -0
- package/src/components/TagRow/constants.ts +5 -0
- package/src/components/TagRow/index.ts +1 -0
- package/src/components/TagRow/utils.ts +16 -0
- package/src/components/index.ts +2 -0
- package/src/constants.ts +16 -0
- package/src/helperComponents/TagList/TagList.tsx +32 -0
- package/src/helperComponents/TagList/index.ts +1 -0
- package/src/helperComponents/TagMore/TagMore.tsx +54 -0
- package/src/helperComponents/TagMore/index.ts +1 -0
- package/src/helperComponents/TagMore/styles.module.scss +61 -0
- package/src/helperComponents/TagRowSimple/TagRowSimple.tsx +25 -0
- package/src/helperComponents/TagRowSimple/index.ts +1 -0
- package/src/helperComponents/TagRowSimple/styles.module.scss +14 -0
- package/src/helperComponents/TagRowTruncated/TagRowTruncated.tsx +127 -0
- package/src/helperComponents/TagRowTruncated/hooks.ts +23 -0
- package/src/helperComponents/TagRowTruncated/index.ts +1 -0
- package/src/helperComponents/TagRowTruncated/styles.module.scss +57 -0
- package/src/helperComponents/TagRowTruncated/utils.ts +7 -0
- package/src/helperComponents/index.ts +2 -0
- package/src/index.ts +1 -0
- package/src/types.ts +11 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
13
|
+
import cn from 'classnames';
|
|
14
|
+
import { useEffect, useRef, useState } from 'react';
|
|
15
|
+
import { extractSupportProps } from '@snack-uikit/utils';
|
|
16
|
+
import { TAG_ROW_TEST_IDS } from '../../components/TagRow/constants';
|
|
17
|
+
import { TagList } from '../TagList';
|
|
18
|
+
import { TagMore } from '../TagMore';
|
|
19
|
+
import { useResizeObserver } from './hooks';
|
|
20
|
+
import styles from './styles.module.css';
|
|
21
|
+
import { getGapWidth } from './utils';
|
|
22
|
+
export function TagRowTruncated(_a) {
|
|
23
|
+
var { items, rowLimit, size, moreButtonLabel = '', className, onItemRemove } = _a, rest = __rest(_a, ["items", "rowLimit", "size", "moreButtonLabel", "className", "onItemRemove"]);
|
|
24
|
+
const [visibleTags, setVisibleTags] = useState([]);
|
|
25
|
+
const [hiddenTags, setHiddenTags] = useState([]);
|
|
26
|
+
const hiddenRowElementRef = useRef(null);
|
|
27
|
+
const hiddenMoreButtonRef = useRef(null);
|
|
28
|
+
const hiddenMoreButtonWrapperRef = useRef(null);
|
|
29
|
+
const [firstTagElement, setFirstTagElement] = useState(null);
|
|
30
|
+
const tagsMapRef = useRef(new Map());
|
|
31
|
+
const { width: maxWidth } = useResizeObserver(hiddenRowElementRef.current);
|
|
32
|
+
const { width: firstVisibleTagWidth } = useResizeObserver(firstTagElement);
|
|
33
|
+
function setTagElement(tag, index) {
|
|
34
|
+
return (tagElement) => {
|
|
35
|
+
if (index === 0 && tagElement) {
|
|
36
|
+
setFirstTagElement(tagElement);
|
|
37
|
+
}
|
|
38
|
+
if (tagElement === null) {
|
|
39
|
+
tagsMapRef.current.delete(tag);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
tagsMapRef.current.set(tag, tagElement);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const gapWidth = getGapWidth(hiddenRowElementRef);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
var _a;
|
|
49
|
+
if (maxWidth < 1) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const newVisibleTags = [];
|
|
53
|
+
const newHiddenTags = [];
|
|
54
|
+
const moreButtonWidth = ((_a = hiddenMoreButtonRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0;
|
|
55
|
+
let currentRowWidth = 0;
|
|
56
|
+
let currentRowCount = 1;
|
|
57
|
+
tagsMapRef.current.forEach((tagElement, tagRowItem) => {
|
|
58
|
+
const tagWidth = (tagElement === null || tagElement === void 0 ? void 0 : tagElement.offsetWidth) || 0;
|
|
59
|
+
const sumRowWidth = currentRowWidth + tagWidth + gapWidth;
|
|
60
|
+
if (currentRowCount > rowLimit) {
|
|
61
|
+
newHiddenTags.push(tagRowItem);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (currentRowCount === rowLimit) {
|
|
65
|
+
if (sumRowWidth + moreButtonWidth > maxWidth) {
|
|
66
|
+
currentRowCount++;
|
|
67
|
+
newHiddenTags.push(tagRowItem);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
currentRowWidth = sumRowWidth;
|
|
71
|
+
newVisibleTags.push(tagRowItem);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (sumRowWidth > maxWidth) {
|
|
75
|
+
currentRowWidth = tagWidth + gapWidth;
|
|
76
|
+
currentRowCount++;
|
|
77
|
+
newVisibleTags.push(tagRowItem);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
currentRowWidth = sumRowWidth;
|
|
81
|
+
newVisibleTags.push(tagRowItem);
|
|
82
|
+
});
|
|
83
|
+
setVisibleTags(newVisibleTags);
|
|
84
|
+
setHiddenTags(newHiddenTags);
|
|
85
|
+
}, [items, rowLimit, maxWidth, onItemRemove, gapWidth, firstVisibleTagWidth]);
|
|
86
|
+
return (_jsxs("div", Object.assign({ className: cn(styles.wrapper, className) }, extractSupportProps(rest), { "data-size": size }, { children: [_jsx("div", Object.assign({ className: styles.hiddenRow, ref: hiddenRowElementRef, "data-size": size }, { children: _jsx(TagList, { items: items, size: size, onItemRemove: onItemRemove, setTagRef: setTagElement }) })), _jsx("div", Object.assign({ className: styles.hiddenMoreButton, ref: hiddenMoreButtonWrapperRef }, { children: _jsx(TagMore, { items: items, text: moreButtonLabel, size: size, buttonRef: hiddenMoreButtonRef }) })), _jsxs("div", Object.assign({ className: styles.visibleRow, "data-size": size, "data-test-id": TAG_ROW_TEST_IDS.visibleTagsWrapper }, { children: [_jsx(TagList, { items: visibleTags, size: size, onItemRemove: onItemRemove }), hiddenTags.length > 0 && (_jsx(TagMore, { items: hiddenTags, text: moreButtonLabel, size: size, onItemRemove: onItemRemove }))] }))] })));
|
|
87
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
export const useResizeObserver = (element) => {
|
|
3
|
+
const [width, setWidth] = useState(0);
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
if (!element) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
9
|
+
if (element.offsetWidth !== width) {
|
|
10
|
+
setWidth(element.offsetWidth);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
resizeObserver.observe(element);
|
|
14
|
+
return () => resizeObserver.disconnect();
|
|
15
|
+
}, [element, width]);
|
|
16
|
+
return { width };
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TagRowTruncated';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TagRowTruncated';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
.wrapper{
|
|
2
|
+
position:relative;
|
|
3
|
+
display:flex;
|
|
4
|
+
flex-wrap:wrap;
|
|
5
|
+
width:100%;
|
|
6
|
+
max-width:100%;
|
|
7
|
+
}
|
|
8
|
+
.wrapper[data-size=xs]{
|
|
9
|
+
gap:var(--space-tag-row-xs-gap, 2px);
|
|
10
|
+
}
|
|
11
|
+
.wrapper[data-size=s]{
|
|
12
|
+
gap:var(--space-tag-row-s-gap, 2px);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.visibleRow{
|
|
16
|
+
display:flex;
|
|
17
|
+
flex-wrap:wrap;
|
|
18
|
+
max-width:100%;
|
|
19
|
+
}
|
|
20
|
+
.visibleRow[data-size=xs]{
|
|
21
|
+
gap:var(--space-tag-row-xs-gap, 2px);
|
|
22
|
+
}
|
|
23
|
+
.visibleRow[data-size=s]{
|
|
24
|
+
gap:var(--space-tag-row-s-gap, 2px);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.hiddenRow{
|
|
28
|
+
position:absolute;
|
|
29
|
+
top:0;
|
|
30
|
+
left:0;
|
|
31
|
+
display:flex;
|
|
32
|
+
flex-wrap:wrap;
|
|
33
|
+
width:100%;
|
|
34
|
+
visibility:hidden;
|
|
35
|
+
}
|
|
36
|
+
.hiddenRow[data-size=xs]{
|
|
37
|
+
gap:var(--space-tag-row-xs-gap, 2px);
|
|
38
|
+
}
|
|
39
|
+
.hiddenRow[data-size=s]{
|
|
40
|
+
gap:var(--space-tag-row-s-gap, 2px);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.hiddenMoreButton{
|
|
44
|
+
position:absolute;
|
|
45
|
+
left:0;
|
|
46
|
+
visibility:hidden;
|
|
47
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './components';
|
package/dist/types.d.ts
ADDED
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@snack-uikit/tag",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"title": "Tag",
|
|
7
|
+
"version": "0.4.10-preview-104ad22c.0",
|
|
8
|
+
"sideEffects": [
|
|
9
|
+
"*.css",
|
|
10
|
+
"*.woff",
|
|
11
|
+
"*.woff2"
|
|
12
|
+
],
|
|
13
|
+
"description": "",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"module": "./dist/index.js",
|
|
16
|
+
"homepage": "https://git.sbercloud.tech/sbercloud-ui/tokens-design-system/snack-uikit/-/tree/master/packages/tag",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://git.sbercloud.tech/sbercloud-ui/tokens-design-system/snack-uikit.git",
|
|
20
|
+
"directory": "packages/tag"
|
|
21
|
+
},
|
|
22
|
+
"author": "Дмитрий Безматерных <dobezmaternih@cloud.ru>",
|
|
23
|
+
"contributors": [
|
|
24
|
+
"Дмитрий Безматерных <dobezmaternih@cloud.ru>"
|
|
25
|
+
],
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"src",
|
|
29
|
+
"./CHANGELOG.md",
|
|
30
|
+
"./LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"license": "Apache-2.0",
|
|
33
|
+
"scripts": {},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@snack-uikit/icons": "0.18.2-preview-104ad22c.0",
|
|
36
|
+
"@snack-uikit/popover-private": "0.10.1-preview-104ad22c.0",
|
|
37
|
+
"@snack-uikit/scroll": "0.3.5-preview-104ad22c.0",
|
|
38
|
+
"@snack-uikit/utils": "2.0.2-preview-104ad22c.0",
|
|
39
|
+
"classnames": "2.3.2"
|
|
40
|
+
},
|
|
41
|
+
"gitHead": "580e0d5c22d04d609bcdf7cb0873114f9fce5f66"
|
|
42
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import cn from 'classnames';
|
|
2
|
+
import { MouseEventHandler } from 'react';
|
|
3
|
+
|
|
4
|
+
import { CrossSVG } from '@snack-uikit/icons';
|
|
5
|
+
import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
|
|
6
|
+
|
|
7
|
+
import { Appearance, Size } from '../../constants';
|
|
8
|
+
import { IconSize } from './constants';
|
|
9
|
+
import styles from './styles.module.scss';
|
|
10
|
+
|
|
11
|
+
export type TagProps = WithSupportProps<{
|
|
12
|
+
/** Текст */
|
|
13
|
+
label: string;
|
|
14
|
+
/** Размер */
|
|
15
|
+
size?: Size;
|
|
16
|
+
/** Внешний вид */
|
|
17
|
+
appearance?: Appearance;
|
|
18
|
+
/** Коллбэк на удаление */
|
|
19
|
+
onDelete?: MouseEventHandler<HTMLButtonElement>;
|
|
20
|
+
/** CSS-класс */
|
|
21
|
+
className?: string;
|
|
22
|
+
}>;
|
|
23
|
+
|
|
24
|
+
export function Tag({
|
|
25
|
+
label,
|
|
26
|
+
size = Size.Xs,
|
|
27
|
+
appearance = Appearance.Neutral,
|
|
28
|
+
onDelete,
|
|
29
|
+
className,
|
|
30
|
+
...rest
|
|
31
|
+
}: TagProps) {
|
|
32
|
+
return (
|
|
33
|
+
<span
|
|
34
|
+
{...extractSupportProps(rest)}
|
|
35
|
+
className={cn(styles.tag, className)}
|
|
36
|
+
data-size={size}
|
|
37
|
+
data-appearance={appearance}
|
|
38
|
+
data-removable={Boolean(onDelete)}
|
|
39
|
+
>
|
|
40
|
+
<span className={styles.label}>{label}</span>
|
|
41
|
+
{onDelete && (
|
|
42
|
+
<button type='button' className={styles.tagButton} onClick={onDelete} data-test-id='tag-remove-button'>
|
|
43
|
+
{size === Size.Xs ? (
|
|
44
|
+
<CrossSVG size={IconSize[size]} className={styles.icon} />
|
|
45
|
+
) : (
|
|
46
|
+
<CrossSVG size={IconSize[size]} className={styles.icon} />
|
|
47
|
+
)}
|
|
48
|
+
</button>
|
|
49
|
+
)}
|
|
50
|
+
</span>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Tag.sizes = Size;
|
|
55
|
+
Tag.appearances = Appearance;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Tag';
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
@import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-tag';
|
|
2
|
+
@import '@snack-uikit/figma-tokens/build/scss/components/styles-tokens-element';
|
|
3
|
+
|
|
4
|
+
$sizes: 'xs', 's';
|
|
5
|
+
|
|
6
|
+
$label-typography: (
|
|
7
|
+
'xs': $sans-label-s,
|
|
8
|
+
's': $sans-label-m
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
$appearances: (
|
|
12
|
+
'neutral': (
|
|
13
|
+
'container': $sys-neutral-decor-default,
|
|
14
|
+
'container-disabled': $sys-neutral-decor-disabled,
|
|
15
|
+
'label': $sys-neutral-text-support,
|
|
16
|
+
'icon': $sys-neutral-text-light,
|
|
17
|
+
'icon-active': $sys-neutral-text-main,
|
|
18
|
+
'button-hovered': $sys-neutral-decor-hovered,
|
|
19
|
+
'button-active': $sys-neutral-decor-activated,
|
|
20
|
+
),
|
|
21
|
+
'primary': (
|
|
22
|
+
'container': $sys-primary-decor-default,
|
|
23
|
+
'container-disabled': $sys-primary-decor-disabled,
|
|
24
|
+
'label': $sys-primary-text-support,
|
|
25
|
+
'icon': $sys-primary-text-light,
|
|
26
|
+
'icon-active': $sys-primary-text-main,
|
|
27
|
+
'button-hovered': $sys-primary-decor-hovered,
|
|
28
|
+
'button-active': $sys-primary-decor-activated,
|
|
29
|
+
),
|
|
30
|
+
'red': (
|
|
31
|
+
'container': $sys-red-decor-default,
|
|
32
|
+
'container-disabled': $sys-red-decor-disabled,
|
|
33
|
+
'label': $sys-red-text-support,
|
|
34
|
+
'icon': $sys-red-text-light,
|
|
35
|
+
'icon-active': $sys-red-text-main,
|
|
36
|
+
'button-hovered': $sys-red-decor-hovered,
|
|
37
|
+
'button-active': $sys-red-decor-activated,
|
|
38
|
+
),
|
|
39
|
+
'orange': (
|
|
40
|
+
'container': $sys-orange-decor-default,
|
|
41
|
+
'container-disabled': $sys-orange-decor-disabled,
|
|
42
|
+
'label': $sys-orange-text-support,
|
|
43
|
+
'icon': $sys-orange-text-light,
|
|
44
|
+
'icon-active': $sys-orange-text-main,
|
|
45
|
+
'button-hovered': $sys-orange-decor-hovered,
|
|
46
|
+
'button-active': $sys-orange-decor-activated,
|
|
47
|
+
),
|
|
48
|
+
'yellow': (
|
|
49
|
+
'container': $sys-yellow-decor-default,
|
|
50
|
+
'container-disabled': $sys-yellow-decor-disabled,
|
|
51
|
+
'label': $sys-yellow-text-support,
|
|
52
|
+
'icon': $sys-yellow-text-light,
|
|
53
|
+
'icon-active': $sys-yellow-text-main,
|
|
54
|
+
'button-hovered': $sys-yellow-decor-hovered,
|
|
55
|
+
'button-active': $sys-yellow-decor-activated,
|
|
56
|
+
),
|
|
57
|
+
'green': (
|
|
58
|
+
'container': $sys-green-decor-default,
|
|
59
|
+
'container-disabled': $sys-green-decor-disabled,
|
|
60
|
+
'label': $sys-green-text-support,
|
|
61
|
+
'icon': $sys-green-text-light,
|
|
62
|
+
'icon-active': $sys-green-text-main,
|
|
63
|
+
'button-hovered': $sys-green-decor-hovered,
|
|
64
|
+
'button-active': $sys-green-decor-activated,
|
|
65
|
+
),
|
|
66
|
+
'blue': (
|
|
67
|
+
'container': $sys-blue-decor-default,
|
|
68
|
+
'container-disabled': $sys-blue-decor-disabled,
|
|
69
|
+
'label': $sys-blue-text-support,
|
|
70
|
+
'icon': $sys-blue-text-light,
|
|
71
|
+
'icon-active': $sys-blue-text-main,
|
|
72
|
+
'button-hovered': $sys-blue-decor-hovered,
|
|
73
|
+
'button-active': $sys-blue-decor-activated,
|
|
74
|
+
),
|
|
75
|
+
'violet': (
|
|
76
|
+
'container': $sys-violet-decor-default,
|
|
77
|
+
'container-disabled': $sys-violet-decor-disabled,
|
|
78
|
+
'label': $sys-violet-text-support,
|
|
79
|
+
'icon': $sys-violet-text-light,
|
|
80
|
+
'icon-active': $sys-violet-text-main,
|
|
81
|
+
'button-hovered': $sys-violet-decor-hovered,
|
|
82
|
+
'button-active': $sys-violet-decor-activated,
|
|
83
|
+
),
|
|
84
|
+
'pink': (
|
|
85
|
+
'container': $sys-pink-decor-default,
|
|
86
|
+
'container-disabled': $sys-pink-decor-disabled,
|
|
87
|
+
'label': $sys-pink-text-support,
|
|
88
|
+
'icon': $sys-pink-text-light,
|
|
89
|
+
'icon-active': $sys-pink-text-main,
|
|
90
|
+
'button-hovered': $sys-pink-decor-hovered,
|
|
91
|
+
'button-active': $sys-pink-decor-activated,
|
|
92
|
+
),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
.tag {
|
|
96
|
+
display: inline-flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
box-sizing: border-box;
|
|
99
|
+
|
|
100
|
+
.tagButton {
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
|
|
103
|
+
position: relative;
|
|
104
|
+
|
|
105
|
+
box-sizing: border-box;
|
|
106
|
+
margin: 0;
|
|
107
|
+
padding: 0;
|
|
108
|
+
|
|
109
|
+
background: none;
|
|
110
|
+
border: none;
|
|
111
|
+
|
|
112
|
+
&:focus {
|
|
113
|
+
@include outline-inside-var($container-focused-s);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
&:active {
|
|
117
|
+
outline: none;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.icon {
|
|
122
|
+
position: absolute;
|
|
123
|
+
top: 50%;
|
|
124
|
+
left: 50%;
|
|
125
|
+
transform: translate(-50%, -50%);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@each $size in $sizes {
|
|
129
|
+
&[data-size=#{$size}] {
|
|
130
|
+
@include composite-var($tag, 'container', $size, 'label-only');
|
|
131
|
+
|
|
132
|
+
&[data-removable="true"] {
|
|
133
|
+
@include composite-var($tag, 'container', $size, 'button-after');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.label {
|
|
137
|
+
@include composite-var($label-typography, $size);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.tagButton {
|
|
141
|
+
@include composite-var($tag-button, 'container', $size, 'icon-only');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@each $appearanceKey, $appearance in $appearances {
|
|
147
|
+
&[data-appearance=#{$appearanceKey}] {
|
|
148
|
+
background-color: simple-var($appearance, 'container');
|
|
149
|
+
|
|
150
|
+
&[data-removable="false"] {
|
|
151
|
+
background-color: simple-var($appearance, 'container-disabled');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.label {
|
|
155
|
+
color: simple-var($appearance, 'label');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.tagButton {
|
|
159
|
+
color: simple-var($appearance, 'icon');
|
|
160
|
+
|
|
161
|
+
&:focus, &:hover, &:active {
|
|
162
|
+
color: simple-var($appearance, 'icon-active');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
&:focus, &:hover {
|
|
166
|
+
background-color: simple-var($appearance, 'button-hovered');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
&:active {
|
|
170
|
+
background-color: simple-var($appearance, 'button-active');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { WithSupportProps } from '@snack-uikit/utils';
|
|
2
|
+
|
|
3
|
+
import { Appearance, Size } from '../../constants';
|
|
4
|
+
import { TagRowSimple, TagRowTruncated } from '../../helperComponents';
|
|
5
|
+
import { TagRowItem } from '../../types';
|
|
6
|
+
import { mapTagRowItem } from './utils';
|
|
7
|
+
|
|
8
|
+
export type TagRowProps = WithSupportProps<{
|
|
9
|
+
/** Массив тэгов */
|
|
10
|
+
items: TagRowItem[];
|
|
11
|
+
/** Лимит количества рядов тэгов. При достижении лимита тэги скрываются под кнопкой. Отсутствие лимита или значение равное нулю отобразит весь список */
|
|
12
|
+
rowLimit?: number;
|
|
13
|
+
/** Размер */
|
|
14
|
+
size?: Size;
|
|
15
|
+
/** Текст кнопки, при наведении на которую отображается список скрытых тэгов */
|
|
16
|
+
moreButtonLabel?: string;
|
|
17
|
+
/** CSS-класс */
|
|
18
|
+
className?: string;
|
|
19
|
+
/** Коллбэк на клик по удалению тэга */
|
|
20
|
+
onItemRemove?(item: string): void;
|
|
21
|
+
}>;
|
|
22
|
+
|
|
23
|
+
export function TagRow({ items, rowLimit, size = Size.Xs, ...props }: TagRowProps) {
|
|
24
|
+
const coloredItems = items.map(mapTagRowItem);
|
|
25
|
+
|
|
26
|
+
if (rowLimit) {
|
|
27
|
+
return <TagRowTruncated items={coloredItems} rowLimit={rowLimit} size={size} {...props} />;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return <TagRowSimple items={coloredItems} size={size} {...props} />;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
TagRow.sizes = Size;
|
|
34
|
+
TagRow.appearances = Appearance;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TagRow';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Appearance } from '../../constants';
|
|
2
|
+
import { TagRowItem, TagRowItemInner } from '../../types';
|
|
3
|
+
|
|
4
|
+
export const mapTagRowItem = ({ label, color }: TagRowItem): TagRowItemInner => {
|
|
5
|
+
if (color) {
|
|
6
|
+
return {
|
|
7
|
+
label,
|
|
8
|
+
color,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return {
|
|
13
|
+
label,
|
|
14
|
+
color: Appearance.Neutral,
|
|
15
|
+
};
|
|
16
|
+
};
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export enum Appearance {
|
|
2
|
+
Neutral = 'neutral',
|
|
3
|
+
Primary = 'primary',
|
|
4
|
+
Red = 'red',
|
|
5
|
+
Orange = 'orange',
|
|
6
|
+
Yellow = 'yellow',
|
|
7
|
+
Green = 'green',
|
|
8
|
+
Blue = 'blue',
|
|
9
|
+
Violet = 'violet',
|
|
10
|
+
Pink = 'pink',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum Size {
|
|
14
|
+
Xs = 'xs',
|
|
15
|
+
S = 's',
|
|
16
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Ref } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Tag } from '../../components';
|
|
4
|
+
import { Size } from '../../constants';
|
|
5
|
+
import { TagRowItemInner } from '../../types';
|
|
6
|
+
|
|
7
|
+
type SetTagRef = (item: TagRowItemInner, index: number) => Ref<HTMLDivElement>;
|
|
8
|
+
|
|
9
|
+
type TagListProps = {
|
|
10
|
+
items: TagRowItemInner[];
|
|
11
|
+
size?: Size;
|
|
12
|
+
onItemRemove?(item: string): void;
|
|
13
|
+
setTagRef?: SetTagRef;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type OnDeleteHandler = () => void;
|
|
17
|
+
|
|
18
|
+
function renderTag(size: Size, handleRemoveItem?: (item: TagRowItemInner) => OnDeleteHandler, setRef?: SetTagRef) {
|
|
19
|
+
return function TagRowItem(item: TagRowItemInner, index: number) {
|
|
20
|
+
return (
|
|
21
|
+
<div key={item.label} ref={setRef?.(item, index)}>
|
|
22
|
+
<Tag label={item.label} appearance={item.color} size={size} onDelete={handleRemoveItem?.(item)} />
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function TagList({ items, size = Size.Xs, onItemRemove, setTagRef }: TagListProps) {
|
|
29
|
+
const handleRemoveItem = onItemRemove ? (item: TagRowItemInner) => () => onItemRemove(item.label) : undefined;
|
|
30
|
+
|
|
31
|
+
return <>{items.map(renderTag(size, handleRemoveItem, setTagRef))}</>;
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TagList';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Ref } from 'react';
|
|
2
|
+
|
|
3
|
+
import { PopoverPrivate } from '@snack-uikit/popover-private';
|
|
4
|
+
import { Scroll } from '@snack-uikit/scroll';
|
|
5
|
+
|
|
6
|
+
import { TAG_ROW_TEST_IDS } from '../../components/TagRow/constants';
|
|
7
|
+
import { Size } from '../../constants';
|
|
8
|
+
import { TagRowItemInner } from '../../types';
|
|
9
|
+
import { TagRowSimple } from '../TagRowSimple';
|
|
10
|
+
import styles from './styles.module.scss';
|
|
11
|
+
|
|
12
|
+
type TagMoreProps = {
|
|
13
|
+
items: TagRowItemInner[];
|
|
14
|
+
size: Size;
|
|
15
|
+
text?: string;
|
|
16
|
+
buttonRef?: Ref<HTMLButtonElement>;
|
|
17
|
+
onItemRemove?(item: string): void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function TagMore({ items, text = '', size = Size.Xs, buttonRef, onItemRemove }: TagMoreProps) {
|
|
21
|
+
return (
|
|
22
|
+
<PopoverPrivate
|
|
23
|
+
placement={PopoverPrivate.placements.BottomEnd}
|
|
24
|
+
trigger={PopoverPrivate.triggers.HoverAndFocusVisible}
|
|
25
|
+
triggerClassName={styles.triggerClassName}
|
|
26
|
+
popoverContent={
|
|
27
|
+
<div className={styles.tagRowDroplistContainer} data-size={size}>
|
|
28
|
+
<Scroll
|
|
29
|
+
className={styles.tagRowDroplistScroll}
|
|
30
|
+
size={Scroll.sizes.S}
|
|
31
|
+
barHideStrategy={Scroll.barHideStrategies.Move}
|
|
32
|
+
resize={Scroll.resizes.None}
|
|
33
|
+
>
|
|
34
|
+
<TagRowSimple
|
|
35
|
+
items={items}
|
|
36
|
+
size={size}
|
|
37
|
+
onItemRemove={onItemRemove}
|
|
38
|
+
data-test-id={TAG_ROW_TEST_IDS.droplistTagsWrapper}
|
|
39
|
+
/>
|
|
40
|
+
</Scroll>
|
|
41
|
+
</div>
|
|
42
|
+
}
|
|
43
|
+
hasArrow={false}
|
|
44
|
+
>
|
|
45
|
+
<button
|
|
46
|
+
type='button'
|
|
47
|
+
className={styles.button}
|
|
48
|
+
ref={buttonRef}
|
|
49
|
+
data-size={size}
|
|
50
|
+
data-test-id={TAG_ROW_TEST_IDS.moreButton}
|
|
51
|
+
>{`${text}${items.length}`}</button>
|
|
52
|
+
</PopoverPrivate>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TagMore';
|