@cloud-ru/ds-uikit-product-toggles-predefined 1.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/CHANGELOG.md +8 -0
- package/LICENSE +201 -0
- package/README.md +251 -0
- package/dist/cjs/components/ToggleCard/ToggleCard.d.ts +8 -0
- package/dist/cjs/components/ToggleCard/ToggleCard.js +42 -0
- package/dist/cjs/components/ToggleCard/index.d.ts +1 -0
- package/dist/cjs/components/ToggleCard/index.js +17 -0
- package/dist/cjs/components/ToggleCard/styles.module.css +143 -0
- package/dist/cjs/components/ToggleCard/utils.d.ts +8 -0
- package/dist/cjs/components/ToggleCard/utils.js +24 -0
- package/dist/cjs/components/ToggleGroup/ToggleGroup.d.ts +7 -0
- package/dist/cjs/components/ToggleGroup/ToggleGroup.js +24 -0
- package/dist/cjs/components/ToggleGroup/index.d.ts +1 -0
- package/dist/cjs/components/ToggleGroup/index.js +17 -0
- package/dist/cjs/components/ToggleGroup/styles.module.css +17 -0
- package/dist/cjs/components/index.d.ts +3 -0
- package/dist/cjs/components/index.js +21 -0
- package/dist/cjs/constants.d.ts +22 -0
- package/dist/cjs/constants.js +25 -0
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.js +19 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/style.css +160 -0
- package/dist/cjs/types.d.ts +61 -0
- package/dist/cjs/types.js +2 -0
- package/dist/esm/components/ToggleCard/ToggleCard.d.ts +8 -0
- package/dist/esm/components/ToggleCard/ToggleCard.js +36 -0
- package/dist/esm/components/ToggleCard/index.d.ts +1 -0
- package/dist/esm/components/ToggleCard/index.js +1 -0
- package/dist/esm/components/ToggleCard/styles.module.css +143 -0
- package/dist/esm/components/ToggleCard/utils.d.ts +8 -0
- package/dist/esm/components/ToggleCard/utils.js +20 -0
- package/dist/esm/components/ToggleGroup/ToggleGroup.d.ts +7 -0
- package/dist/esm/components/ToggleGroup/ToggleGroup.js +18 -0
- package/dist/esm/components/ToggleGroup/index.d.ts +1 -0
- package/dist/esm/components/ToggleGroup/index.js +1 -0
- package/dist/esm/components/ToggleGroup/styles.module.css +17 -0
- package/dist/esm/components/index.d.ts +3 -0
- package/dist/esm/components/index.js +3 -0
- package/dist/esm/constants.d.ts +22 -0
- package/dist/esm/constants.js +22 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/style.css +160 -0
- package/dist/esm/types.d.ts +61 -0
- package/dist/esm/types.js +1 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/package.json +47 -0
- package/src/components/ToggleCard/ToggleCard.tsx +102 -0
- package/src/components/ToggleCard/index.ts +1 -0
- package/src/components/ToggleCard/styles.module.scss +150 -0
- package/src/components/ToggleCard/utils.ts +24 -0
- package/src/components/ToggleGroup/ToggleGroup.tsx +36 -0
- package/src/components/ToggleGroup/index.ts +1 -0
- package/src/components/ToggleGroup/styles.module.scss +28 -0
- package/src/components/index.ts +4 -0
- package/src/constants.ts +25 -0
- package/src/index.ts +3 -0
- package/src/types.ts +69 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Card, VIEW } from '@cloud-ru/ds-card';
|
|
2
|
+
import { IconPredefined } from '@cloud-ru/ds-icon-predefined';
|
|
3
|
+
import { PromoTag } from '@cloud-ru/ds-promo-tag';
|
|
4
|
+
import { useToggleGroup } from '@cloud-ru/ds-toggles';
|
|
5
|
+
import { TruncateString } from '@cloud-ru/ds-truncate-string';
|
|
6
|
+
import { extractSupportProps } from '@cloud-ru/ds-utils';
|
|
7
|
+
import cn from 'classnames';
|
|
8
|
+
import { KeyboardEventHandler } from 'react';
|
|
9
|
+
|
|
10
|
+
import { SIZE, TEST_IDS } from '../../constants';
|
|
11
|
+
import { ToggleCardProps } from '../../types';
|
|
12
|
+
import styles from './styles.module.scss';
|
|
13
|
+
import { isEmblemPicture, sizeToEmblemSize } from './utils';
|
|
14
|
+
|
|
15
|
+
const TRUNCATE_DEFAULTS = { title: 1, description: 2 };
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* ToggleCard — кликабельная карточка выбора. Работает внутри `ToggleGroup`:
|
|
19
|
+
* клик / Enter / Space по карточке переключает её значение в контексте группы.
|
|
20
|
+
* Визуальный chrome (acrylic-фон, state-layer выбора, outline, focus-ring)
|
|
21
|
+
* приходит из `@cloud-ru/ds-card`; карточка добавляет раскладку контента и клавиатуру.
|
|
22
|
+
*/
|
|
23
|
+
export function ToggleCard({
|
|
24
|
+
title,
|
|
25
|
+
value,
|
|
26
|
+
description,
|
|
27
|
+
emblem,
|
|
28
|
+
promoBadge,
|
|
29
|
+
size = SIZE.M,
|
|
30
|
+
truncate,
|
|
31
|
+
disabled = false,
|
|
32
|
+
className,
|
|
33
|
+
...rest
|
|
34
|
+
}: ToggleCardProps) {
|
|
35
|
+
const { isChecked, handleClick, multipleSelection } = useToggleGroup({ value });
|
|
36
|
+
|
|
37
|
+
const handleKeyDown: KeyboardEventHandler<HTMLDivElement> = e => {
|
|
38
|
+
if (disabled) return;
|
|
39
|
+
|
|
40
|
+
if (e.code === 'Enter' || e.code === 'Space') {
|
|
41
|
+
e.preventDefault();
|
|
42
|
+
handleClick();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// `?? DEFAULT` вместо spread: явный `truncate={{ description: undefined }}`
|
|
47
|
+
// (сборка объекта из optional-переменной) не должен перетирать дефолт.
|
|
48
|
+
const maxLines = {
|
|
49
|
+
title: truncate?.title ?? TRUNCATE_DEFAULTS.title,
|
|
50
|
+
description: truncate?.description ?? TRUNCATE_DEFAULTS.description,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<Card
|
|
55
|
+
className={cn(styles.card, className)}
|
|
56
|
+
view={VIEW.Outline}
|
|
57
|
+
radius={size}
|
|
58
|
+
checked={isChecked}
|
|
59
|
+
disabled={disabled}
|
|
60
|
+
role={multipleSelection ? 'checkbox' : 'radio'}
|
|
61
|
+
aria-checked={isChecked}
|
|
62
|
+
onClick={!disabled ? handleClick : undefined}
|
|
63
|
+
onKeyDown={handleKeyDown}
|
|
64
|
+
data-test-id={TEST_IDS.card}
|
|
65
|
+
{...extractSupportProps(rest)}
|
|
66
|
+
>
|
|
67
|
+
{promoBadge && (
|
|
68
|
+
<div className={styles.promoBadge} data-size={size} data-test-id={TEST_IDS.promoBadge}>
|
|
69
|
+
<PromoTag {...(typeof promoBadge === 'string' ? { label: promoBadge } : promoBadge)} roleAppearance='decor' />
|
|
70
|
+
</div>
|
|
71
|
+
)}
|
|
72
|
+
|
|
73
|
+
<div className={styles.content} data-size={size}>
|
|
74
|
+
{emblem && (
|
|
75
|
+
<span
|
|
76
|
+
className={styles.emblem}
|
|
77
|
+
data-test-id={TEST_IDS.cardEmblem}
|
|
78
|
+
aria-hidden={isEmblemPicture(emblem) ? undefined : true}
|
|
79
|
+
>
|
|
80
|
+
{isEmblemPicture(emblem) ? (
|
|
81
|
+
<img className={styles.picture} src={emblem.src} alt={emblem.alt} data-size={sizeToEmblemSize(size)} />
|
|
82
|
+
) : (
|
|
83
|
+
<IconPredefined {...emblem} size={sizeToEmblemSize(size)} background={emblem.background ?? false} />
|
|
84
|
+
)}
|
|
85
|
+
</span>
|
|
86
|
+
)}
|
|
87
|
+
|
|
88
|
+
<div className={styles.textContent}>
|
|
89
|
+
<span className={styles.title} data-test-id={TEST_IDS.cardTitle}>
|
|
90
|
+
<TruncateString text={title} maxLines={maxLines.title} />
|
|
91
|
+
</span>
|
|
92
|
+
|
|
93
|
+
{description && (
|
|
94
|
+
<span className={styles.description} data-test-id={TEST_IDS.cardDescription}>
|
|
95
|
+
<TruncateString text={description} maxLines={maxLines.description} />
|
|
96
|
+
</span>
|
|
97
|
+
)}
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</Card>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ToggleCard';
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToggleCard — раскладка контента поверх chrome `@cloud-ru/ds-card`.
|
|
3
|
+
* Сам card (acrylic-фон, state-layer выбора, outline, focus-ring) рендерит `@cloud-ru/ds-card`;
|
|
4
|
+
* `.content` соответствует Figma-слою `wrapper`. `@cloud-ru/ds-card` content-слот padding
|
|
5
|
+
* не задаёт — он целиком на этом пакете.
|
|
6
|
+
*
|
|
7
|
+
* Ось `size` (как в продуктовом ките) масштабирует анатомию карточки целиком:
|
|
8
|
+
* size | padding | gap | title | description
|
|
9
|
+
* s | 8 | 4 | title/s | body/m
|
|
10
|
+
* m | 16 | 8 | title/m | body/m
|
|
11
|
+
* l | 24 | 16 | title/l | body/l
|
|
12
|
+
*/
|
|
13
|
+
@use 'sass:map';
|
|
14
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
15
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/card.module' as card;
|
|
16
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/components/iconPredefined.module' as iconPredefined;
|
|
17
|
+
|
|
18
|
+
$paddings: (
|
|
19
|
+
's': base.$sn-density-spacing-interval-s,
|
|
20
|
+
'm': base.$sn-density-spacing-interval-m,
|
|
21
|
+
'l': base.$sn-density-spacing-interval-l,
|
|
22
|
+
);
|
|
23
|
+
$gaps: (
|
|
24
|
+
's': base.$sn-density-spacing-interval-xs,
|
|
25
|
+
'm': base.$sn-density-spacing-interval-s,
|
|
26
|
+
'l': base.$sn-density-spacing-interval-m,
|
|
27
|
+
);
|
|
28
|
+
$title-typography: (
|
|
29
|
+
's': base.$sn-regular-title-s,
|
|
30
|
+
'm': base.$sn-regular-title-m,
|
|
31
|
+
'l': base.$sn-regular-title-l,
|
|
32
|
+
);
|
|
33
|
+
$description-typography: (
|
|
34
|
+
's': base.$sn-regular-body-m,
|
|
35
|
+
'm': base.$sn-regular-body-m,
|
|
36
|
+
'l': base.$sn-regular-body-l,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
$radius-to-badge-padding-top: (
|
|
40
|
+
's': card.$sn-card-anatomy-radius-s-container-badge-paddingTop,
|
|
41
|
+
'm': card.$sn-card-anatomy-radius-m-container-badge-paddingTop,
|
|
42
|
+
'l': card.$sn-card-anatomy-radius-l-container-badge-paddingTop,
|
|
43
|
+
);
|
|
44
|
+
$radius-to-badge-padding-right: (
|
|
45
|
+
's': card.$sn-card-anatomy-radius-s-container-badge-paddingLeft,
|
|
46
|
+
'm': card.$sn-card-anatomy-radius-m-container-badge-paddingLeft,
|
|
47
|
+
'l': card.$sn-card-anatomy-radius-l-container-badge-paddingLeft,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
.card {
|
|
51
|
+
cursor: pointer;
|
|
52
|
+
|
|
53
|
+
&[data-disabled] {
|
|
54
|
+
cursor: not-allowed;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.promoBadge {
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
|
|
61
|
+
position: absolute;
|
|
62
|
+
z-index: 1;
|
|
63
|
+
top: 0;
|
|
64
|
+
right: 0;
|
|
65
|
+
|
|
66
|
+
display: flex;
|
|
67
|
+
|
|
68
|
+
box-sizing: border-box;
|
|
69
|
+
|
|
70
|
+
@each $size in ('s', 'm', 'l') {
|
|
71
|
+
&[data-size='#{$size}'] {
|
|
72
|
+
padding-top: map.get($radius-to-badge-padding-top, $size);
|
|
73
|
+
padding-right: map.get($radius-to-badge-padding-right, $size);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.content {
|
|
79
|
+
display: flex;
|
|
80
|
+
align-items: center;
|
|
81
|
+
box-sizing: border-box;
|
|
82
|
+
width: 100%;
|
|
83
|
+
|
|
84
|
+
@each $size in ('s', 'm', 'l') {
|
|
85
|
+
&[data-size='#{$size}'] {
|
|
86
|
+
gap: map.get($gaps, $size);
|
|
87
|
+
padding: map.get($paddings, $size);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.emblem {
|
|
93
|
+
// Слот ведущей эмблемы. Размер и цвет иконки задаёт встроенный `IconPredefined`
|
|
94
|
+
// (size выводится из размера карточки), поэтому здесь только flex-обвязка.
|
|
95
|
+
display: inline-flex;
|
|
96
|
+
flex-shrink: 0;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.picture {
|
|
102
|
+
// `data-size` уже приведён к размеру эмблемы (m/l/5xl) в компоненте — ключуемся
|
|
103
|
+
// прямо по нему, без второго маппинга card→emblem. `rounded`-сегмент даёт
|
|
104
|
+
// border-radius (круглый бейдж, как у дефолтного IconPredefined), иначе
|
|
105
|
+
// картинка осталась бы прямоугольной и overflow:hidden ничего не обрезал бы.
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
box-sizing: border-box;
|
|
108
|
+
object-fit: cover;
|
|
109
|
+
|
|
110
|
+
@each $size in ('m', 'l', '5xl') {
|
|
111
|
+
&[data-size='#{$size}'] {
|
|
112
|
+
@include base.composite-var(iconPredefined.$iconPredefined, 'anatomy', 'size', $size);
|
|
113
|
+
@include base.composite-var(iconPredefined.$iconPredefined, 'anatomy', 'size', $size, 'rounded');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.textContent {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex: 1 0 0;
|
|
121
|
+
flex-direction: column;
|
|
122
|
+
align-items: flex-start;
|
|
123
|
+
|
|
124
|
+
min-width: 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.title {
|
|
128
|
+
// width: 100% обязателен: в колонке `align-items: flex-start` без него заголовок
|
|
129
|
+
// тянется по контенту и переполняет карточку — TruncateString не может измерить
|
|
130
|
+
// доступную ширину. С шириной 100% он считает её от textContent и обрезает.
|
|
131
|
+
width: 100%;
|
|
132
|
+
color: base.$sn-theme-color-available-version-textMain;
|
|
133
|
+
|
|
134
|
+
@each $size in ('s', 'm', 'l') {
|
|
135
|
+
.content[data-size='#{$size}'] & {
|
|
136
|
+
@include base.composite-var(map.get($title-typography, $size));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.description {
|
|
142
|
+
width: 100%;
|
|
143
|
+
color: base.$sn-theme-color-available-version-textSecondary;
|
|
144
|
+
|
|
145
|
+
@each $size in ('s', 'm', 'l') {
|
|
146
|
+
.content[data-size='#{$size}'] & {
|
|
147
|
+
@include base.composite-var(map.get($description-typography, $size));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SIZE as ICON_SIZE, Size as IconSize } from '@cloud-ru/ds-icon-predefined';
|
|
2
|
+
|
|
3
|
+
import { SIZE } from '../../constants';
|
|
4
|
+
import { Emblem, EmblemPicture, Size } from '../../types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Эмблема масштабируется вместе с карточкой (как в продуктовом ките):
|
|
8
|
+
* размер `IconPredefined` выводится из `size` карточки, а не задаётся снаружи.
|
|
9
|
+
*/
|
|
10
|
+
export function sizeToEmblemSize(size: Size): IconSize {
|
|
11
|
+
switch (size) {
|
|
12
|
+
case SIZE.S:
|
|
13
|
+
return ICON_SIZE.M;
|
|
14
|
+
case SIZE.L:
|
|
15
|
+
return ICON_SIZE['5XL'];
|
|
16
|
+
case SIZE.M:
|
|
17
|
+
default:
|
|
18
|
+
return ICON_SIZE.L;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isEmblemPicture(emblem: Emblem): emblem is EmblemPicture {
|
|
23
|
+
return 'src' in emblem;
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ToggleGroup as ToggleGroupBase, ToggleGroupProps as ToggleGroupBaseProps } from '@cloud-ru/ds-toggles';
|
|
2
|
+
import { excludeSupportProps, extractSupportProps } from '@cloud-ru/ds-utils';
|
|
3
|
+
import cn from 'classnames';
|
|
4
|
+
import { CSSProperties } from 'react';
|
|
5
|
+
|
|
6
|
+
import { GAP, ORIENTATION, TEST_IDS } from '../../constants';
|
|
7
|
+
import { ToggleGroupProps } from '../../types';
|
|
8
|
+
import styles from './styles.module.scss';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* ToggleGroup — провайдер выбора + grid-раскладка карточек `ToggleCard`.
|
|
12
|
+
* Состояние (controlled/uncontrolled, single/multiple) держит `@cloud-ru/ds-toggles::ToggleGroup`;
|
|
13
|
+
* обёртка добавляет ориентацию, gap и breakpoint горизонтальной раскладки.
|
|
14
|
+
*/
|
|
15
|
+
export function ToggleGroup(props: ToggleGroupProps) {
|
|
16
|
+
const { children, orientation = ORIENTATION.Vertical, gap = GAP.S, breakpoint = 0, className, ...rest } = props;
|
|
17
|
+
|
|
18
|
+
const restProps = rest as Record<string, unknown>;
|
|
19
|
+
const supportProps = extractSupportProps(restProps);
|
|
20
|
+
const groupProps = excludeSupportProps(restProps) as ToggleGroupBaseProps;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<ToggleGroupBase {...groupProps}>
|
|
24
|
+
<div
|
|
25
|
+
className={cn(styles.toggleGroup, className)}
|
|
26
|
+
style={{ '--toggle-group-breakpoint': `${breakpoint}px` } as CSSProperties}
|
|
27
|
+
data-orientation={orientation}
|
|
28
|
+
data-gap={gap}
|
|
29
|
+
data-test-id={TEST_IDS.group}
|
|
30
|
+
{...supportProps}
|
|
31
|
+
>
|
|
32
|
+
{children}
|
|
33
|
+
</div>
|
|
34
|
+
</ToggleGroupBase>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ToggleGroup';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToggleGroup — grid-раскладка карточек.
|
|
3
|
+
* gap s/m/l → density spacing interval s(8)/m(16)/l(24).
|
|
4
|
+
* Горизонтальная ориентация раскладывает карточки в авто-колонки с минимальной
|
|
5
|
+
* шириной `--toggle-group-breakpoint` (px, из пропа `breakpoint`).
|
|
6
|
+
*/
|
|
7
|
+
@use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
|
|
8
|
+
|
|
9
|
+
$gaps: (
|
|
10
|
+
's': base.$sn-density-spacing-interval-s,
|
|
11
|
+
'm': base.$sn-density-spacing-interval-m,
|
|
12
|
+
'l': base.$sn-density-spacing-interval-l,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
.toggleGroup {
|
|
16
|
+
display: grid;
|
|
17
|
+
|
|
18
|
+
@each $gap, $token in $gaps {
|
|
19
|
+
&[data-gap='#{$gap}'] {
|
|
20
|
+
gap: $token;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&[data-orientation='horizontal'] {
|
|
25
|
+
grid-auto-rows: 1fr;
|
|
26
|
+
grid-template-columns: repeat(auto-fit, minmax(var(--toggle-group-breakpoint, 0), 1fr));
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const SIZE = {
|
|
2
|
+
S: 's',
|
|
3
|
+
M: 'm',
|
|
4
|
+
L: 'l',
|
|
5
|
+
} as const;
|
|
6
|
+
|
|
7
|
+
export const ORIENTATION = {
|
|
8
|
+
Horizontal: 'horizontal',
|
|
9
|
+
Vertical: 'vertical',
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
export const GAP = {
|
|
13
|
+
S: 's',
|
|
14
|
+
M: 'm',
|
|
15
|
+
L: 'l',
|
|
16
|
+
} as const;
|
|
17
|
+
|
|
18
|
+
export const TEST_IDS = {
|
|
19
|
+
card: 'toggle-card',
|
|
20
|
+
cardEmblem: 'toggle-card__emblem',
|
|
21
|
+
cardTitle: 'toggle-card__title',
|
|
22
|
+
cardDescription: 'toggle-card__description',
|
|
23
|
+
promoBadge: 'toggle-card__promo-badge',
|
|
24
|
+
group: 'toggle-group',
|
|
25
|
+
} as const;
|
package/src/index.ts
ADDED
package/src/types.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { IconPredefinedProps } from '@cloud-ru/ds-icon-predefined';
|
|
2
|
+
import { PromoTagProps } from '@cloud-ru/ds-promo-tag';
|
|
3
|
+
import { ToggleGroupProps as ToggleGroupPropsDs } from '@cloud-ru/ds-toggles';
|
|
4
|
+
import { ValueOf, WithSupportProps } from '@cloud-ru/ds-utils';
|
|
5
|
+
import { ReactNode } from 'react';
|
|
6
|
+
|
|
7
|
+
import { GAP, ORIENTATION, SIZE } from './constants';
|
|
8
|
+
|
|
9
|
+
export type Size = ValueOf<typeof SIZE>;
|
|
10
|
+
export type Orientation = ValueOf<typeof ORIENTATION>;
|
|
11
|
+
export type Gap = ValueOf<typeof GAP>;
|
|
12
|
+
|
|
13
|
+
export type EmblemPicture = {
|
|
14
|
+
/** URL картинки-эмблемы */
|
|
15
|
+
src: string;
|
|
16
|
+
/** Альтернативный текст картинки */
|
|
17
|
+
alt: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type EmblemIcon = Pick<IconPredefinedProps, 'icon' | 'appearance' | 'background' | 'shape'>;
|
|
21
|
+
|
|
22
|
+
/** Эмблема карточки: параметры встроенного `IconPredefined` либо картинка (`src` / `alt`). */
|
|
23
|
+
export type Emblem = EmblemPicture | EmblemIcon;
|
|
24
|
+
|
|
25
|
+
export type ToggleCardProps = WithSupportProps<{
|
|
26
|
+
/** Заголовок карточки */
|
|
27
|
+
title: string;
|
|
28
|
+
/** Значение карточки в контексте `ToggleGroup` */
|
|
29
|
+
value: string;
|
|
30
|
+
/** Основной текст под заголовком */
|
|
31
|
+
description?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Ведущая эмблема. Передаются только параметры — сам `IconPredefined`
|
|
34
|
+
* встроен в компонент; `size` эмблемы выводится из `size` карточки.
|
|
35
|
+
*/
|
|
36
|
+
emblem?: Emblem;
|
|
37
|
+
/** Промо-бейдж в правом верхнем углу карточки */
|
|
38
|
+
promoBadge?: Pick<PromoTagProps, 'label' | 'appearance'> | string;
|
|
39
|
+
/** Размер карточки — масштабирует padding, gap, типографику и `radius` контейнера `@cloud-ru/ds-card` */
|
|
40
|
+
size?: Size;
|
|
41
|
+
/**
|
|
42
|
+
* Максимальное число строк до обрезки.
|
|
43
|
+
* @default '{ title: 1; description: 2; }'
|
|
44
|
+
*/
|
|
45
|
+
truncate?: {
|
|
46
|
+
/** Максимум строк заголовка */
|
|
47
|
+
title?: number;
|
|
48
|
+
/** Максимум строк содержимого */
|
|
49
|
+
description?: number;
|
|
50
|
+
};
|
|
51
|
+
/** Заблокированное состояние: интерактив отключён */
|
|
52
|
+
disabled?: boolean;
|
|
53
|
+
/** CSS-класс корневого элемента */
|
|
54
|
+
className?: string;
|
|
55
|
+
}>;
|
|
56
|
+
|
|
57
|
+
export type ToggleGroupProps = ToggleGroupPropsDs &
|
|
58
|
+
WithSupportProps<{
|
|
59
|
+
/** Дочерние карточки `ToggleCard` */
|
|
60
|
+
children?: ReactNode;
|
|
61
|
+
/** Направление раскладки */
|
|
62
|
+
orientation?: Orientation;
|
|
63
|
+
/** Расстояние между карточками */
|
|
64
|
+
gap?: Gap;
|
|
65
|
+
/** Минимальная ширина карточки для горизонтальной раскладки (px) */
|
|
66
|
+
breakpoint?: number;
|
|
67
|
+
/** CSS-класс корневого элемента */
|
|
68
|
+
className?: string;
|
|
69
|
+
}>;
|