@gitlab/ui 63.0.0 → 63.1.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/CHANGELOG.md +7 -0
- package/dist/components/base/new_dropdowns/listbox/listbox.js +62 -2
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/package.json +1 -1
- package/src/components/base/new_dropdowns/dropdown.scss +66 -0
- package/src/components/base/new_dropdowns/dropdown_item.scss +7 -2
- package/src/components/base/new_dropdowns/listbox/listbox.vue +80 -2
package/package.json
CHANGED
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
.gl-new-dropdown-contents {
|
|
35
|
+
@include gl-relative;
|
|
35
36
|
@include gl-flex-grow-1;
|
|
36
37
|
@include gl-overflow-y-auto;
|
|
37
38
|
@include gl-pl-0;
|
|
@@ -101,4 +102,69 @@
|
|
|
101
102
|
@include gl-mx-0;
|
|
102
103
|
}
|
|
103
104
|
}
|
|
105
|
+
|
|
106
|
+
$dropdown-content-padding: 0.25rem;
|
|
107
|
+
|
|
108
|
+
// Scrim overlay related styles (the shadow that appears above and below the content) indicating that the content is scrollable
|
|
109
|
+
.gl-new-dropdown-contents-with-scrim-overlay {
|
|
110
|
+
padding: 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.gl-new-dropdown-contents {
|
|
114
|
+
.top-scrim-wrapper,
|
|
115
|
+
.bottom-scrim-wrapper {
|
|
116
|
+
height: $dropdown-content-padding;
|
|
117
|
+
opacity: 0;
|
|
118
|
+
position: sticky;
|
|
119
|
+
z-index: 1;
|
|
120
|
+
display: block;
|
|
121
|
+
overflow: visible;
|
|
122
|
+
left: 1px;
|
|
123
|
+
right: 1px;
|
|
124
|
+
pointer-events: none;
|
|
125
|
+
transition: opacity 0.1s;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.top-scrim-wrapper {
|
|
129
|
+
top: 0;
|
|
130
|
+
|
|
131
|
+
.top-scrim {
|
|
132
|
+
left: 0;
|
|
133
|
+
right: 0;
|
|
134
|
+
|
|
135
|
+
&.top-scrim-light {
|
|
136
|
+
height: 2.25rem;
|
|
137
|
+
border-radius: 0.375rem 0.375rem 0 0;
|
|
138
|
+
background: linear-gradient(180deg, rgba(255, 255, 255, 1) 0%, rgba(255, 255, 255, 0));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
&.top-scrim-dark {
|
|
142
|
+
height: 0.25rem;
|
|
143
|
+
background: linear-gradient(180deg, rgba(0, 0, 0, 0.16) 0%, rgba(255, 255, 255, 0) 100%);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.bottom-scrim-wrapper {
|
|
149
|
+
bottom: 0;
|
|
150
|
+
height: $dropdown-content-padding;
|
|
151
|
+
|
|
152
|
+
.bottom-scrim {
|
|
153
|
+
height: 0;
|
|
154
|
+
position: relative;
|
|
155
|
+
top: calc(-2.25rem + #{$dropdown-content-padding});
|
|
156
|
+
border-radius: 0 0 0.375rem 0.375rem;
|
|
157
|
+
background: linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 1));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
&.top-scrim-visible .top-scrim-wrapper,
|
|
162
|
+
&.bottom-scrim-visible .bottom-scrim-wrapper {
|
|
163
|
+
opacity: 1;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
&.bottom-scrim-visible .bottom-scrim {
|
|
167
|
+
height: 2.25rem;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
104
170
|
}
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
@include gl-px-2;
|
|
4
4
|
@include gl-my-1;
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/* when there is a scrim `li` items inside the list, the first and last real items
|
|
7
|
+
do not match the selector `:first-child` and `:last-child`,
|
|
8
|
+
that's why we have to target them with a different selector */
|
|
9
|
+
&:first-child,
|
|
10
|
+
.gl-new-dropdown-contents-with-scrim-overlay > &:nth-child(3):not(:last-child) {
|
|
7
11
|
@include gl-mt-0;
|
|
8
12
|
}
|
|
9
13
|
|
|
10
|
-
&:last-child
|
|
14
|
+
&:last-child,
|
|
15
|
+
.gl-new-dropdown-contents-with-scrim-overlay > &:nth-last-child(3):not(:first-child) {
|
|
11
16
|
@include gl-mb-0;
|
|
12
17
|
}
|
|
13
18
|
|
|
@@ -314,6 +314,8 @@ export default {
|
|
|
314
314
|
listboxId: uniqueId('listbox-'),
|
|
315
315
|
nextFocusedItemIndex: null,
|
|
316
316
|
searchStr: '',
|
|
317
|
+
topBoundaryVisible: true,
|
|
318
|
+
bottomBoundaryVisible: true,
|
|
317
319
|
};
|
|
318
320
|
},
|
|
319
321
|
computed: {
|
|
@@ -321,6 +323,15 @@ export default {
|
|
|
321
323
|
if (this.items.length === 0 || isOption(this.items[0])) return 'ul';
|
|
322
324
|
return 'div';
|
|
323
325
|
},
|
|
326
|
+
listboxClasses() {
|
|
327
|
+
return {
|
|
328
|
+
'top-scrim-visible': !this.topBoundaryVisible,
|
|
329
|
+
'bottom-scrim-visible': !this.bottomBoundaryVisible,
|
|
330
|
+
};
|
|
331
|
+
},
|
|
332
|
+
itemTag() {
|
|
333
|
+
return this.listboxTag === 'ul' ? 'li' : 'div';
|
|
334
|
+
},
|
|
324
335
|
flattenedOptions() {
|
|
325
336
|
return flattenedOptions(this.items);
|
|
326
337
|
},
|
|
@@ -379,6 +390,12 @@ export default {
|
|
|
379
390
|
}
|
|
380
391
|
return toggleClasses;
|
|
381
392
|
},
|
|
393
|
+
hasHeader() {
|
|
394
|
+
return this.headerText || this.searchable;
|
|
395
|
+
},
|
|
396
|
+
hasFooter() {
|
|
397
|
+
return Boolean(this.$scopedSlots.footer);
|
|
398
|
+
},
|
|
382
399
|
},
|
|
383
400
|
watch: {
|
|
384
401
|
selected: {
|
|
@@ -394,6 +411,15 @@ export default {
|
|
|
394
411
|
}
|
|
395
412
|
},
|
|
396
413
|
},
|
|
414
|
+
items: {
|
|
415
|
+
handler() {
|
|
416
|
+
this.$nextTick(() => {
|
|
417
|
+
/* Every time the list of items changes (on search),
|
|
418
|
+
* the observed elements are recreated, thus we need to start obesrving them again */
|
|
419
|
+
this.observeScroll();
|
|
420
|
+
});
|
|
421
|
+
},
|
|
422
|
+
},
|
|
397
423
|
...(process.env.NODE_ENV !== 'production'
|
|
398
424
|
? {
|
|
399
425
|
resetButtonLabel: {
|
|
@@ -419,6 +445,12 @@ export default {
|
|
|
419
445
|
}
|
|
420
446
|
: {}),
|
|
421
447
|
},
|
|
448
|
+
mounted() {
|
|
449
|
+
this.observeScroll();
|
|
450
|
+
},
|
|
451
|
+
beforeDestroy() {
|
|
452
|
+
this.scrollObserver?.disconnect();
|
|
453
|
+
},
|
|
422
454
|
methods: {
|
|
423
455
|
open() {
|
|
424
456
|
this.$refs.baseDropdown.open();
|
|
@@ -581,6 +613,35 @@ export default {
|
|
|
581
613
|
'aria-posinset': index + 1,
|
|
582
614
|
};
|
|
583
615
|
},
|
|
616
|
+
observeScroll() {
|
|
617
|
+
const root = this.$refs.list;
|
|
618
|
+
|
|
619
|
+
const options = {
|
|
620
|
+
rootMargin: '8px',
|
|
621
|
+
root,
|
|
622
|
+
threshold: 1.0,
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
this.scrollObserver?.disconnect();
|
|
626
|
+
|
|
627
|
+
const observer = new IntersectionObserver((entries) => {
|
|
628
|
+
entries.forEach((entry) => {
|
|
629
|
+
this[entry.target?.$__visibilityProp] = entry.isIntersecting;
|
|
630
|
+
});
|
|
631
|
+
}, options);
|
|
632
|
+
|
|
633
|
+
const topBoundary = this.$refs['top-boundary'];
|
|
634
|
+
const bottomBoundary = this.$refs['bottom-boundary'];
|
|
635
|
+
if (topBoundary) {
|
|
636
|
+
topBoundary.$__visibilityProp = 'topBoundaryVisible';
|
|
637
|
+
observer.observe(topBoundary);
|
|
638
|
+
}
|
|
639
|
+
if (bottomBoundary) {
|
|
640
|
+
bottomBoundary.$__visibilityProp = 'bottomBoundaryVisible';
|
|
641
|
+
observer.observe(bottomBoundary);
|
|
642
|
+
}
|
|
643
|
+
this.scrollObserver = observer;
|
|
644
|
+
},
|
|
584
645
|
isOption,
|
|
585
646
|
},
|
|
586
647
|
};
|
|
@@ -663,10 +724,18 @@ export default {
|
|
|
663
724
|
ref="list"
|
|
664
725
|
:aria-labelledby="listAriaLabelledBy || headerId || toggleId"
|
|
665
726
|
role="listbox"
|
|
666
|
-
class="gl-new-dropdown-contents"
|
|
727
|
+
class="gl-new-dropdown-contents gl-new-dropdown-contents-with-scrim-overlay"
|
|
728
|
+
:class="listboxClasses"
|
|
667
729
|
tabindex="-1"
|
|
668
730
|
@keydown="onKeydown"
|
|
669
731
|
>
|
|
732
|
+
<component :is="itemTag" class="top-scrim-wrapper" aria-hidden="true" data-testid="top-scrim">
|
|
733
|
+
<div
|
|
734
|
+
class="top-scrim"
|
|
735
|
+
:class="{ 'top-scrim-light': !hasHeader, 'top-scrim-dark': hasHeader }"
|
|
736
|
+
></div>
|
|
737
|
+
</component>
|
|
738
|
+
<component :is="itemTag" ref="top-boundary" aria-hidden="true" />
|
|
670
739
|
<template v-for="(item, index) in items">
|
|
671
740
|
<template v-if="isOption(item)">
|
|
672
741
|
<gl-listbox-item
|
|
@@ -714,13 +783,22 @@ export default {
|
|
|
714
783
|
</gl-listbox-group>
|
|
715
784
|
</template>
|
|
716
785
|
</template>
|
|
717
|
-
<component :is="
|
|
786
|
+
<component :is="itemTag" v-if="infiniteScrollLoading">
|
|
718
787
|
<gl-loading-icon data-testid="listbox-infinite-scroll-loader" size="md" class="gl-my-3" />
|
|
719
788
|
</component>
|
|
720
789
|
<gl-intersection-observer
|
|
721
790
|
v-if="showIntersectionObserver"
|
|
722
791
|
@appear="onIntersectionObserverAppear"
|
|
723
792
|
/>
|
|
793
|
+
<component :is="itemTag" ref="bottom-boundary" aria-hidden="true" />
|
|
794
|
+
<component
|
|
795
|
+
:is="itemTag"
|
|
796
|
+
class="bottom-scrim-wrapper"
|
|
797
|
+
aria-hidden="true"
|
|
798
|
+
data-testid="bottom-scrim"
|
|
799
|
+
>
|
|
800
|
+
<div class="bottom-scrim" :class="{ 'gl-rounded-0!': hasFooter }"></div>
|
|
801
|
+
</component>
|
|
724
802
|
</component>
|
|
725
803
|
<span
|
|
726
804
|
v-if="announceSRSearchResults"
|