@gitlab/ui 103.5.0 → 103.6.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,17 @@
1
+ # [103.6.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v103.5.1...v103.6.0) (2024-11-26)
2
+
3
+
4
+ ### Features
5
+
6
+ * **Tailwind:** add status design tokens to Tailwind classes ([b57449f](https://gitlab.com/gitlab-org/gitlab-ui/commit/b57449f522dd4c38c58830cc84735658c12a09be))
7
+
8
+ ## [103.5.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v103.5.0...v103.5.1) (2024-11-26)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **GlIntersperse:** Ignore empty nodes in Vue 3 ([91ec35b](https://gitlab.com/gitlab-org/gitlab-ui/commit/91ec35b664aa9c8a8959247e92dd29c1409e57ea))
14
+
1
15
  # [103.5.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v103.4.1...v103.5.0) (2024-11-22)
2
16
 
3
17
 
@@ -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
  };
@@ -282,6 +282,32 @@ const brandColors = {
282
282
  },
283
283
  'brand-pink': { '01g': 'var(--gl-color-brand-pink-01g, #ffb9c9)' },
284
284
  };
285
+ const statusBackgroundColors = {
286
+ 'status-neutral':
287
+ 'var(--gl-status-neutral-background-color, var(--gl-color-neutral-100, #dcdcde))',
288
+ 'status-info': 'var(--gl-status-info-background-color, var(--gl-color-blue-100, #cbe2f9))',
289
+ 'status-success': 'var(--gl-status-success-background-color, var(--gl-color-green-100, #c3e6cd))',
290
+ 'status-warning':
291
+ 'var(--gl-status-warning-background-color, var(--gl-color-orange-100, #f5d9a8))',
292
+ 'status-danger': 'var(--gl-status-danger-background-color, var(--gl-color-red-100, #fdd4cd))',
293
+ 'status-brand': 'var(--gl-status-brand-background-color, var(--gl-color-purple-100, #e1d8f9))',
294
+ };
295
+ const statusTextColors = {
296
+ 'status-neutral': 'var(--gl-status-neutral-text-color, var(--gl-color-neutral-700, #4c4b51))',
297
+ 'status-info': 'var(--gl-status-info-text-color, var(--gl-color-blue-700, #0b5cad))',
298
+ 'status-success': 'var(--gl-status-success-text-color, var(--gl-color-green-700, #24663b))',
299
+ 'status-warning': 'var(--gl-status-warning-text-color, var(--gl-color-orange-700, #8f4700))',
300
+ 'status-danger': 'var(--gl-status-danger-text-color, var(--gl-color-red-700, #ae1800))',
301
+ 'status-brand': 'var(--gl-status-brand-text-color, var(--gl-color-purple-700, #5943b6))',
302
+ };
303
+ const statusIconColors = {
304
+ 'status-neutral': 'var(--gl-status-neutral-icon-color, var(--gl-color-neutral-500, #737278))',
305
+ 'status-info': 'var(--gl-status-info-icon-color, var(--gl-color-blue-500, #1f75cb))',
306
+ 'status-success': 'var(--gl-status-success-icon-color, var(--gl-color-green-500, #108548))',
307
+ 'status-warning': 'var(--gl-status-warning-icon-color, var(--gl-color-orange-500, #ab6100))',
308
+ 'status-danger': 'var(--gl-status-danger-icon-color, var(--gl-color-red-500, #dd2b0e))',
309
+ 'status-brand': 'var(--gl-status-brand-icon-color, var(--gl-color-purple-500, #7b58cf))',
310
+ };
285
311
 
286
312
  const colors = {
287
313
  inherit: 'inherit',
@@ -302,6 +328,7 @@ const colors = {
302
328
  const backgroundColor = {
303
329
  ...colors,
304
330
  ...backgroundColors,
331
+ ...statusBackgroundColors,
305
332
  dropdown: 'var(--gl-dropdown-background-color, var(--gl-background-color-overlap, #fff))',
306
333
  };
307
334
 
@@ -317,6 +344,7 @@ const outlineColor = {
317
344
 
318
345
  const fill = {
319
346
  ...colors,
347
+ ...statusIconColors,
320
348
  icon: {
321
349
  ...iconColors,
322
350
  },
@@ -325,6 +353,7 @@ const fill = {
325
353
  const textColor = {
326
354
  ...colors,
327
355
  ...textColors,
356
+ ...statusTextColors,
328
357
  primary: 'var(--gl-text-primary, #28272d)',
329
358
  secondary: 'var(--gl-text-secondary, #737278)',
330
359
  tertiary: 'var(--gl-text-tertiary, #89888d)',
@@ -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.6.0",
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';
@@ -282,6 +282,32 @@ const brandColors = {
282
282
  },
283
283
  'brand-pink': { '01g': 'var(--gl-color-brand-pink-01g, #ffb9c9)' },
284
284
  };
285
+ const statusBackgroundColors = {
286
+ 'status-neutral':
287
+ 'var(--gl-status-neutral-background-color, var(--gl-color-neutral-100, #dcdcde))',
288
+ 'status-info': 'var(--gl-status-info-background-color, var(--gl-color-blue-100, #cbe2f9))',
289
+ 'status-success': 'var(--gl-status-success-background-color, var(--gl-color-green-100, #c3e6cd))',
290
+ 'status-warning':
291
+ 'var(--gl-status-warning-background-color, var(--gl-color-orange-100, #f5d9a8))',
292
+ 'status-danger': 'var(--gl-status-danger-background-color, var(--gl-color-red-100, #fdd4cd))',
293
+ 'status-brand': 'var(--gl-status-brand-background-color, var(--gl-color-purple-100, #e1d8f9))',
294
+ };
295
+ const statusTextColors = {
296
+ 'status-neutral': 'var(--gl-status-neutral-text-color, var(--gl-color-neutral-700, #4c4b51))',
297
+ 'status-info': 'var(--gl-status-info-text-color, var(--gl-color-blue-700, #0b5cad))',
298
+ 'status-success': 'var(--gl-status-success-text-color, var(--gl-color-green-700, #24663b))',
299
+ 'status-warning': 'var(--gl-status-warning-text-color, var(--gl-color-orange-700, #8f4700))',
300
+ 'status-danger': 'var(--gl-status-danger-text-color, var(--gl-color-red-700, #ae1800))',
301
+ 'status-brand': 'var(--gl-status-brand-text-color, var(--gl-color-purple-700, #5943b6))',
302
+ };
303
+ const statusIconColors = {
304
+ 'status-neutral': 'var(--gl-status-neutral-icon-color, var(--gl-color-neutral-500, #737278))',
305
+ 'status-info': 'var(--gl-status-info-icon-color, var(--gl-color-blue-500, #1f75cb))',
306
+ 'status-success': 'var(--gl-status-success-icon-color, var(--gl-color-green-500, #108548))',
307
+ 'status-warning': 'var(--gl-status-warning-icon-color, var(--gl-color-orange-500, #ab6100))',
308
+ 'status-danger': 'var(--gl-status-danger-icon-color, var(--gl-color-red-500, #dd2b0e))',
309
+ 'status-brand': 'var(--gl-status-brand-icon-color, var(--gl-color-purple-500, #7b58cf))',
310
+ };
285
311
 
286
312
  const colors = {
287
313
  inherit: 'inherit',
@@ -302,6 +328,7 @@ const colors = {
302
328
  const backgroundColor = {
303
329
  ...colors,
304
330
  ...backgroundColors,
331
+ ...statusBackgroundColors,
305
332
  dropdown: 'var(--gl-dropdown-background-color, var(--gl-background-color-overlap, #fff))',
306
333
  };
307
334
 
@@ -317,6 +344,7 @@ const outlineColor = {
317
344
 
318
345
  const fill = {
319
346
  ...colors,
347
+ ...statusIconColors,
320
348
  icon: {
321
349
  ...iconColors,
322
350
  },
@@ -325,6 +353,7 @@ const fill = {
325
353
  const textColor = {
326
354
  ...colors,
327
355
  ...textColors,
356
+ ...statusTextColors,
328
357
  primary: 'var(--gl-text-primary, #28272d)',
329
358
  secondary: 'var(--gl-text-secondary, #737278)',
330
359
  tertiary: 'var(--gl-text-tertiary, #89888d)',
@@ -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
  }