@cloud-ru/uikit-product-claudia 1.6.2

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/LICENSE +201 -0
  3. package/README.md +586 -0
  4. package/package.json +60 -0
  5. package/src/components/ButtonClaudia/ButtonClaudia.tsx +33 -0
  6. package/src/components/ButtonClaudia/constants.ts +29 -0
  7. package/src/components/ButtonClaudia/helperComponents/ButtonPrivate/ButtonPrivate.tsx +99 -0
  8. package/src/components/ButtonClaudia/helperComponents/ButtonPrivate/constants.ts +13 -0
  9. package/src/components/ButtonClaudia/helperComponents/ButtonPrivate/index.ts +1 -0
  10. package/src/components/ButtonClaudia/helperComponents/ButtonPrivate/styles.module.scss +46 -0
  11. package/src/components/ButtonClaudia/helperComponents/ButtonPrivate/utils.tsx +92 -0
  12. package/src/components/ButtonClaudia/helperComponents/index.ts +1 -0
  13. package/src/components/ButtonClaudia/index.ts +1 -0
  14. package/src/components/ButtonClaudia/styles.module.scss +141 -0
  15. package/src/components/ButtonClaudia/types.ts +63 -0
  16. package/src/components/ButtonClaudia/utils.ts +15 -0
  17. package/src/components/ButtonGiga/ButtonGigaFunction/ButtonGigaFunction.tsx +43 -0
  18. package/src/components/ButtonGiga/ButtonGigaFunction/index.ts +1 -0
  19. package/src/components/ButtonGiga/ButtonGigaFunction/styles.module.scss +179 -0
  20. package/src/components/ButtonGiga/ButtonGigaFunction/types.ts +43 -0
  21. package/src/components/ButtonGiga/ButtonGigaFunction/utils.ts +16 -0
  22. package/src/components/ButtonGiga/ButtonGigaMama/ButtonGigaMama.tsx +29 -0
  23. package/src/components/ButtonGiga/ButtonGigaMama/index.ts +1 -0
  24. package/src/components/ButtonGiga/ButtonGigaMama/styles.module.scss +180 -0
  25. package/src/components/ButtonGiga/ButtonGigaMama/utils.ts +15 -0
  26. package/src/components/ButtonGiga/ButtonGigaOutline/ButtonGigaOutline.tsx +43 -0
  27. package/src/components/ButtonGiga/ButtonGigaOutline/index.ts +1 -0
  28. package/src/components/ButtonGiga/ButtonGigaOutline/styles.module.scss +223 -0
  29. package/src/components/ButtonGiga/ButtonGigaOutline/types.ts +63 -0
  30. package/src/components/ButtonGiga/ButtonGigaOutline/utils.ts +16 -0
  31. package/src/components/ButtonGiga/constants.ts +29 -0
  32. package/src/components/ButtonGiga/helperComponents/ButtonPrivate/ButtonPrivate.tsx +99 -0
  33. package/src/components/ButtonGiga/helperComponents/ButtonPrivate/constants.ts +15 -0
  34. package/src/components/ButtonGiga/helperComponents/ButtonPrivate/index.ts +1 -0
  35. package/src/components/ButtonGiga/helperComponents/ButtonPrivate/styles.module.scss +46 -0
  36. package/src/components/ButtonGiga/helperComponents/ButtonPrivate/types.ts +63 -0
  37. package/src/components/ButtonGiga/helperComponents/ButtonPrivate/utils.tsx +92 -0
  38. package/src/components/ButtonGiga/helperComponents/index.ts +1 -0
  39. package/src/components/ButtonGiga/index.ts +3 -0
  40. package/src/components/ButtonGiga/types.ts +43 -0
  41. package/src/components/ChatStatusAnnouncement/ChatStatusAnnouncement.tsx +109 -0
  42. package/src/components/ChatStatusAnnouncement/constants.ts +1 -0
  43. package/src/components/ChatStatusAnnouncement/helperComponents/AlertButton/AlertButton.tsx +24 -0
  44. package/src/components/ChatStatusAnnouncement/helperComponents/AlertButton/index.ts +1 -0
  45. package/src/components/ChatStatusAnnouncement/helperComponents/AlertButton/styles.module.scss +27 -0
  46. package/src/components/ChatStatusAnnouncement/helperComponents/TextContent/TextContent.tsx +18 -0
  47. package/src/components/ChatStatusAnnouncement/helperComponents/TextContent/index.ts +1 -0
  48. package/src/components/ChatStatusAnnouncement/index.ts +1 -0
  49. package/src/components/ChatStatusAnnouncement/styled.module.scss +65 -0
  50. package/src/components/ChatStatusAnnouncement/types.ts +17 -0
  51. package/src/components/ChatStatusAnnouncement/utils/index.ts +52 -0
  52. package/src/components/IconGiga/IconGiga.tsx +64 -0
  53. package/src/components/IconGiga/constants.ts +23 -0
  54. package/src/components/IconGiga/index.ts +1 -0
  55. package/src/components/RecommendPannel/RecommendPanel.tsx +131 -0
  56. package/src/components/RecommendPannel/helperComponents/Chip/Chip.tsx +47 -0
  57. package/src/components/RecommendPannel/helperComponents/Chip/index.ts +1 -0
  58. package/src/components/RecommendPannel/helperComponents/Chip/styles.module.scss +45 -0
  59. package/src/components/RecommendPannel/helperComponents/ClaudiaChip/ClaudiaChip.tsx +40 -0
  60. package/src/components/RecommendPannel/helperComponents/ClaudiaChip/index.ts +1 -0
  61. package/src/components/RecommendPannel/helperComponents/CloseChip/CloseChip.tsx +106 -0
  62. package/src/components/RecommendPannel/helperComponents/CloseChip/index.ts +1 -0
  63. package/src/components/RecommendPannel/helperComponents/CloseChip/styles.module.scss +73 -0
  64. package/src/components/RecommendPannel/helperComponents/DropdownChip/DropdownChip.tsx +112 -0
  65. package/src/components/RecommendPannel/helperComponents/DropdownChip/index.ts +1 -0
  66. package/src/components/RecommendPannel/helperComponents/DropdownChip/styles.module.scss +56 -0
  67. package/src/components/RecommendPannel/hooks/index.ts +15 -0
  68. package/src/components/RecommendPannel/index.ts +1 -0
  69. package/src/components/RecommendPannel/styles.module.scss +4 -0
  70. package/src/components/RecommendPannel/types.ts +21 -0
  71. package/src/components/RecommendPannel/utils/gitVisibleChipsCount.ts +57 -0
  72. package/src/components/SshField/SshField.tsx +222 -0
  73. package/src/components/SshField/components/MobileFieldAi/MobileFieldAi.tsx +71 -0
  74. package/src/components/SshField/components/MobileFieldAi/index.ts +1 -0
  75. package/src/components/SshField/components/MobileFieldAi/styles.module.scss +80 -0
  76. package/src/components/SshField/components/TextArea/TextArea.tsx +113 -0
  77. package/src/components/SshField/components/TextArea/index.ts +1 -0
  78. package/src/components/SshField/components/TextArea/styles.module.scss +35 -0
  79. package/src/components/SshField/helperComponents/DropZoneContent/DropZoneContent.tsx +15 -0
  80. package/src/components/SshField/helperComponents/DropZoneContent/index.ts +1 -0
  81. package/src/components/SshField/helperComponents/DropZoneContent/styles.module.scss +17 -0
  82. package/src/components/SshField/helperComponents/FieldSubmitButton/FieldSubmitButton.tsx +45 -0
  83. package/src/components/SshField/helperComponents/FieldSubmitButton/index.ts +1 -0
  84. package/src/components/SshField/helperComponents/TextAreaActionsFooter/TextAreaActionsFooter.tsx +18 -0
  85. package/src/components/SshField/helperComponents/TextAreaActionsFooter/index.ts +1 -0
  86. package/src/components/SshField/helperComponents/TextAreaActionsFooter/styles.module.scss +23 -0
  87. package/src/components/SshField/index.ts +1 -0
  88. package/src/components/SshField/styles.module.scss +54 -0
  89. package/src/components/SshField/utils/handleFileError.ts +41 -0
  90. package/src/components/SshField/utils/isTouchDevice.ts +5 -0
  91. package/src/components/SshField/utils/readFileContent.ts +23 -0
  92. package/src/components/SshField/utils/validateSSHKey.ts +84 -0
  93. package/src/components/index.ts +6 -0
  94. package/src/index.ts +1 -0
@@ -0,0 +1,223 @@
1
+ /* stylelint-disable color-no-hex */
2
+ // TODO: refactor styles to use tokens
3
+ @use '@sbercloud/figma-tokens-giga-id/build/scss/components/styles-tokens-button-buttonOutline' as buttonOutline;
4
+ @use '@sbercloud/figma-tokens-giga-id/build/scss/styles-theme-variables' as stv;
5
+ @use '@sbercloud/figma-tokens-giga-id/build/scss/components/styles-tokens-element';
6
+
7
+ $sizes: 'xs', 's', 'm', 'l';
8
+ $variants: 'label-only', 'icon-only', 'icon-after';
9
+ $appearances: 'primary', 'neutral';
10
+ $typography: (
11
+ 'xs': stv.$sans-label-s,
12
+ 's': stv.$sans-label-m,
13
+ 'm': stv.$sans-label-l,
14
+ 'l': stv.$sans-label-l,
15
+ );
16
+
17
+ $outline-gradient-color-start: #7cb5f2;
18
+ $outline-gradient-color-middle: #5fd7c2;
19
+ $outline-gradient-color-end: #26d07c;
20
+ $outline-gradient: radial-gradient(
21
+ 92.53% 92.53% at 65.87% 21.69%,
22
+ $outline-gradient-color-start 15%,
23
+ $outline-gradient-color-middle 45%,
24
+ $outline-gradient-color-end 65%
25
+ );
26
+ $outline-box-shadow-hover: 0px 0px 1px 0px #00000026 inset;
27
+ $outline-box-shadow-active: 0px 0px 1px 0px #0000004d inset;
28
+ $outline-filter-brightness-hover: 0.9;
29
+ $outline-filter-brightness-active: 0.7;
30
+
31
+ @mixin icon-fill($color) {
32
+ .icon {
33
+ color: $color;
34
+ }
35
+ }
36
+
37
+ @mixin label-color($color) {
38
+ .label {
39
+ color: $color;
40
+ }
41
+ }
42
+
43
+ @mixin button-anatomy-styles($button-theme, $sizes, $variants, $typography) {
44
+ @each $size in $sizes {
45
+ &[data-size='#{$size}'] {
46
+ .label {
47
+ @include styles-tokens-element.composite-var($typography, $size);
48
+ }
49
+
50
+ .icon {
51
+ display: inline-flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+
55
+ width: styles-tokens-element.$icon-s;
56
+ height: styles-tokens-element.$icon-s;
57
+
58
+ svg {
59
+ max-width: styles-tokens-element.$icon-s;
60
+ max-height: styles-tokens-element.$icon-s;
61
+ }
62
+ }
63
+
64
+ @each $variant in $variants {
65
+ &[data-variant='#{$variant}'] {
66
+ @include styles-tokens-element.composite-var($button-theme, 'container', $size, $variant);
67
+ }
68
+ }
69
+
70
+ &[data-variant='icon-before'] {
71
+ @include styles-tokens-element.composite-var($button-theme, 'container', $size, 'icon-after');
72
+ $padding-from-icon: styles-tokens-element.simple-var(
73
+ $button-theme,
74
+ 'container',
75
+ $size,
76
+ 'icon-after',
77
+ 'padding-right'
78
+ );
79
+ $padding-from-label: styles-tokens-element.simple-var(
80
+ $button-theme,
81
+ 'container',
82
+ $size,
83
+ 'icon-after',
84
+ 'padding-left'
85
+ );
86
+ padding-left: $padding-from-icon;
87
+ padding-right: $padding-from-label;
88
+ }
89
+ }
90
+ }
91
+ }
92
+
93
+ @mixin loading-label-only($button-theme) {
94
+ &[data-loading][data-variant='label-only'] {
95
+ .icon {
96
+ position: absolute;
97
+ top: 50%;
98
+ left: 50%;
99
+ transform: translate(-50%, -50%);
100
+ }
101
+
102
+ .label {
103
+ @include styles-tokens-element.composite-var($button-theme, 'label', 'load-label-only');
104
+ }
105
+ }
106
+ }
107
+
108
+ @mixin button-focus-outline {
109
+ &:focus-visible {
110
+ @include styles-tokens-element.outline-var(styles-tokens-element.$container-focused-s);
111
+
112
+ outline-offset: styles-tokens-element.$spacing-state-focus-offset;
113
+ outline-color: stv.$sys-available-complementary;
114
+ }
115
+ }
116
+
117
+ @mixin giga-outline-colors {
118
+ @each $appearance in $appearances {
119
+ &[data-appearance='#{$appearance}'] {
120
+ @include label-color(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-default'));
121
+ @include icon-fill(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-default'));
122
+
123
+ background-color: transparent;
124
+ border: none;
125
+
126
+ &::before {
127
+ content: '';
128
+ position: absolute;
129
+ inset: 0;
130
+ padding: 1px;
131
+ border-radius: inherit;
132
+ background: $outline-gradient;
133
+ mask:
134
+ linear-gradient(#fff 0 0) content-box,
135
+ linear-gradient(#fff 0 0);
136
+ -webkit-mask-composite: xor;
137
+ mask-composite: exclude;
138
+ pointer-events: none;
139
+ }
140
+
141
+ @media (hover: hover) {
142
+ &:hover {
143
+ @include label-color(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-hovered'));
144
+ @include icon-fill(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-hovered'));
145
+
146
+ box-shadow: $outline-box-shadow-hover;
147
+
148
+ &::before {
149
+ filter: brightness($outline-filter-brightness-hover);
150
+ }
151
+
152
+ .icon {
153
+ filter: brightness($outline-filter-brightness-hover);
154
+ }
155
+ }
156
+ }
157
+
158
+ @media (hover: none) or (hover: hover) {
159
+ &:focus-visible {
160
+ @include label-color(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-hovered'));
161
+ @include icon-fill(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-hovered'));
162
+ }
163
+
164
+ &:active {
165
+ @include label-color(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-pressed'));
166
+ @include icon-fill(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-pressed'));
167
+
168
+ box-shadow: $outline-box-shadow-active;
169
+
170
+ &::before {
171
+ filter: brightness($outline-filter-brightness-active);
172
+ }
173
+
174
+ .icon {
175
+ filter: brightness($outline-filter-brightness-active);
176
+ }
177
+ }
178
+
179
+ &[data-loading] {
180
+ @include label-color(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-pressed'));
181
+ @include icon-fill(stv.simple-var(stv.$theme-variables, 'sys', $appearance, 'accent-pressed'));
182
+
183
+ box-shadow: $outline-box-shadow-active;
184
+
185
+ &::before {
186
+ filter: brightness($outline-filter-brightness-active);
187
+ }
188
+
189
+ .icon {
190
+ filter: brightness($outline-filter-brightness-active);
191
+ }
192
+ }
193
+
194
+ &:disabled,
195
+ &[data-disabled] {
196
+ @include label-color(stv.simple-var(stv.$theme-variables, 'sys', 'neutral', 'text-disabled'));
197
+ @include icon-fill(stv.simple-var(stv.$theme-variables, 'sys', 'neutral', 'text-disabled'));
198
+
199
+ background-color: transparent;
200
+
201
+ &::before {
202
+ background: stv.simple-var(stv.$theme-variables, 'sys', 'neutral', 'text-disabled');
203
+ }
204
+
205
+ .icon {
206
+ svg path {
207
+ fill: currentColor;
208
+ }
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ .button.specificityX2 {
217
+ display: inline-flex;
218
+
219
+ @include button-anatomy-styles(buttonOutline.$button-outline, $sizes, $variants, $typography);
220
+ @include loading-label-only(buttonOutline.$button-outline);
221
+ @include giga-outline-colors;
222
+ @include button-focus-outline;
223
+ }
@@ -0,0 +1,63 @@
1
+ import {
2
+ AnchorHTMLAttributes,
3
+ ButtonHTMLAttributes,
4
+ FocusEventHandler,
5
+ KeyboardEventHandler,
6
+ MouseEventHandler,
7
+ ReactElement,
8
+ } from 'react';
9
+
10
+ import { ValueOf } from '@snack-uikit/utils';
11
+
12
+ import { APPEARANCE, ICON_POSITION, SIZE } from '../constants';
13
+
14
+ export type Appearance = ValueOf<typeof APPEARANCE>;
15
+
16
+ export type IconPosition = ValueOf<typeof ICON_POSITION>;
17
+
18
+ export type Size = ValueOf<typeof SIZE>;
19
+
20
+ export type BaseButtonProps = {
21
+ /** CSS-класс */
22
+ className?: string;
23
+ /** Флаг неактивности компонента */
24
+ disabled?: boolean;
25
+ /**
26
+ * Иконка
27
+ * @type ReactElement
28
+ */
29
+ icon?: ReactElement;
30
+ /** Позиция иконки */
31
+ iconPosition?: IconPosition;
32
+ /** Текст кнопки */
33
+ label?: string;
34
+ /** Флаг состояния загрузки */
35
+ loading?: boolean;
36
+ /** Колбек обработки клика */
37
+ onClick?: MouseEventHandler<HTMLElement>;
38
+ /** Колбек обработки нажатия клавиши */
39
+ onKeyDown?: KeyboardEventHandler<HTMLElement>;
40
+ /** Колбек обработки фокуса */
41
+ onFocus?: FocusEventHandler<HTMLAnchorElement | HTMLButtonElement>;
42
+ /** Колбек обработки блюра */
43
+ onBlur?: FocusEventHandler<HTMLAnchorElement | HTMLButtonElement>;
44
+ /** Размер */
45
+ size?: Size;
46
+ /** Внешний вид кнопки */
47
+ appearance?: Appearance;
48
+ /** HTML-аттрибут type */
49
+ type?: ButtonHTMLAttributes<HTMLButtonElement>['type'];
50
+ /** HTML-аттрибут tab-index */
51
+ tabIndex?: number;
52
+ /** Сделать кнопку во всю ширину */
53
+ fullWidth?: boolean;
54
+ };
55
+
56
+ export type AnchorButtonProps = {
57
+ /** Ссылка */
58
+ href?: string;
59
+ /** HTML-аттрибут target */
60
+ target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
61
+ };
62
+
63
+ export type CommonButtonProps = AnchorButtonProps & BaseButtonProps;
@@ -0,0 +1,16 @@
1
+ import { CommonButtonProps } from './types';
2
+
3
+ export function extractCommonButtonProps({
4
+ disabled,
5
+ href,
6
+ icon,
7
+ iconPosition,
8
+ label,
9
+ loading,
10
+ onClick,
11
+ onFocus,
12
+ onBlur,
13
+ onKeyDown,
14
+ }: CommonButtonProps) {
15
+ return { disabled, href, icon, iconPosition, label, loading, onClick, onKeyDown, onFocus, onBlur };
16
+ }
@@ -0,0 +1,29 @@
1
+ export const APPEARANCE = {
2
+ Primary: 'primary',
3
+ Neutral: 'neutral',
4
+ } as const;
5
+
6
+ export const HTML_TYPE = {
7
+ Button: 'button',
8
+ Submit: 'submit',
9
+ Reset: 'reset',
10
+ } as const;
11
+
12
+ export const TARGET = {
13
+ Blank: '_blank',
14
+ Self: '_self',
15
+ Parent: '_parent',
16
+ Top: '_top',
17
+ } as const;
18
+
19
+ export const SIZE = {
20
+ Xs: 'xs',
21
+ S: 's',
22
+ M: 'm',
23
+ L: 'l',
24
+ } as const;
25
+
26
+ export const ICON_POSITION = {
27
+ Before: 'before',
28
+ After: 'after',
29
+ } as const;
@@ -0,0 +1,99 @@
1
+ import cn from 'classnames';
2
+ import { ForwardedRef, forwardRef, MouseEvent } from 'react';
3
+
4
+ import { extractSupportProps, WithSupportProps } from '@snack-uikit/utils';
5
+
6
+ import { APPEARANCE, HTML_TYPE, ICON_POSITION, TARGET } from '../../constants';
7
+ import { APPEARANCE_TO_COLOR_MAP } from './constants';
8
+ import styles from './styles.module.scss';
9
+ import { CommonButtonProps } from './types';
10
+ import { getChildren, getVariant } from './utils';
11
+
12
+ export type ButtonPrivateProps = WithSupportProps<
13
+ CommonButtonProps & {
14
+ iconClassName: string;
15
+ labelClassName: string;
16
+ fullWidth?: boolean;
17
+ }
18
+ >;
19
+
20
+ export const ButtonPrivate = forwardRef<HTMLButtonElement | HTMLAnchorElement, ButtonPrivateProps>(
21
+ (
22
+ {
23
+ className,
24
+ disabled,
25
+ href,
26
+ icon,
27
+ iconClassName,
28
+ iconPosition = ICON_POSITION.Before,
29
+ label,
30
+ labelClassName,
31
+ loading,
32
+ onClick,
33
+ onKeyDown,
34
+ onFocus,
35
+ onBlur,
36
+ size,
37
+ target = TARGET.Blank,
38
+ type = HTML_TYPE.Button,
39
+ appearance = APPEARANCE.Primary,
40
+ tabIndex: tabIndexProp = 0,
41
+ fullWidth,
42
+ ...rest
43
+ },
44
+ ref,
45
+ ) => {
46
+ const variant = getVariant({ label, iconPosition, icon });
47
+ const children = getChildren({
48
+ icon,
49
+ iconClassName,
50
+ iconPosition,
51
+ label,
52
+ labelClassName,
53
+ loading,
54
+ });
55
+ const tabIndex = loading || disabled ? -1 : tabIndexProp;
56
+
57
+ const handleClick = (event: MouseEvent<HTMLElement>) => {
58
+ if (disabled || loading) {
59
+ event.preventDefault();
60
+ return;
61
+ }
62
+
63
+ if (onClick) {
64
+ onClick(event);
65
+ }
66
+ };
67
+
68
+ const buttonProps = {
69
+ ...extractSupportProps(rest),
70
+ className: cn(styles.button, className),
71
+ 'data-disabled': disabled || undefined,
72
+ 'aria-disabled': disabled || undefined,
73
+ 'data-loading': loading || undefined,
74
+ 'data-size': size,
75
+ 'data-full-width': fullWidth || undefined,
76
+ 'data-appearance': APPEARANCE_TO_COLOR_MAP[appearance],
77
+ 'data-variant': variant,
78
+ onClick: handleClick,
79
+ onKeyDown,
80
+ onFocus,
81
+ onBlur,
82
+ tabIndex,
83
+ };
84
+
85
+ if (href) {
86
+ return (
87
+ <a role='button' href={href} target={target} {...buttonProps} ref={ref as ForwardedRef<HTMLAnchorElement>}>
88
+ {children}
89
+ </a>
90
+ );
91
+ }
92
+
93
+ return (
94
+ <button {...buttonProps} type={type} ref={ref as ForwardedRef<HTMLButtonElement>}>
95
+ {children}
96
+ </button>
97
+ );
98
+ },
99
+ );
@@ -0,0 +1,15 @@
1
+ import { ValueOf } from '@snack-uikit/utils';
2
+
3
+ import { APPEARANCE } from '../../constants';
4
+
5
+ export enum Variant {
6
+ LabelOnly = 'label-only',
7
+ IconOnly = 'icon-only',
8
+ IconBefore = 'icon-before',
9
+ IconAfter = 'icon-after',
10
+ }
11
+
12
+ export const APPEARANCE_TO_COLOR_MAP: Record<ValueOf<typeof APPEARANCE>, ValueOf<typeof APPEARANCE>> = {
13
+ [APPEARANCE.Primary]: APPEARANCE.Primary,
14
+ [APPEARANCE.Neutral]: APPEARANCE.Neutral,
15
+ };
@@ -0,0 +1 @@
1
+ export * from './ButtonPrivate';
@@ -0,0 +1,46 @@
1
+ @use '@sbercloud/figma-tokens-web/build/scss/components/styles-tokens-element';
2
+
3
+ .button {
4
+ cursor: pointer;
5
+
6
+ position: relative;
7
+
8
+ display: inline-flex;
9
+ flex-shrink: 0;
10
+ align-items: center;
11
+ justify-content: center;
12
+
13
+ box-sizing: border-box;
14
+ width: max-content;
15
+ min-width: max-content;
16
+ margin: 0;
17
+ padding: 0;
18
+
19
+ color: transparent;
20
+ text-decoration: none;
21
+ text-transform: none;
22
+
23
+ background-color: transparent;
24
+ border: 0 solid transparent;
25
+ outline: 0;
26
+ outline-offset: 0;
27
+
28
+ &[data-full-width] {
29
+ flex-grow: 1;
30
+ flex-shrink: 1;
31
+ width: 100%;
32
+ }
33
+
34
+ > * {
35
+ cursor: pointer;
36
+ }
37
+
38
+ &:disabled,
39
+ &[data-disabled],
40
+ &[data-loading] {
41
+ cursor: not-allowed;
42
+ > * {
43
+ cursor: not-allowed;
44
+ }
45
+ }
46
+ }
@@ -0,0 +1,63 @@
1
+ import {
2
+ AnchorHTMLAttributes,
3
+ ButtonHTMLAttributes,
4
+ FocusEventHandler,
5
+ KeyboardEventHandler,
6
+ MouseEventHandler,
7
+ ReactElement,
8
+ } from 'react';
9
+
10
+ import { ValueOf } from '@snack-uikit/utils';
11
+
12
+ import { APPEARANCE, ICON_POSITION, SIZE } from '../../constants';
13
+
14
+ export type Appearance = ValueOf<typeof APPEARANCE>;
15
+
16
+ export type IconPosition = ValueOf<typeof ICON_POSITION>;
17
+
18
+ export type Size = ValueOf<typeof SIZE>;
19
+
20
+ export type BaseButtonProps = {
21
+ /** CSS-класс */
22
+ className?: string;
23
+ /** Флаг неактивности компонента */
24
+ disabled?: boolean;
25
+ /**
26
+ * Иконка
27
+ * @type ReactElement
28
+ */
29
+ icon?: ReactElement;
30
+ /** Позиция иконки */
31
+ iconPosition?: IconPosition;
32
+ /** Текст кнопки */
33
+ label?: string;
34
+ /** Флаг состояния загрузки */
35
+ loading?: boolean;
36
+ /** Колбек обработки клика */
37
+ onClick?: MouseEventHandler<HTMLElement>;
38
+ /** Колбек обработки нажатия клавиши */
39
+ onKeyDown?: KeyboardEventHandler<HTMLElement>;
40
+ /** Колбек обработки фокуса */
41
+ onFocus?: FocusEventHandler<HTMLAnchorElement | HTMLButtonElement>;
42
+ /** Колбек обработки блюра */
43
+ onBlur?: FocusEventHandler<HTMLAnchorElement | HTMLButtonElement>;
44
+ /** Размер */
45
+ size?: Size;
46
+ /** Внешний вид кнопки */
47
+ appearance?: Appearance;
48
+ /** HTML-аттрибут type */
49
+ type?: ButtonHTMLAttributes<HTMLButtonElement>['type'];
50
+ /** HTML-аттрибут tab-index */
51
+ tabIndex?: number;
52
+ /** Сделать кнопку во всю ширину */
53
+ fullWidth?: boolean;
54
+ };
55
+
56
+ export type AnchorButtonProps = {
57
+ /** Ссылка */
58
+ href?: string;
59
+ /** HTML-аттрибут target */
60
+ target?: AnchorHTMLAttributes<HTMLAnchorElement>['target'];
61
+ };
62
+
63
+ export type CommonButtonProps = AnchorButtonProps & BaseButtonProps;
@@ -0,0 +1,92 @@
1
+ import { Sun } from '@snack-uikit/loaders';
2
+
3
+ import { ICON_POSITION } from '../../constants';
4
+ import { ButtonPrivateProps } from './ButtonPrivate';
5
+ import { Variant } from './constants';
6
+
7
+ type GetVariantProps = Pick<ButtonPrivateProps, 'label' | 'icon' | 'iconPosition'>;
8
+
9
+ export function getVariant({ label, icon, iconPosition }: GetVariantProps) {
10
+ if (label && icon && iconPosition === ICON_POSITION.After) {
11
+ return Variant.IconAfter;
12
+ }
13
+
14
+ if (label && icon && iconPosition === ICON_POSITION.Before) {
15
+ return Variant.IconBefore;
16
+ }
17
+
18
+ if (label) {
19
+ return Variant.LabelOnly;
20
+ }
21
+
22
+ return Variant.IconOnly;
23
+ }
24
+
25
+ type GetWrappedIconProps = Pick<ButtonPrivateProps, 'icon' | 'iconClassName' | 'loading'>;
26
+
27
+ export function getWrappedIcon({ icon, iconClassName, loading }: GetWrappedIconProps) {
28
+ if (loading) {
29
+ return (
30
+ <span data-test-id={'loading-icon'} className={iconClassName}>
31
+ <Sun size='s' />
32
+ </span>
33
+ );
34
+ }
35
+
36
+ if (icon) {
37
+ return (
38
+ <span data-test-id={'icon'} className={iconClassName}>
39
+ {icon}
40
+ </span>
41
+ );
42
+ }
43
+
44
+ return undefined;
45
+ }
46
+
47
+ type GetWrappedLabelProps = Pick<ButtonPrivateProps, 'label' | 'labelClassName'>;
48
+
49
+ export function getWrappedLabel({ label, labelClassName }: GetWrappedLabelProps) {
50
+ return label ? (
51
+ <span data-test-id={'label'} className={labelClassName}>
52
+ {label}
53
+ </span>
54
+ ) : undefined;
55
+ }
56
+
57
+ type GetChildrenProps = Pick<
58
+ ButtonPrivateProps,
59
+ 'icon' | 'label' | 'iconPosition' | 'iconClassName' | 'labelClassName' | 'loading'
60
+ >;
61
+
62
+ export function getChildren({ icon, label, iconPosition, iconClassName, labelClassName, loading }: GetChildrenProps) {
63
+ const wrappedIcon = getWrappedIcon({
64
+ icon,
65
+ iconClassName,
66
+ loading,
67
+ });
68
+ const wrappedLabel = getWrappedLabel({
69
+ label,
70
+ labelClassName,
71
+ });
72
+
73
+ switch (iconPosition) {
74
+ case ICON_POSITION.Before: {
75
+ return (
76
+ <>
77
+ {wrappedIcon}
78
+ {wrappedLabel}
79
+ </>
80
+ );
81
+ }
82
+ case ICON_POSITION.After:
83
+ default: {
84
+ return (
85
+ <>
86
+ {wrappedLabel}
87
+ {wrappedIcon}
88
+ </>
89
+ );
90
+ }
91
+ }
92
+ }
@@ -0,0 +1 @@
1
+ export * from './ButtonPrivate';
@@ -0,0 +1,3 @@
1
+ export * from './ButtonGigaMama';
2
+ export * from './ButtonGigaOutline';
3
+ export * from './ButtonGigaFunction';