@eturnity/eturnity_reusable_components 9.25.4 → 9.25.6
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 +1 -1
- package/src/assets/svgIcons/redo.svg +4 -2
- package/src/assets/svgIcons/undo.svg +1 -1
- package/src/components/filterComponent/viewFilter.vue +22 -6
- package/src/components/inputs/inputText/index.vue +18 -18
- package/src/components/inputs/select/index.vue +36 -36
- package/src/components/tabsHeader/TabsHeader.spec.js +142 -0
- package/src/components/tabsHeader/TabsHeader.stories.js +63 -0
- package/src/components/tabsHeader/index.vue +176 -101
package/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
<svg width="
|
|
2
|
-
<
|
|
1
|
+
<svg width="14" height="14" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<g transform="matrix(-1,0,0,1,14,0)">
|
|
3
|
+
<path d="M4.64648 1.64655C4.84173 1.4513 5.15825 1.45133 5.35352 1.64655C5.54878 1.84181 5.54878 2.15831 5.35352 2.35358L3.20703 4.50006H9.5C12.2614 4.50006 14.5 6.73864 14.5 9.50006C14.5 12.2614 12.2614 14.5001 9.5 14.5001H2C1.72397 14.5 1.50005 14.2761 1.5 14.0001C1.5 13.724 1.72394 13.5002 2 13.5001H9.5C11.7091 13.5001 13.5 11.7092 13.5 9.50006C13.5 7.29092 11.7091 5.50006 9.5 5.50006H3.20703L5.35352 7.64655C5.54878 7.84181 5.54878 8.15831 5.35352 8.35358C5.15824 8.54871 4.8417 8.54879 4.64648 8.35358L1.64648 5.35358C1.45132 5.15836 1.45137 4.8418 1.64648 4.64655L4.64648 1.64655Z" fill="#263238"/>
|
|
4
|
+
</g>
|
|
3
5
|
</svg>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<svg width="
|
|
1
|
+
<svg width="14" height="14" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
2
|
<path d="M4.64648 1.64655C4.84173 1.4513 5.15825 1.45133 5.35352 1.64655C5.54878 1.84181 5.54878 2.15831 5.35352 2.35358L3.20703 4.50006H9.5C12.2614 4.50006 14.5 6.73864 14.5 9.50006C14.5 12.2614 12.2614 14.5001 9.5 14.5001H2C1.72397 14.5 1.50005 14.2761 1.5 14.0001C1.5 13.724 1.72394 13.5002 2 13.5001H9.5C11.7091 13.5001 13.5 11.7092 13.5 9.50006C13.5 7.29092 11.7091 5.50006 9.5 5.50006H3.20703L5.35352 7.64655C5.54878 7.84181 5.54878 8.15831 5.35352 8.35358C5.15824 8.54871 4.8417 8.54879 4.64648 8.35358L1.64648 5.35358C1.45132 5.15836 1.45137 4.8418 1.64648 4.64655L4.64648 1.64655Z" fill="#263238"/>
|
|
3
3
|
</svg>
|
|
@@ -201,11 +201,15 @@
|
|
|
201
201
|
>
|
|
202
202
|
<RcCheckbox
|
|
203
203
|
:is-checked="
|
|
204
|
-
selectedSort[index].selectedOptions?.
|
|
205
|
-
|
|
204
|
+
selectedSort[index].selectedOptions?.some(
|
|
205
|
+
(selectedValue) =>
|
|
206
|
+
filterOptionValuesMatch(
|
|
207
|
+
selectedValue,
|
|
208
|
+
option.value
|
|
209
|
+
)
|
|
206
210
|
)
|
|
207
211
|
"
|
|
208
|
-
:label="
|
|
212
|
+
:label="getOptionLabel(option)"
|
|
209
213
|
size="small"
|
|
210
214
|
@on-event-handler="
|
|
211
215
|
onSelectFilter({
|
|
@@ -602,6 +606,12 @@
|
|
|
602
606
|
select.closeDropdown()
|
|
603
607
|
})
|
|
604
608
|
},
|
|
609
|
+
filterOptionValuesMatch(left, right) {
|
|
610
|
+
if (left == null || right == null) {
|
|
611
|
+
return left === right
|
|
612
|
+
}
|
|
613
|
+
return String(left) === String(right)
|
|
614
|
+
},
|
|
605
615
|
getSelectedLabel({ type, value, index }) {
|
|
606
616
|
if (!value) return
|
|
607
617
|
if (type === 'column') {
|
|
@@ -621,10 +631,10 @@
|
|
|
621
631
|
const optionsList = this.optionsList(index)
|
|
622
632
|
const selectedLabels = selectedOptions
|
|
623
633
|
.map((optionValue) => {
|
|
624
|
-
const option = optionsList.find(
|
|
625
|
-
(opt
|
|
634
|
+
const option = optionsList.find((opt) =>
|
|
635
|
+
this.filterOptionValuesMatch(opt.value, optionValue)
|
|
626
636
|
)
|
|
627
|
-
return option ? option
|
|
637
|
+
return option ? this.getOptionLabel(option) : optionValue
|
|
628
638
|
})
|
|
629
639
|
.join(', ')
|
|
630
640
|
|
|
@@ -686,9 +696,15 @@
|
|
|
686
696
|
...option,
|
|
687
697
|
value: option[selectedItem.valueSelector],
|
|
688
698
|
label: option[selectedItem.labelSelector],
|
|
699
|
+
optionLabelsTranslated: !!selectedItem.optionLabelsTranslated,
|
|
689
700
|
})
|
|
690
701
|
)
|
|
691
702
|
},
|
|
703
|
+
getOptionLabel(option) {
|
|
704
|
+
return option.optionLabelsTranslated
|
|
705
|
+
? option.label
|
|
706
|
+
: this.$gettext(option.label)
|
|
707
|
+
},
|
|
692
708
|
},
|
|
693
709
|
}
|
|
694
710
|
</script>
|
|
@@ -125,8 +125,8 @@
|
|
|
125
125
|
props.theme.colors[props.labelFontColor]
|
|
126
126
|
? props.theme.colors[props.labelFontColor]
|
|
127
127
|
: props.labelFontColor
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
? props.labelFontColor
|
|
129
|
+
: props.theme.colors.eturnityGrey};
|
|
130
130
|
|
|
131
131
|
font-size: ${(props) =>
|
|
132
132
|
props.fontSize ? props.fontSize : inputLabelFontSize};
|
|
@@ -172,20 +172,20 @@
|
|
|
172
172
|
props.noBorder
|
|
173
173
|
? 'none'
|
|
174
174
|
: props.isError
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
175
|
+
? '1px solid ' + props.theme.colors.red
|
|
176
|
+
: props.borderColor
|
|
177
|
+
? props.theme.colors[props.borderColor]
|
|
178
|
+
? '1px solid ' + props.theme.colors[props.borderColor]
|
|
179
|
+
: '1px solid ' + props.borderColor
|
|
180
|
+
: '1px solid ' + props.theme.colors.grey4};
|
|
181
181
|
padding: ${(props) =>
|
|
182
182
|
props.isError
|
|
183
183
|
? '11px 25px 11px 10px'
|
|
184
184
|
: props.inputType === 'password'
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
? '11px 25px 11px 10px'
|
|
186
|
+
: props.defaultPadding
|
|
187
|
+
? '10px 35px 10px 15px'
|
|
188
|
+
: '11px 5px 11px 10px'};
|
|
189
189
|
border-radius: 4px;
|
|
190
190
|
position: relative;
|
|
191
191
|
font-size: ${(props) => (props.fontSize ? props.fontSize : '14px')};
|
|
@@ -193,8 +193,8 @@
|
|
|
193
193
|
props.isDisabled
|
|
194
194
|
? props.theme.colors.grey2
|
|
195
195
|
: props.fontColor
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
? props.fontColor + ' !important'
|
|
197
|
+
: props.theme.semanticColors.grey[900]};
|
|
198
198
|
|
|
199
199
|
width: ${(props) => (props.inputWidth ? props.inputWidth : '100%')};
|
|
200
200
|
min-width: ${(props) => (props.minWidth ? props.minWidth : 'unset')};
|
|
@@ -208,8 +208,8 @@
|
|
|
208
208
|
? props.disabledBackgroundColor + ' !important'
|
|
209
209
|
: props.theme.colors.grey5
|
|
210
210
|
: props.backgroundColor
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
? props.backgroundColor + ' !important'
|
|
212
|
+
: props.theme.colors.white};
|
|
213
213
|
&::placeholder {
|
|
214
214
|
color: ${(props) => props.theme.colors.grey2};
|
|
215
215
|
}
|
|
@@ -369,7 +369,7 @@
|
|
|
369
369
|
},
|
|
370
370
|
labelFontColor: {
|
|
371
371
|
required: false,
|
|
372
|
-
default: '
|
|
372
|
+
default: '',
|
|
373
373
|
type: String,
|
|
374
374
|
},
|
|
375
375
|
backgroundColor: {
|
|
@@ -383,7 +383,7 @@
|
|
|
383
383
|
},
|
|
384
384
|
fontColor: {
|
|
385
385
|
required: false,
|
|
386
|
-
default: '
|
|
386
|
+
default: '',
|
|
387
387
|
type: String,
|
|
388
388
|
},
|
|
389
389
|
hasFocus: {
|
|
@@ -49,10 +49,10 @@
|
|
|
49
49
|
buttonBgColor
|
|
50
50
|
? buttonBgColor
|
|
51
51
|
: colorMode == 'dark'
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
? 'transparent'
|
|
53
|
+
: colorMode == 'transparent'
|
|
54
|
+
? 'transparent'
|
|
55
|
+
: 'white'
|
|
56
56
|
"
|
|
57
57
|
class="select-button"
|
|
58
58
|
:color-mode="colorMode"
|
|
@@ -169,8 +169,8 @@
|
|
|
169
169
|
colorMode == 'dark'
|
|
170
170
|
? '#000000'
|
|
171
171
|
: colorMode == 'transparent'
|
|
172
|
-
|
|
173
|
-
|
|
172
|
+
? 'grey6'
|
|
173
|
+
: dropdownBgColor
|
|
174
174
|
"
|
|
175
175
|
:hovered-index="hoveredIndex"
|
|
176
176
|
:hovered-value="hoveredValueDomAttr"
|
|
@@ -307,14 +307,14 @@
|
|
|
307
307
|
props.sidebarCaret
|
|
308
308
|
? '24px'
|
|
309
309
|
: props.colorMode === 'transparent'
|
|
310
|
-
|
|
311
|
-
|
|
310
|
+
? '15px'
|
|
311
|
+
: CARET_WIDTH};
|
|
312
312
|
min-width: ${(props) =>
|
|
313
313
|
props.sidebarCaret
|
|
314
314
|
? '24px'
|
|
315
315
|
: props.colorMode === 'transparent'
|
|
316
|
-
|
|
317
|
-
|
|
316
|
+
? '15px'
|
|
317
|
+
: CARET_WIDTH};
|
|
318
318
|
height: 100%;
|
|
319
319
|
align-items: center;
|
|
320
320
|
cursor: pointer;
|
|
@@ -434,23 +434,23 @@
|
|
|
434
434
|
? 'padding: 10px 15px 10px 5px;'
|
|
435
435
|
: 'padding: 10px 15px;'
|
|
436
436
|
: props.isSearchBarVisible
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
437
|
+
? ''
|
|
438
|
+
: `padding-left: ${
|
|
439
|
+
props.hasNoPadding
|
|
440
|
+
? '0'
|
|
441
|
+
: props.tablePaddingLeft
|
|
442
|
+
? props.tablePaddingLeft
|
|
443
|
+
: props.paddingLeft
|
|
444
|
+
}`};
|
|
445
445
|
text-align: ${(props) => (props.textCenter ? 'center' : 'left')};
|
|
446
446
|
min-height: ${(props) =>
|
|
447
447
|
props.selectHeight
|
|
448
448
|
? props.selectHeight
|
|
449
449
|
: props.selectMinHeight
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
450
|
+
? props.selectMinHeight
|
|
451
|
+
: props.height
|
|
452
|
+
? props.height
|
|
453
|
+
: '36px'};
|
|
454
454
|
display: flex;
|
|
455
455
|
align-items: center;
|
|
456
456
|
${(props) => (props.selectHeight ? `height: ${props.selectHeight};` : '')}
|
|
@@ -458,8 +458,8 @@
|
|
|
458
458
|
showBorder &&
|
|
459
459
|
`
|
|
460
460
|
border: ${BORDER_WIDTH} solid ${
|
|
461
|
-
|
|
462
|
-
|
|
461
|
+
hasError ? theme.colors.red : theme.colors.grey4
|
|
462
|
+
}
|
|
463
463
|
`}
|
|
464
464
|
opacity: ${(props) =>
|
|
465
465
|
props.colorMode === 'transparent' && props.disabled ? '0.4' : '1'};
|
|
@@ -467,18 +467,18 @@
|
|
|
467
467
|
props.colorMode === 'transparent'
|
|
468
468
|
? 'transparent'
|
|
469
469
|
: props.disabled && props.showDisabledBackground
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
470
|
+
? props.theme.colors.grey5
|
|
471
|
+
: props.theme.colors[props.bgColor]
|
|
472
|
+
? props.theme.colors[props.bgColor]
|
|
473
|
+
: props.bgColor} !important;
|
|
474
474
|
color: ${(props) =>
|
|
475
475
|
props.colorMode === 'transparent'
|
|
476
476
|
? props.theme.colors.white
|
|
477
477
|
: props.disabled && props.showDisabledBackground
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
478
|
+
? props.theme.colors.black
|
|
479
|
+
: props.theme.colors[props.fontColor]
|
|
480
|
+
? props.theme.colors[props.fontColor]
|
|
481
|
+
: props.fontColor};
|
|
482
482
|
${(props) => (props.disabled ? 'pointer-events: none' : '')};
|
|
483
483
|
overflow: hidden;
|
|
484
484
|
& > .handle {
|
|
@@ -486,8 +486,8 @@
|
|
|
486
486
|
props.hasError
|
|
487
487
|
? props.theme.colors.red
|
|
488
488
|
: props.colorMode === 'light'
|
|
489
|
-
|
|
490
|
-
|
|
489
|
+
? props.theme.colors.grey4
|
|
490
|
+
: props.theme.colors.white}
|
|
491
491
|
1px solid;
|
|
492
492
|
}
|
|
493
493
|
`
|
|
@@ -533,8 +533,8 @@
|
|
|
533
533
|
props.minWidth
|
|
534
534
|
? props.minWidth
|
|
535
535
|
: props.optionWidth
|
|
536
|
-
|
|
537
|
-
|
|
536
|
+
? props.optionWidth
|
|
537
|
+
: '100%'};
|
|
538
538
|
background-color: ${(props) =>
|
|
539
539
|
props.theme.colors[props.bgColor]
|
|
540
540
|
? props.theme.colors[props.bgColor]
|
|
@@ -98,4 +98,146 @@ describe('TabsHeader', () => {
|
|
|
98
98
|
const tabs = wrapper.findAll('[data-test-id="tab-item"]')
|
|
99
99
|
expect(tabs.length).toBeGreaterThan(0)
|
|
100
100
|
})
|
|
101
|
+
|
|
102
|
+
it('renders tab-menu slot when tab is active and showTabMenu', () => {
|
|
103
|
+
const wrapper = mount(TabsHeader, {
|
|
104
|
+
props: {
|
|
105
|
+
tabsData: [
|
|
106
|
+
{ text: 'A', id: 'a', dataId: 'a', showTabMenu: true },
|
|
107
|
+
{ text: 'B', id: 'b', dataId: 'b' },
|
|
108
|
+
],
|
|
109
|
+
activeTab: 'a',
|
|
110
|
+
fullSize: false,
|
|
111
|
+
},
|
|
112
|
+
slots: {
|
|
113
|
+
'tab-menu': '<div data-slot-mark="tab-menu">menu</div>',
|
|
114
|
+
},
|
|
115
|
+
global: {
|
|
116
|
+
provide: { theme },
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
expect(wrapper.find('[data-test-id="tab-menu-slot"]').exists()).toBe(true)
|
|
121
|
+
expect(wrapper.find('[data-slot-mark="tab-menu"]').exists()).toBe(true)
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('renders tab-menu slot for inactive tabs that have showTabMenu (revealed via hover styling)', () => {
|
|
125
|
+
const wrapper = mount(TabsHeader, {
|
|
126
|
+
props: {
|
|
127
|
+
tabsData: [
|
|
128
|
+
{ text: 'A', id: 'a', dataId: 'a', showTabMenu: true },
|
|
129
|
+
{ text: 'B', id: 'b', dataId: 'b' },
|
|
130
|
+
],
|
|
131
|
+
activeTab: 'b',
|
|
132
|
+
fullSize: false,
|
|
133
|
+
},
|
|
134
|
+
slots: {
|
|
135
|
+
'tab-menu': '<div data-slot-mark="tab-menu">menu</div>',
|
|
136
|
+
},
|
|
137
|
+
global: {
|
|
138
|
+
provide: { theme },
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
expect(wrapper.find('[data-test-id="tab-menu-slot"]').exists()).toBe(true)
|
|
143
|
+
expect(wrapper.find('[data-slot-mark="tab-menu"]').exists()).toBe(true)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('does not render tab-menu slot when showTabMenu is false', () => {
|
|
147
|
+
const wrapper = mount(TabsHeader, {
|
|
148
|
+
props: {
|
|
149
|
+
tabsData: [
|
|
150
|
+
{ text: 'A', id: 'a', dataId: 'a' },
|
|
151
|
+
{ text: 'B', id: 'b', dataId: 'b' },
|
|
152
|
+
],
|
|
153
|
+
activeTab: 'a',
|
|
154
|
+
fullSize: false,
|
|
155
|
+
},
|
|
156
|
+
slots: {
|
|
157
|
+
'tab-menu': '<div data-slot-mark="tab-menu">menu</div>',
|
|
158
|
+
},
|
|
159
|
+
global: {
|
|
160
|
+
provide: { theme },
|
|
161
|
+
},
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
expect(wrapper.find('[data-test-id="tab-menu-slot"]').exists()).toBe(false)
|
|
165
|
+
expect(wrapper.find('[data-slot-mark="tab-menu"]').exists()).toBe(false)
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
it('passes is-active=true to the tab-menu slot scope when the slot tab is the active one', () => {
|
|
169
|
+
const wrapper = mount(TabsHeader, {
|
|
170
|
+
props: {
|
|
171
|
+
tabsData: [
|
|
172
|
+
{ text: 'A', id: 'a', dataId: 'a', showTabMenu: true },
|
|
173
|
+
{ text: 'B', id: 'b', dataId: 'b', showTabMenu: true },
|
|
174
|
+
],
|
|
175
|
+
activeTab: 'a',
|
|
176
|
+
fullSize: false,
|
|
177
|
+
},
|
|
178
|
+
slots: {
|
|
179
|
+
'tab-menu': `
|
|
180
|
+
<template #default="{ item, isActive }">
|
|
181
|
+
<span :data-slot-mark="item.id" :data-active="isActive">menu</span>
|
|
182
|
+
</template>
|
|
183
|
+
`,
|
|
184
|
+
},
|
|
185
|
+
global: {
|
|
186
|
+
provide: { theme },
|
|
187
|
+
},
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
expect(wrapper.find('[data-slot-mark="a"]').attributes('data-active')).toBe(
|
|
191
|
+
'true'
|
|
192
|
+
)
|
|
193
|
+
expect(wrapper.find('[data-slot-mark="b"]').attributes('data-active')).toBe(
|
|
194
|
+
'false'
|
|
195
|
+
)
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
it('renders after-tabs slot when provided', () => {
|
|
199
|
+
const wrapper = mount(TabsHeader, {
|
|
200
|
+
props: {
|
|
201
|
+
tabsData: mockTabsData,
|
|
202
|
+
activeTab: 0,
|
|
203
|
+
fullSize: false,
|
|
204
|
+
},
|
|
205
|
+
slots: {
|
|
206
|
+
'after-tabs': '<aside data-slot-mark="after-tabs">trail</aside>',
|
|
207
|
+
},
|
|
208
|
+
global: {
|
|
209
|
+
provide: { theme },
|
|
210
|
+
},
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
expect(wrapper.find('[data-test-id="after-tabs-slot"]').exists()).toBe(
|
|
214
|
+
true
|
|
215
|
+
)
|
|
216
|
+
expect(wrapper.find('[data-slot-mark="after-tabs"]').exists()).toBe(true)
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('keeps after-tabs outside the scroll area when scrollOverflow is enabled', () => {
|
|
220
|
+
const wrapper = mount(TabsHeader, {
|
|
221
|
+
props: {
|
|
222
|
+
tabsData: mockTabsData,
|
|
223
|
+
activeTab: 0,
|
|
224
|
+
fullSize: false,
|
|
225
|
+
scrollOverflow: true,
|
|
226
|
+
},
|
|
227
|
+
slots: {
|
|
228
|
+
'after-tabs': '<aside data-slot-mark="after-tabs">trail</aside>',
|
|
229
|
+
},
|
|
230
|
+
global: {
|
|
231
|
+
provide: { theme },
|
|
232
|
+
},
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
const scrollArea = wrapper.find('[data-test-id="tabs-scroll-area"]')
|
|
236
|
+
const afterTabs = wrapper.find('[data-test-id="after-tabs-slot"]')
|
|
237
|
+
expect(scrollArea.exists()).toBe(true)
|
|
238
|
+
expect(afterTabs.exists()).toBe(true)
|
|
239
|
+
expect(scrollArea.find('[data-test-id="after-tabs-slot"]').exists()).toBe(
|
|
240
|
+
false
|
|
241
|
+
)
|
|
242
|
+
})
|
|
101
243
|
})
|
|
@@ -140,3 +140,66 @@ StringIds.args = {
|
|
|
140
140
|
],
|
|
141
141
|
activeTab: 'tab1',
|
|
142
142
|
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Tab menu (#tab-menu) and trailing “Create view” (#after-tabs) — consumes
|
|
146
|
+
* slots like ProjectList. The active tab shows the kebab persistently; inactive
|
|
147
|
+
* tabs flagged `showTabMenu: true` reveal it on hover.
|
|
148
|
+
*/
|
|
149
|
+
export const WithTabMenuAndAfterTabs = () => ({
|
|
150
|
+
components: { TabsHeader },
|
|
151
|
+
data() {
|
|
152
|
+
return {
|
|
153
|
+
activeTab: 'saved',
|
|
154
|
+
tabsData: [
|
|
155
|
+
{
|
|
156
|
+
text: 'Table view',
|
|
157
|
+
id: 'table',
|
|
158
|
+
icon: 'table_view',
|
|
159
|
+
dataId: 'kanban_tab_story_table',
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
text: 'My saved view',
|
|
163
|
+
id: 'saved',
|
|
164
|
+
icon: 'kanban_view',
|
|
165
|
+
dataId: 'kanban_tab_story_saved',
|
|
166
|
+
showTabMenu: true,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
text: 'Inactive saved view (hover me)',
|
|
170
|
+
id: 'saved-2',
|
|
171
|
+
icon: 'table_view',
|
|
172
|
+
dataId: 'kanban_tab_story_saved_2',
|
|
173
|
+
showTabMenu: true,
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
methods: {
|
|
179
|
+
onTabChange(id) {
|
|
180
|
+
this.activeTab = id
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
template: `
|
|
184
|
+
<TabsHeader
|
|
185
|
+
:tabs-data="tabsData"
|
|
186
|
+
:active-tab="activeTab"
|
|
187
|
+
:full-size="false"
|
|
188
|
+
@on-tab-change="onTabChange"
|
|
189
|
+
>
|
|
190
|
+
<template #tab-menu>
|
|
191
|
+
<span
|
|
192
|
+
data-test-id="story_tab_menu_trigger"
|
|
193
|
+
style="width: 26px; height: 26px; border-radius: 4px; background: #e8d8fe; display: inline-flex; align-items: center; justify-content: center; font-weight: bold; font-size: 12px; color: #6f20dc;"
|
|
194
|
+
>
|
|
195
|
+
⋮
|
|
196
|
+
</span>
|
|
197
|
+
</template>
|
|
198
|
+
<template #after-tabs>
|
|
199
|
+
<span style="margin-left: 4px; margin-bottom: 2px; color: #6f20dc; font-size: 14px;">
|
|
200
|
+
+ Create view (story)
|
|
201
|
+
</span>
|
|
202
|
+
</template>
|
|
203
|
+
</TabsHeader>
|
|
204
|
+
`,
|
|
205
|
+
})
|
|
@@ -1,100 +1,94 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
:
|
|
10
|
-
data-test-id="tab-item"
|
|
11
|
-
:full-size="fullSize"
|
|
12
|
-
:is-active="activeTab === item.id"
|
|
13
|
-
:is-disabled="item.isDisabled"
|
|
14
|
-
@click="onTabClick({ id: item.id, isDisabled: item.isDisabled })"
|
|
2
|
+
<RootContainer data-test-id="tabs-header-container">
|
|
3
|
+
<TabsScrollArea
|
|
4
|
+
data-test-id="tabs-scroll-area"
|
|
5
|
+
:scroll-overflow="scrollOverflow"
|
|
6
|
+
>
|
|
7
|
+
<TabsContainer
|
|
8
|
+
data-test-id="tabs-container"
|
|
9
|
+
:scroll-overflow="scrollOverflow"
|
|
15
10
|
>
|
|
16
|
-
<
|
|
17
|
-
v-
|
|
18
|
-
:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
:hovered-color="
|
|
25
|
-
activeTab === item.id
|
|
26
|
-
? theme.semanticColors.purple[500]
|
|
27
|
-
: theme.semanticColors.teal[800]
|
|
28
|
-
"
|
|
29
|
-
:name="item.icon"
|
|
30
|
-
size="14px"
|
|
31
|
-
/>
|
|
32
|
-
<TabText
|
|
33
|
-
data-test-id="tab-text"
|
|
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"
|
|
34
19
|
:is-active="activeTab === item.id"
|
|
35
20
|
:is-disabled="item.isDisabled"
|
|
36
|
-
|
|
21
|
+
:scroll-overflow="scrollOverflow"
|
|
22
|
+
@click="onTabClick({ id: item.id, isDisabled: item.isDisabled })"
|
|
37
23
|
>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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"
|
|
42
|
+
:is-active="activeTab === item.id"
|
|
43
|
+
:is-disabled="item.isDisabled"
|
|
44
|
+
>{{ item.text }}</TabText
|
|
45
|
+
>
|
|
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"
|
|
55
|
+
:is-active="activeTab === item.id"
|
|
56
|
+
/>
|
|
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>
|
|
84
|
+
</TabsScrollArea>
|
|
85
|
+
<AfterTabsSlot v-if="$slots['after-tabs']" data-test-id="after-tabs-slot">
|
|
86
|
+
<slot name="after-tabs" />
|
|
87
|
+
</AfterTabsSlot>
|
|
88
|
+
</RootContainer>
|
|
78
89
|
</template>
|
|
79
90
|
|
|
80
91
|
<script>
|
|
81
|
-
// import RCTabsHeader from "@eturnity/eturnity_reusable_components/src/components/tabsHeader"
|
|
82
|
-
// To use:
|
|
83
|
-
// <RCTabsHeader
|
|
84
|
-
// :activeTab="activeTabIndex" // should match the 'id'
|
|
85
|
-
// :tabsData="[
|
|
86
|
-
// {
|
|
87
|
-
// text: 'Tab 1',
|
|
88
|
-
// id: 0,
|
|
89
|
-
// hasError: true // optional
|
|
90
|
-
// },
|
|
91
|
-
// {
|
|
92
|
-
// text: 'Tab 1',
|
|
93
|
-
// id: 1,
|
|
94
|
-
// hasError: false // optional
|
|
95
|
-
// }
|
|
96
|
-
// ]"
|
|
97
|
-
// />
|
|
98
92
|
import styled from 'vue3-styled-components'
|
|
99
93
|
import RCIcon from '../icon'
|
|
100
94
|
import theme from '@/assets/theme'
|
|
@@ -114,15 +108,60 @@
|
|
|
114
108
|
color: ${(props) => props.theme.colors.black};
|
|
115
109
|
`
|
|
116
110
|
|
|
117
|
-
const
|
|
111
|
+
const RootContainer = styled.div`
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: stretch;
|
|
114
|
+
width: 100%;
|
|
115
|
+
min-width: 0;
|
|
116
|
+
`
|
|
117
|
+
|
|
118
|
+
const TabsScrollAreaAttrs = { scrollOverflow: Boolean }
|
|
119
|
+
const TabsScrollArea = styled('div', TabsScrollAreaAttrs)`
|
|
120
|
+
flex: 1 1 auto;
|
|
121
|
+
min-width: 0;
|
|
122
|
+
${(props) =>
|
|
123
|
+
props.scrollOverflow
|
|
124
|
+
? `
|
|
125
|
+
overflow-x: auto;
|
|
126
|
+
overflow-y: hidden;
|
|
127
|
+
-webkit-overflow-scrolling: touch;
|
|
128
|
+
padding-bottom: 1px;
|
|
129
|
+
margin-bottom: -1px;
|
|
130
|
+
`
|
|
131
|
+
: ''}
|
|
132
|
+
`
|
|
118
133
|
|
|
119
|
-
const
|
|
134
|
+
const TabsContainerAttrs = { scrollOverflow: Boolean }
|
|
135
|
+
const TabsContainer = styled('div', TabsContainerAttrs)`
|
|
120
136
|
display: flex;
|
|
137
|
+
flex-wrap: ${(props) => (props.scrollOverflow ? 'nowrap' : 'wrap')};
|
|
138
|
+
align-items: stretch;
|
|
121
139
|
cursor: pointer;
|
|
122
|
-
width: 100
|
|
140
|
+
width: ${(props) => (props.scrollOverflow ? 'max-content' : '100%')};
|
|
141
|
+
`
|
|
142
|
+
|
|
143
|
+
const AfterTabsSlot = styled.div`
|
|
144
|
+
flex-shrink: 0;
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
align-self: stretch;
|
|
123
148
|
`
|
|
124
149
|
|
|
125
|
-
const
|
|
150
|
+
const TabMenuSlotAttrs = { isActive: Boolean }
|
|
151
|
+
const TabMenuSlot = styled('div', TabMenuSlotAttrs)`
|
|
152
|
+
display: inline-flex;
|
|
153
|
+
align-items: center;
|
|
154
|
+
opacity: ${(props) => (props.isActive ? 1 : 0)};
|
|
155
|
+
transition: opacity 0.15s ease;
|
|
156
|
+
pointer-events: ${(props) => (props.isActive ? 'auto' : 'none')};
|
|
157
|
+
`
|
|
158
|
+
|
|
159
|
+
const TabAttrs = {
|
|
160
|
+
isActive: Boolean,
|
|
161
|
+
fullSize: Boolean,
|
|
162
|
+
isDisabled: Boolean,
|
|
163
|
+
scrollOverflow: Boolean,
|
|
164
|
+
}
|
|
126
165
|
const TabItem = styled('div', TabAttrs)`
|
|
127
166
|
display: flex;
|
|
128
167
|
align-items: center;
|
|
@@ -136,12 +175,40 @@
|
|
|
136
175
|
props.isActive
|
|
137
176
|
? props.theme.semanticColors.purple[500]
|
|
138
177
|
: props.theme.semanticColors.teal[800]};
|
|
139
|
-
flex-grow: ${(props) => (props.fullSize ? 1 : 0)};
|
|
178
|
+
flex-grow: ${(props) => (props.fullSize && !props.scrollOverflow ? 1 : 0)};
|
|
179
|
+
flex-shrink: ${(props) => (props.scrollOverflow ? 0 : 1)};
|
|
180
|
+
white-space: ${(props) => (props.scrollOverflow ? 'nowrap' : 'normal')};
|
|
140
181
|
background-color: ${(props) => props.theme.colors.white};
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
182
|
+
position: relative;
|
|
183
|
+
z-index: ${(props) => (props.isActive ? 1 : 0)};
|
|
184
|
+
border-bottom: ${(props) => {
|
|
185
|
+
if (props.scrollOverflow) {
|
|
186
|
+
return '1px solid transparent'
|
|
187
|
+
}
|
|
188
|
+
if (props.isActive) {
|
|
189
|
+
return `2px solid ${props.theme.semanticColors.purple[400]}`
|
|
190
|
+
}
|
|
191
|
+
return `2px solid ${props.theme.semanticColors.grey[400]}`
|
|
192
|
+
}};
|
|
193
|
+
${(props) =>
|
|
194
|
+
props.scrollOverflow && props.isActive
|
|
195
|
+
? `
|
|
196
|
+
&::after {
|
|
197
|
+
content: '';
|
|
198
|
+
position: absolute;
|
|
199
|
+
left: 0;
|
|
200
|
+
right: 0;
|
|
201
|
+
bottom: -1px;
|
|
202
|
+
height: 2px;
|
|
203
|
+
background-color: ${props.theme.semanticColors.purple[400]};
|
|
204
|
+
z-index: 1;
|
|
205
|
+
}
|
|
206
|
+
`
|
|
207
|
+
: ''}
|
|
208
|
+
&:hover .rc-tabs-header__menu-slot {
|
|
209
|
+
opacity: 1;
|
|
210
|
+
pointer-events: auto;
|
|
211
|
+
}
|
|
145
212
|
`
|
|
146
213
|
|
|
147
214
|
const TabTextAttrs = { isActive: Boolean, isDisabled: Boolean }
|
|
@@ -152,17 +219,20 @@
|
|
|
152
219
|
props.isActive
|
|
153
220
|
? props.theme.semanticColors.purple[500]
|
|
154
221
|
: props.isDisabled
|
|
155
|
-
|
|
156
|
-
|
|
222
|
+
? props.theme.semanticColors.grey[600]
|
|
223
|
+
: props.theme.semanticColors.teal[700]};
|
|
157
224
|
cursor: ${(props) => (props.isDisabled ? 'not-allowed' : 'pointer')};
|
|
158
225
|
`
|
|
159
226
|
|
|
160
227
|
export default {
|
|
161
228
|
name: 'RCTabsHeader',
|
|
162
229
|
components: {
|
|
163
|
-
|
|
230
|
+
RootContainer,
|
|
231
|
+
TabsScrollArea,
|
|
164
232
|
TabsContainer,
|
|
233
|
+
AfterTabsSlot,
|
|
165
234
|
TabItem,
|
|
235
|
+
TabMenuSlot,
|
|
166
236
|
SubText,
|
|
167
237
|
DotIcon,
|
|
168
238
|
RCIcon,
|
|
@@ -182,6 +252,11 @@
|
|
|
182
252
|
type: Boolean,
|
|
183
253
|
default: true,
|
|
184
254
|
},
|
|
255
|
+
/** Horizontal scroll when tabs overflow; keeps tabs on one row. */
|
|
256
|
+
scrollOverflow: {
|
|
257
|
+
type: Boolean,
|
|
258
|
+
default: false,
|
|
259
|
+
},
|
|
185
260
|
/** When true, emit on-tab-change even when clicking the currently active tab */
|
|
186
261
|
emitWhenActiveTabClicked: {
|
|
187
262
|
type: Boolean,
|