@gitlab/ui 62.12.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "62.12.1",
3
+ "version": "63.1.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -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
- &:first-child {
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="listboxTag === 'ul' ? 'li' : 'div'" v-if="infiniteScrollLoading">
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"
@@ -2856,18 +2856,6 @@
2856
2856
  display: none !important;
2857
2857
  }
2858
2858
 
2859
- .gl-xs-display-none {
2860
- @include gl-media-breakpoint-down(sm) {
2861
- display: none;
2862
- }
2863
- }
2864
-
2865
- .gl-xs-display-none\! {
2866
- @include gl-media-breakpoint-down(sm) {
2867
- display: none !important;
2868
- }
2869
- }
2870
-
2871
2859
  .gl-sm-display-none {
2872
2860
  @include gl-media-breakpoint-up(sm) {
2873
2861
  display: none;
@@ -6769,16 +6757,6 @@
6769
6757
  margin-bottom: $gl-spacing-scale-3 !important;
6770
6758
  }
6771
6759
  }
6772
- .gl-xs-mb-4 {
6773
- @include gl-media-breakpoint-down(sm) {
6774
- margin-bottom: $gl-spacing-scale-4;
6775
- }
6776
- }
6777
- .gl-xs-mb-4\! {
6778
- @include gl-media-breakpoint-down(sm) {
6779
- margin-bottom: $gl-spacing-scale-4 !important;
6780
- }
6781
- }
6782
6760
  .gl-sm-ml-3 {
6783
6761
  @include gl-media-breakpoint-up(sm) {
6784
6762
  margin-left: $gl-spacing-scale-3;
@@ -7171,26 +7149,6 @@
7171
7149
  padding-right: $gl-spacing-scale-2 !important;
7172
7150
  }
7173
7151
  }
7174
- .gl-sm-pr-3 {
7175
- @include gl-media-breakpoint-down(sm) {
7176
- padding-right: $gl-spacing-scale-3;
7177
- }
7178
- }
7179
- .gl-sm-pr-3\! {
7180
- @include gl-media-breakpoint-down(sm) {
7181
- padding-right: $gl-spacing-scale-3 !important;
7182
- }
7183
- }
7184
- .gl-sm-pr-5 {
7185
- @include gl-media-breakpoint-down(sm) {
7186
- padding-right: $gl-spacing-scale-5;
7187
- }
7188
- }
7189
- .gl-sm-pr-5\! {
7190
- @include gl-media-breakpoint-down(sm) {
7191
- padding-right: $gl-spacing-scale-5 !important;
7192
- }
7193
- }
7194
7152
  .gl-sm-pl-0 {
7195
7153
  @include gl-media-breakpoint-up(sm) {
7196
7154
  padding-left: 0;
@@ -7201,16 +7159,6 @@
7201
7159
  padding-left: 0 !important;
7202
7160
  }
7203
7161
  }
7204
- .gl-sm-pl-5 {
7205
- @include gl-media-breakpoint-down(sm) {
7206
- padding-left: $gl-spacing-scale-5;
7207
- }
7208
- }
7209
- .gl-sm-pl-5\! {
7210
- @include gl-media-breakpoint-down(sm) {
7211
- padding-left: $gl-spacing-scale-5 !important;
7212
- }
7213
- }
7214
7162
  .gl-sm-pl-6 {
7215
7163
  @include gl-media-breakpoint-up(sm) {
7216
7164
  padding-left: $gl-spacing-scale-6;
@@ -7,13 +7,6 @@
7
7
  display: none;
8
8
  }
9
9
 
10
- @mixin gl-xs-display-none {
11
- // stylelint-disable-next-line @gitlab/no-gl-media-breakpoint-down
12
- @include gl-media-breakpoint-down(sm) {
13
- @include gl-display-none;
14
- }
15
- }
16
-
17
10
  @mixin gl-sm-display-none {
18
11
  @include gl-media-breakpoint-up(sm) {
19
12
  @include gl-display-none;
@@ -917,13 +917,6 @@
917
917
  }
918
918
  }
919
919
 
920
- @mixin gl-xs-mb-4 {
921
- // stylelint-disable-next-line @gitlab/no-gl-media-breakpoint-down
922
- @include gl-media-breakpoint-down(sm) {
923
- @include gl-mb-4;
924
- }
925
- }
926
-
927
920
  @mixin gl-sm-ml-3 {
928
921
  @include gl-media-breakpoint-up(sm) {
929
922
  @include gl-ml-3;
@@ -1161,33 +1154,12 @@
1161
1154
  }
1162
1155
  }
1163
1156
 
1164
- @mixin gl-sm-pr-3 {
1165
- // stylelint-disable-next-line @gitlab/no-gl-media-breakpoint-down
1166
- @include gl-media-breakpoint-down(sm) {
1167
- @include gl-pr-3;
1168
- }
1169
- }
1170
-
1171
- @mixin gl-sm-pr-5 {
1172
- // stylelint-disable-next-line @gitlab/no-gl-media-breakpoint-down
1173
- @include gl-media-breakpoint-down(sm) {
1174
- @include gl-pr-5;
1175
- }
1176
- }
1177
-
1178
1157
  @mixin gl-sm-pl-0 {
1179
1158
  @include gl-media-breakpoint-up(sm) {
1180
1159
  @include gl-pl-0;
1181
1160
  }
1182
1161
  }
1183
1162
 
1184
- @mixin gl-sm-pl-5 {
1185
- // stylelint-disable-next-line @gitlab/no-gl-media-breakpoint-down
1186
- @include gl-media-breakpoint-down(sm) {
1187
- @include gl-pl-5;
1188
- }
1189
- }
1190
-
1191
1163
  @mixin gl-sm-pl-6 {
1192
1164
  @include gl-media-breakpoint-up(sm) {
1193
1165
  @include gl-pl-6;