@redocly/theme 0.25.2 → 0.26.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 (78) hide show
  1. package/lib/components/Feedback/Comment.d.ts +1 -1
  2. package/lib/components/Feedback/Comment.js +28 -9
  3. package/lib/components/Feedback/Emotions.js +8 -25
  4. package/lib/components/Feedback/Feedback.js +6 -0
  5. package/lib/components/Feedback/Mood.js +115 -47
  6. package/lib/components/Feedback/Rating.d.ts +1 -0
  7. package/lib/components/Feedback/Rating.js +81 -42
  8. package/lib/components/Feedback/Reasons.d.ts +1 -1
  9. package/lib/components/Feedback/Reasons.js +4 -16
  10. package/lib/components/Feedback/Scale.d.ts +4 -0
  11. package/lib/components/Feedback/Scale.js +178 -0
  12. package/lib/components/Feedback/Sentiment.js +105 -35
  13. package/lib/components/Feedback/Stars.d.ts +8 -0
  14. package/lib/components/Feedback/Stars.js +54 -0
  15. package/lib/components/Feedback/Thumbs.d.ts +2 -6
  16. package/lib/components/Feedback/Thumbs.js +9 -46
  17. package/lib/components/Feedback/index.d.ts +1 -0
  18. package/lib/components/Feedback/index.js +3 -1
  19. package/lib/components/Feedback/types.d.ts +26 -5
  20. package/lib/components/Feedback/useReportDialog.js +3 -1
  21. package/lib/components/Markdown/MarkdownLayout.js +1 -0
  22. package/lib/components/Markdown/styledVariables.js +54 -0
  23. package/lib/components/Tabs/Tab.js +30 -6
  24. package/lib/components/Tabs/Tabs.js +22 -8
  25. package/lib/config.d.ts +7 -4
  26. package/lib/config.js +3 -2
  27. package/lib/icons/CheckboxIcon/CheckboxIcon.js +3 -3
  28. package/lib/icons/ColorModeIcon/ColorModeIcon.js +4 -4
  29. package/lib/icons/DissatisfiedIcon/DissatisfiedIcon.js +5 -5
  30. package/lib/icons/NeutralIcon/NeutralIcon.js +5 -5
  31. package/lib/icons/RadioCheckButtonIcon/RadioCheckButtonIcon.d.ts +4 -0
  32. package/lib/icons/RadioCheckButtonIcon/RadioCheckButtonIcon.js +16 -0
  33. package/lib/icons/RadioCheckButtonIcon/index.d.ts +1 -0
  34. package/lib/icons/RadioCheckButtonIcon/index.js +18 -0
  35. package/lib/icons/SatisfiedIcon/SatisfiedIcon.js +5 -5
  36. package/lib/icons/ThumbDownIcon/ThumbDownIcon.d.ts +4 -0
  37. package/lib/icons/ThumbDownIcon/ThumbDownIcon.js +14 -0
  38. package/lib/icons/ThumbDownIcon/index.d.ts +1 -0
  39. package/lib/icons/ThumbDownIcon/index.js +18 -0
  40. package/lib/icons/ThumbUpIcon/ThumbUpIcon.d.ts +4 -0
  41. package/lib/icons/ThumbUpIcon/ThumbUpIcon.js +14 -0
  42. package/lib/icons/ThumbUpIcon/index.d.ts +1 -0
  43. package/lib/icons/ThumbUpIcon/index.js +18 -0
  44. package/lib/types/portal/src/shared/constants.d.ts +2 -1
  45. package/lib/types/portal/src/shared/constants.js +1 -0
  46. package/lib/types/portal/src/shared/types/feedback.d.ts +2 -2
  47. package/package.json +2 -2
  48. package/src/components/Feedback/Comment.tsx +53 -20
  49. package/src/components/Feedback/Emotions.tsx +11 -32
  50. package/src/components/Feedback/Feedback.tsx +13 -1
  51. package/src/components/Feedback/Mood.tsx +164 -80
  52. package/src/components/Feedback/Rating.tsx +106 -79
  53. package/src/components/Feedback/Reasons.tsx +3 -19
  54. package/src/components/Feedback/Scale.tsx +229 -0
  55. package/src/components/Feedback/Sentiment.tsx +150 -56
  56. package/src/components/Feedback/Stars.tsx +51 -0
  57. package/src/components/Feedback/Thumbs.tsx +9 -106
  58. package/src/components/Feedback/index.ts +1 -0
  59. package/src/components/Feedback/types.ts +23 -4
  60. package/src/components/Feedback/useReportDialog.ts +3 -1
  61. package/src/components/Markdown/MarkdownLayout.tsx +1 -0
  62. package/src/components/Markdown/styledVariables.ts +54 -0
  63. package/src/components/Tabs/Tab.tsx +30 -6
  64. package/src/components/Tabs/Tabs.tsx +22 -8
  65. package/src/config.ts +3 -2
  66. package/src/icons/CheckboxIcon/CheckboxIcon.tsx +4 -4
  67. package/src/icons/ColorModeIcon/ColorModeIcon.tsx +4 -4
  68. package/src/icons/DissatisfiedIcon/DissatisfiedIcon.tsx +5 -15
  69. package/src/icons/NeutralIcon/NeutralIcon.tsx +5 -14
  70. package/src/icons/RadioCheckButtonIcon/RadioCheckButtonIcon.tsx +19 -0
  71. package/src/icons/RadioCheckButtonIcon/index.ts +1 -0
  72. package/src/icons/SatisfiedIcon/SatisfiedIcon.tsx +5 -9
  73. package/src/icons/ThumbDownIcon/ThumbDownIcon.tsx +15 -0
  74. package/src/icons/ThumbDownIcon/index.ts +1 -0
  75. package/src/icons/ThumbUpIcon/ThumbUpIcon.tsx +15 -0
  76. package/src/icons/ThumbUpIcon/index.ts +1 -0
  77. package/src/types/portal/src/shared/constants.ts +1 -0
  78. package/src/types/portal/src/shared/types/feedback.ts +2 -2
@@ -4,8 +4,16 @@ import styled from 'styled-components';
4
4
  import { Button } from '@theme/components/Button/Button';
5
5
  import type { CommentProps } from '@theme/components/Feedback';
6
6
  import { useTranslate } from '@portal/hooks';
7
+ import { RadioCheckButtonIcon } from '@theme/icons/RadioCheckButtonIcon';
8
+ import { breakpoints } from '@portal/media-css';
7
9
 
8
- export const Comment = ({ settings, onSubmit, onCancel, className }: CommentProps): JSX.Element => {
10
+ export const Comment = ({
11
+ settings,
12
+ onSubmit,
13
+ onCancel,
14
+ className,
15
+ standAlone = true,
16
+ }: CommentProps): JSX.Element => {
9
17
  const { label, submitText } = settings || {};
10
18
  const [text, setText] = React.useState('');
11
19
  const [submitValue, setSubmitValue] = React.useState('');
@@ -17,24 +25,34 @@ export const Comment = ({ settings, onSubmit, onCancel, className }: CommentProp
17
25
  onSubmit({ comment: text });
18
26
  };
19
27
  const handleTextAreaChange = (e: any) => {
20
- setText(e.target.value);
28
+ const commentValue = e.target.value;
29
+ setText(commentValue);
30
+
31
+ if (!standAlone) {
32
+ onSubmit({ comment: commentValue });
33
+ }
21
34
  };
22
35
 
23
36
  if (submitValue) {
24
37
  return (
25
- <Wrapper className={className}>
38
+ <StateWrapper className={className}>
26
39
  <Label data-translation-key="theme.feedback.settings.comment.submitText">
27
40
  {translate(
28
41
  'theme.feedback.settings.comment.submitText',
29
42
  submitText || 'Thank you for helping improve our documentation!',
30
43
  )}
31
44
  </Label>
32
- </Wrapper>
45
+ <RadioCheckButtonIcon />
46
+ </StateWrapper>
33
47
  );
34
48
  }
35
49
 
36
50
  return (
37
- <Wrapper data-component-name="Feedback/Comment" className={className}>
51
+ <Wrapper
52
+ data-component-name="Feedback/Comment"
53
+ className={className}
54
+ style={standAlone ? { width: '424px', padding: '16px 24px' } : { width: 'auto' }}
55
+ >
38
56
  <Label data-translation-key="theme.feedback.settings.comment.label">
39
57
  {translate(
40
58
  'theme.feedback.settings.comment.label',
@@ -42,19 +60,21 @@ export const Comment = ({ settings, onSubmit, onCancel, className }: CommentProp
42
60
  )}
43
61
  </Label>
44
62
  <TextArea rows={3} onChange={handleTextAreaChange} />
45
- <ButtonsContainer>
46
- <SendButton data-translation-key="theme.feedback.settings.comment.send" onClick={send}>
47
- {translate('theme.feedback.settings.comment.send', 'Send')}
48
- </SendButton>
49
- {onCancel && (
50
- <CancelButton
51
- data-translation-key="theme.feedback.settings.comment.cancel"
52
- onClick={onCancel}
53
- >
54
- {translate('theme.feedback.settings.comment.cancel', 'Cancel')}
55
- </CancelButton>
56
- )}
57
- </ButtonsContainer>
63
+ {standAlone && (
64
+ <ButtonsContainer>
65
+ <SendButton data-translation-key="theme.feedback.settings.comment.send" onClick={send}>
66
+ {translate('theme.feedback.settings.comment.send', 'Send')}
67
+ </SendButton>
68
+ {onCancel && (
69
+ <CancelButton
70
+ data-translation-key="theme.feedback.settings.comment.cancel"
71
+ onClick={onCancel}
72
+ >
73
+ {translate('theme.feedback.settings.comment.cancel', 'Cancel')}
74
+ </CancelButton>
75
+ )}
76
+ </ButtonsContainer>
77
+ )}
58
78
  </Wrapper>
59
79
  );
60
80
  };
@@ -63,7 +83,20 @@ const Wrapper = styled.div`
63
83
  font-family: var(--font-family-base);
64
84
  display: flex;
65
85
  flex-direction: column;
66
- width: 100%;
86
+ justify-content: space-between;
87
+ border-radius: 8px;
88
+ background: var(--bg-raised);
89
+ `;
90
+
91
+ const StateWrapper = styled(Wrapper)`
92
+ flex-direction: row;
93
+ align-items: center;
94
+ width: 424px;
95
+ padding: 16px 24px;
96
+
97
+ @media screen and (max-width: ${breakpoints.small}) {
98
+ width: 100%;
99
+ }
67
100
  `;
68
101
 
69
102
  const Label = styled.h3`
@@ -86,7 +119,7 @@ const TextArea = styled.textarea`
86
119
 
87
120
  const ButtonsContainer = styled.div`
88
121
  display: flex;
89
- justify-content: start;
122
+ justify-content: end;
90
123
  `;
91
124
 
92
125
  const SendButton = styled(Button).attrs(() => ({
@@ -5,52 +5,31 @@ import { SatisfiedIcon, DissatisfiedIcon, NeutralIcon } from '@theme/icons';
5
5
 
6
6
  export const Satisfied = () => {
7
7
  return (
8
- <Wrapper>
9
- <Icon>
10
- <SatisfiedIcon />
11
- </Icon>
12
- </Wrapper>
8
+ <Icon>
9
+ <SatisfiedIcon />
10
+ </Icon>
13
11
  );
14
12
  };
15
13
 
16
14
  export const Dissatisfied = () => {
17
15
  return (
18
- <Wrapper>
19
- <Icon>
20
- <DissatisfiedIcon />
21
- </Icon>
22
- </Wrapper>
16
+ <Icon>
17
+ <DissatisfiedIcon />
18
+ </Icon>
23
19
  );
24
20
  };
25
21
 
26
22
  export const Neutral = () => {
27
23
  return (
28
- <Wrapper>
29
- <Icon>
30
- <NeutralIcon />
31
- </Icon>
32
- </Wrapper>
24
+ <Icon>
25
+ <NeutralIcon />
26
+ </Icon>
33
27
  );
34
28
  };
35
29
 
36
- const Wrapper = styled.div`
37
- font-family: var(--font-family-base);
38
- display: flex;
39
- color: var(--color-info-text);
40
- &:hover {
41
- color: var(--color-info-text-active);
42
- svg {
43
- > g {
44
- fill: var(--color-info-text-active);
45
- }
46
- }
47
- }
48
- `;
49
-
50
30
  const Icon = styled.div`
51
- width: 16px;
52
- height: 16px;
53
- margin-right: 5px;
31
+ display: flex;
32
+ align-items: center;
54
33
  > svg {
55
34
  > g {
56
35
  fill: var(--color-info-text);
@@ -3,7 +3,7 @@ import { useLocation } from 'react-router-dom';
3
3
  import styled from 'styled-components';
4
4
 
5
5
  import type { FeedbackProps } from '@theme/types/portal/src/shared/types/feedback';
6
- import { Rating, Sentiment, Comment, Mood } from '@theme/components/Feedback';
6
+ import { Rating, Sentiment, Comment, Mood, Scale } from '@theme/components/Feedback';
7
7
  import { useThemeConfig } from '@theme/hooks';
8
8
  import { useSubmitFeedback } from '@portal/Feedback/useSubmitFeedback';
9
9
  import { telemetry } from '@portal/telemetry';
@@ -54,6 +54,18 @@ export const Feedback = (props: FeedbackProps & { path?: string }) => {
54
54
  />
55
55
  </Wrapper>
56
56
  );
57
+ case 'scale':
58
+ return (
59
+ <Wrapper>
60
+ <Scale
61
+ settings={settings}
62
+ onSubmit={(values) => {
63
+ submitFeedback({ type: 'scale', values, path });
64
+ telemetry.send('feedback_sent', { type: 'scale' });
65
+ }}
66
+ />
67
+ </Wrapper>
68
+ );
57
69
  case 'comment':
58
70
  return (
59
71
  <Wrapper>
@@ -1,10 +1,14 @@
1
1
  import * as React from 'react';
2
+ import { useEffect } from 'react';
2
3
  import styled from 'styled-components';
3
4
 
4
5
  import type { MoodProps, ReasonsProps } from '@theme/components/';
5
6
  import { useTranslate } from '@portal/hooks';
6
7
  import { Dissatisfied, Neutral, Satisfied } from '@theme/components/Feedback/Emotions';
7
8
  import { Comment, Reasons } from '@theme/components/Feedback';
9
+ import { RadioCheckButtonIcon } from '@theme/icons/RadioCheckButtonIcon';
10
+ import { Button } from '@theme/components/';
11
+ import { breakpoints } from '@portal/media-css';
8
12
 
9
13
  export enum MOOD_STATES {
10
14
  SATISFIED = 'satisfied',
@@ -20,99 +24,126 @@ export const Mood = ({ settings, onSubmit, className }: MoodProps): JSX.Element
20
24
  const [reasons, setReasons] = React.useState([] as ReasonsProps['settings']['items']);
21
25
  const { translate } = useTranslate();
22
26
 
23
- if (score && reasonsSettings?.enable && !reasons.length) {
24
- const { label: reasonsLabel, items, multi } = reasonsSettings;
25
- const buttonText = commentSettings?.enable ? 'Next' : 'Send';
26
- return (
27
- <Reasons
28
- onSubmit={({ reasons }) => setReasons(reasons)}
29
- settings={{ label: reasonsLabel, items, multi, buttonText }}
30
- />
31
- );
32
- }
27
+ const renderCommentLabel = (score: string) => {
28
+ if (!commentSettings?.enable) return '';
33
29
 
34
- if (score && commentSettings?.enable && !comment) {
35
- const renderCommentLabel = (score: string) => {
36
- switch (score) {
37
- case MOOD_STATES.SATISFIED:
38
- return translate(
39
- 'theme.feedback.settings.comment.satisfiedLabel',
40
- commentSettings.satisfiedLabel || 'What was most helpful?',
41
- );
42
- case MOOD_STATES.NEUTRAL:
43
- return translate(
44
- 'theme.feedback.settings.comment.neutralLabel',
45
- commentSettings.neutralLabel || 'What can we improve?',
46
- );
47
- case MOOD_STATES.DISSATISFIED:
48
- return translate(
49
- 'theme.feedback.settings.comment.dissatisfiedLabel',
50
- commentSettings.dissatisfiedLabel || 'What can we improve?',
51
- );
52
- default:
53
- return translate(
54
- 'theme.feedback.settings.comment.satisfiedLabel',
55
- 'What can we improve?',
56
- );
57
- }
58
- };
59
- return (
60
- <Comment
61
- onSubmit={({ comment }) => setComment(comment)}
62
- settings={{ label: renderCommentLabel(score) }}
63
- />
64
- );
65
- }
30
+ switch (score) {
31
+ case MOOD_STATES.SATISFIED:
32
+ return translate(
33
+ 'theme.feedback.settings.comment.satisfiedLabel',
34
+ commentSettings.satisfiedLabel || 'What was most helpful?',
35
+ );
36
+ case MOOD_STATES.NEUTRAL:
37
+ return translate(
38
+ 'theme.feedback.settings.comment.neutralLabel',
39
+ commentSettings.neutralLabel || 'What can we improve?',
40
+ );
41
+ case MOOD_STATES.DISSATISFIED:
42
+ return translate(
43
+ 'theme.feedback.settings.comment.dissatisfiedLabel',
44
+ commentSettings.dissatisfiedLabel || 'What can we improve?',
45
+ );
46
+ default:
47
+ return translate('theme.feedback.settings.comment.satisfiedLabel', 'What can we improve?');
48
+ }
49
+ };
66
50
 
67
- if (score) {
68
- if (!isSubmitted) {
69
- onSubmit({
70
- score,
71
- comment,
72
- reasons,
73
- });
51
+ const displayReasons = !!score && reasonsSettings?.enable;
52
+ const displayComment = !!score && commentSettings?.enable;
53
+ const displaySubmitBnt = !!score && (displayReasons || displayComment);
74
54
 
75
- setIsSubmitted(true);
55
+ const onSubmitMoodForm = () => {
56
+ onSubmit({
57
+ score,
58
+ comment,
59
+ reasons,
60
+ });
61
+ setIsSubmitted(true);
62
+ };
63
+
64
+ useEffect(() => {
65
+ if (score && !displayComment && !displayReasons) {
66
+ onSubmitMoodForm();
76
67
  }
68
+ // eslint-disable-next-line react-hooks/exhaustive-deps
69
+ }, [score, displayComment, displayReasons]);
77
70
 
71
+ if (isSubmitted) {
78
72
  return (
79
73
  <Wrapper>
80
74
  <Label data-translation-key="theme.feedback.settings.submitText">
81
75
  {translate(
82
76
  'theme.feedback.settings.submitText',
83
- submitText || 'Thank you for your feedback!',
77
+ submitText || 'Thank you for helping improve our documentation!',
84
78
  )}
85
79
  </Label>
80
+ <RadioCheckButtonIcon />
86
81
  </Wrapper>
87
82
  );
88
83
  }
89
84
 
90
85
  return (
91
86
  <Wrapper data-component-name="Feedback/Mood" className={className}>
92
- <Label data-translation-key="theme.feedback.settings.label">
93
- {translate('theme.feedback.settings.label', label || 'Was this page helpful?')}
94
- </Label>
95
- <Vote
96
- onClick={() => {
97
- setScore(MOOD_STATES.DISSATISFIED);
98
- }}
99
- >
100
- <Dissatisfied />
101
- </Vote>
102
- <Vote
103
- onClick={() => {
104
- setScore(MOOD_STATES.NEUTRAL);
105
- }}
106
- >
107
- <Neutral />
108
- </Vote>
109
- <Vote
110
- onClick={() => {
111
- setScore(MOOD_STATES.SATISFIED);
112
- }}
113
- >
114
- <Satisfied />
115
- </Vote>
87
+ <StyledForm>
88
+ <StyledFormMandatoryFields>
89
+ <Label data-translation-key="theme.feedback.settings.label">
90
+ {translate('theme.feedback.settings.label', label || 'Was this page helpful?')}
91
+ </Label>
92
+ <StyledMandatoryFieldContainer>
93
+ <>
94
+ <Vote
95
+ className={`${score === MOOD_STATES.DISSATISFIED ? 'active' : ''}`}
96
+ onClick={() => {
97
+ setScore(MOOD_STATES.DISSATISFIED);
98
+ }}
99
+ >
100
+ <Dissatisfied />
101
+ </Vote>
102
+ <Vote
103
+ className={`${score === MOOD_STATES.NEUTRAL ? 'active' : ''}`}
104
+ onClick={() => {
105
+ setScore(MOOD_STATES.NEUTRAL);
106
+ }}
107
+ >
108
+ <Neutral />
109
+ </Vote>
110
+ <Vote
111
+ className={`${score === MOOD_STATES.SATISFIED ? 'active' : ''}`}
112
+ onClick={() => {
113
+ setScore(MOOD_STATES.SATISFIED);
114
+ }}
115
+ >
116
+ <Satisfied />
117
+ </Vote>
118
+ </>
119
+ </StyledMandatoryFieldContainer>
120
+ </StyledFormMandatoryFields>
121
+ <StyledFormOptionalFields>
122
+ {displayReasons && (
123
+ <Reasons
124
+ settings={{
125
+ label: reasonsSettings?.label,
126
+ items: reasonsSettings?.items || [],
127
+ multi: reasonsSettings?.multi,
128
+ }}
129
+ onChange={setReasons}
130
+ />
131
+ )}
132
+
133
+ {displayComment && (
134
+ <Comment
135
+ standAlone={false}
136
+ onSubmit={({ comment }) => setComment(comment)}
137
+ settings={{ label: renderCommentLabel(score) }}
138
+ />
139
+ )}
140
+ </StyledFormOptionalFields>
141
+ {displaySubmitBnt && (
142
+ <ButtonsContainer>
143
+ <SubmitButton onClick={onSubmitMoodForm}>Submit</SubmitButton>
144
+ </ButtonsContainer>
145
+ )}
146
+ </StyledForm>
116
147
  </Wrapper>
117
148
  );
118
149
  };
@@ -120,19 +151,72 @@ export const Mood = ({ settings, onSubmit, className }: MoodProps): JSX.Element
120
151
  const Wrapper = styled.div`
121
152
  font-family: var(--font-family-base);
122
153
  display: flex;
154
+ justify-content: space-between;
123
155
  align-items: center;
156
+ padding: 16px 24px;
157
+ width: 424px;
158
+ border-radius: 8px;
159
+ background: var(--bg-raised);
160
+
161
+ @media screen and (max-width: ${breakpoints.small}) {
162
+ width: 100%;
163
+ }
124
164
  `;
125
165
 
126
166
  const Label = styled.h3`
127
- font-family: var(--h3-font-family);
128
- font-weight: var(--h3-font-weight);
129
- font-size: var(--h3-font-size);
130
- line-height: var(--h3-line-height);
131
- color: var(--h3-text-color);
132
167
  margin-right: 15px;
168
+ font-family: var(--h4-font-family);
169
+ font-weight: var(--h4-font-weight);
170
+ font-size: var(--h4-font-size);
171
+ line-height: var(--h4-line-height);
172
+ color: var(--h3-text-color);
133
173
  `;
134
174
 
135
175
  const Vote = styled.div`
136
176
  cursor: pointer;
137
177
  margin: 0 10px;
178
+ color: var(--text-description);
179
+ &.active {
180
+ color: var(--text-primary);
181
+ }
182
+ &:hover {
183
+ color: var(--text-primary);
184
+ svg {
185
+ > g {
186
+ fill: var(--text-primary);
187
+ }
188
+ }
189
+ }
190
+ `;
191
+
192
+ const SubmitButton = styled(Button).attrs(() => ({
193
+ color: 'primary',
194
+ }))`
195
+ width: 100px;
196
+ margin-left: 0;
197
+ margin-right: 0;
198
+ `;
199
+
200
+ const ButtonsContainer = styled.div`
201
+ display: flex;
202
+ justify-content: end;
203
+ `;
204
+
205
+ const StyledForm = styled.form`
206
+ width: 100%;
207
+ `;
208
+
209
+ const StyledFormOptionalFields = styled.div`
210
+ display: flex;
211
+ flex-flow: column;
212
+ `;
213
+
214
+ const StyledFormMandatoryFields = styled.div`
215
+ display: flex;
216
+ justify-content: space-between;
217
+ `;
218
+
219
+ const StyledMandatoryFieldContainer = styled.div`
220
+ display: flex;
221
+ align-items: center;
138
222
  `;