@cloud-ru/uikit-product-claudia 1.8.4 → 1.9.1

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 (53) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +21 -0
  3. package/dist/cjs/components/RateForm/RateForm.d.ts +45 -0
  4. package/dist/cjs/components/RateForm/RateForm.js +27 -0
  5. package/dist/cjs/components/RateForm/components/FieldSubmitButton.d.ts +15 -0
  6. package/dist/cjs/components/RateForm/components/FieldSubmitButton.js +13 -0
  7. package/dist/cjs/components/RateForm/components/TextFieldWithAccordionMessage/TextFieldWithAccordionMessage.d.ts +19 -0
  8. package/dist/cjs/components/RateForm/components/TextFieldWithAccordionMessage/TextFieldWithAccordionMessage.js +56 -0
  9. package/dist/cjs/components/RateForm/components/TextFieldWithAccordionMessage/index.d.ts +1 -0
  10. package/dist/cjs/components/RateForm/components/TextFieldWithAccordionMessage/index.js +17 -0
  11. package/dist/cjs/components/RateForm/components/TextFieldWithAccordionMessage/styles.module.css +62 -0
  12. package/dist/cjs/components/RateForm/constants.d.ts +2 -0
  13. package/dist/cjs/components/RateForm/constants.js +5 -0
  14. package/dist/cjs/components/RateForm/index.d.ts +3 -0
  15. package/dist/cjs/components/RateForm/index.js +21 -0
  16. package/dist/cjs/components/RateForm/styles.module.css +127 -0
  17. package/dist/cjs/components/RateForm/types.d.ts +8 -0
  18. package/dist/cjs/components/RateForm/types.js +2 -0
  19. package/dist/cjs/components/SshField/SshField.d.ts +1 -1
  20. package/dist/cjs/components/SshField/components/MobileFieldAi/MobileFieldAi.d.ts +1 -1
  21. package/dist/cjs/components/index.d.ts +1 -0
  22. package/dist/cjs/components/index.js +1 -0
  23. package/dist/esm/components/RateForm/RateForm.d.ts +45 -0
  24. package/dist/esm/components/RateForm/RateForm.js +21 -0
  25. package/dist/esm/components/RateForm/components/FieldSubmitButton.d.ts +15 -0
  26. package/dist/esm/components/RateForm/components/FieldSubmitButton.js +10 -0
  27. package/dist/esm/components/RateForm/components/TextFieldWithAccordionMessage/TextFieldWithAccordionMessage.d.ts +19 -0
  28. package/dist/esm/components/RateForm/components/TextFieldWithAccordionMessage/TextFieldWithAccordionMessage.js +50 -0
  29. package/dist/esm/components/RateForm/components/TextFieldWithAccordionMessage/index.d.ts +1 -0
  30. package/dist/esm/components/RateForm/components/TextFieldWithAccordionMessage/index.js +1 -0
  31. package/dist/esm/components/RateForm/components/TextFieldWithAccordionMessage/styles.module.css +62 -0
  32. package/dist/esm/components/RateForm/constants.d.ts +2 -0
  33. package/dist/esm/components/RateForm/constants.js +2 -0
  34. package/dist/esm/components/RateForm/index.d.ts +3 -0
  35. package/dist/esm/components/RateForm/index.js +2 -0
  36. package/dist/esm/components/RateForm/styles.module.css +127 -0
  37. package/dist/esm/components/RateForm/types.d.ts +8 -0
  38. package/dist/esm/components/RateForm/types.js +1 -0
  39. package/dist/esm/components/SshField/SshField.d.ts +1 -1
  40. package/dist/esm/components/SshField/components/MobileFieldAi/MobileFieldAi.d.ts +1 -1
  41. package/dist/esm/components/index.d.ts +1 -0
  42. package/dist/esm/components/index.js +1 -0
  43. package/package.json +6 -3
  44. package/src/components/RateForm/RateForm.tsx +136 -0
  45. package/src/components/RateForm/components/FieldSubmitButton.tsx +45 -0
  46. package/src/components/RateForm/components/TextFieldWithAccordionMessage/TextFieldWithAccordionMessage.tsx +147 -0
  47. package/src/components/RateForm/components/TextFieldWithAccordionMessage/index.ts +1 -0
  48. package/src/components/RateForm/components/TextFieldWithAccordionMessage/styles.module.scss +68 -0
  49. package/src/components/RateForm/constants.ts +3 -0
  50. package/src/components/RateForm/index.ts +3 -0
  51. package/src/components/RateForm/styles.module.scss +143 -0
  52. package/src/components/RateForm/types.ts +8 -0
  53. package/src/components/index.ts +1 -0
@@ -0,0 +1,147 @@
1
+ import { KeyboardEventHandler, useRef, useState } from 'react';
2
+
3
+ import { themeVars } from '@sbercloud/figma-tokens-cloud-platform';
4
+ import { ChevronUpInterfaceSVG } from '@cloud-ru/uikit-product-icons';
5
+ import { Divider } from '@snack-uikit/divider';
6
+ import { FieldTextArea } from '@snack-uikit/fields';
7
+ import { Typography } from '@snack-uikit/typography';
8
+ import { useLayoutEffect } from '@snack-uikit/utils';
9
+
10
+ import { MESSAGE_MAX_LENGTH, STATIC_LINE_HEIGHT } from '../../constants';
11
+ import { FieldSubmitButton } from '../FieldSubmitButton';
12
+ import styles from './styles.module.scss';
13
+
14
+ export type TextFieldWithAccordionMessageProps = {
15
+ /** Существующий комментарий */
16
+ comment?: string;
17
+ /** Плейсхолдер для поля ввода */
18
+ placeholder?: string;
19
+ /** Callback при изменении текста */
20
+ onChange?: (value: string) => void;
21
+ /** Callback при отправке */
22
+ onSubmit?: (value: string) => void;
23
+ /** Максимальная длина сообщения */
24
+ maxLength?: number;
25
+ /** Является ли устройство тач-девайсом */
26
+ isTouchDevice?: boolean;
27
+ /** Показывать ли тултип на кнопке отправки */
28
+ showSubmitTooltip?: boolean;
29
+ /** Текст тултипа для кнопки отправки */
30
+ submitTooltipText?: string;
31
+ };
32
+
33
+ export function TextFieldWithAccordionMessage({
34
+ comment,
35
+ placeholder,
36
+ onChange,
37
+ onSubmit,
38
+ maxLength = MESSAGE_MAX_LENGTH,
39
+ isTouchDevice = false,
40
+ showSubmitTooltip = true,
41
+ submitTooltipText,
42
+ }: TextFieldWithAccordionMessageProps) {
43
+ const textRef = useRef<HTMLDivElement>(null);
44
+ const [isMultiLine, setIsMultiLine] = useState(false);
45
+ const [isExpanded, setIsExpanded] = useState(false);
46
+ const [message, setMessage] = useState(comment || '');
47
+
48
+ const isValid = typeof message === 'string' && message.trim().length > 0;
49
+
50
+ useLayoutEffect(() => {
51
+ if (!comment) return;
52
+
53
+ setMessage(comment);
54
+
55
+ const timeout = setTimeout(() => {
56
+ if (textRef.current) {
57
+ const textHeight = textRef.current.scrollHeight;
58
+ setIsMultiLine(textHeight > STATIC_LINE_HEIGHT * 2 + 5);
59
+ }
60
+ }, 0);
61
+
62
+ return () => clearTimeout(timeout);
63
+ }, [comment]);
64
+
65
+ const handleClickMessage = () => {
66
+ setIsExpanded(!isExpanded);
67
+ };
68
+
69
+ const handleChangeMessage = (value: string) => {
70
+ const truncatedValue = value.slice(0, maxLength);
71
+ setMessage(truncatedValue);
72
+ onChange?.(truncatedValue);
73
+ };
74
+
75
+ const handleSubmit = () => {
76
+ if (isValid) {
77
+ onSubmit?.(message);
78
+ }
79
+ };
80
+
81
+ const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = event => {
82
+ if (event.key === 'Enter' && !event.shiftKey && !isTouchDevice) {
83
+ event.preventDefault();
84
+ handleSubmit();
85
+ }
86
+ };
87
+
88
+ return (
89
+ <>
90
+ {comment && (
91
+ <div className={styles.comment}>
92
+ <Divider />
93
+
94
+ <div
95
+ className={styles.container}
96
+ data-clickable={isMultiLine || undefined}
97
+ onClick={isMultiLine ? handleClickMessage : undefined}
98
+ role={isMultiLine ? 'button' : undefined}
99
+ >
100
+ <div
101
+ ref={textRef}
102
+ className={styles.textContainer}
103
+ data-collapsed={(isMultiLine && !isExpanded) || undefined}
104
+ >
105
+ <Typography.LightBodyS className={styles.text}>{message}</Typography.LightBodyS>
106
+ </div>
107
+
108
+ {isMultiLine && (
109
+ <ChevronUpInterfaceSVG
110
+ color={themeVars.sys.neutral.textLight}
111
+ className={styles.textIcon}
112
+ data-rotated={!isExpanded || undefined}
113
+ size={20}
114
+ />
115
+ )}
116
+ </div>
117
+ </div>
118
+ )}
119
+
120
+ {!comment && (
121
+ <FieldTextArea
122
+ value={message}
123
+ size='m'
124
+ minRows={1}
125
+ maxRows={4}
126
+ placeholder={placeholder}
127
+ onChange={handleChangeMessage}
128
+ onKeyDown={handleKeyDown}
129
+ spellCheck
130
+ footer={
131
+ <div className={styles.actionsFooter}>
132
+ <FieldSubmitButton
133
+ tooltipText={showSubmitTooltip && !isTouchDevice ? submitTooltipText : undefined}
134
+ className={styles.buttonRight}
135
+ data-mobile={isTouchDevice || undefined}
136
+ active={isValid}
137
+ onClick={handleSubmit}
138
+ size={isTouchDevice ? 's' : 'xs'}
139
+ />
140
+ </div>
141
+ }
142
+ showClearButton={false}
143
+ />
144
+ )}
145
+ </>
146
+ );
147
+ }
@@ -0,0 +1 @@
1
+ export * from './TextFieldWithAccordionMessage';
@@ -0,0 +1,68 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as var;
2
+
3
+ .actionsFooter {
4
+ display: flex;
5
+ flex-direction: row;
6
+ justify-content: flex-end;
7
+ align-items: center;
8
+ width: 100%;
9
+ padding: 0 10px 9px 0;
10
+ cursor: text;
11
+ }
12
+
13
+ .textIcon {
14
+ min-width: 20px;
15
+ min-height: 20px;
16
+ transition: transform 0.2s ease;
17
+
18
+ &[data-rotated] {
19
+ transform: rotate(180deg);
20
+ }
21
+ }
22
+
23
+ .textContainer {
24
+ flex: 1;
25
+ min-width: 0;
26
+ line-height: 16px;
27
+
28
+ &[data-collapsed] {
29
+ display: -webkit-box;
30
+ -webkit-box-orient: vertical;
31
+ -webkit-line-clamp: 2;
32
+ line-clamp: 2;
33
+ overflow: hidden;
34
+ text-overflow: ellipsis;
35
+ line-height: 16px;
36
+ max-height: 32px;
37
+ }
38
+ }
39
+
40
+ .comment {
41
+ width: 100%;
42
+ display: flex;
43
+ flex-direction: column;
44
+ justify-content: center;
45
+ align-items: flex-start;
46
+ gap: 16px;
47
+ }
48
+
49
+ .text {
50
+ color: var.$sys-neutral-text-light;
51
+ line-height: 16px;
52
+ }
53
+
54
+ .container {
55
+ display: flex;
56
+ flex-direction: row;
57
+ align-items: flex-end;
58
+ gap: 4px;
59
+ width: 100%;
60
+
61
+ svg path {
62
+ fill: var.$sys-neutral-text-light;
63
+ }
64
+
65
+ &[data-clickable] {
66
+ cursor: pointer;
67
+ }
68
+ }
@@ -0,0 +1,3 @@
1
+ export const MESSAGE_MAX_LENGTH = 255;
2
+
3
+ export const STATIC_LINE_HEIGHT = 16;
@@ -0,0 +1,3 @@
1
+ export * from './RateForm';
2
+ export type { Grade } from './types';
3
+ export { MESSAGE_MAX_LENGTH, STATIC_LINE_HEIGHT } from './constants';
@@ -0,0 +1,143 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as var;
2
+
3
+ .closeIcon {
4
+ cursor: pointer;
5
+ position: absolute;
6
+ top: 8px;
7
+ right: 8px;
8
+ opacity: 0;
9
+ transition: opacity 0.2s ease;
10
+ will-change: opacity;
11
+ }
12
+
13
+ .feedbackForm {
14
+ position: relative;
15
+ display: flex;
16
+ flex-direction: column;
17
+ align-items: center;
18
+ justify-content: center;
19
+ width: 296px;
20
+ background-color: var.$sys-neutral-background2-level;
21
+ border: 1px solid var.$sys-neutral-decor-default;
22
+ border-radius: 8px;
23
+ padding: 24px;
24
+ gap: 16px;
25
+
26
+ &:hover {
27
+ .closeIcon {
28
+ opacity: 1;
29
+ }
30
+ }
31
+
32
+ &[data-touch] {
33
+ .closeIcon {
34
+ opacity: 1;
35
+ }
36
+ }
37
+ }
38
+
39
+ .feedbackFormTitle {
40
+ color: var.$sys-neutral-text-main;
41
+ }
42
+
43
+ .feedbackFormLoading {
44
+ display: flex;
45
+ flex-direction: column;
46
+ align-items: center;
47
+ justify-content: center;
48
+ width: 296px;
49
+ height: 141px;
50
+ background-color: var.$sys-neutral-background2-level;
51
+ border: 1px solid var.$sys-neutral-decor-default;
52
+ border-radius: 8px;
53
+ padding: 24px;
54
+
55
+ &[data-loading] {
56
+ cursor: wait;
57
+ }
58
+ }
59
+
60
+ .gradeBlock {
61
+ display: flex;
62
+ flex-direction: row;
63
+ align-items: center;
64
+ justify-content: center;
65
+ gap: 14px;
66
+ position: relative;
67
+ }
68
+
69
+ .description {
70
+ color: var.$sys-neutral-text-light;
71
+ position: absolute;
72
+ bottom: -12px;
73
+ opacity: 0;
74
+ }
75
+
76
+ .grade {
77
+ cursor: pointer;
78
+ display: flex;
79
+ flex-direction: column;
80
+ justify-content: center;
81
+ align-items: center;
82
+ transition: all 0.2s ease;
83
+ height: 40px;
84
+ width: 36px;
85
+
86
+ &:hover > .description {
87
+ opacity: 1;
88
+ }
89
+ }
90
+
91
+ .gradeIcon {
92
+ transition: all 0.2s ease;
93
+ font-size: 32px;
94
+
95
+ &:hover {
96
+ /* stylelint-disable-next-line declaration-no-important */
97
+ font-size: 36px !important;
98
+ }
99
+ }
100
+
101
+ .ratingContainer {
102
+ display: flex;
103
+ flex-direction: column;
104
+ justify-content: center;
105
+ align-items: center;
106
+ gap: 4px;
107
+ }
108
+
109
+ .ratingTitle {
110
+ display: flex;
111
+ flex-direction: row;
112
+ justify-content: center;
113
+ align-items: center;
114
+ gap: 4px;
115
+ color: var.$sys-neutral-text-main;
116
+ }
117
+
118
+ .ratingSubtitle {
119
+ color: var.$sys-neutral-text-main;
120
+ }
121
+
122
+ .ratingIcon {
123
+ /* stylelint-disable-next-line declaration-no-important */
124
+ line-height: 20px !important;
125
+ }
126
+
127
+ .mobileSubmitButton {
128
+ /* stylelint-disable-next-line declaration-no-important */
129
+ position: relative !important;
130
+ /* stylelint-disable-next-line declaration-no-important */
131
+ flex-shrink: 0 !important;
132
+
133
+ &:after {
134
+ content: '';
135
+ display: flex;
136
+ width: 48px;
137
+ height: 48px;
138
+ position: absolute;
139
+ top: 50%;
140
+ left: 50%;
141
+ transform: translate(-50%, -50%);
142
+ }
143
+ }
@@ -0,0 +1,8 @@
1
+ export type Grade = {
2
+ /** Уникальный идентификатор оценки */
3
+ id: string;
4
+ /** Иконка (эмодзи) */
5
+ icon: string;
6
+ /** Описание оценки */
7
+ description: string;
8
+ };
@@ -1,6 +1,7 @@
1
1
  export * from './ButtonClaudia';
2
2
  export * from './ButtonGiga';
3
3
  export * from './ChatStatusAnnouncement';
4
+ export * from './RateForm';
4
5
  export * from './IconGiga';
5
6
  export * from './RecommendPannel';
6
7
  export * from './SshField';