@bethinkpl/design-system 18.5.0 → 18.7.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.
Files changed (47) hide show
  1. package/dist/design-system.umd.js +240 -90
  2. package/dist/design-system.umd.js.map +1 -1
  3. package/dist/lib/js/components/Banner/Banner.vue.d.ts +1 -0
  4. package/dist/lib/js/components/Buttons/Button/Button.vue.d.ts +1 -0
  5. package/dist/lib/js/components/Buttons/IconButton/IconButton.vue.d.ts +1 -0
  6. package/dist/lib/js/components/Cards/CardExpandable/CardExpandable.vue.d.ts +1 -0
  7. package/dist/lib/js/components/Drawer/DrawerSection/DrawerSection.vue.d.ts +1 -0
  8. package/dist/lib/js/components/Dropdown/Dropdown.vue.d.ts +8 -0
  9. package/dist/lib/js/components/Form/Checkbox/Checkbox.vue.d.ts +1 -0
  10. package/dist/lib/js/components/Form/RadioButton/RadioButton.vue.d.ts +1 -0
  11. package/dist/lib/js/components/Headers/OverlayHeader/OverlayHeader.vue.d.ts +1 -0
  12. package/dist/lib/js/components/Headers/SectionHeader/SectionHeader.vue.d.ts +1 -0
  13. package/dist/lib/js/components/Icons/Icon/Icon.consts.d.ts +1 -0
  14. package/dist/lib/js/components/Modal/Modal.vue.d.ts +1 -0
  15. package/dist/lib/js/components/Modals/Modal/Modal.vue.d.ts +1 -0
  16. package/dist/lib/js/components/Outline/OutlineItem/OutlineItem.vue.d.ts +1 -0
  17. package/dist/lib/js/components/Pagination/Pagination.vue.d.ts +16 -0
  18. package/dist/lib/js/components/Pill/Pill.vue.d.ts +1 -0
  19. package/dist/lib/js/components/ProgressBar/ProgressBar.vue.d.ts +1 -0
  20. package/dist/lib/js/components/ProgressDonutChart/ProgressDonutChart.vue.d.ts +1 -0
  21. package/dist/lib/js/components/SelectList/SelectListItemToggle/SelectListItemToggle.vue.d.ts +58 -3
  22. package/dist/lib/js/components/SelectionTile/SelectionTile.vue.d.ts +1 -0
  23. package/dist/lib/js/components/Statuses/AccessStatus/AccessStatus.vue.d.ts +1 -0
  24. package/dist/lib/js/components/Statuses/BlockadeStatus/BlockadeStatus.vue.d.ts +1 -0
  25. package/dist/lib/js/components/SurveyQuestions/SurveyQuestionOpenEnded/SurveyQuestionOpenEnded.vue.d.ts +1 -0
  26. package/dist/lib/js/components/SurveyQuestions/SurveyQuestionScale/SurveyQuestionScale.vue.d.ts +1 -0
  27. package/dist/lib/js/components/Tile/Tile.consts.d.ts +2 -0
  28. package/dist/lib/js/components/Tile/Tile.sb.shared.d.ts +1 -0
  29. package/dist/lib/js/components/Tile/Tile.vue.d.ts +1 -0
  30. package/dist/lib/js/components/Toggles/ToggleButton/ToggleButton.vue.d.ts +1 -0
  31. package/docs/iframe.html +1 -1
  32. package/docs/main.c992e5f2.iframe.bundle.js +1 -0
  33. package/docs/project.json +1 -1
  34. package/jest.config.js +1 -0
  35. package/lib/images/icons/comments-check.svg +1 -0
  36. package/lib/js/components/Dropdown/Dropdown.stories.ts +22 -12
  37. package/lib/js/components/Dropdown/Dropdown.vue +36 -4
  38. package/lib/js/components/Icons/Icon/Icon.consts.ts +2 -0
  39. package/lib/js/components/Pagination/Pagination.spec.ts +115 -0
  40. package/lib/js/components/Pagination/Pagination.vue +71 -17
  41. package/lib/js/components/SelectList/SelectListItem/SelectListItem.stories.ts +6 -2
  42. package/lib/js/components/SelectList/SelectListItem/SelectListItem.vue +44 -3
  43. package/lib/js/components/Tile/Tile.consts.ts +2 -0
  44. package/lib/js/components/Tile/Tile.vue +34 -0
  45. package/package.json +2 -2
  46. package/.yarnrc.yml +0 -1
  47. package/docs/main.4908f297.iframe.bundle.js +0 -1
package/docs/project.json CHANGED
@@ -1 +1 @@
1
- {"generatedAt":1694009089312,"builder":{"name":"webpack5"},"hasCustomBabel":false,"hasCustomWebpack":true,"hasStaticDirs":false,"hasStorybookEslint":true,"refCount":0,"metaFramework":{"name":"vue-cli","packageName":"@vue/cli-service","version":"5.0.4"},"packageManager":{"type":"yarn","version":"1.22.19"},"storybookVersion":"6.5.13","language":"typescript","storybookPackages":{"@storybook/builder-webpack5":{"version":"6.5.13"},"@storybook/manager-webpack5":{"version":"6.5.13"},"@storybook/vue3":{"version":"6.5.13"},"eslint-plugin-storybook":{"version":"0.6.6"}},"framework":{"name":"vue3"},"addons":{"@storybook/addon-actions":{"version":"6.5.16"},"@storybook/addon-docs":{"version":"6.5.15"},"@storybook/addon-controls":{"version":"6.5.15"},"@storybook/addon-storysource":{"version":"6.5.15"},"@storybook/addon-viewport":{"version":"6.5.15"},"storybook-addon-designs":{"version":"6.3.1"}}}
1
+ {"generatedAt":1695643463435,"builder":{"name":"webpack5"},"hasCustomBabel":false,"hasCustomWebpack":true,"hasStaticDirs":false,"hasStorybookEslint":true,"refCount":0,"metaFramework":{"name":"vue-cli","packageName":"@vue/cli-service","version":"5.0.4"},"packageManager":{"type":"yarn","version":"1.22.19"},"storybookVersion":"6.5.13","language":"typescript","storybookPackages":{"@storybook/builder-webpack5":{"version":"6.5.13"},"@storybook/manager-webpack5":{"version":"6.5.13"},"@storybook/vue3":{"version":"6.5.13"},"eslint-plugin-storybook":{"version":"0.6.6"}},"framework":{"name":"vue3"},"addons":{"@storybook/addon-actions":{"version":"6.5.16"},"@storybook/addon-docs":{"version":"6.5.15"},"@storybook/addon-controls":{"version":"6.5.15"},"@storybook/addon-storysource":{"version":"6.5.15"},"@storybook/addon-viewport":{"version":"6.5.15"},"storybook-addon-designs":{"version":"6.3.1"}}}
package/jest.config.js CHANGED
@@ -6,6 +6,7 @@ module.exports = {
6
6
  '^design-system/lib/(.*)$': '<rootDir>/lib/$1',
7
7
  '^design-system/styles/(.*)$': '<rootDir>/lib/styles/$1',
8
8
  '^design-system/images/(.*)$': '<rootDir>/lib/images/$1',
9
+ '^vue-popperjs/dist/vue-popper.css': '<rootDir>/lib/js/tests/emptyModule.ts',
9
10
  },
10
11
  testMatch: ['<rootDir>/lib/js/**/*.spec.ts', '<rootDir>/tools/importers/*.spec.ts'],
11
12
  transform: {
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 64 64"><g fill="currentColor" clip-path="url(#a)"><path d="M20.823 6c11.394 0 20.789 8.023 20.789 17.875 0 9.953-9.395 17.875-20.79 17.875-1.898 0-3.697-.203-5.496-.61C12.327 43.07 7.93 45 2.433 45c-1 0-1.9-.508-2.2-1.523-.399-.914-.299-1.93.4-2.743.1 0 2.3-2.437 3.899-5.687C1.733 32 .034 28.14.034 23.875.034 14.023 9.329 6 20.823 6Zm-4.398 30.367c1.5.406 2.899.508 4.398.508 8.795 0 15.991-5.79 15.991-13 0-7.11-7.196-13-15.991-13-8.895 0-15.992 5.89-15.992 13 0 3.656 1.7 6.297 3.199 7.82l2.398 2.54-1.599 3.148c-.4.61-.8 1.32-1.2 2.031 1.8-.508 3.5-1.32 5.198-2.437l1.7-1.016 1.898.406Zm27.686-17.265C55.205 19.508 64 27.328 64 36.875c0 4.266-1.799 8.125-4.598 11.172 1.6 3.25 3.798 5.687 3.898 5.687.7.813.8 1.828.4 2.743C63.4 57.492 62.5 58 61.501 58c-5.497 0-9.894-1.93-12.893-3.86-1.799.407-3.598.61-5.397.61-8.196 0-15.292-4.063-18.69-9.953 1.699-.203 3.398-.61 4.897-1.219 2.799 3.86 7.896 6.297 13.793 6.297 1.4 0 2.799-.102 4.298-.508l1.899-.406 1.699 1.016c1.699 1.117 3.398 1.93 5.197 2.437-.4-.71-.8-1.422-1.2-2.031l-1.598-3.149 2.398-2.539c1.5-1.523 3.298-4.164 3.298-7.82 0-6.703-6.396-12.188-14.492-12.898l.1-.102c0-1.625-.3-3.25-.7-4.773Z"/><path d="M19.746 29.73c-.6.61-1.699.61-2.298 0l-3.998-4.062c-.6-.61-.6-1.727 0-2.336.6-.61 1.699-.61 2.299 0l2.898 2.945 7.596-7.82c.6-.61 1.7-.61 2.299 0 .6.61.6 1.727 0 2.336l-8.796 8.938Z"/></g><defs><clipPath id="a"><path fill="currentColor" d="M0 0h64v64H0z"/></clipPath></defs></svg>
@@ -20,18 +20,23 @@ const StoryTemplate: StoryFn<typeof Dropdown> = (args) => ({
20
20
  return { ...args };
21
21
  },
22
22
  template: `
23
- <div style="position: relative">
24
- <dropdown :trigger-action="triggerAction" :force-show="forceShow" :same-width="sameWidth" :radius="radius"
25
- :placement="placement">
26
- <template #reference><span>Dropdown entry point</span></template>
27
- <template #default="{ close }">
28
- <select-list>
29
- <select-list-item label="One" @click.native="close" />
30
- <select-list-item label="Two" @click.native="close" />
31
- </select-list>
32
- </template>
33
- </dropdown>
34
- </div>`,
23
+ <div style="position: relative">
24
+ <dropdown :trigger-action="triggerAction"
25
+ :force-show="forceShow"
26
+ :same-width="sameWidth"
27
+ :radius="radius"
28
+ :placement="placement"
29
+ :max-height="maxHeight">
30
+ <template #reference="{ isOpened }"><span>Dropdown entry point {{ isOpened ? 'opened' : 'closed' }}</span>
31
+ </template>
32
+ <template #default="{ close }">
33
+ <select-list>
34
+ <select-list-item label="One" @click.native="close" />
35
+ <select-list-item label="Two" @click.native="close" />
36
+ </select-list>
37
+ </template>
38
+ </dropdown>
39
+ </div>`,
35
40
  });
36
41
 
37
42
  export const Interactive = StoryTemplate.bind({});
@@ -41,6 +46,7 @@ const args = {
41
46
  radius: DROPDOWN_RADIUSES.BOTH,
42
47
  forceShow: false,
43
48
  sameWidth: false,
49
+ maxHeight: '',
44
50
  } as Args;
45
51
 
46
52
  const argTypes = {
@@ -56,6 +62,10 @@ const argTypes = {
56
62
  control: { type: 'select', options: Object.values(DROPDOWN_PLACEMENTS) },
57
63
  defaultValue: DROPDOWN_PLACEMENTS.BOTTOM_START,
58
64
  },
65
+ maxHeight: {
66
+ control: { type: 'text' },
67
+ defaultValue: '',
68
+ },
59
69
  } as ArgTypes;
60
70
 
61
71
  Interactive.argTypes = argTypes;
@@ -9,8 +9,8 @@
9
9
  :trigger="triggerAction"
10
10
  :delay-on-mouse-out="300"
11
11
  @document-click="$emit('document-click')"
12
- @hide="$emit('hide')"
13
- @show="$emit('show')"
12
+ @hide="onHide"
13
+ @show="onShow"
14
14
  >
15
15
  <div
16
16
  class="popper dsDropdown"
@@ -20,11 +20,17 @@
20
20
  '-radiusBottom -radiusTop': radius === DROPDOWN_RADIUSES.BOTH,
21
21
  }"
22
22
  >
23
- <slot :close="close" />
23
+ <div
24
+ class="dsDropdown__scrollableWrapper"
25
+ :class="{ '-heightLimited': !!maxHeight }"
26
+ :style="scrollableWrapperStyles"
27
+ >
28
+ <slot :close="close" />
29
+ </div>
24
30
  </div>
25
31
 
26
32
  <template #reference>
27
- <slot name="reference" />
33
+ <slot name="reference" :is-opened="isOpened" />
28
34
  </template>
29
35
  </vue-popper>
30
36
  </template>
@@ -42,6 +48,7 @@
42
48
  box-shadow: $shadow-m;
43
49
  max-width: 100%;
44
50
  min-width: 128px;
51
+ overflow: hidden;
45
52
  padding: 0;
46
53
  text-align: left;
47
54
 
@@ -62,6 +69,12 @@
62
69
  &[x-placement^='top'] {
63
70
  margin-bottom: $space-xxxxs;
64
71
  }
72
+
73
+ &__scrollableWrapper {
74
+ &.-heightLimited {
75
+ overflow-y: auto;
76
+ }
77
+ }
65
78
  }
66
79
  </style>
67
80
 
@@ -113,15 +126,25 @@ export default {
113
126
  return Object.values(DROPDOWN_PLACEMENTS).includes(placement);
114
127
  },
115
128
  },
129
+ maxHeight: {
130
+ type: String,
131
+ default: null,
132
+ },
116
133
  },
117
134
  emits: ['document-click', 'hide', 'show'],
118
135
  data() {
119
136
  return {
120
137
  key: 1,
138
+ isOpened: false,
121
139
  DROPDOWN_RADIUSES: Object.freeze(DROPDOWN_RADIUSES),
122
140
  };
123
141
  },
124
142
  computed: {
143
+ scrollableWrapperStyles() {
144
+ return {
145
+ ...(this.maxHeight && { maxHeight: this.maxHeight }),
146
+ };
147
+ },
125
148
  options() {
126
149
  return {
127
150
  modifiers: { preventOverflow: { padding: 0 } },
@@ -153,6 +176,7 @@ export default {
153
176
  },
154
177
  methods: {
155
178
  close() {
179
+ this.isOpened = false;
156
180
  this.$refs.popper.doClose();
157
181
  },
158
182
  updateKey() {
@@ -160,6 +184,14 @@ export default {
160
184
  // vue-popperjs doesn't support changing props in existing component
161
185
  this.key++;
162
186
  },
187
+ onHide() {
188
+ this.isOpened = false;
189
+ this.$emit('hide');
190
+ },
191
+ onShow() {
192
+ this.isOpened = true;
193
+ this.$emit('show');
194
+ },
163
195
  },
164
196
  };
165
197
  </script>
@@ -1,6 +1,7 @@
1
1
  import HeadWithQuestionMark from '../../../../images/icons/head-with-question-mark.svg';
2
2
  import Ribbon from '../../../../images/icons/ribbon.svg';
3
3
  import SlidersSearch from '../../../../images/icons/sliders-search.svg';
4
+ import CommentsCheck from '../../../../images/icons/comments-check.svg';
4
5
  import { FONTAWESOME_ICONS } from '../../../icons/fontawesome';
5
6
  import { Value } from '../../../utils/type.utils';
6
7
 
@@ -21,6 +22,7 @@ const BETHINK_ICONS = {
21
22
  HEAD_WITH_QUESTION_MARK: HeadWithQuestionMark,
22
23
  RIBBON: Ribbon,
23
24
  SLIDERS_SEARCH: SlidersSearch,
25
+ COMMENTS_CHECK: CommentsCheck,
24
26
  } as const;
25
27
 
26
28
  export const ICONS = {
@@ -9,6 +9,19 @@ describe('Pagination', () => {
9
9
  currentPage,
10
10
  itemsTotalAmount,
11
11
  } as any,
12
+ global: {
13
+ stubs: {
14
+ Dropdown: {
15
+ template: '<div class="dropdown"><slot name="reference" /><slot/></div>',
16
+ },
17
+ SelectList: {
18
+ template: '<div class="select-list"><slot/></div>',
19
+ },
20
+ SelectListItem: {
21
+ template: '<div class="select-list-item"><slot/></div>',
22
+ },
23
+ },
24
+ },
12
25
  });
13
26
  };
14
27
 
@@ -98,10 +111,112 @@ describe('Pagination', () => {
98
111
  },
99
112
  ])('should calculate correct pagination for %o', ({ props, expected }) => {
100
113
  const component = createComponent(props);
114
+
101
115
  const elements: Array<string> = [];
102
116
  component.findAll('.ds-pagination__itemWrapper').forEach((element) => {
103
117
  elements.push(element.text().trim());
104
118
  });
105
119
  expect(elements).toEqual(expected);
106
120
  });
121
+
122
+ test.each([
123
+ {
124
+ props: {
125
+ currentPage: 3,
126
+ itemsTotalAmount: 300,
127
+ },
128
+ expected: {
129
+ dropdowns: 1,
130
+ dropdownItemsCount: 10,
131
+ dropdownItems: [
132
+ { label: '1 (1 - 30)', isSelected: 'false' },
133
+ { label: '2 (31 - 60)', isSelected: 'false' },
134
+ { label: '3 (61 - 90)', isSelected: 'true' },
135
+ { label: '4 (91 - 120)', isSelected: 'false' },
136
+ { label: '5 (121 - 150)', isSelected: 'false' },
137
+ { label: '6 (151 - 180)', isSelected: 'false' },
138
+ { label: '7 (181 - 210)', isSelected: 'false' },
139
+ { label: '8 (211 - 240)', isSelected: 'false' },
140
+ { label: '9 (241 - 270)', isSelected: 'false' },
141
+ { label: '10 (271 - 300)', isSelected: 'false' },
142
+ ],
143
+ },
144
+ },
145
+ {
146
+ props: {
147
+ currentPage: 3,
148
+ itemsTotalAmount: 221,
149
+ },
150
+ expected: {
151
+ dropdowns: 1,
152
+ dropdownItemsCount: 8,
153
+ dropdownItems: [
154
+ { label: '1 (1 - 30)', isSelected: 'false' },
155
+ { label: '2 (31 - 60)', isSelected: 'false' },
156
+ { label: '3 (61 - 90)', isSelected: 'true' },
157
+ { label: '4 (91 - 120)', isSelected: 'false' },
158
+ { label: '5 (121 - 150)', isSelected: 'false' },
159
+ { label: '6 (151 - 180)', isSelected: 'false' },
160
+ { label: '7 (181 - 210)', isSelected: 'false' },
161
+ { label: '8 (211 - 221)', isSelected: 'false' },
162
+ ],
163
+ },
164
+ },
165
+ {
166
+ props: {
167
+ currentPage: 6,
168
+ itemsTotalAmount: 311,
169
+ },
170
+ expected: {
171
+ dropdowns: 2,
172
+ dropdownItemsCount: 11,
173
+ dropdownItems: [
174
+ { label: '1 (1 - 30)', isSelected: 'false' },
175
+ { label: '2 (31 - 60)', isSelected: 'false' },
176
+ { label: '3 (61 - 90)', isSelected: 'false' },
177
+ { label: '4 (91 - 120)', isSelected: 'false' },
178
+ { label: '5 (121 - 150)', isSelected: 'false' },
179
+ { label: '6 (151 - 180)', isSelected: 'true' },
180
+ { label: '7 (181 - 210)', isSelected: 'false' },
181
+ { label: '8 (211 - 240)', isSelected: 'false' },
182
+ { label: '9 (241 - 270)', isSelected: 'false' },
183
+ { label: '10 (271 - 300)', isSelected: 'false' },
184
+ { label: '11 (301 - 311)', isSelected: 'false' },
185
+ ],
186
+ },
187
+ },
188
+ ])('should render dropdown for %o', ({ props, expected }) => {
189
+ const component = createComponent(props);
190
+
191
+ expect(component.findAll('.dropdown').length).toBe(expected.dropdowns);
192
+
193
+ const dropdown = component.find('.dropdown');
194
+ expect(dropdown.findAll('.select-list-item').length).toBe(expected.dropdownItemsCount);
195
+
196
+ dropdown.findAll('.select-list-item').forEach((item, index) => {
197
+ expect(item.attributes('label')).toBe(expected.dropdownItems[index].label);
198
+ expect(item.attributes('is-selected')).toBe(expected.dropdownItems[index].isSelected);
199
+ });
200
+ });
201
+
202
+ it('should update selected item after page change', async () => {
203
+ let currentPage = 3;
204
+ const component = createComponent({
205
+ currentPage,
206
+ itemsTotalAmount: 300,
207
+ });
208
+
209
+ const dropdown = component.find('.dropdown');
210
+ expect(
211
+ dropdown.findAll('.select-list-item')[currentPage - 1].attributes('is-selected'),
212
+ ).toBe('true');
213
+
214
+ await component.setProps({ currentPage: 1 });
215
+
216
+ expect(component.findAll('.select-list-item')[0].attributes('is-selected')).toBe('true');
217
+
218
+ expect(
219
+ component.findAll('.select-list-item')[currentPage - 1].attributes('is-selected'),
220
+ ).toBe('false');
221
+ });
107
222
  });
@@ -27,8 +27,42 @@
27
27
  {{ navigationItem }}
28
28
  </span>
29
29
  </div>
30
- <div v-else :key="`ellipsis${index}`" class="ds-pagination__itemWrapper">
31
- <span class="ds-pagination__ellipsis">&hellip;</span>
30
+ <div v-else :key="`ellipsis${index}`">
31
+ <dropdown
32
+ :radius="DROPDOWN_RADIUSES.BOTTOM"
33
+ max-height="250px"
34
+ :placement="
35
+ ellipsisAsSecond(index)
36
+ ? DROPDOWN_PLACEMENTS.BOTTOM_START
37
+ : DROPDOWN_PLACEMENTS.BOTTOM_END
38
+ "
39
+ >
40
+ <template #reference="{ isOpened }">
41
+ <div class="ds-pagination__itemWrapper -touchable">
42
+ <span
43
+ class="ds-pagination__item"
44
+ :class="{ '-selected': isOpened }"
45
+ >&hellip;</span
46
+ >
47
+ </div>
48
+ </template>
49
+
50
+ <template #default="{ close }">
51
+ <select-list v-if="navigationItemsForDropdown.length">
52
+ <select-list-item
53
+ v-for="(
54
+ dropdownNavigationItem, dropdownIndex
55
+ ) in navigationItemsForDropdown"
56
+ :key="dropdownIndex"
57
+ :label="dropdownNavigationItem.label"
58
+ :is-selected="currentPage === dropdownNavigationItem.value"
59
+ @click="
60
+ onDropdownClick(dropdownNavigationItem.value, close)
61
+ "
62
+ />
63
+ </select-list>
64
+ </template>
65
+ </dropdown>
32
66
  </div>
33
67
  </template>
34
68
  </div>
@@ -164,10 +198,10 @@ $pagination-input-height: 32px;
164
198
  }
165
199
 
166
200
  &__text {
167
- @include text-m-default-regular;
201
+ @include label-l-default-regular;
168
202
 
169
203
  color: $color-neutral-text;
170
- padding: $space-xxxs;
204
+ padding: $space-xxs $space-xxxs;
171
205
  text-align: center;
172
206
  }
173
207
 
@@ -178,7 +212,7 @@ $pagination-input-height: 32px;
178
212
  }
179
213
 
180
214
  &__itemWrapper {
181
- @include text-m-default-regular;
215
+ @include label-l-default-regular;
182
216
 
183
217
  padding: $space-xxxxs;
184
218
  text-align: center;
@@ -201,10 +235,10 @@ $pagination-input-height: 32px;
201
235
  flex-direction: column;
202
236
  justify-content: center;
203
237
  min-width: $pagination-item-min-width;
204
- padding: $space-xxxs;
238
+ padding: $space-xxs;
205
239
 
206
240
  &.-selected {
207
- @include text-m-default-bold;
241
+ @include label-l-default-bold;
208
242
 
209
243
  background: $color-neutral-background-medium;
210
244
  color: $color-neutral-text-heavy;
@@ -216,15 +250,6 @@ $pagination-input-height: 32px;
216
250
  }
217
251
  }
218
252
 
219
- &__ellipsis {
220
- align-items: center;
221
- color: $color-neutral-text-weak;
222
- display: flex;
223
- flex-direction: column;
224
- justify-content: center;
225
- padding: $space-xxxs;
226
- }
227
-
228
253
  &__accessorySlot {
229
254
  align-items: center;
230
255
  display: flex;
@@ -240,13 +265,19 @@ import IconButton from '../Buttons/IconButton/IconButton.vue';
240
265
  import { ICON_BUTTON_COLORS, ICON_BUTTON_SIZES, ICON_BUTTON_STATES } from '../Buttons/IconButton';
241
266
  import { ICONS } from '../Icons/Icon';
242
267
 
268
+ import { DROPDOWN_PLACEMENTS, DROPDOWN_RADIUSES } from '../Dropdown/Dropdown.consts';
269
+ import Dropdown from '../Dropdown/Dropdown.vue';
270
+
271
+ import SelectList from '../SelectList/SelectList.vue';
272
+ import SelectListItem from '../SelectList/SelectListItem/SelectListItem.vue';
273
+
243
274
  const MAX_NAVIGATION_ITEMS = 7;
244
275
  const ELLIPSIS_FILL = 'ellipsis';
245
276
  const FIRST_PAGE_NUMBER = 1;
246
277
 
247
278
  export default {
248
279
  name: 'Pagination',
249
- components: { IconButton },
280
+ components: { IconButton, Dropdown, SelectListItem, SelectList },
250
281
  props: {
251
282
  currentPage: {
252
283
  type: Number,
@@ -278,6 +309,8 @@ export default {
278
309
  emits: ['change-page'],
279
310
  data() {
280
311
  return {
312
+ DROPDOWN_PLACEMENTS: Object.freeze(DROPDOWN_PLACEMENTS),
313
+ DROPDOWN_RADIUSES: Object.freeze(DROPDOWN_RADIUSES),
281
314
  ICON_BUTTON_SIZES: Object.freeze(ICON_BUTTON_SIZES),
282
315
  ICON_BUTTON_COLORS: Object.freeze(ICON_BUTTON_COLORS),
283
316
  ICON_BUTTON_STATES: Object.freeze(ICON_BUTTON_STATES),
@@ -333,8 +366,25 @@ export default {
333
366
 
334
367
  return navigationItems;
335
368
  },
369
+ navigationItemsForDropdown() {
370
+ return this.getRange(FIRST_PAGE_NUMBER, this.lastPage).map((pageNumber: number) => {
371
+ const startItem = (pageNumber - 1) * this.itemsPerPage;
372
+ const endItem =
373
+ pageNumber < this.lastPage
374
+ ? startItem + this.itemsPerPage
375
+ : this.itemsTotalAmount;
376
+
377
+ return {
378
+ label: `${pageNumber} (${startItem + 1} - ${endItem})`,
379
+ value: pageNumber,
380
+ };
381
+ });
382
+ },
336
383
  },
337
384
  methods: {
385
+ ellipsisAsSecond(index: number) {
386
+ return index === 1;
387
+ },
338
388
  getRange(start: number, end: number): Array<number> {
339
389
  return Array(end - start + 1)
340
390
  .fill(null)
@@ -355,6 +405,10 @@ export default {
355
405
 
356
406
  this.changePage(page);
357
407
  },
408
+ onDropdownClick(page: number, close: () => void) {
409
+ this.changePage(page);
410
+ close();
411
+ },
358
412
  },
359
413
  };
360
414
  </script>
@@ -3,9 +3,9 @@ import { ICONS } from '../../Icons/Icon';
3
3
 
4
4
  import { Args, ArgTypes, Meta, StoryFn } from '@storybook/vue3';
5
5
  import {
6
- SELECT_LIST_ITEM_STATES,
7
- SELECT_LIST_ITEM_SIZES,
8
6
  SELECT_LIST_ITEM_SELECTION_MODE,
7
+ SELECT_LIST_ITEM_SIZES,
8
+ SELECT_LIST_ITEM_STATES,
9
9
  } from './SelectListItem.consts';
10
10
 
11
11
  export default {
@@ -22,6 +22,8 @@ const StoryTemplate: StoryFn<typeof SelectListItem> = (args) => ({
22
22
  <select-list-item
23
23
  :icon-left="ICONS[iconLeft]"
24
24
  :label="label"
25
+ :eyebrow-text="eyebrowText"
26
+ :is-eyebrow-text-uppercase="isEyebrowTextUppercase"
25
27
  :is-selected="isSelected"
26
28
  :selection-mode="selectionMode"
27
29
  :size="size"
@@ -41,6 +43,8 @@ const args = {
41
43
  size: SELECT_LIST_ITEM_SIZES.SMALL,
42
44
  iconLeft: null,
43
45
  label: 'Label',
46
+ eyebrowText: 'Eyebrow Text',
47
+ isEyebrowTextUppercase: false,
44
48
  state: SELECT_LIST_ITEM_STATES.DEFAULT,
45
49
  isSelected: false,
46
50
  selectionMode: SELECT_LIST_ITEM_SELECTION_MODE.SELECT_ONLY,
@@ -18,7 +18,15 @@
18
18
  :spinning="isLoading"
19
19
  />
20
20
 
21
- <span class="selectListItem__text">{{ label }}</span>
21
+ <span class="selectListItem__textWrapper">
22
+ <span
23
+ v-if="eyebrowText"
24
+ class="selectListItem__eyebrowText"
25
+ :class="{ '-uppercase': isEyebrowTextUppercase }"
26
+ >{{ eyebrowText }}</span
27
+ >
28
+ <span class="selectListItem__text">{{ label }}</span>
29
+ </span>
22
30
 
23
31
  <ds-icon
24
32
  v-if="isSelected"
@@ -38,6 +46,7 @@
38
46
 
39
47
  .selectListItem {
40
48
  $self: &;
49
+ $minHeight: 40px;
41
50
 
42
51
  @include label-l-default-regular;
43
52
 
@@ -45,6 +54,7 @@
45
54
  color: $color-neutral-text-heavy;
46
55
  cursor: pointer;
47
56
  display: flex;
57
+ min-height: $minHeight;
48
58
  padding: $space-xs;
49
59
 
50
60
  &:focus {
@@ -104,13 +114,32 @@
104
114
  width: $icon-xs;
105
115
  }
106
116
 
107
- &__text {
117
+ &__textWrapper {
118
+ display: flex;
119
+ flex-direction: column;
108
120
  flex-grow: 1;
121
+ gap: $space-xxxxxs;
109
122
  overflow: hidden;
110
- text-overflow: ellipsis;
111
123
  white-space: nowrap;
112
124
  }
113
125
 
126
+ &__text {
127
+ overflow: hidden;
128
+ text-overflow: ellipsis;
129
+ }
130
+
131
+ &__eyebrowText {
132
+ @include info-s-default-bold;
133
+
134
+ color: $color-neutral-text-weak;
135
+ overflow: hidden;
136
+ text-overflow: ellipsis;
137
+
138
+ &.-uppercase {
139
+ @include info-s-extensive-bold-uppercase;
140
+ }
141
+ }
142
+
114
143
  &.-disabled {
115
144
  #{$self}__iconLeft {
116
145
  color: $color-neutral-icon-disabled;
@@ -123,6 +152,10 @@
123
152
  #{$self}__text {
124
153
  color: $color-neutral-text-heavy-disabled;
125
154
  }
155
+
156
+ #{$self}__eyebrowText {
157
+ color: $color-neutral-text-weak-disabled;
158
+ }
126
159
  }
127
160
  }
128
161
  </style>
@@ -157,6 +190,14 @@ export default {
157
190
  type: String,
158
191
  required: true,
159
192
  },
193
+ eyebrowText: {
194
+ type: String,
195
+ default: '',
196
+ },
197
+ isEyebrowTextUppercase: {
198
+ type: Boolean,
199
+ default: false,
200
+ },
160
201
  selectionMode: {
161
202
  type: String,
162
203
  default: SELECT_LIST_ITEM_SELECTION_MODE.SELECT_ONLY,
@@ -1,8 +1,10 @@
1
1
  export const TILE_COLORS = {
2
2
  NEUTRAL: 'neutral',
3
+ NEUTRAL_WEAK: 'neutralWeak',
3
4
  PRIMARY: 'primary',
4
5
  SUCCESS: 'success',
5
6
  FAIL: 'fail',
7
+ WARNING: 'warning',
6
8
  INFO: 'info',
7
9
  } as const;
8
10
 
@@ -35,6 +35,7 @@
35
35
  </template>
36
36
 
37
37
  <style lang="scss" scoped>
38
+ @import '../../../styles/settings/animations';
38
39
  @import '../../../styles/settings/spacings';
39
40
  @import '../../../styles/settings/radiuses';
40
41
  @import '../../../styles/settings/colors/tokens';
@@ -56,6 +57,21 @@ $tile-colors: (
56
57
  'icon-interactive': $color-primary-icon-disabled,
57
58
  ),
58
59
  ),
60
+ 'neutralWeak': (
61
+ 'default': (
62
+ 'background': $color-neutral-background-weak,
63
+ 'background-hover': $color-neutral-background-weak-hovered,
64
+ 'eyebrow-text': $color-neutral-text-weak,
65
+ 'icon': $color-neutral-icon,
66
+ 'icon-interactive': $color-primary-icon,
67
+ ),
68
+ 'disabled': (
69
+ 'background': $color-neutral-background-weak-disabled,
70
+ 'eyebrow-text': $color-neutral-text-weak-disabled,
71
+ 'icon': $color-neutral-icon-disabled,
72
+ 'icon-interactive': $color-primary-icon-disabled,
73
+ ),
74
+ ),
59
75
  'primary': (
60
76
  'default': (
61
77
  'background': $color-primary-background,
@@ -101,6 +117,21 @@ $tile-colors: (
101
117
  'icon-interactive': $color-fail-icon-disabled,
102
118
  ),
103
119
  ),
120
+ 'warning': (
121
+ 'default': (
122
+ 'background': $color-warning-background,
123
+ 'background-hover': $color-warning-background-hovered,
124
+ 'eyebrow-text': $color-warning-text,
125
+ 'icon': $color-warning-icon,
126
+ 'icon-interactive': $color-warning-icon,
127
+ ),
128
+ 'disabled': (
129
+ 'background': $color-warning-background-disabled,
130
+ 'eyebrow-text': $color-warning-text-disabled,
131
+ 'icon': $color-warning-icon-disabled,
132
+ 'icon-interactive': $color-warning-icon-disabled,
133
+ ),
134
+ ),
104
135
  'info': (
105
136
  'default': (
106
137
  'background': $color-info-background,
@@ -162,6 +193,7 @@ $tile-colors: (
162
193
  flex-direction: row;
163
194
  min-height: 48px;
164
195
  padding: $space-xxs $space-xs;
196
+ transition: background-color ease-in-out $default-transition-time;
165
197
 
166
198
  &.-disabled {
167
199
  @each $color-name, $color-map in $tile-colors {
@@ -258,9 +290,11 @@ export default {
258
290
  tileColor() {
259
291
  return {
260
292
  [TILE_COLORS.NEUTRAL]: '-neutral',
293
+ [TILE_COLORS.NEUTRAL_WEAK]: '-neutralWeak',
261
294
  [TILE_COLORS.PRIMARY]: '-primary',
262
295
  [TILE_COLORS.SUCCESS]: '-success',
263
296
  [TILE_COLORS.FAIL]: '-fail',
297
+ [TILE_COLORS.WARNING]: '-warning',
264
298
  [TILE_COLORS.INFO]: '-info',
265
299
  }[this.color];
266
300
  },