@gitlab/ui 103.5.0 → 103.5.1

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,10 @@
1
+ ## [103.5.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v103.5.0...v103.5.1) (2024-11-26)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **GlIntersperse:** Ignore empty nodes in Vue 3 ([91ec35b](https://gitlab.com/gitlab-org/gitlab-ui/commit/91ec35b664aa9c8a8959247e92dd29c1409e57ea))
7
+
1
8
  # [103.5.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v103.4.1...v103.5.0) (2024-11-22)
2
9
 
3
10
 
@@ -1,13 +1,27 @@
1
+ import Vue from 'vue';
1
2
  import compose from 'lodash/fp/compose';
2
3
  import fill from 'lodash/fp/fill';
3
4
  import filter from 'lodash/fp/filter';
4
5
  import { insert, intersperse } from '../../../utils/data_utils';
6
+ import { isVnodeEmpty } from '../../../utils/is_slot_empty';
5
7
  import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
6
8
 
7
9
  //
8
- const containsWhitespaceOnly = vNode => vNode.text.trim() === '';
9
- const isTag = vNode => typeof vNode.tag === 'string';
10
- const filterWhitespaceNodes = filter(vNode => isTag(vNode) || !containsWhitespaceOnly(vNode));
10
+ const filterEmptyNodesVue2 = filter(vNode => typeof vNode.tag === 'string' || vNode.text.trim() !== '');
11
+ const {
12
+ Fragment
13
+ } = Vue;
14
+ const filterEmptyNodesVue3 = vNode => {
15
+ return vNode.reduce((acc, node) => {
16
+ if (Fragment && node.type === Fragment && Array.isArray(node.children)) {
17
+ acc.push(...node.children);
18
+ } else {
19
+ acc.push(node);
20
+ }
21
+ return acc;
22
+ }, []).filter(node => !isVnodeEmpty(node));
23
+ };
24
+ const filterEmptyNodes = Vue.version.startsWith('3') ? filterEmptyNodesVue3 : filterEmptyNodesVue2;
11
25
  const insertAfterSecondLastItem = insert(-1);
12
26
  const replaceSecondLastItem = fill(-2, -1);
13
27
 
@@ -44,7 +58,7 @@ var script = {
44
58
  slots,
45
59
  data
46
60
  } = context;
47
- const filterAndSeparate = compose(addLastSeparator(lastSeparator), intersperse(separator), filterWhitespaceNodes);
61
+ const filterAndSeparate = compose(addLastSeparator(lastSeparator), intersperse(separator), filterEmptyNodes);
48
62
  return createElement('span', data, filterAndSeparate(slots().default));
49
63
  }
50
64
  };
@@ -3,23 +3,28 @@ import Vue from 'vue';
3
3
  // Fragment will be available only in Vue.js 3
4
4
  const {
5
5
  Fragment,
6
- Comment
6
+ Comment,
7
+ Text
7
8
  } = Vue;
8
9
  function callIfNeeded(fnOrResult, args) {
9
10
  return fnOrResult instanceof Function ? fnOrResult(args) : fnOrResult;
10
11
  }
11
- function isEmpty(vnode) {
12
+ function isVnodeEmpty(vnode) {
12
13
  if (!vnode || Comment && vnode.type === Comment) {
13
14
  return true;
14
15
  }
16
+ if (Text && vnode.type === Text && !vnode.children.trim()) {
17
+ // Vue.js 3 text string is located in the children
18
+ return true;
19
+ }
15
20
  if (Array.isArray(vnode)) {
16
21
  // eslint-disable-next-line unicorn/no-array-callback-reference
17
- return vnode.every(isEmpty);
22
+ return vnode.every(isVnodeEmpty);
18
23
  }
19
24
  if (Fragment && vnode.type === Fragment) {
20
25
  // Vue.js 3 fragment, check children
21
26
  // eslint-disable-next-line unicorn/no-array-callback-reference
22
- return vnode.children.every(isEmpty);
27
+ return vnode.children.every(isVnodeEmpty);
23
28
  }
24
29
  return false;
25
30
  }
@@ -32,7 +37,7 @@ function isSlotEmpty(vueInstance, slot, slotArgs) {
32
37
  callIfNeeded(vueInstance.$slots[slot] || vueInstance.$scopedSlots[slot], slotArgs) : (_vueInstance$$scopedS = (_vueInstance$$scopedS2 = vueInstance.$scopedSlots)[slot]) === null || _vueInstance$$scopedS === void 0 ? void 0 : _vueInstance$$scopedS.call(_vueInstance$$scopedS2, slotArgs);
33
38
 
34
39
  // eslint-disable-next-line unicorn/no-array-callback-reference
35
- return isEmpty(slotContent);
40
+ return isVnodeEmpty(slotContent);
36
41
  }
37
42
 
38
- export { isSlotEmpty };
43
+ export { isSlotEmpty, isVnodeEmpty };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "103.5.0",
3
+ "version": "103.5.1",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -143,16 +143,17 @@
143
143
  "axe-core": "^4.2.3",
144
144
  "babel-jest": "29.0.1",
145
145
  "babel-loader": "^8.0.5",
146
- "cypress": "13.15.2",
146
+ "cypress": "13.16.0",
147
147
  "cypress-axe": "^1.4.0",
148
148
  "cypress-real-events": "^1.11.0",
149
149
  "dompurify": "^3.1.2",
150
150
  "emoji-regex": "^10.0.0",
151
151
  "esbuild": "^0.18.0",
152
152
  "eslint": "8.57.1",
153
+ "eslint-formatter-gitlab": "^5.1.0",
153
154
  "eslint-import-resolver-jest": "3.0.2",
154
155
  "eslint-plugin-cypress": "3.6.0",
155
- "eslint-plugin-storybook": "0.10.1",
156
+ "eslint-plugin-storybook": "0.11.1",
156
157
  "gitlab-api-async-iterator": "^1.3.1",
157
158
  "glob": "10.3.3",
158
159
  "globby": "^11.1.0",
@@ -167,8 +168,8 @@
167
168
  "module-alias": "^2.2.2",
168
169
  "npm-run-all": "^4.1.5",
169
170
  "pikaday": "^1.8.0",
170
- "playwright": "^1.48.2",
171
- "playwright-core": "^1.48.2",
171
+ "playwright": "^1.49.0",
172
+ "playwright-core": "^1.49.0",
172
173
  "postcss": "8.4.28",
173
174
  "postcss-loader": "^7.0.2",
174
175
  "postcss-scss": "4.0.4",
@@ -1,15 +1,31 @@
1
1
  <!-- eslint-disable vue/multi-word-component-names -->
2
2
  <script>
3
+ import Vue from 'vue';
3
4
  import compose from 'lodash/fp/compose';
4
5
  import fill from 'lodash/fp/fill';
5
6
  import filter from 'lodash/fp/filter';
6
-
7
7
  import { intersperse, insert } from '../../../utils/data_utils';
8
+ import { isVnodeEmpty } from '../../../utils/is_slot_empty';
9
+
10
+ const filterEmptyNodesVue2 = filter(
11
+ (vNode) => typeof vNode.tag === 'string' || vNode.text.trim() !== ''
12
+ );
8
13
 
9
- const containsWhitespaceOnly = (vNode) => vNode.text.trim() === '';
10
- const isTag = (vNode) => typeof vNode.tag === 'string';
11
- const filterWhitespaceNodes = filter((vNode) => isTag(vNode) || !containsWhitespaceOnly(vNode));
14
+ const { Fragment } = Vue;
15
+ const filterEmptyNodesVue3 = (vNode) => {
16
+ return vNode
17
+ .reduce((acc, node) => {
18
+ if (Fragment && node.type === Fragment && Array.isArray(node.children)) {
19
+ acc.push(...node.children);
20
+ } else {
21
+ acc.push(node);
22
+ }
23
+ return acc;
24
+ }, [])
25
+ .filter((node) => !isVnodeEmpty(node));
26
+ };
12
27
 
28
+ const filterEmptyNodes = Vue.version.startsWith('3') ? filterEmptyNodesVue3 : filterEmptyNodesVue2;
13
29
  const insertAfterSecondLastItem = insert(-1);
14
30
  const replaceSecondLastItem = fill(-2, -1);
15
31
 
@@ -51,7 +67,7 @@ export default {
51
67
  const filterAndSeparate = compose(
52
68
  addLastSeparator(lastSeparator),
53
69
  intersperse(separator),
54
- filterWhitespaceNodes
70
+ filterEmptyNodes
55
71
  );
56
72
 
57
73
  return createElement('span', data, filterAndSeparate(slots().default));
package/src/index.js CHANGED
@@ -4,7 +4,6 @@
4
4
  // builds. We do this to avoid having the stylesheet included multiple times in Storybook.
5
5
 
6
6
  // Components
7
- // ADD COMPONENT EXPORTS - needed for yarn generate:component. Do not remove
8
7
  export { default as GlDuoWorkflowPrompt } from './components/experimental/duo/workflow/components/duo_workflow_prompt/duo_workflow_prompt.vue';
9
8
  export { default as GlDuoWorkflowPanel } from './components/experimental/duo/workflow/components/duo_workflow_panel/duo_workflow_panel.vue';
10
9
  export { default as GlTableLite } from './components/base/table_lite/table_lite.vue';
@@ -2,7 +2,6 @@
2
2
  // Import component stylesheets located in components here. i.e.
3
3
  // @import '../components/base/dropdown/dropdown'
4
4
  //
5
- // ADD COMPONENT IMPORTS - needed for yarn generate:component. Do not remove
6
5
  @import '../components/experimental/duo/chat/duo_chat';
7
6
  @import '../components/experimental/duo/chat/components/duo_chat_message/duo_chat_message';
8
7
  @import '../components/experimental/duo/chat/components/duo_chat_loader/duo_chat_loader';
@@ -1,26 +1,31 @@
1
1
  import Vue from 'vue';
2
2
 
3
3
  // Fragment will be available only in Vue.js 3
4
- const { Fragment, Comment } = Vue;
4
+ const { Fragment, Comment, Text } = Vue;
5
5
 
6
6
  function callIfNeeded(fnOrResult, args) {
7
7
  return fnOrResult instanceof Function ? fnOrResult(args) : fnOrResult;
8
8
  }
9
9
 
10
- function isEmpty(vnode) {
10
+ export function isVnodeEmpty(vnode) {
11
11
  if (!vnode || (Comment && vnode.type === Comment)) {
12
12
  return true;
13
13
  }
14
14
 
15
+ if (Text && vnode.type === Text && !vnode.children.trim()) {
16
+ // Vue.js 3 text string is located in the children
17
+ return true;
18
+ }
19
+
15
20
  if (Array.isArray(vnode)) {
16
21
  // eslint-disable-next-line unicorn/no-array-callback-reference
17
- return vnode.every(isEmpty);
22
+ return vnode.every(isVnodeEmpty);
18
23
  }
19
24
 
20
25
  if (Fragment && vnode.type === Fragment) {
21
26
  // Vue.js 3 fragment, check children
22
27
  // eslint-disable-next-line unicorn/no-array-callback-reference
23
- return vnode.children.every(isEmpty);
28
+ return vnode.children.every(isVnodeEmpty);
24
29
  }
25
30
 
26
31
  return false;
@@ -36,5 +41,5 @@ export function isSlotEmpty(vueInstance, slot, slotArgs) {
36
41
  : vueInstance.$scopedSlots[slot]?.(slotArgs);
37
42
 
38
43
  // eslint-disable-next-line unicorn/no-array-callback-reference
39
- return isEmpty(slotContent);
44
+ return isVnodeEmpty(slotContent);
40
45
  }