@eturnity/eturnity_reusable_components 9.31.4-ZOO-65.0 → 9.34.0-dev-06.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "9.31.4-ZOO-65.0",
3
+ "version": "9.34.0-dev-06.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -0,0 +1,3 @@
1
+ <svg width="11" height="13" viewBox="0 0 11 13" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M7.5 0C7.63261 0 7.75975 0.0527162 7.85352 0.146484L10.3535 2.64648C10.4473 2.74025 10.5 2.86739 10.5 3V9C10.5 9.55228 10.0523 10 9.5 10H8V11.5C8 12.0523 7.55228 12.5 7 12.5H1C0.447715 12.5 0 12.0523 0 11.5V3.5C0 2.94772 0.447715 2.5 1 2.5H2.5V1C2.5 0.447715 2.94772 0 3.5 0H7.5ZM1 11.5H7V6H5.5C4.94772 6 4.5 5.55228 4.5 5V3.5H1V11.5ZM3.5 2.5H5C5.13261 2.5 5.25975 2.55272 5.35352 2.64648L7.85352 5.14648C7.94728 5.24025 8 5.36739 8 5.5V9H9.5V3.5H8C7.44772 3.5 7 3.05228 7 2.5V1H3.5V2.5ZM5.5 5H6.29297L5.5 4.20703V5ZM8 2.5H8.79297L8 1.70703V2.5Z" fill="#151B1E"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M1 10.6008C1 10.877 1.22386 11.1008 1.5 11.1008H12.5C12.7761 11.1008 13 10.877 13 10.6008V8.10083C13 7.82469 13.2239 7.60083 13.5 7.60083C13.7761 7.60083 14 7.82469 14 8.10083V10.6008C14 11.4293 13.3284 12.1008 12.5 12.1008H1.5C0.671573 12.1008 0 11.4293 0 10.6008V8.10083C0 7.82469 0.223858 7.60083 0.5 7.60083C0.776142 7.60083 1 7.82469 1 8.10083V10.6008ZM6.72265 0.184805L7 -9.44138e-05L7.27735 0.184805L10.2774 2.1848C10.5071 2.33798 10.5692 2.64842 10.416 2.87818C10.2628 3.10794 9.95241 3.17003 9.72265 3.01686L7.5 1.53509L7.5 9.60083C7.5 9.87697 7.27614 10.1008 7 10.1008C6.72386 10.1008 6.5 9.87697 6.5 9.60083L6.5 1.53509L4.27735 3.01686C4.04759 3.17003 3.73715 3.10795 3.58398 2.87818C3.4308 2.64842 3.49289 2.33798 3.72265 2.18481L6.72265 0.184805Z" fill="#263238"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M11 5.591C11 5.45013 10.9402 5.31564 10.8359 5.22088L6.33594 1.13006C6.1453 0.95698 5.8547 0.95698 5.66406 1.13006L1.16406 5.22088C1.05983 5.31564 1 5.45013 1 5.591V12.1486C1 12.4248 1.22386 12.6486 1.5 12.6486H3C3.27614 12.6486 3.5 12.4248 3.5 12.1486V9.14862C3.5 8.32019 4.17157 7.64862 5 7.64862H7C7.82843 7.64862 8.5 8.32019 8.5 9.14862V12.1486C8.5 12.4248 8.72386 12.6486 9 12.6486H10.5C10.7761 12.6486 11 12.4248 11 12.1486V5.591ZM12 12.1486C12 12.977 11.3284 13.6486 10.5 13.6486H9C8.17157 13.6486 7.5 12.977 7.5 12.1486V9.14862C7.5 8.87247 7.27614 8.64862 7 8.64862H5C4.72386 8.64862 4.5 8.87247 4.5 9.14862V12.1486C4.5 12.977 3.82843 13.6486 3 13.6486H1.5C0.671573 13.6486 0 12.977 0 12.1486V5.591C0 5.16838 0.178499 4.76493 0.491211 4.48065L4.99121 0.389826C5.56325 -0.129942 6.43675 -0.129943 7.00879 0.389826L11.5088 4.48065C11.8215 4.76493 12 5.16838 12 5.591V12.1486Z" fill="#263238"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M1 1.5C1 1.22386 1.22386 1 1.5 1H12.5C12.7761 1 13 1.22386 13 1.5V4C13 4.27614 13.2239 4.5 13.5 4.5C13.7761 4.5 14 4.27614 14 4V1.5C14 0.671573 13.3284 0 12.5 0H1.5C0.671573 0 0 0.671573 0 1.5V4C0 4.27614 0.223858 4.5 0.5 4.5C0.776142 4.5 1 4.27614 1 4V1.5ZM6.72265 11.916L7 12.1009L7.27735 11.916L10.2774 9.91603C10.5071 9.76285 10.5692 9.45241 10.416 9.22265C10.2628 8.99289 9.95241 8.9308 9.72265 9.08397L7.5 10.5657L7.5 2.5C7.5 2.22386 7.27614 2 7 2C6.72386 2 6.5 2.22386 6.5 2.5L6.5 10.5657L4.27735 9.08397C4.04759 8.9308 3.73715 8.99288 3.58398 9.22265C3.4308 9.45241 3.49289 9.76285 3.72265 9.91602L6.72265 11.916Z" fill="#263238"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="10" height="14" viewBox="0 0 10 14" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M5.58594 0C5.98371 4.00002e-05 6.36522 0.158184 6.64648 0.439453L9.56055 3.35352C9.84182 3.63478 9.99996 4.01629 10 4.41406V7.5H9V5H7C6.17157 5 5.5 4.32843 5.5 3.5V1H1.5C1.22386 1 1 1.22386 1 1.5V12.5C1 12.7761 1.22386 13 1.5 13H6V14H1.5C0.671573 14 0 13.3284 0 12.5V1.5C2.01331e-08 0.671573 0.671573 1.61064e-08 1.5 0H5.58594ZM7.7998 7.59961L9.7998 9.09961C10.0206 9.26522 10.0658 9.57891 9.90039 9.7998C9.73478 10.0206 9.42109 10.0658 9.2002 9.90039L8 9V13.5C8 13.7761 7.77614 14 7.5 14C7.22386 14 7 13.7761 7 13.5V9L5.7998 9.90039C5.57891 10.0658 5.26522 10.0206 5.09961 9.7998C4.9342 9.57891 4.97939 9.26522 5.2002 9.09961L7.2002 7.59961L7.5 7.375L7.7998 7.59961ZM6.5 3.5C6.5 3.77614 6.72386 4 7 4H8.79297L6.5 1.70703V3.5Z" fill="#151B1E"/>
3
+ </svg>
@@ -4,83 +4,103 @@
4
4
  data-test-id="tabs-scroll-area"
5
5
  :scroll-overflow="scrollOverflow"
6
6
  >
7
- <TabsContainer
7
+ <Draggable
8
+ class="rc-tabs-header__tabs"
9
+ :class="{ 'rc-tabs-header__tabs--scroll': scrollOverflow }"
8
10
  data-test-id="tabs-container"
9
- :scroll-overflow="scrollOverflow"
11
+ :model-value="localTabs"
12
+ item-key="id"
13
+ :disabled="!dragEnabled"
14
+ :animation="150"
15
+ direction="horizontal"
16
+ :force-fallback="true"
17
+ :fallback-tolerance="5"
18
+ :scroll="true"
19
+ :scroll-sensitivity="60"
20
+ filter=".rc-tabs-header__menu-slot"
21
+ :prevent-on-filter="false"
22
+ ghost-class="rc-tabs-header__tab--ghost"
23
+ chosen-class="rc-tabs-header__tab--chosen"
24
+ drag-class="rc-tabs-header__tab--drag"
25
+ @start="onDragStart"
26
+ @end="onDragEnd"
27
+ @update:model-value="onDragOrderUpdate"
10
28
  >
11
- <TabItem
12
- v-for="item in tabsData"
13
- :key="item.id"
14
- :data-id="item.dataId"
15
- :data-qa-id="item.dataId"
16
- :data-test-active="activeTab === item.id"
17
- data-test-id="tab-item"
18
- :full-size="fullSize"
19
- :is-active="activeTab === item.id"
20
- :is-disabled="item.isDisabled"
21
- :scroll-overflow="scrollOverflow"
22
- @click="onTabClick({ id: item.id, isDisabled: item.isDisabled })"
23
- >
24
- <RCIcon
25
- v-if="item.icon"
26
- :color="
27
- activeTab === item.id
28
- ? theme.semanticColors.purple[500]
29
- : theme.semanticColors.teal[800]
30
- "
31
- data-test-id="tab-icon"
32
- :hovered-color="
33
- activeTab === item.id
34
- ? theme.semanticColors.purple[500]
35
- : theme.semanticColors.teal[800]
36
- "
37
- :name="item.icon"
38
- size="14px"
39
- />
40
- <TabText
41
- data-test-id="tab-text"
29
+ <template #item="{ element: item }">
30
+ <TabItem
31
+ :data-id="item.dataId"
32
+ :data-qa-id="item.dataId"
33
+ :data-test-active="activeTab === item.id"
34
+ data-test-id="tab-item"
35
+ :full-size="fullSize"
42
36
  :is-active="activeTab === item.id"
43
37
  :is-disabled="item.isDisabled"
44
- >{{ item.text }}</TabText
38
+ :is-draggable="dragEnabled"
39
+ :scroll-overflow="scrollOverflow"
40
+ @click="onTabClick({ id: item.id, isDisabled: item.isDisabled })"
45
41
  >
46
- <TabMenuSlot
47
- v-if="item.showTabMenu && $slots['tab-menu']"
48
- class="rc-tabs-header__menu-slot"
49
- data-test-id="tab-menu-slot"
50
- :is-active="activeTab === item.id"
51
- >
52
- <slot
53
- name="tab-menu"
54
- :item="item"
42
+ <RCIcon
43
+ v-if="item.icon"
44
+ :color="
45
+ activeTab === item.id
46
+ ? theme.semanticColors.purple[500]
47
+ : theme.semanticColors.teal[800]
48
+ "
49
+ data-test-id="tab-icon"
50
+ :hovered-color="
51
+ activeTab === item.id
52
+ ? theme.semanticColors.purple[500]
53
+ : theme.semanticColors.teal[800]
54
+ "
55
+ :name="item.icon"
56
+ size="14px"
57
+ />
58
+ <TabText
59
+ data-test-id="tab-text"
60
+ :is-active="activeTab === item.id"
61
+ :is-disabled="item.isDisabled"
62
+ :is-draggable="dragEnabled"
63
+ >{{ item.text }}</TabText
64
+ >
65
+ <TabMenuSlot
66
+ v-if="item.showTabMenu && $slots['tab-menu']"
67
+ class="rc-tabs-header__menu-slot"
68
+ data-test-id="tab-menu-slot"
69
+ :is-active="activeTab === item.id"
70
+ >
71
+ <slot
72
+ name="tab-menu"
73
+ :item="item"
74
+ :is-active="activeTab === item.id"
75
+ />
76
+ </TabMenuSlot>
77
+ <DotIcon
78
+ v-if="item.subText"
79
+ data-test-id="dot-icon"
55
80
  :is-active="activeTab === item.id"
56
81
  />
57
- </TabMenuSlot>
58
- <DotIcon
59
- v-if="item.subText"
60
- data-test-id="dot-icon"
61
- :is-active="activeTab === item.id"
62
- />
63
- <SubText v-if="item.subText" data-test-id="tab-subtext">{{
64
- item.subText
65
- }}</SubText>
66
- <RCIcon
67
- v-if="item.hasError"
68
- data-test-id="warning-icon"
69
- name="warning"
70
- size="14px"
71
- />
72
- <ConversionTag
73
- v-if="item.showUpgradeTag"
74
- :data-id="
75
- item.isTrialEnded || item.isTrialActive
76
- ? `${item.upgradeName}_upgrade_only`
77
- : `conversion_tag_import_${item.upgradeName}_available_trial_${item.isTrialAvailable}`
78
- "
79
- :is-capitalized="true"
80
- :text="item.upgradeTagText"
81
- />
82
- </TabItem>
83
- </TabsContainer>
82
+ <SubText v-if="item.subText" data-test-id="tab-subtext">{{
83
+ item.subText
84
+ }}</SubText>
85
+ <RCIcon
86
+ v-if="item.hasError"
87
+ data-test-id="warning-icon"
88
+ name="warning"
89
+ size="14px"
90
+ />
91
+ <ConversionTag
92
+ v-if="item.showUpgradeTag"
93
+ :data-id="
94
+ item.isTrialEnded || item.isTrialActive
95
+ ? `${item.upgradeName}_upgrade_only`
96
+ : `conversion_tag_import_${item.upgradeName}_available_trial_${item.isTrialAvailable}`
97
+ "
98
+ :is-capitalized="true"
99
+ :text="item.upgradeTagText"
100
+ />
101
+ </TabItem>
102
+ </template>
103
+ </Draggable>
84
104
  </TabsScrollArea>
85
105
  <AfterTabsSlot v-if="$slots['after-tabs']" data-test-id="after-tabs-slot">
86
106
  <slot name="after-tabs" />
@@ -90,6 +110,7 @@
90
110
 
91
111
  <script>
92
112
  import styled from 'vue3-styled-components'
113
+ import Draggable from 'vuedraggable'
93
114
  import RCIcon from '../icon'
94
115
  import theme from '@/assets/theme'
95
116
  import ConversionTag from '../tag/conversionTag'
@@ -131,15 +152,6 @@
131
152
  : ''}
132
153
  `
133
154
 
134
- const TabsContainerAttrs = { scrollOverflow: Boolean }
135
- const TabsContainer = styled('div', TabsContainerAttrs)`
136
- display: flex;
137
- flex-wrap: ${(props) => (props.scrollOverflow ? 'nowrap' : 'wrap')};
138
- align-items: stretch;
139
- cursor: pointer;
140
- width: ${(props) => (props.scrollOverflow ? 'max-content' : '100%')};
141
- `
142
-
143
155
  const AfterTabsSlot = styled.div`
144
156
  flex-shrink: 0;
145
157
  display: flex;
@@ -160,6 +172,7 @@
160
172
  isActive: Boolean,
161
173
  fullSize: Boolean,
162
174
  isDisabled: Boolean,
175
+ isDraggable: Boolean,
163
176
  scrollOverflow: Boolean,
164
177
  }
165
178
  const TabItem = styled('div', TabAttrs)`
@@ -169,7 +182,10 @@
169
182
  gap: 8px;
170
183
  padding: 10px 25px;
171
184
  font-size: 14px;
172
- cursor: ${(props) => (props.isDisabled ? 'not-allowed' : 'pointer')};
185
+ user-select: none;
186
+ -webkit-user-select: none;
187
+ cursor: ${(props) =>
188
+ props.isDisabled ? 'not-allowed' : props.isDraggable ? 'grab' : 'pointer'};
173
189
  font-weight: ${(props) => (props.isActive ? '500' : '400')};
174
190
  color: ${(props) =>
175
191
  props.isActive
@@ -199,7 +215,11 @@
199
215
  }
200
216
  `
201
217
 
202
- const TabTextAttrs = { isActive: Boolean, isDisabled: Boolean }
218
+ const TabTextAttrs = {
219
+ isActive: Boolean,
220
+ isDisabled: Boolean,
221
+ isDraggable: Boolean,
222
+ }
203
223
  const TabText = styled('div', TabTextAttrs)`
204
224
  font-size: 14px;
205
225
  font-weight: 400;
@@ -209,15 +229,16 @@
209
229
  : props.isDisabled
210
230
  ? props.theme.semanticColors.grey[600]
211
231
  : props.theme.semanticColors.teal[700]};
212
- cursor: ${(props) => (props.isDisabled ? 'not-allowed' : 'pointer')};
232
+ cursor: ${(props) =>
233
+ props.isDisabled ? 'not-allowed' : props.isDraggable ? 'grab' : 'pointer'};
213
234
  `
214
235
 
215
236
  export default {
216
237
  name: 'RCTabsHeader',
217
238
  components: {
239
+ Draggable,
218
240
  RootContainer,
219
241
  TabsScrollArea,
220
- TabsContainer,
221
242
  AfterTabsSlot,
222
243
  TabItem,
223
244
  TabMenuSlot,
@@ -250,13 +271,41 @@
250
271
  type: Boolean,
251
272
  default: false,
252
273
  },
274
+ /**
275
+ * Opt-in drag-and-drop reordering of the tabs. Off by default so existing
276
+ * usages are unaffected. When on, dragging a tab emits `on-tabs-reorder`
277
+ * with the new ordered list of tab ids. No affordance is shown for a
278
+ * single tab.
279
+ */
280
+ draggable: {
281
+ type: Boolean,
282
+ default: false,
283
+ },
253
284
  },
254
- emits: ['on-tab-change', 'on-tab-close'],
285
+ emits: ['on-tab-change', 'on-tab-close', 'on-tabs-reorder'],
255
286
  data() {
256
287
  return {
257
288
  theme,
289
+ localTabs: [],
258
290
  }
259
291
  },
292
+ computed: {
293
+ dragEnabled() {
294
+ return (
295
+ this.draggable &&
296
+ Array.isArray(this.tabsData) &&
297
+ this.tabsData.length > 1
298
+ )
299
+ },
300
+ },
301
+ watch: {
302
+ tabsData: {
303
+ immediate: true,
304
+ handler(next) {
305
+ this.localTabs = Array.isArray(next) ? [...next] : []
306
+ },
307
+ },
308
+ },
260
309
  methods: {
261
310
  onTabClick({ id, isDisabled }) {
262
311
  if (isDisabled) {
@@ -267,6 +316,64 @@
267
316
  }
268
317
  this.$emit('on-tab-change', id)
269
318
  },
319
+ onDragOrderUpdate(nextTabs) {
320
+ this.localTabs = nextTabs
321
+ this.$emit(
322
+ 'on-tabs-reorder',
323
+ nextTabs.map((tab) => tab.id)
324
+ )
325
+ },
326
+ onDragStart() {
327
+ // Force a consistent grabbing cursor for the whole drag: the fallback
328
+ // clone has pointer-events none, so without this the cursor flickers to
329
+ // whatever sits under the pointer (a tab, a gap, the body).
330
+ document.body.classList.add('rc-tabs-header--dragging')
331
+ },
332
+ onDragEnd() {
333
+ document.body.classList.remove('rc-tabs-header--dragging')
334
+ },
335
+ },
336
+ beforeUnmount() {
337
+ // Guard against a drag interrupted by an unmount leaving the class stuck.
338
+ document.body.classList.remove('rc-tabs-header--dragging')
270
339
  },
271
340
  }
272
341
  </script>
342
+
343
+ <style scoped>
344
+ .rc-tabs-header__tabs {
345
+ display: flex;
346
+ flex-wrap: wrap;
347
+ align-items: stretch;
348
+ cursor: pointer;
349
+ width: 100%;
350
+ }
351
+
352
+ .rc-tabs-header__tabs--scroll {
353
+ flex-wrap: nowrap;
354
+ width: max-content;
355
+ }
356
+
357
+ /* Drop position: a slim gap rather than a swap highlight. */
358
+ .rc-tabs-header__tab--ghost {
359
+ opacity: 0.25;
360
+ }
361
+
362
+ .rc-tabs-header__tab--chosen {
363
+ cursor: grabbing;
364
+ }
365
+
366
+ .rc-tabs-header__tab--drag {
367
+ opacity: 0.9;
368
+ }
369
+ </style>
370
+
371
+ <style>
372
+ /* While a tab is being dragged, keep the grabbing cursor everywhere — the
373
+ forceFallback clone lets the pointer fall through to elements underneath,
374
+ which would otherwise flip the cursor between grab / default / grabbing. */
375
+ body.rc-tabs-header--dragging,
376
+ body.rc-tabs-header--dragging * {
377
+ cursor: grabbing !important;
378
+ }
379
+ </style>