@gitlab/ui 78.2.3 → 78.3.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 +12 -0
- package/dist/components/base/breadcrumb/breadcrumb.js +103 -29
- package/dist/components/base/new_dropdowns/disclosure/disclosure_dropdown.js +1 -1
- package/dist/index.css +1 -1
- package/dist/index.css.map +1 -1
- package/dist/tokens/css/tokens.css +1 -1
- package/dist/tokens/css/tokens.dark.css +1 -1
- package/dist/tokens/js/tokens.dark.js +1 -1
- package/dist/tokens/js/tokens.js +1 -1
- package/dist/tokens/scss/_tokens.dark.scss +1 -1
- package/dist/tokens/scss/_tokens.scss +1 -1
- package/package.json +2 -2
- package/src/components/base/breadcrumb/breadcrumb.scss +3 -6
- package/src/components/base/breadcrumb/breadcrumb.spec.js +74 -42
- package/src/components/base/breadcrumb/breadcrumb.stories.js +18 -1
- package/src/components/base/breadcrumb/breadcrumb.vue +133 -63
- package/src/components/base/new_dropdowns/disclosure/disclosure_dropdown.vue +1 -1
- package/translations.json +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [78.3.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.2.3...v78.3.0) (2024-03-22)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **GlDisclosureDropdown:** Prevent unwanted slot overrides in Vue 3 ([6aef295](https://gitlab.com/gitlab-org/gitlab-ui/commit/6aef29519a86cbc187218ebe34437e98ddcdebd1))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **GlBreadcrumb:** Always show as many breadcrumbs as possible ([b58ba76](https://gitlab.com/gitlab-org/gitlab-ui/commit/b58ba764e40ee70eace928f4ffa849eeafff0455))
|
|
12
|
+
|
|
1
13
|
## [78.2.3](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.2.2...v78.2.3) (2024-03-21)
|
|
2
14
|
|
|
3
15
|
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { BBreadcrumb } from 'bootstrap-vue/esm/index.js';
|
|
2
|
-
import
|
|
2
|
+
import debounce from 'lodash/debounce';
|
|
3
|
+
import { translate } from '../../../utils/i18n';
|
|
3
4
|
import GlAvatar from '../avatar/avatar';
|
|
5
|
+
import GlDisclosureDropdown from '../new_dropdowns/disclosure/disclosure_dropdown';
|
|
4
6
|
import { GlTooltipDirective } from '../../../directives/tooltip';
|
|
5
7
|
import GlBreadcrumbItem from './breadcrumb_item';
|
|
6
8
|
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
7
9
|
|
|
8
10
|
//
|
|
9
|
-
const COLLAPSE_AT_SIZE = 4;
|
|
10
11
|
var script = {
|
|
11
12
|
name: 'GlBreadcrumb',
|
|
12
13
|
components: {
|
|
13
14
|
BBreadcrumb,
|
|
14
|
-
GlButton,
|
|
15
15
|
GlBreadcrumbItem,
|
|
16
|
-
GlAvatar
|
|
16
|
+
GlAvatar,
|
|
17
|
+
GlDisclosureDropdown
|
|
17
18
|
},
|
|
18
19
|
directives: {
|
|
19
20
|
GlTooltip: GlTooltipDirective
|
|
@@ -41,45 +42,119 @@ var script = {
|
|
|
41
42
|
type: String,
|
|
42
43
|
required: false,
|
|
43
44
|
default: 'Breadcrumb'
|
|
45
|
+
},
|
|
46
|
+
/**
|
|
47
|
+
* The label for the collapsed dropdown toggle. Screen-reader only.
|
|
48
|
+
*/
|
|
49
|
+
showMoreLabel: {
|
|
50
|
+
type: String,
|
|
51
|
+
required: false,
|
|
52
|
+
default: () => translate('GlBreadcrumb.showMoreLabel', 'Show more breadcrumbs')
|
|
44
53
|
}
|
|
45
54
|
},
|
|
46
55
|
data() {
|
|
47
56
|
return {
|
|
48
|
-
|
|
57
|
+
fittingItems: [...this.items],
|
|
58
|
+
// array of items that fit on the screen
|
|
59
|
+
overflowingItems: [],
|
|
60
|
+
// array of items that didn't fit and were put in a dropdown instead
|
|
61
|
+
totalBreadcrumbsWidth: 0,
|
|
62
|
+
// the total width of all breadcrumb items combined
|
|
63
|
+
widthPerItem: [],
|
|
64
|
+
// array with the indivudal widths of each breadcrumb item
|
|
65
|
+
resizeDone: false // to apply some CSS only during/after resizing
|
|
49
66
|
};
|
|
50
67
|
},
|
|
51
68
|
computed: {
|
|
52
|
-
breadcrumbsSize() {
|
|
53
|
-
return this.items.length;
|
|
54
|
-
},
|
|
55
69
|
hasCollapsible() {
|
|
56
|
-
return this.
|
|
70
|
+
return this.overflowingItems.length > 0;
|
|
57
71
|
},
|
|
58
|
-
|
|
59
|
-
return
|
|
72
|
+
breadcrumbStyle() {
|
|
73
|
+
return this.resizeDone ? {} : {
|
|
74
|
+
opacity: 0
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
itemStyle() {
|
|
78
|
+
/**
|
|
79
|
+
* If the last/only item, which is always visible, has a very long title,
|
|
80
|
+
* it could overflow the breadcrumb component. This CSS makes sure it
|
|
81
|
+
* shows an ellipsis instead.
|
|
82
|
+
* But this CSS cannot be active while we do the size calculation, as that
|
|
83
|
+
* would then not take the real unshrunk width of that item into account.
|
|
84
|
+
*/
|
|
85
|
+
if (this.resizeDone && this.fittingItems.length === 1) {
|
|
86
|
+
return {
|
|
87
|
+
'flex-shrink': 1,
|
|
88
|
+
'text-overflow': 'ellipsis',
|
|
89
|
+
'overflow-x': 'hidden',
|
|
90
|
+
'text-wrap': 'nowrap'
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
watch: {
|
|
97
|
+
items: {
|
|
98
|
+
handler: 'measureAndMakeBreadcrumbsFit',
|
|
99
|
+
deep: true
|
|
60
100
|
}
|
|
61
101
|
},
|
|
102
|
+
created() {
|
|
103
|
+
this.debounceMakeBreadcrumbsFit = debounce(this.makeBreadcrumbsFit, 25);
|
|
104
|
+
},
|
|
105
|
+
mounted() {
|
|
106
|
+
window.addEventListener('resize', this.debounceMakeBreadcrumbsFit);
|
|
107
|
+
this.measureAndMakeBreadcrumbsFit();
|
|
108
|
+
},
|
|
109
|
+
beforeDestroy() {
|
|
110
|
+
window.removeEventListener('resize', this.debounceMakeBreadcrumbsFit);
|
|
111
|
+
},
|
|
62
112
|
methods: {
|
|
63
|
-
|
|
64
|
-
|
|
113
|
+
resetItems() {
|
|
114
|
+
this.fittingItems = [...this.items];
|
|
115
|
+
this.overflowingItems = [];
|
|
65
116
|
},
|
|
66
|
-
|
|
67
|
-
|
|
117
|
+
async measureAndMakeBreadcrumbsFit() {
|
|
118
|
+
this.resizeDone = false;
|
|
119
|
+
this.resetItems();
|
|
120
|
+
|
|
121
|
+
// Wait for DOM update so all items get rendered and can be measured.
|
|
122
|
+
await this.$nextTick();
|
|
123
|
+
this.totalBreadcrumbsWidth = 0;
|
|
124
|
+
this.$refs.breadcrumbs.forEach((b, index) => {
|
|
125
|
+
const width = b.$el.clientWidth;
|
|
126
|
+
this.totalBreadcrumbsWidth += width;
|
|
127
|
+
this.widthPerItem[index] = width;
|
|
128
|
+
});
|
|
129
|
+
this.makeBreadcrumbsFit();
|
|
68
130
|
},
|
|
69
|
-
|
|
70
|
-
this.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
131
|
+
makeBreadcrumbsFit() {
|
|
132
|
+
this.resizeDone = false;
|
|
133
|
+
this.resetItems();
|
|
134
|
+
const containerWidth = this.$el.clientWidth;
|
|
135
|
+
const buttonWidth = 50; // px
|
|
136
|
+
|
|
137
|
+
if (this.totalBreadcrumbsWidth + buttonWidth > containerWidth) {
|
|
138
|
+
// Not all breadcrumb items fit. Start moving items over to the dropdown.
|
|
139
|
+
const startSlicingAt = 0;
|
|
140
|
+
|
|
141
|
+
// The last item will never be moved into the dropdown.
|
|
142
|
+
const stopSlicingAt = this.items.length - 1;
|
|
143
|
+
let widthNeeded = this.totalBreadcrumbsWidth;
|
|
144
|
+
for (let index = startSlicingAt; index < stopSlicingAt; index += 1) {
|
|
145
|
+
// Move one breadcrumb item into the dropdown
|
|
146
|
+
this.overflowingItems.push(this.fittingItems[startSlicingAt]);
|
|
147
|
+
this.fittingItems.splice(startSlicingAt, 1);
|
|
148
|
+
widthNeeded -= this.widthPerItem[index];
|
|
149
|
+
|
|
150
|
+
// Does it fit now? Then stop.
|
|
151
|
+
if (widthNeeded + buttonWidth < containerWidth) break;
|
|
152
|
+
}
|
|
76
153
|
}
|
|
154
|
+
this.resizeDone = true;
|
|
77
155
|
},
|
|
78
|
-
|
|
79
|
-
return index ===
|
|
80
|
-
},
|
|
81
|
-
isItemCollapsed(index) {
|
|
82
|
-
return this.hasCollapsible && this.isListCollapsed && !this.nonCollapsibleIndices.includes(index);
|
|
156
|
+
isLastItem(index) {
|
|
157
|
+
return index === this.fittingItems.length - 1;
|
|
83
158
|
},
|
|
84
159
|
getAriaCurrentAttr(index) {
|
|
85
160
|
return this.isLastItem(index) ? 'page' : false;
|
|
@@ -91,7 +166,7 @@ var script = {
|
|
|
91
166
|
const __vue_script__ = script;
|
|
92
167
|
|
|
93
168
|
/* template */
|
|
94
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('nav',{staticClass:"gl-breadcrumbs",attrs:{"aria-label":_vm.ariaLabel}},[_c('b-breadcrumb',_vm._g(_vm._b({staticClass:"gl-breadcrumb-list"},'b-breadcrumb',_vm.$attrs,false),_vm.$listeners),[
|
|
169
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('nav',{staticClass:"gl-breadcrumbs",style:(_vm.breadcrumbStyle),attrs:{"aria-label":_vm.ariaLabel}},[_c('b-breadcrumb',_vm._g(_vm._b({staticClass:"gl-breadcrumb-list"},'b-breadcrumb',_vm.$attrs,false),_vm.$listeners),[(_vm.hasCollapsible)?_c('li',{staticClass:"gl-breadcrumb-item"},[_c('gl-disclosure-dropdown',{staticStyle:{"height":"16px"},attrs:{"items":_vm.overflowingItems,"toggle-text":_vm.showMoreLabel,"fluid-width":"","text-sr-only":"","no-caret":"","icon":"ellipsis_h","size":"small","placement":"left"}})],1):_vm._e(),_vm._v(" "),_vm._l((_vm.fittingItems),function(item,index){return _c('gl-breadcrumb-item',{ref:"breadcrumbs",refInFor:true,style:(_vm.itemStyle),attrs:{"text":item.text,"href":item.href,"to":item.to,"aria-current":_vm.getAriaCurrentAttr(index)}},[(item.avatarPath)?_c('gl-avatar',{staticClass:"gl-breadcrumb-avatar-tile gl-border gl-mr-2 gl-rounded-base!",attrs:{"src":item.avatarPath,"size":16,"aria-hidden":"true","shape":"rect","data-testid":"avatar"}}):_vm._e(),_c('span',[_vm._v(_vm._s(item.text))])],1)})],2)],1)};
|
|
95
170
|
var __vue_staticRenderFns__ = [];
|
|
96
171
|
|
|
97
172
|
/* style */
|
|
@@ -124,4 +199,3 @@ var __vue_staticRenderFns__ = [];
|
|
|
124
199
|
);
|
|
125
200
|
|
|
126
201
|
export default __vue_component__;
|
|
127
|
-
export { COLLAPSE_AT_SIZE };
|
|
@@ -334,7 +334,7 @@ var script = {
|
|
|
334
334
|
const __vue_script__ = script;
|
|
335
335
|
|
|
336
336
|
/* template */
|
|
337
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-base-dropdown',{ref:"baseDropdown",staticClass:"gl-disclosure-dropdown",attrs:{"aria-labelledby":_vm.toggleAriaLabelledBy,"toggle-id":_vm.toggleId,"toggle-text":_vm.toggleText,"toggle-class":_vm.toggleClass,"text-sr-only":_vm.textSrOnly,"category":_vm.category,"variant":_vm.variant,"size":_vm.size,"icon":_vm.icon,"disabled":_vm.disabled,"loading":_vm.loading,"no-caret":_vm.noCaret,"placement":_vm.placement,"block":_vm.block,"offset":_vm.dropdownOffset,"fluid-width":_vm.fluidWidth,"positioning-strategy":_vm.positioningStrategy},on:_vm._d({},[_vm.$options.events.GL_DROPDOWN_SHOWN,_vm.onShow,_vm.$options.events.GL_DROPDOWN_HIDDEN,_vm.onHide,_vm.$options.events.GL_DROPDOWN_BEFORE_CLOSE,_vm.onBeforeClose,_vm.$options.events.GL_DROPDOWN_FOCUS_CONTENT,_vm.onKeydown]),scopedSlots:_vm._u([(_vm.hasCustomToggle)?{key:"toggle",fn:function(){return [_vm._t("toggle")]},proxy:true}:null],null,true)},[_vm._v(" "),_vm._t("header"),_vm._v(" "),_c(_vm.disclosureTag,{ref:"content",tag:"component",class:_vm.$options.GL_DROPDOWN_CONTENTS_CLASS,attrs:{"id":_vm.disclosureId,"aria-labelledby":_vm.listAriaLabelledBy || _vm.toggleId,"data-testid":"disclosure-content","tabindex":"-1"},on:{"keydown":_vm.onKeydown,"click":_vm.handleAutoClose}},[_vm._t("default",function(){return [_vm._l((_vm.items),function(item,index){return [(_vm.isItem(item))?[_c('gl-disclosure-dropdown-item',{key:_vm.uniqueItemId(),attrs:{"item":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":item})]},proxy:true}],null,true)})]:[_c('gl-disclosure-dropdown-group',{key:item.name,attrs:{"bordered":index !== 0,"group":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([(_vm.$scopedSlots['group-label'])?{key:"group-label",fn:function(){return [_vm._t("group-label",null,{"group":item})]},proxy:true}:null],null,true)},[_vm._v(" "),(_vm.$scopedSlots['list-item'])?_vm._l((item.items),function(groupItem){return _c('gl-disclosure-dropdown-item',{key:_vm.uniqueItemId(),attrs:{"item":groupItem},on:{"action":_vm.handleAction},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":groupItem})]},proxy:true}],null,true)})}):_vm._e()],2)]]})]})],2),_vm._v(" "),_vm._t("footer")],2)};
|
|
337
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('gl-base-dropdown',{ref:"baseDropdown",staticClass:"gl-disclosure-dropdown",attrs:{"aria-labelledby":_vm.toggleAriaLabelledBy,"toggle-id":_vm.toggleId,"toggle-text":_vm.toggleText,"toggle-class":_vm.toggleClass,"text-sr-only":_vm.textSrOnly,"category":_vm.category,"variant":_vm.variant,"size":_vm.size,"icon":_vm.icon,"disabled":_vm.disabled,"loading":_vm.loading,"no-caret":_vm.noCaret,"placement":_vm.placement,"block":_vm.block,"offset":_vm.dropdownOffset,"fluid-width":_vm.fluidWidth,"positioning-strategy":_vm.positioningStrategy},on:_vm._d({},[_vm.$options.events.GL_DROPDOWN_SHOWN,_vm.onShow,_vm.$options.events.GL_DROPDOWN_HIDDEN,_vm.onHide,_vm.$options.events.GL_DROPDOWN_BEFORE_CLOSE,_vm.onBeforeClose,_vm.$options.events.GL_DROPDOWN_FOCUS_CONTENT,_vm.onKeydown]),scopedSlots:_vm._u([(_vm.hasCustomToggle)?{key:"toggle",fn:function(){return [_vm._t("toggle")]},proxy:true}:null],null,true)},[_vm._v(" "),_vm._t("header"),_vm._v(" "),_c(_vm.disclosureTag,{ref:"content",tag:"component",class:_vm.$options.GL_DROPDOWN_CONTENTS_CLASS,attrs:{"id":_vm.disclosureId,"aria-labelledby":_vm.listAriaLabelledBy || _vm.toggleId,"data-testid":"disclosure-content","tabindex":"-1"},on:{"keydown":_vm.onKeydown,"click":_vm.handleAutoClose}},[_vm._t("default",function(){return [_vm._l((_vm.items),function(item,index){return [(_vm.isItem(item))?[_c('gl-disclosure-dropdown-item',{key:_vm.uniqueItemId(),attrs:{"item":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([('list-item' in _vm.$scopedSlots)?{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":item})]},proxy:true}:null],null,true)})]:[_c('gl-disclosure-dropdown-group',{key:item.name,attrs:{"bordered":index !== 0,"group":item},on:{"action":_vm.handleAction},scopedSlots:_vm._u([(_vm.$scopedSlots['group-label'])?{key:"group-label",fn:function(){return [_vm._t("group-label",null,{"group":item})]},proxy:true}:null],null,true)},[_vm._v(" "),(_vm.$scopedSlots['list-item'])?_vm._l((item.items),function(groupItem){return _c('gl-disclosure-dropdown-item',{key:_vm.uniqueItemId(),attrs:{"item":groupItem},on:{"action":_vm.handleAction},scopedSlots:_vm._u([{key:"list-item",fn:function(){return [_vm._t("list-item",null,{"item":groupItem})]},proxy:true}],null,true)})}):_vm._e()],2)]]})]})],2),_vm._v(" "),_vm._t("footer")],2)};
|
|
338
338
|
var __vue_staticRenderFns__ = [];
|
|
339
339
|
|
|
340
340
|
/* style */
|