@gitlab/ui 78.2.3 → 78.4.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 CHANGED
@@ -1,3 +1,22 @@
1
+ # [78.4.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.3.0...v78.4.0) (2024-03-25)
2
+
3
+
4
+ ### Features
5
+
6
+ * **GlDuoChat:** trim the prompt ([89b1253](https://gitlab.com/gitlab-org/gitlab-ui/commit/89b125332b9674d97848cdb8586338147fa10b20))
7
+
8
+ # [78.3.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.2.3...v78.3.0) (2024-03-22)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **GlDisclosureDropdown:** Prevent unwanted slot overrides in Vue 3 ([6aef295](https://gitlab.com/gitlab-org/gitlab-ui/commit/6aef29519a86cbc187218ebe34437e98ddcdebd1))
14
+
15
+
16
+ ### Features
17
+
18
+ * **GlBreadcrumb:** Always show as many breadcrumbs as possible ([b58ba76](https://gitlab.com/gitlab-org/gitlab-ui/commit/b58ba764e40ee70eace928f4ffa849eeafff0455))
19
+
1
20
  ## [78.2.3](https://gitlab.com/gitlab-org/gitlab-ui/compare/v78.2.2...v78.2.3) (2024-03-21)
2
21
 
3
22
 
@@ -1,19 +1,20 @@
1
1
  import { BBreadcrumb } from 'bootstrap-vue/esm/index.js';
2
- import GlButton from '../button/button';
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
- isListCollapsed: true
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.breadcrumbsSize > COLLAPSE_AT_SIZE;
70
+ return this.overflowingItems.length > 0;
57
71
  },
58
- nonCollapsibleIndices() {
59
- return [0, this.breadcrumbsSize - 1, this.breadcrumbsSize - 2];
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
- isFirstItem(index) {
64
- return index === 0;
113
+ resetItems() {
114
+ this.fittingItems = [...this.items];
115
+ this.overflowingItems = [];
65
116
  },
66
- isLastItem(index) {
67
- return index === this.breadcrumbsSize - 1;
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
- expandBreadcrumbs() {
70
- this.isListCollapsed = false;
71
- try {
72
- this.$refs.firstItem[0].querySelector('a').focus();
73
- } catch (e) {
74
- /* eslint-disable-next-line no-console */
75
- console.error(`Failed to set focus on the first breadcrumb item.`);
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
- showCollapsedBreadcrumbsExpander(index) {
79
- return index === 0 && this.hasCollapsible && this.isListCollapsed;
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),[_vm._l((_vm.items),function(item,index){return [_c('gl-breadcrumb-item',{directives:[{name:"show",rawName:"v-show",value:(!_vm.isItemCollapsed(index)),expression:"!isItemCollapsed(index)"}],ref:_vm.isFirstItem(index) ? 'firstItem' : null,refInFor:true,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),_vm._v(" "),(_vm.showCollapsedBreadcrumbsExpander(index))?[_c('li',{staticClass:"gl-breadcrumb-item"},[_c('gl-button',{directives:[{name:"gl-tooltip",rawName:"v-gl-tooltip.hover",value:('Show all breadcrumbs'),expression:"'Show all breadcrumbs'",modifiers:{"hover":true}}],attrs:{"aria-label":"Show all breadcrumbs","data-testid":"collapsed-expander","icon":"ellipsis_h","category":"primary"},on:{"click":_vm.expandBreadcrumbs}})],1)]:_vm._e()]})],2)],1)};
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 */
@@ -269,7 +269,7 @@ var script = {
269
269
  *
270
270
  * @param {String} prompt The user prompt to send.
271
271
  */
272
- this.$emit('send-chat-prompt', this.prompt);
272
+ this.$emit('send-chat-prompt', this.prompt.trim());
273
273
  this.setPromptAndFocus();
274
274
  }
275
275
  },