@gitlab/ui 108.3.1 → 108.4.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.
@@ -171,6 +171,12 @@ const animatedIconVariantOptions = {
171
171
  danger: 'gl-animated-icon-danger',
172
172
  success: 'gl-animated-icon-success'
173
173
  };
174
+ const linkVariantOptions = {
175
+ inline: 'gl-link-inline',
176
+ meta: 'gl-link-meta',
177
+ mention: 'gl-link-mention',
178
+ mentionCurrent: 'gl-link-mention-current'
179
+ };
174
180
  const triggerVariantOptions = {
175
181
  click: 'click',
176
182
  hover: 'hover',
@@ -311,4 +317,4 @@ const loadingIconVariants = {
311
317
  dots: 'dots'
312
318
  };
313
319
 
314
- export { COMMA, CONTRAST_LEVELS, HEX_REGEX, LEFT_MOUSE_BUTTON, alertVariantIconMap, alertVariantOptions, alignOptions, animatedIconVariantOptions, avatarShapeOptions, avatarSizeOptions, avatarsInlineSizeOptions, badgeForButtonOptions, badgeIconSizeOptions, badgeSizeOptions, badgeVariantOptions, bannerVariants, breadCrumbSizeOptions, buttonCategoryOptions, buttonSizeOptions, buttonVariantOptions, colorThemes, columnOptions, datepickerWidthOptionsMap, defaultDateFormat, drawerVariants, dropdownAllowedAutoPlacements, dropdownItemVariantOptions, dropdownPlacements, dropdownVariantOptions, focusableTags, formInputWidths, formStateOptions, iconSizeOptions, iconVariantOptions, keyboard, labelColorOptions, loadingIconSizes, loadingIconVariants, maxZIndex, modalButtonDefaults, modalSizeOptions, popoverPlacements, progressBarVariantOptions, resizeDebounceTime, tabsButtonDefaults, targetOptions, toggleLabelPosition, tokenVariants, tooltipActionEvents, tooltipDelay, tooltipPlacements, triggerVariantOptions, truncateOptions, variantCssColorMap, viewModeOptions };
320
+ export { COMMA, CONTRAST_LEVELS, HEX_REGEX, LEFT_MOUSE_BUTTON, alertVariantIconMap, alertVariantOptions, alignOptions, animatedIconVariantOptions, avatarShapeOptions, avatarSizeOptions, avatarsInlineSizeOptions, badgeForButtonOptions, badgeIconSizeOptions, badgeSizeOptions, badgeVariantOptions, bannerVariants, breadCrumbSizeOptions, buttonCategoryOptions, buttonSizeOptions, buttonVariantOptions, colorThemes, columnOptions, datepickerWidthOptionsMap, defaultDateFormat, drawerVariants, dropdownAllowedAutoPlacements, dropdownItemVariantOptions, dropdownPlacements, dropdownVariantOptions, focusableTags, formInputWidths, formStateOptions, iconSizeOptions, iconVariantOptions, keyboard, labelColorOptions, linkVariantOptions, loadingIconSizes, loadingIconVariants, maxZIndex, modalButtonDefaults, modalSizeOptions, popoverPlacements, progressBarVariantOptions, resizeDebounceTime, tabsButtonDefaults, targetOptions, toggleLabelPosition, tokenVariants, tooltipActionEvents, tooltipDelay, tooltipPlacements, triggerVariantOptions, truncateOptions, variantCssColorMap, viewModeOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "108.3.1",
3
+ "version": "108.4.1",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -100,10 +100,10 @@
100
100
  "jackspeak": "2.1.1"
101
101
  },
102
102
  "devDependencies": {
103
- "@babel/core": "^7.26.8",
103
+ "@babel/core": "^7.26.9",
104
104
  "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
105
105
  "@babel/plugin-proposal-optional-chaining": "^7.21.0",
106
- "@babel/preset-env": "^7.26.8",
106
+ "@babel/preset-env": "^7.26.9",
107
107
  "@babel/preset-react": "^7.26.3",
108
108
  "@cypress/grep": "^4.0.1",
109
109
  "@gitlab/eslint-plugin": "20.7.1",
@@ -155,7 +155,7 @@
155
155
  "eslint-formatter-gitlab": "^5.1.0",
156
156
  "eslint-import-resolver-jest": "3.0.2",
157
157
  "eslint-plugin-cypress": "3.6.0",
158
- "eslint-plugin-storybook": "0.11.2",
158
+ "eslint-plugin-storybook": "0.11.3",
159
159
  "fuse.js": "^7.0.0",
160
160
  "gitlab-api-async-iterator": "^1.3.1",
161
161
  "glob": "10.3.3",
@@ -74,14 +74,20 @@ export default {
74
74
  <gl-avatar v-bind="$attrs" :class="avatarCssClasses" alt v-on="avatarListeners" />
75
75
  <div class="gl-avatar-labeled-labels !gl-text-left" :class="avatarRowLayoutClass">
76
76
  <div class="-gl-mx-1 -gl-my-1 gl-flex gl-flex-wrap gl-items-center !gl-text-left">
77
- <gl-link v-if="hasLabelLink" ref="labelLink" :href="labelLink" class="gl-avatar-link">
77
+ <gl-link
78
+ v-if="hasLabelLink"
79
+ ref="labelLink"
80
+ :href="labelLink"
81
+ class="gl-avatar-link"
82
+ variant="meta"
83
+ >
78
84
  <span class="gl-avatar-labeled-label">{{ label }}</span>
79
85
  </gl-link>
80
86
  <span v-else class="gl-avatar-labeled-label">{{ label }}</span>
81
87
  <!-- @slot Metadata to add to the avatar. Generally used for badges or user status emoji. -->
82
88
  <slot name="meta"></slot>
83
89
  </div>
84
- <gl-link v-if="hasSubLabelLink" :href="subLabelLink" class="gl-avatar-link">
90
+ <gl-link v-if="hasSubLabelLink" :href="subLabelLink" class="gl-avatar-link" variant="meta">
85
91
  <span class="gl-avatar-labeled-sublabel">{{ subLabel }}</span>
86
92
  </gl-link>
87
93
  <span v-else class="gl-avatar-labeled-sublabel">{{ subLabel }}</span>
@@ -9,7 +9,7 @@ export default {
9
9
  };
10
10
  </script>
11
11
  <template>
12
- <gl-link class="gl-avatar-link" v-bind="$attrs" v-on="$listeners">
12
+ <gl-link class="gl-avatar-link" v-bind="$attrs" variant="meta" v-on="$listeners">
13
13
  <slot></slot>
14
14
  </gl-link>
15
15
  </template>
@@ -201,6 +201,12 @@ export default {
201
201
  }
202
202
  this.resetItems();
203
203
  },
204
+ hideItemClass(item) {
205
+ // TODO once https://gitlab.com/gitlab-org/gitlab/-/issues/520089 is addressed:
206
+ // - Remove this hiding of empty breadcrumbs.
207
+ // - Tighten `items` validator to require non-empty `text`.
208
+ return !item.text ? 'gl-hidden' : '';
209
+ },
204
210
  },
205
211
  };
206
212
  </script>
@@ -229,6 +235,7 @@ export default {
229
235
  :to="item.to"
230
236
  :size="size"
231
237
  :aria-current="getAriaCurrentAttr(index)"
238
+ :class="hideItemClass(item)"
232
239
  ><gl-avatar
233
240
  v-if="item.avatarPath"
234
241
  :src="item.avatarPath"
@@ -1,4 +1,5 @@
1
1
  <script>
2
+ import uniqueId from 'lodash/uniqueId';
2
3
  import { GlTooltipDirective } from '../../../directives/tooltip';
3
4
  import { getDayDifference, getDateInPast, getDateInFuture } from '../../../utils/datetime_utility';
4
5
  import GlDatepicker from '../datepicker/datepicker.vue';
@@ -33,6 +34,16 @@ export default {
33
34
  required: false,
34
35
  default: 'To',
35
36
  },
37
+ fromAriaLabel: {
38
+ type: String,
39
+ required: false,
40
+ default: 'From date',
41
+ },
42
+ toAriaLabel: {
43
+ type: String,
44
+ required: false,
45
+ default: 'To date',
46
+ },
36
47
  value: {
37
48
  type: Object,
38
49
  required: false,
@@ -208,6 +219,12 @@ export default {
208
219
  showIndicator() {
209
220
  return Boolean(this.$scopedSlots.default || this.tooltip);
210
221
  },
222
+ fromId() {
223
+ return uniqueId('date-from-field-');
224
+ },
225
+ toId() {
226
+ return uniqueId('date-to-field-');
227
+ },
211
228
  },
212
229
  watch: {
213
230
  value(val) {
@@ -274,10 +291,12 @@ export default {
274
291
  <template>
275
292
  <div class="gl-daterange-picker gl-flex gl-gap-5">
276
293
  <div :class="startContainerClasses" data-testid="daterange-picker-start-container">
277
- <label :class="labelClass">{{ fromLabel }}</label>
294
+ <label :class="labelClass" :for="fromId">{{ fromLabel }}</label>
278
295
 
279
296
  <gl-datepicker
280
297
  v-model="startDate"
298
+ :input-id="fromId"
299
+ :input-label="fromAriaLabel"
281
300
  :min-date="defaultMinDate"
282
301
  :max-date="fromCalendarMaxDate"
283
302
  :start-range="defaultMinDate"
@@ -299,10 +318,12 @@ export default {
299
318
  </gl-datepicker>
300
319
  </div>
301
320
  <div :class="endContainerClasses" data-testid="daterange-picker-end-container">
302
- <label :class="labelClass">{{ toLabel }}</label>
321
+ <label :class="labelClass" :for="toId">{{ toLabel }}</label>
303
322
  <gl-datepicker
304
323
  :key="numericStartTime"
305
324
  v-model="endDate"
325
+ :input-id="toId"
326
+ :input-label="toAriaLabel"
306
327
  :min-date="toCalendarMinDate"
307
328
  :max-date="toCalendarMaxDate"
308
329
  :start-range="toCalendarMinDate"
@@ -1,3 +1,23 @@
1
+ ## Variants
2
+
3
+ - **Inline**: Link that appears within body text, like a paragraph or sentence. In order to
4
+ distinguish a linked reference from surrounding content, a link within body copy must be
5
+ underlined. Inline text links can be user-generated, for example, referencing an issue with
6
+ "#3126" in the markdown editor of a merge request description where the link's primary function
7
+ is linking to the referred issue. They can also be in text generated from a source file, for
8
+ example, a "learn more about pipelines" link in the paragraph of an empty state template.
9
+ - **User interface (UI)**: Standalone link in the UI. User interface links are not user-generated.
10
+ For example, a link in the system notes that compares the changes in a new commit to a previous
11
+ one. The placement, color, and actionable text all provide link affordance. A link button has a
12
+ similar style, but is used for an action and not a link.
13
+ - **Meta**: Standalone text or text within a short string of system-generated content may contain
14
+ multiple meta links. Meta links share a meaningful datapoint or reference, and are only links
15
+ secondarily. For example, the primary function of including "%15.8" in a string is to
16
+ communicate the milestone, though it can also link to more information about it. Meta links represent
17
+ a wide variety of content and should be styled specifically for the contexts in which they appear.
18
+ - **Mention**: Indicates when a user is "@" mentioned in the content. The username links to the
19
+ user's profile. A mention link can be within body or meta content.
20
+
1
21
  ## Security
2
22
 
3
23
  This component implements a few security measures to make it as safe as possible by default.
@@ -15,7 +35,10 @@ sanitization. This component exposes the `is-unsafe-link` prop for that purpose.
15
35
  <gl-link
16
36
  is-unsafe-link
17
37
  download="file.txt"
18
- href="data:text/plain;charset=utf-8,GitLab%20is%20awesome">Download</gl-link>
38
+ href="data:text/plain;charset=utf-8,GitLab%20is%20awesome"
39
+ >
40
+ Download
41
+ </gl-link>
19
42
  ```
20
43
 
21
44
  [SafeLinkDirective docs]: https://gitlab-org.gitlab.io/gitlab-ui/?path=/docs/directives-safe-link-directive--default
@@ -1,6 +1,14 @@
1
1
  .gl-link {
2
- &,
2
+ text-underline-offset: 0.125em;
3
+
3
4
  &:hover {
5
+ @apply gl-cursor-pointer;
6
+ }
7
+
8
+ &,
9
+ &:hover,
10
+ &:active,
11
+ &:focus {
4
12
  @apply gl-text-link;
5
13
  }
6
14
 
@@ -11,3 +19,72 @@
11
19
  @include gl-focus($outline: true, $outline-offset: $outline-width);
12
20
  }
13
21
  }
22
+
23
+ .gl-link-inline {
24
+ @apply gl-underline;
25
+
26
+ &:hover {
27
+ @apply gl-underline;
28
+ }
29
+ }
30
+
31
+ .gl-link-inline-external::after {
32
+ content: ' ↗';
33
+ font-size: 1em;
34
+ }
35
+
36
+ .gl-link-meta {
37
+ @apply gl-no-underline;
38
+
39
+ &:hover {
40
+ @apply gl-underline;
41
+ }
42
+
43
+ &,
44
+ &:hover,
45
+ &:focus,
46
+ &:focus:hover {
47
+ @apply gl-text-inherit;
48
+ }
49
+ }
50
+
51
+ .gl-link-mention,
52
+ .gl-link-mention-current {
53
+ @apply gl-px-1;
54
+ @apply gl-rounded-base;
55
+ @apply gl-no-underline;
56
+
57
+ &:hover {
58
+ @apply gl-underline;
59
+ }
60
+
61
+ &:active,
62
+ &:focus,
63
+ &:focus:active {
64
+ @apply gl-no-underline;
65
+ }
66
+ }
67
+
68
+ .gl-link-mention {
69
+ background-color: var(--gl-link-mention-background-color-default);
70
+
71
+ &,
72
+ &:hover,
73
+ &:active,
74
+ &:focus,
75
+ &:focus:active {
76
+ color: var(--gl-link-mention-text-color-default);
77
+ }
78
+ }
79
+
80
+ .gl-link-mention-current {
81
+ background-color: var(--gl-link-mention-background-color-current);
82
+
83
+ &,
84
+ &:hover,
85
+ &:active,
86
+ &:focus,
87
+ &:focus:active {
88
+ color: var(--gl-link-mention-text-color-current);
89
+ }
90
+ }
@@ -2,6 +2,8 @@
2
2
  <script>
3
3
  import { BLink } from '../../../vendor/bootstrap-vue/src/components/link/link';
4
4
  import { SafeLinkMixin } from '../../mixins/safe_link_mixin';
5
+ import { isExternalURL } from '../../../directives/safe_link/safe_link';
6
+ import { linkVariantOptions } from '../../../utils/constants';
5
7
 
6
8
  export default {
7
9
  name: 'GlLink',
@@ -9,6 +11,42 @@ export default {
9
11
  BLink,
10
12
  },
11
13
  mixins: [SafeLinkMixin],
14
+ props: {
15
+ /**
16
+ * If inline variant, controls ↗ character visibility
17
+ */
18
+ showExternalIcon: {
19
+ type: Boolean,
20
+ required: false,
21
+ default: false,
22
+ },
23
+ /**
24
+ * Link variant
25
+ */
26
+ variant: {
27
+ type: String,
28
+ required: false,
29
+ default: null,
30
+ validator: (value) => value && Object.hasOwn(linkVariantOptions, value),
31
+ },
32
+ },
33
+ computed: {
34
+ isInlineAndHasExternalIcon() {
35
+ return (
36
+ this.showExternalIcon &&
37
+ this.variant === 'inline' &&
38
+ this.$attrs.href &&
39
+ isExternalURL(this.target, this.$attrs.href)
40
+ );
41
+ },
42
+ linkClasses() {
43
+ return [
44
+ 'gl-link',
45
+ linkVariantOptions[this.variant],
46
+ { 'gl-link-inline-external': this.isInlineAndHasExternalIcon },
47
+ ];
48
+ },
49
+ },
12
50
  };
13
51
  </script>
14
52
  <template>
@@ -16,7 +54,7 @@ export default {
16
54
  v-safe-link:[safeLinkConfig]
17
55
  v-bind="$attrs"
18
56
  :target="target"
19
- class="gl-link"
57
+ :class="linkClasses"
20
58
  v-on="$listeners"
21
59
  >
22
60
  <!-- @slot The link to display. -->
@@ -5,7 +5,7 @@ const getBaseURL = () => {
5
5
  return `${protocol}//${host}`;
6
6
  };
7
7
 
8
- const isExternalURL = (target, hostname) => {
8
+ export const isExternalURL = (target, hostname) => {
9
9
  return target === '_blank' && hostname !== window.location.hostname;
10
10
  };
11
11
 
@@ -203,6 +203,13 @@ export const animatedIconVariantOptions = {
203
203
  success: 'gl-animated-icon-success',
204
204
  };
205
205
 
206
+ export const linkVariantOptions = {
207
+ inline: 'gl-link-inline',
208
+ meta: 'gl-link-meta',
209
+ mention: 'gl-link-mention',
210
+ mentionCurrent: 'gl-link-mention-current',
211
+ };
212
+
206
213
  export const triggerVariantOptions = {
207
214
  click: 'click',
208
215
  hover: 'hover',