@bethinkpl/design-system 15.0.3 → 15.1.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 (48) hide show
  1. package/dist/design-system.umd.js +1451 -1121
  2. package/dist/design-system.umd.js.map +1 -1
  3. package/dist/lib/js/components/PopOver/PopOver.consts.d.ts +4 -0
  4. package/dist/lib/js/components/PopOver/PopOver.stories.d.ts +1 -0
  5. package/dist/lib/js/components/ProgressDonutChart/ProgressDonutChart.consts.d.ts +38 -0
  6. package/dist/lib/js/components/ProgressDonutChart/ProgressDonutChart.spec.d.ts +1 -0
  7. package/dist/lib/js/components/ProgressDonutChart/ProgressDonutChart.stories.d.ts +531 -0
  8. package/dist/lib/js/components/ProgressDonutChart/ProgressDonutChart.vue.d.ts +267 -0
  9. package/dist/lib/js/components/ProgressDonutChart/index.d.ts +3 -0
  10. package/dist/lib/js/index.d.ts +2 -0
  11. package/docs/iframe.html +1 -1
  12. package/docs/main.c8783f38.iframe.bundle.js +1 -0
  13. package/docs/project.json +1 -1
  14. package/lib/js/components/Badges/Badge/Badge.vue +2 -2
  15. package/lib/js/components/Badges/BadgeScore/BadgeScore.vue +2 -2
  16. package/lib/js/components/Banner/Banner.vue +15 -15
  17. package/lib/js/components/Buttons/IconButton/IconButton.vue +2 -2
  18. package/lib/js/components/IconText/IconText.vue +1 -1
  19. package/lib/js/components/Modals/Modal/Modal.vue +42 -49
  20. package/lib/js/components/NumberInCircle/NumberInCircle.vue +7 -7
  21. package/lib/js/components/Pagination/Pagination.vue +17 -17
  22. package/lib/js/components/Pill/Pill.vue +2 -2
  23. package/lib/js/components/PopOver/PopOver.consts.ts +5 -0
  24. package/lib/js/components/PopOver/PopOver.stories.ts +49 -8
  25. package/lib/js/components/PopOver/PopOver.vue +61 -5
  26. package/lib/js/components/ProgressBar/ProgressBar.vue +2 -2
  27. package/lib/js/components/ProgressDonutChart/ProgressDonutChart.consts.ts +47 -0
  28. package/lib/js/components/ProgressDonutChart/ProgressDonutChart.spec.ts +97 -0
  29. package/lib/js/components/ProgressDonutChart/ProgressDonutChart.stories.ts +64 -0
  30. package/lib/js/components/ProgressDonutChart/ProgressDonutChart.vue +293 -0
  31. package/lib/js/components/ProgressDonutChart/index.ts +4 -0
  32. package/lib/js/components/SectionHeader/SectionHeader.vue +1 -1
  33. package/lib/js/components/SurveyQuestions/SurveyQuestionOpenEnded/SurveyQuestionOpenEnded.vue +2 -2
  34. package/lib/js/components/SurveyQuestions/SurveyQuestionScale/SurveyQuestionScale.vue +4 -4
  35. package/lib/js/components/SurveyQuestions/SurveyQuestionTextarea.vue +2 -2
  36. package/lib/js/components/SurveyToggle/SurveyToggle.vue +5 -5
  37. package/lib/js/components/Toggles/CounterToggle/CounterToggle.vue +2 -2
  38. package/lib/js/index.ts +2 -0
  39. package/lib/js/styles/ItemsList.vue +1 -1
  40. package/lib/styles/components/_buttons.scss +2 -2
  41. package/lib/styles/components/_items-list-item.scss +1 -1
  42. package/lib/styles/components/_links.scss +2 -2
  43. package/lib/styles/mixins/_layout.scss +1 -1
  44. package/lib/styles/mixins/_scrollbars.scss +2 -2
  45. package/lib/styles/storybook.scss +3 -3
  46. package/package.json +3 -3
  47. package/stylelint.config.js +2 -0
  48. package/docs/main.ad3bccd0.iframe.bundle.js +0 -1
@@ -9,16 +9,24 @@
9
9
  :delay-on-mouse-over="300"
10
10
  :delay-on-mouse-out="300"
11
11
  :append-to-body="appendToBody"
12
+ :visible-arrow="isPointerVisible"
13
+ :root-class="rootClass"
12
14
  >
13
15
  <div
14
16
  class="popper popOver"
15
- :class="{ '-color-neutral': color === POP_OVER_COLORS.NEUTRAL }"
17
+ :class="{
18
+ '-color-neutral': color === POP_OVER_COLORS.NEUTRAL,
19
+ '-small': size === POP_OVER_SIZES.SMALL,
20
+ '-medium': size === POP_OVER_SIZES.MEDIUM,
21
+ }"
16
22
  >
17
23
  <img v-if="headerImageUrl" class="popOver__image" :src="headerImageUrl" alt="" />
18
24
  <div class="popOver__content">
19
25
  <div v-if="titleText" class="popOver__title"> {{ titleText }} </div>
20
26
  <div v-if="subtitleText" class="popOver__subtitle"> {{ subtitleText }} </div>
21
- <slot :close="close" />
27
+ <div class="popOver__contentSlot" :class="{ '-maxHeight': maxHeight }">
28
+ <slot :close="close" />
29
+ </div>
22
30
  </div>
23
31
  <ds-button
24
32
  v-if="buttonText"
@@ -53,7 +61,6 @@
53
61
  display: flex;
54
62
  flex-direction: column;
55
63
  padding: 0;
56
- max-width: 320px;
57
64
 
58
65
  &.-color-neutral ::v-deep .popper__arrow {
59
66
  border-color: $color-neutral-background transparent !important;
@@ -63,6 +70,30 @@
63
70
  background-color: $color-neutral-background;
64
71
  }
65
72
 
73
+ .popOver__contentSlot {
74
+ word-break: break-word;
75
+ }
76
+
77
+ .popOver__contentSlot.-maxHeight {
78
+ overflow: hidden scroll;
79
+ }
80
+
81
+ &.-small {
82
+ width: 320px;
83
+
84
+ .popOver__contentSlot.-maxHeight {
85
+ max-height: 160px;
86
+ }
87
+ }
88
+
89
+ &.-medium {
90
+ width: min(90vw, 460px);
91
+
92
+ .popOver__contentSlot.-maxHeight {
93
+ max-height: 250px;
94
+ }
95
+ }
96
+
66
97
  &[x-placement^='bottom'] {
67
98
  margin-top: $space-s;
68
99
 
@@ -145,8 +176,8 @@
145
176
  }
146
177
 
147
178
  &__button {
148
- margin: 0 $space-s $space-xs;
149
179
  align-self: flex-end;
180
+ margin: 0 $space-s $space-xs;
150
181
  }
151
182
  }
152
183
  </style>
@@ -154,7 +185,12 @@
154
185
  <script>
155
186
  import VuePopper from 'vue-popperjs';
156
187
  import 'vue-popperjs/dist/vue-popper.css';
157
- import { POP_OVER_COLORS, POP_OVER_PLACEMENTS, POP_OVER_TRIGGER_ACTIONS } from './PopOver.consts';
188
+ import {
189
+ POP_OVER_COLORS,
190
+ POP_OVER_PLACEMENTS,
191
+ POP_OVER_TRIGGER_ACTIONS,
192
+ POP_OVER_SIZES,
193
+ } from './PopOver.consts';
158
194
  import DsButton, { BUTTON_SIZES, BUTTON_TYPES } from '../Buttons/Button';
159
195
 
160
196
  export default {
@@ -217,10 +253,30 @@ export default {
217
253
  type: Object,
218
254
  default: () => ({}),
219
255
  },
256
+ size: {
257
+ type: String,
258
+ default: POP_OVER_SIZES.SMALL,
259
+ validator(size) {
260
+ return Object.values(POP_OVER_SIZES).includes(size);
261
+ },
262
+ },
263
+ maxHeight: {
264
+ type: Boolean,
265
+ default: false,
266
+ },
267
+ isPointerVisible: {
268
+ type: Boolean,
269
+ default: true,
270
+ },
271
+ rootClass: {
272
+ type: String,
273
+ default: '',
274
+ },
220
275
  },
221
276
  data() {
222
277
  return {
223
278
  POP_OVER_COLORS: Object.freeze(POP_OVER_COLORS),
279
+ POP_OVER_SIZES: Object.freeze(POP_OVER_SIZES),
224
280
  BUTTON_TYPES: Object.freeze(BUTTON_TYPES),
225
281
  BUTTON_SIZES: Object.freeze(BUTTON_SIZES),
226
282
  key: 1,
@@ -229,8 +229,8 @@ $progress-bar-badge-colors: (
229
229
  display: flex;
230
230
  flex-wrap: wrap;
231
231
  justify-content: right;
232
- margin-left: $space-xxs;
233
232
  margin-bottom: $space-xxxxxs;
233
+ margin-left: $space-xxs;
234
234
  max-width: $progress-bar-label-data-max-width;
235
235
  }
236
236
 
@@ -272,8 +272,8 @@ $progress-bar-badge-colors: (
272
272
  }
273
273
 
274
274
  align-items: center;
275
- border-radius: 50%;
276
275
  border: 1px solid $color-inverted-border;
276
+ border-radius: 50%;
277
277
  display: flex;
278
278
  height: $progress-bar-badge-size;
279
279
  justify-content: center;
@@ -0,0 +1,47 @@
1
+ export const PROGRESS_DONUT_CHART_RANGE_COLORS = {
2
+ PRIMARY_MEDIUM: 'primaryMedium',
3
+ PRIMARY: 'primary',
4
+ PRIMARY_WEAK: 'primaryWeak',
5
+ PRIMARY_GHOST: 'primaryGhost',
6
+
7
+ NEUTRAL_MEDIUM: 'neutralMedium',
8
+ NEUTRAL: 'neutral',
9
+ NEUTRAL_WEAK: 'neutralWeak',
10
+ NEUTRAL_GHOST: 'neutralGhost',
11
+
12
+ INFO_MEDIUM: 'infoMedium',
13
+ INFO: 'info',
14
+ INFO_WEAK: 'infoWeak',
15
+ INFO_GHOST: 'infoGhost',
16
+
17
+ SUCCESS_MEDIUM: 'successMedium',
18
+ SUCCESS: 'success',
19
+ SUCCESS_WEAK: 'successWeak',
20
+ SUCCESS_GHOST: 'successGhost',
21
+
22
+ WARNING_MEDIUM: 'warningMedium',
23
+ WARNING: 'warning',
24
+ WARNING_WEAK: 'warningWeak',
25
+ WARNING_GHOST: 'warningGhost',
26
+
27
+ FAIL_MEDIUM: 'failMedium',
28
+ FAIL: 'fail',
29
+ FAIL_WEAK: 'failWeak',
30
+ FAIL_GHOST: 'failGhost',
31
+ } as const;
32
+
33
+ export const PROGRESS_DONUT_CHART_STATES = {
34
+ DEFAULT: 'default',
35
+ LOADING: 'loading',
36
+ DONE: 'done',
37
+ OVERAGE: 'overage',
38
+ };
39
+
40
+ export type ProgressDonutChartState =
41
+ typeof PROGRESS_DONUT_CHART_STATES[keyof typeof PROGRESS_DONUT_CHART_STATES];
42
+
43
+ export interface ProgressDonutChartRange {
44
+ color: typeof PROGRESS_DONUT_CHART_RANGE_COLORS[keyof typeof PROGRESS_DONUT_CHART_RANGE_COLORS];
45
+ start: number;
46
+ length: number;
47
+ }
@@ -0,0 +1,97 @@
1
+ import { createLocalVue, shallowMount } from '@vue/test-utils';
2
+
3
+ import ProgressDonutChart from './ProgressDonutChart.vue';
4
+ import {
5
+ PROGRESS_DONUT_CHART_RANGE_COLORS,
6
+ PROGRESS_DONUT_CHART_STATES,
7
+ ProgressDonutChartRange,
8
+ ProgressDonutChartState,
9
+ } from './ProgressDonutChart.consts';
10
+
11
+ const localVue = createLocalVue();
12
+ const createComponent = function ({
13
+ label = '',
14
+ state = PROGRESS_DONUT_CHART_STATES.DEFAULT,
15
+ ranges = [],
16
+ }: createComponentOptions) {
17
+ return shallowMount(ProgressDonutChart, {
18
+ localVue,
19
+ propsData: {
20
+ label,
21
+ state,
22
+ ranges,
23
+ },
24
+ });
25
+ };
26
+
27
+ const rangesMock = [
28
+ {
29
+ color: PROGRESS_DONUT_CHART_RANGE_COLORS.SUCCESS,
30
+ start: 0,
31
+ length: 30,
32
+ } as ProgressDonutChartRange,
33
+ {
34
+ color: PROGRESS_DONUT_CHART_RANGE_COLORS.INFO,
35
+ start: 30,
36
+ length: 25,
37
+ } as ProgressDonutChartRange,
38
+ {
39
+ color: PROGRESS_DONUT_CHART_RANGE_COLORS.FAIL_GHOST,
40
+ start: 55,
41
+ length: 25,
42
+ } as ProgressDonutChartRange,
43
+ ];
44
+
45
+ interface createComponentOptions {
46
+ label: string;
47
+ state?: ProgressDonutChartState;
48
+ ranges?: Array<ProgressDonutChartRange>;
49
+ }
50
+
51
+ describe('ProgressDonutChart', () => {
52
+ it('should render loading', () => {
53
+ const component = createComponent({
54
+ label: 'test',
55
+ state: PROGRESS_DONUT_CHART_STATES.LOADING,
56
+ ranges: rangesMock,
57
+ });
58
+
59
+ expect(component.find('.progressDonutChart__loader').exists()).toBeTruthy();
60
+ expect(component.find('.progressDonutChart__track').exists()).toBeFalsy();
61
+ });
62
+
63
+ it('should render icon when done', async () => {
64
+ const component = createComponent({
65
+ label: 'test',
66
+ state: PROGRESS_DONUT_CHART_STATES.DONE,
67
+ ranges: rangesMock,
68
+ });
69
+
70
+ expect(component.find('ds-icon-stub').exists()).toBeTruthy();
71
+ });
72
+
73
+ it('should render + sign when overage', () => {
74
+ const component = createComponent({
75
+ label: 'test',
76
+ state: PROGRESS_DONUT_CHART_STATES.OVERAGE,
77
+ ranges: rangesMock,
78
+ });
79
+
80
+ expect(component.find('.progressDonutChart__track.-success').exists()).toBeTruthy();
81
+ expect(component.find('.progressDonutChart__labelText').exists()).toBeTruthy();
82
+ expect(component.find('.progressDonutChart__labelText').text()).toBe('+test');
83
+ });
84
+
85
+ it('should calculate track rotation based on start and length', () => {
86
+ const component = createComponent({
87
+ label: 'test',
88
+ state: PROGRESS_DONUT_CHART_STATES.DEFAULT,
89
+ ranges: rangesMock,
90
+ });
91
+ const tracks = component.findAll('.progressDonutChart__track');
92
+ expect(tracks.length).toBe(3);
93
+ expect(tracks.at(0).attributes('style')).toBe('transform: rotate(90deg);');
94
+ expect(tracks.at(1).attributes('style')).toBe('transform: rotate(198deg);');
95
+ expect(tracks.at(2).attributes('style')).toBe('transform: rotate(288deg);');
96
+ });
97
+ });
@@ -0,0 +1,64 @@
1
+ import ProgressDonutChart from './ProgressDonutChart.vue';
2
+
3
+ import { ArgTypes, Meta, StoryFn } from '@storybook/vue';
4
+ import {
5
+ PROGRESS_DONUT_CHART_RANGE_COLORS,
6
+ PROGRESS_DONUT_CHART_STATES,
7
+ ProgressDonutChartRange,
8
+ } from './ProgressDonutChart.consts';
9
+
10
+ export default {
11
+ title: 'Components/ProgressDonutChart',
12
+ component: ProgressDonutChart,
13
+ } as Meta<typeof ProgressDonutChart>;
14
+
15
+ const StoryTemplate: StoryFn<typeof ProgressDonutChart> = (argTypes) => ({
16
+ components: { ProgressDonutChart },
17
+ props: Object.keys(argTypes),
18
+ template: `
19
+ <ProgressDonutChart
20
+ v-bind=$props
21
+ />`,
22
+ });
23
+
24
+ export const Interactive = StoryTemplate.bind({});
25
+
26
+ const argTypes = {
27
+ label: {
28
+ control: { type: 'text' },
29
+ defaultValue: '70',
30
+ },
31
+ state: {
32
+ control: { type: 'select', options: Object.values(PROGRESS_DONUT_CHART_STATES) },
33
+ defaultValue: PROGRESS_DONUT_CHART_STATES.DEFAULT,
34
+ },
35
+ ranges: {
36
+ control: { type: 'array' },
37
+ defaultValue: [
38
+ {
39
+ color: PROGRESS_DONUT_CHART_RANGE_COLORS.SUCCESS,
40
+ start: 0,
41
+ length: 30,
42
+ } as ProgressDonutChartRange,
43
+ {
44
+ color: PROGRESS_DONUT_CHART_RANGE_COLORS.INFO,
45
+ start: 30,
46
+ length: 25,
47
+ } as ProgressDonutChartRange,
48
+ {
49
+ color: PROGRESS_DONUT_CHART_RANGE_COLORS.FAIL_GHOST,
50
+ start: 55,
51
+ length: 25,
52
+ } as ProgressDonutChartRange,
53
+ ],
54
+ },
55
+ } as ArgTypes;
56
+
57
+ Interactive.argTypes = argTypes;
58
+
59
+ Interactive.parameters = {
60
+ design: {
61
+ type: 'figma',
62
+ url: 'https://www.figma.com/file/izQdYyiBR1GQgFkaOIfIJI/LMS---DS-Components?node-id=5867-97923&t=wQeUoflFyMwdW7Ne-4',
63
+ },
64
+ };
@@ -0,0 +1,293 @@
1
+ <template>
2
+ <div
3
+ :class="{
4
+ progressDonutChart: true,
5
+ }"
6
+ >
7
+ <svg
8
+ class="progressDonutChart__svg"
9
+ :width="PROGRESS_DONUT_CHART_SIZE"
10
+ :height="PROGRESS_DONUT_CHART_SIZE"
11
+ xmlns="http://www.w3.org/2000/svg"
12
+ >
13
+ <circle
14
+ class="progressDonutChart__circle progressDonutChart__thumb"
15
+ :cx="PROGRESS_DONUT_CHART_CIRCLE_CENTER_POINT"
16
+ :cy="PROGRESS_DONUT_CHART_CIRCLE_CENTER_POINT"
17
+ :r="PROGRESS_DONUT_CHART_CIRCLE_RADIUS"
18
+ />
19
+ <circle
20
+ v-if="state === PROGRESS_DONUT_CHART_STATES.LOADING"
21
+ class="progressDonutChart__circle progressDonutChart__loader"
22
+ :cx="PROGRESS_DONUT_CHART_CIRCLE_CENTER_POINT"
23
+ :cy="PROGRESS_DONUT_CHART_CIRCLE_CENTER_POINT"
24
+ :r="PROGRESS_DONUT_CHART_CIRCLE_RADIUS"
25
+ />
26
+ <template v-else>
27
+ <circle
28
+ v-for="(range, index) in calculatedRanges"
29
+ :key="`circle_${index}`"
30
+ class="progressDonutChart__circle progressDonutChart__track"
31
+ :cx="PROGRESS_DONUT_CHART_CIRCLE_CENTER_POINT"
32
+ :cy="PROGRESS_DONUT_CHART_CIRCLE_CENTER_POINT"
33
+ :r="PROGRESS_DONUT_CHART_CIRCLE_RADIUS"
34
+ :style="`--length: ${range.length}; transform: rotate(${range.rotate}deg);`"
35
+ :class="[`-${range.color}`]"
36
+ />
37
+ </template>
38
+ </svg>
39
+ <div class="progressDonutChart__label">
40
+ <div
41
+ v-if="state === PROGRESS_DONUT_CHART_STATES.LOADING"
42
+ class="progressDonutChart__loaderText"
43
+ />
44
+ <ds-icon
45
+ v-else-if="state === PROGRESS_DONUT_CHART_STATES.DONE"
46
+ class="progressDonutChart__icon"
47
+ :icon="ICONS.FA_CHECK_SOLID"
48
+ :size="ICON_SIZES.X_SMALL"
49
+ />
50
+ <div
51
+ v-else-if="label"
52
+ class="progressDonutChart__labelText"
53
+ :class="{ '-hasOverage': state === PROGRESS_DONUT_CHART_STATES.OVERAGE }"
54
+ >
55
+ {{ labelText }}
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </template>
60
+
61
+ <style scoped lang="scss">
62
+ @import '../../../styles/settings/animations';
63
+ @import '../../../styles/settings/colors/tokens';
64
+ @import '../../../styles/settings/spacings';
65
+ @import '../../../styles/settings/typography/tokens';
66
+
67
+ $progress-donut-chart-size: 40px;
68
+ $progress-donut-chart-circle-stroke-width: 4;
69
+ $pi: 3.1416;
70
+ $progress-donut-chart-circle-radius: 18; // (width / 2) - (stroke-width / 2)
71
+ $circle-circumference: 2 * $pi * $progress-donut-chart-circle-radius;
72
+ $progress-donut-chart-loading-dot-size: 2px;
73
+
74
+ $progress-donut-chart-range-colors: (
75
+ 'primaryMedium': $color-primary-data-medium,
76
+ 'primary': $color-primary-data,
77
+ 'primaryWeak': $color-primary-data-weak,
78
+ 'primaryGhost': $color-primary-data-ghost,
79
+ 'neutralMedium': $color-neutral-data-medium,
80
+ 'neutral': $color-neutral-data,
81
+ 'neutralWeak': $color-neutral-data-weak,
82
+ 'neutralGhost': $color-neutral-data-ghost,
83
+ 'infoMedium': $color-info-data-medium,
84
+ 'info': $color-info-data,
85
+ 'infoWeak': $color-info-data-weak,
86
+ 'infoGhost': $color-info-data-ghost,
87
+ 'successMedium': $color-success-data-medium,
88
+ 'success': $color-success-data,
89
+ 'successWeak': $color-success-data-weak,
90
+ 'successGhost': $color-success-data-ghost,
91
+ 'warningMedium': $color-warning-data-medium,
92
+ 'warning': $color-warning-data,
93
+ 'warningWeak': $color-warning-data-weak,
94
+ 'warningGhost': $color-warning-data-ghost,
95
+ 'failMedium': $color-fail-data-medium,
96
+ 'fail': $color-fail-data,
97
+ 'failWeak': $color-fail-data-weak,
98
+ 'failGhost': $color-fail-data-ghost,
99
+ );
100
+
101
+ @keyframes dot-flashing {
102
+ 0% {
103
+ background-color: $color-neutral-text;
104
+ }
105
+
106
+ 50%,
107
+ 100% {
108
+ background-color: transparent;
109
+ }
110
+ }
111
+
112
+ .progressDonutChart {
113
+ box-sizing: border-box;
114
+ height: $progress-donut-chart-size;
115
+ margin: 0;
116
+ padding: 0;
117
+ position: relative;
118
+ width: $progress-donut-chart-size;
119
+
120
+ &__svg {
121
+ height: $progress-donut-chart-size;
122
+ width: $progress-donut-chart-size;
123
+ }
124
+
125
+ &__circle {
126
+ fill: none;
127
+ stroke-width: $progress-donut-chart-circle-stroke-width;
128
+ transform: rotate(90deg);
129
+ transform-origin: 50% 50%;
130
+ // Disabled for v3.0
131
+ //stroke-linecap: round;
132
+ //stroke-linejoin: round;
133
+ transition: all $default-transition-time ease-out;
134
+ }
135
+
136
+ &__thumb {
137
+ stroke: $color-neutral-data-ghost;
138
+ }
139
+
140
+ &__track {
141
+ @each $class, $color-name in $progress-donut-chart-range-colors {
142
+ &.-#{$class} {
143
+ stroke: $color-name;
144
+ }
145
+ }
146
+
147
+ stroke-dasharray: $circle-circumference;
148
+ stroke-dashoffset: calc(
149
+ #{$circle-circumference} - (#{$circle-circumference} * (var(--length, 0) / 100))
150
+ );
151
+ }
152
+
153
+ &__loader {
154
+ animation: a-spinAround 2s infinite linear;
155
+ stroke: $color-neutral-background-strong;
156
+ stroke-dasharray: $circle-circumference;
157
+ stroke-dashoffset: #{$circle-circumference - ($circle-circumference * (25 / 100))};
158
+ transform: rotate(0deg);
159
+ }
160
+
161
+ &__label {
162
+ @include info-m-default-bold;
163
+
164
+ align-items: center;
165
+ color: $color-neutral-text;
166
+ display: flex;
167
+ height: 100%;
168
+ justify-content: center;
169
+ left: 0;
170
+ position: absolute;
171
+ top: 0;
172
+ width: 100%;
173
+ }
174
+
175
+ &__icon {
176
+ color: $color-success-icon;
177
+ }
178
+
179
+ &__labelText {
180
+ max-width: 80%;
181
+ overflow: hidden;
182
+
183
+ &.-hasOverage {
184
+ color: $color-success-text;
185
+ margin-left: -$space-xxxxxs;
186
+ }
187
+ }
188
+
189
+ &__loaderText {
190
+ animation: dot-flashing #{2 * $default-transition-time} infinite linear alternate;
191
+ animation-delay: $default-transition-time;
192
+ background-color: $color-neutral-text;
193
+ border-radius: 100%;
194
+ color: $color-neutral-text;
195
+ height: $progress-donut-chart-loading-dot-size;
196
+ margin-top: $space-xxxs;
197
+ position: relative;
198
+ width: $progress-donut-chart-loading-dot-size;
199
+
200
+ &::before,
201
+ &::after {
202
+ animation: dot-flashing #{2 * $default-transition-time} infinite alternate;
203
+ background-color: $color-neutral-text;
204
+ border-radius: 100%;
205
+ color: $color-neutral-text;
206
+ content: '';
207
+ display: inline-block;
208
+ height: $progress-donut-chart-loading-dot-size;
209
+ position: absolute;
210
+ top: 0;
211
+ width: $progress-donut-chart-loading-dot-size;
212
+ }
213
+
214
+ &::before {
215
+ animation-delay: 0s;
216
+ left: -($progress-donut-chart-loading-dot-size * 2);
217
+ }
218
+
219
+ &::after {
220
+ animation-delay: 2 * $default-transition-time;
221
+ left: $progress-donut-chart-loading-dot-size * 2;
222
+ }
223
+ }
224
+ }
225
+ </style>
226
+
227
+ <script lang="ts">
228
+ import {
229
+ PROGRESS_DONUT_CHART_STATES,
230
+ ProgressDonutChartRange,
231
+ ProgressDonutChartState,
232
+ } from './ProgressDonutChart.consts';
233
+ import { PropType } from 'vue';
234
+ import DsIcon, { ICON_SIZES, ICONS } from '../Icons/Icon';
235
+
236
+ const OFFSET_IN_DEGREES_OF_TRACK_START_POINT = 90; // 90 is to set starting point at the bottom
237
+ const PROGRESS_DONUT_CHART_SIZE = 40; // keep consider with $progress-donut-chart-size
238
+ const PROGRESS_DONUT_CHART_STROKE_WIDTH = 4; // keep consider with $progress-donut-chart-circle-stroke-width
239
+ const PROGRESS_DONUT_CHART_CIRCLE_CENTER_POINT = PROGRESS_DONUT_CHART_SIZE / 2;
240
+ const PROGRESS_DONUT_CHART_CIRCLE_RADIUS =
241
+ PROGRESS_DONUT_CHART_SIZE / 2 - PROGRESS_DONUT_CHART_STROKE_WIDTH / 2;
242
+ export default {
243
+ name: 'ProgressDonutChart',
244
+ components: {
245
+ DsIcon,
246
+ },
247
+ props: {
248
+ label: { type: String, default: '' },
249
+ state: {
250
+ type: String as PropType<ProgressDonutChartState>,
251
+ default: PROGRESS_DONUT_CHART_STATES.DEFAULT,
252
+ validator(state) {
253
+ return Object.values(PROGRESS_DONUT_CHART_STATES).includes(state);
254
+ },
255
+ },
256
+ ranges: {
257
+ type: Array as PropType<Array<ProgressDonutChartRange>>,
258
+ required: true,
259
+ validator(ranges) {
260
+ return ranges.every(
261
+ (range: ProgressDonutChartRange) =>
262
+ range.start >= 0 && range.length >= 0 && range.start + range.length <= 100,
263
+ );
264
+ },
265
+ },
266
+ },
267
+ data() {
268
+ return {
269
+ PROGRESS_DONUT_CHART_STATES: Object.freeze(PROGRESS_DONUT_CHART_STATES),
270
+ ICONS: Object.freeze(ICONS),
271
+ ICON_SIZES: Object.freeze(ICON_SIZES),
272
+ PROGRESS_DONUT_CHART_SIZE,
273
+ PROGRESS_DONUT_CHART_CIRCLE_CENTER_POINT,
274
+ PROGRESS_DONUT_CHART_CIRCLE_RADIUS,
275
+ };
276
+ },
277
+ computed: {
278
+ labelText() {
279
+ return [this.state === PROGRESS_DONUT_CHART_STATES.OVERAGE && '+', this.label]
280
+ .filter(Boolean)
281
+ .join('');
282
+ },
283
+ calculatedRanges() {
284
+ return this.ranges.map((range) => {
285
+ return {
286
+ ...range,
287
+ rotate: (range.start / 100) * 360 + OFFSET_IN_DEGREES_OF_TRACK_START_POINT,
288
+ };
289
+ });
290
+ },
291
+ },
292
+ };
293
+ </script>
@@ -0,0 +1,4 @@
1
+ import ProgressDonutChart from './ProgressDonutChart.vue';
2
+
3
+ export default ProgressDonutChart;
4
+ export * from './ProgressDonutChart.consts';
@@ -86,8 +86,8 @@ $icons-and-slot-min-height-l: 50px;
86
86
 
87
87
  &__slot,
88
88
  &__iconWrapper {
89
- display: flex;
90
89
  align-items: center;
90
+ display: flex;
91
91
  }
92
92
 
93
93
  &__iconWrapper {
@@ -53,10 +53,10 @@
53
53
  .surveyQuestionOpenEnded {
54
54
  &__header {
55
55
  display: flex;
56
+ justify-content: space-between;
57
+ margin-bottom: $space-s;
56
58
  // header without explanation iconButton has to be the same size as with iconButton
57
59
  min-height: $icon-button-medium-size;
58
- margin-bottom: $space-s;
59
- justify-content: space-between;
60
60
  }
61
61
 
62
62
  &__title {
@@ -90,10 +90,10 @@
90
90
  @include heading-m-default-regular;
91
91
 
92
92
  display: flex;
93
+ justify-content: space-between;
94
+ margin-bottom: $space-m;
93
95
  // title without explanation iconButton has to be the same size as with iconButton
94
96
  min-height: $icon-button-medium-size;
95
- margin-bottom: $space-m;
96
- justify-content: space-between;
97
97
  }
98
98
 
99
99
  &__title {
@@ -110,8 +110,8 @@
110
110
  border-radius: $radius-s;
111
111
  display: flex;
112
112
  justify-content: space-between;
113
- padding: $space-s $space-xxs;
114
113
  overflow-x: auto;
114
+ padding: $space-s $space-xxs;
115
115
 
116
116
  @media #{breakpoint-s()} {
117
117
  padding: $space-s $space-l;
@@ -132,8 +132,8 @@
132
132
  display: none;
133
133
 
134
134
  @media #{breakpoint-s()} {
135
- width: $space-l;
136
135
  display: block;
136
+ width: $space-l;
137
137
  }
138
138
  }
139
139