@gitlab/ui 108.10.0 → 109.0.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,33 @@
1
+ # [109.0.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v108.10.0...v109.0.0) (2025-03-03)
2
+
3
+
4
+ ### Code Refactoring
5
+
6
+ * **GlCollapse:** remove `BCollapse` component ([f53fdd4](https://gitlab.com/gitlab-org/gitlab-ui/commit/f53fdd4fc9d0ee3bfa01ad19cc209f54612ccda6))
7
+
8
+
9
+ ### BREAKING CHANGES
10
+
11
+ * **GlCollapse:** `GlCollapse` now has its own implementation and does not rely on
12
+ `BCollapse` anymore.
13
+
14
+ Drops support of the `toggle` directive for toggling the `GlCollapse`'s
15
+ state. Going forward, the `v-model` should be used instead.
16
+ Drops support of `hide`, `show` events.
17
+
18
+ Also drops supports of:
19
+ - `appear` prop
20
+ - `v-b-toggle`, which can be used to trigger multiple collapse elements
21
+ - turn a group of collapse components into an accordion with `accordion`
22
+ prop
23
+ - navbar support with `is-nav` prop
24
+ - $root event
25
+ - `show` and `hide` events
26
+
27
+ See bootstrap doc
28
+ (https://bootstrap-vue.org/docs/components/collapse#collapse) for
29
+ details.
30
+
1
31
  # [108.10.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v108.9.1...v108.10.0) (2025-03-03)
2
32
 
3
33
 
@@ -1,12 +1,9 @@
1
- import { BCollapse } from '../../../vendor/bootstrap-vue/src/components/collapse/collapse';
2
1
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
3
2
 
4
3
  //
4
+
5
5
  var script = {
6
6
  name: 'GlCollapse',
7
- components: {
8
- BCollapse
9
- },
10
7
  model: {
11
8
  prop: 'visible',
12
9
  event: 'input'
@@ -16,6 +13,109 @@ var script = {
16
13
  type: Boolean,
17
14
  default: false,
18
15
  required: false
16
+ },
17
+ tag: {
18
+ type: String,
19
+ required: false,
20
+ default: 'div'
21
+ }
22
+ },
23
+ data() {
24
+ return {
25
+ show: this.visible,
26
+ transitioning: false
27
+ };
28
+ },
29
+ computed: {
30
+ classObject() {
31
+ const {
32
+ transitioning
33
+ } = this;
34
+ return {
35
+ collapse: !transitioning,
36
+ show: this.show && !transitioning
37
+ };
38
+ },
39
+ slotScope() {
40
+ return {
41
+ visible: this.show,
42
+ close: () => {
43
+ this.show = false;
44
+ }
45
+ };
46
+ },
47
+ transitionProps() {
48
+ return {
49
+ ...this.$attrs,
50
+ css: true,
51
+ enterClass: '',
52
+ enterActiveClass: 'collapsing',
53
+ enterToClass: 'collapse show',
54
+ leaveClass: 'collapse show',
55
+ leaveActiveClass: 'collapsing',
56
+ leaveToClass: 'collapse'
57
+ };
58
+ }
59
+ },
60
+ watch: {
61
+ visible(newValue) {
62
+ if (newValue !== this.show) {
63
+ this.show = newValue;
64
+ }
65
+ },
66
+ show(newValue, oldValue) {
67
+ if (newValue !== oldValue) {
68
+ this.emitState();
69
+ }
70
+ }
71
+ },
72
+ mounted() {
73
+ this.$nextTick(() => {
74
+ this.emitState();
75
+ });
76
+ },
77
+ beforeDestroy() {
78
+ // Trigger state emit if needed
79
+ this.show = false;
80
+ },
81
+ methods: {
82
+ reflow(el) {
83
+ // Requesting an elements offsetHeight will trigger a reflow of the element content
84
+ // Without forcing a reflow, the browser optimize the operation and cause animation to fail
85
+ return Boolean(el && el.nodeType === Node.ELEMENT_NODE) && el.offsetHeight;
86
+ },
87
+ emitState() {
88
+ const {
89
+ show
90
+ } = this;
91
+ this.$emit('input', show);
92
+ },
93
+ enter(el) {
94
+ this.transitioning = true;
95
+ el.style.height = 0;
96
+ // In a `debounceByAnimationFrame()` for `appear` to work
97
+ window.requestAnimationFrame(() => {
98
+ this.reflow(el);
99
+ el.style.height = `${el.scrollHeight}px`;
100
+ });
101
+ },
102
+ afterEnter(el) {
103
+ this.transitioning = false;
104
+ this.$emit('shown');
105
+ el.style.height = '';
106
+ },
107
+ leave(el) {
108
+ this.transitioning = true;
109
+ el.style.height = 'auto';
110
+ el.style.display = 'block';
111
+ el.style.height = `${el.getBoundingClientRect().height}px`;
112
+ this.reflow(el);
113
+ el.style.height = 0;
114
+ },
115
+ afterLeave(el) {
116
+ this.transitioning = false;
117
+ this.$emit('hidden');
118
+ el.style.height = '';
19
119
  }
20
120
  }
21
121
  };
@@ -24,7 +124,7 @@ var script = {
24
124
  const __vue_script__ = script;
25
125
 
26
126
  /* template */
27
- var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('b-collapse',_vm._g(_vm._b({attrs:{"visible":_vm.visible}},'b-collapse',_vm.$attrs,false),_vm.$listeners),[_vm._t("default")],2)};
127
+ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('transition',_vm._g(_vm._b({attrs:{"visible":_vm.visible},on:{"enter":_vm.enter,"after-enter":_vm.afterEnter,"leave":_vm.leave,"afterLeave":_vm.afterLeave}},'transition',_vm.transitionProps,false),_vm.$listeners),[_c(_vm.tag,{directives:[{name:"show",rawName:"v-show",value:(_vm.show),expression:"show"}],tag:"component",class:_vm.classObject},[_vm._t("default",null,null,_vm.slotScope)],2)],1)};
28
128
  var __vue_staticRenderFns__ = [];
29
129
 
30
130
  /* style */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "108.10.0",
3
+ "version": "109.0.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -2,6 +2,44 @@ Collapse is used to keep pages focused on the overview of what the user can do.
2
2
  additional actions are hidden in the fold, and can be opened if the user wants to interact with
3
3
  those elements.
4
4
 
5
+ ## `v-model` support
6
+
7
+ The component's collapsed (visible) state can be set with `v-model` which binds internally to
8
+ the `visible` prop.
9
+
10
+ Note that when using `v-model` to control `<gl-collapse>`, the `aria-*` attributes are not
11
+ automatically placed on the trigger button. Specifically, you should add `aria-expanded` to
12
+ reflect the state of the target `<gl-collapse>` component, and `aria-controls` should be set
13
+ to the ID(s) of the target `<gl-collapse>` component(s).
14
+
15
+ ```html
16
+ <template>
17
+ <div>
18
+ <gl-button
19
+ :class="visible ? null : 'collapsed'"
20
+ :aria-expanded="visible ? 'true' : 'false'"
21
+ aria-controls="collapse-4"
22
+ @click="visible = !visible"
23
+ >
24
+ Toggle Collapse
25
+ </gl-button>
26
+ <gl-collapse id="collapse-4" v-model="visible">
27
+ <span>Surprise! But I am just a span</span>
28
+ </gl-collapse>
29
+ </div>
30
+ </template>
31
+
32
+ <script>
33
+ export default {
34
+ data() {
35
+ return {
36
+ visible: true
37
+ }
38
+ }
39
+ }
40
+ </script>
41
+ ```
42
+
5
43
  ## Troubleshooting
6
44
 
7
45
  When collapsing the container, padding on the collapse component causes
@@ -1,12 +1,7 @@
1
1
  <!-- eslint-disable vue/multi-word-component-names -->
2
2
  <script>
3
- import { BCollapse } from '../../../vendor/bootstrap-vue/src/components/collapse/collapse';
4
-
5
3
  export default {
6
4
  name: 'GlCollapse',
7
- components: {
8
- BCollapse,
9
- },
10
5
  model: {
11
6
  prop: 'visible',
12
7
  event: 'input',
@@ -17,13 +12,124 @@ export default {
17
12
  default: false,
18
13
  required: false,
19
14
  },
15
+ tag: {
16
+ type: String,
17
+ required: false,
18
+ default: 'div',
19
+ },
20
+ },
21
+ data() {
22
+ return {
23
+ show: this.visible,
24
+ transitioning: false,
25
+ };
26
+ },
27
+ computed: {
28
+ classObject() {
29
+ const { transitioning } = this;
30
+
31
+ return {
32
+ collapse: !transitioning,
33
+ show: this.show && !transitioning,
34
+ };
35
+ },
36
+ slotScope() {
37
+ return {
38
+ visible: this.show,
39
+ close: () => {
40
+ this.show = false;
41
+ },
42
+ };
43
+ },
44
+ transitionProps() {
45
+ return {
46
+ ...this.$attrs,
47
+ css: true,
48
+ enterClass: '',
49
+ enterActiveClass: 'collapsing',
50
+ enterToClass: 'collapse show',
51
+ leaveClass: 'collapse show',
52
+ leaveActiveClass: 'collapsing',
53
+ leaveToClass: 'collapse',
54
+ };
55
+ },
56
+ },
57
+ watch: {
58
+ visible(newValue) {
59
+ if (newValue !== this.show) {
60
+ this.show = newValue;
61
+ }
62
+ },
63
+ show(newValue, oldValue) {
64
+ if (newValue !== oldValue) {
65
+ this.emitState();
66
+ }
67
+ },
68
+ },
69
+ mounted() {
70
+ this.$nextTick(() => {
71
+ this.emitState();
72
+ });
73
+ },
74
+ beforeDestroy() {
75
+ // Trigger state emit if needed
76
+ this.show = false;
77
+ },
78
+ methods: {
79
+ reflow(el) {
80
+ // Requesting an elements offsetHeight will trigger a reflow of the element content
81
+ // Without forcing a reflow, the browser optimize the operation and cause animation to fail
82
+ return Boolean(el && el.nodeType === Node.ELEMENT_NODE) && el.offsetHeight;
83
+ },
84
+ emitState() {
85
+ const { show } = this;
86
+ this.$emit('input', show);
87
+ },
88
+ enter(el) {
89
+ this.transitioning = true;
90
+
91
+ el.style.height = 0;
92
+ // In a `debounceByAnimationFrame()` for `appear` to work
93
+ window.requestAnimationFrame(() => {
94
+ this.reflow(el);
95
+ el.style.height = `${el.scrollHeight}px`;
96
+ });
97
+ },
98
+ afterEnter(el) {
99
+ this.transitioning = false;
100
+ this.$emit('shown');
101
+ el.style.height = '';
102
+ },
103
+ leave(el) {
104
+ this.transitioning = true;
105
+ el.style.height = 'auto';
106
+ el.style.display = 'block';
107
+ el.style.height = `${el.getBoundingClientRect().height}px`;
108
+ this.reflow(el);
109
+ el.style.height = 0;
110
+ },
111
+ afterLeave(el) {
112
+ this.transitioning = false;
113
+ this.$emit('hidden');
114
+ el.style.height = '';
115
+ },
20
116
  },
21
117
  };
22
118
  </script>
23
119
 
24
120
  <template>
25
- <b-collapse :visible="visible" v-bind="$attrs" v-on="$listeners">
26
- <!-- @slot The content to show/hide. -->
27
- <slot></slot>
28
- </b-collapse>
121
+ <transition
122
+ :visible="visible"
123
+ v-bind="transitionProps"
124
+ v-on="$listeners"
125
+ @enter="enter"
126
+ @after-enter="afterEnter"
127
+ @leave="leave"
128
+ @afterLeave="afterLeave"
129
+ >
130
+ <component :is="tag" v-show="show" :class="classObject">
131
+ <!-- @slot The content to show/hide. -->
132
+ <slot v-bind="slotScope"></slot>
133
+ </component>
134
+ </transition>
29
135
  </template>