@gitlab/ui 124.1.1 → 124.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "124.1.1",
3
+ "version": "124.2.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -20,7 +20,7 @@ $breadcrumb-max-width: $grid-size * 16;
20
20
  @apply gl-leading-normal;
21
21
  @apply gl-shrink-0;
22
22
 
23
- &:not(:last-child)::after {
23
+ &:not(:last-child, :has(+ .gl-breadcrumb-clipboard-button))::after {
24
24
  color: var(--gl-breadcrumb-separator-color);
25
25
  @apply gl-px-3;
26
26
  content: '/';
@@ -75,3 +75,8 @@ $breadcrumb-max-width: $grid-size * 16;
75
75
  }
76
76
  }
77
77
  }
78
+
79
+ .gl-breadcrumb-clipboard-button {
80
+ @apply gl-leading-normal;
81
+ @apply gl-shrink-0;
82
+ }
@@ -6,6 +6,7 @@ import GlAvatar from '../avatar/avatar.vue';
6
6
  import GlDisclosureDropdown from '../new_dropdowns/disclosure/disclosure_dropdown.vue';
7
7
  import { GlTooltipDirective } from '../../../directives/tooltip/tooltip';
8
8
  import { breadCrumbSizeOptions } from '../../../utils/constants';
9
+ import ClipboardButton from '../../shared_components/clipboard_button/clipboard_button.vue';
9
10
  import GlBreadcrumbItem from './breadcrumb_item.vue';
10
11
 
11
12
  export default {
@@ -14,6 +15,7 @@ export default {
14
15
  GlBreadcrumbItem,
15
16
  GlAvatar,
16
17
  GlDisclosureDropdown,
18
+ ClipboardButton,
17
19
  },
18
20
  directives: {
19
21
  GlTooltip: GlTooltipDirective,
@@ -64,6 +66,30 @@ export default {
64
66
  default: breadCrumbSizeOptions.sm,
65
67
  validator: (value) => Object.keys(breadCrumbSizeOptions).includes(value),
66
68
  },
69
+ /**
70
+ * Copy to clipboard button for breadcrumbs path.
71
+ */
72
+ showClipboardButton: {
73
+ type: Boolean,
74
+ required: false,
75
+ default: false,
76
+ },
77
+ /**
78
+ * Custom path for copy to clipboard button. By default, it resolves to all items text values with `/` separator.
79
+ */
80
+ pathToCopy: {
81
+ type: String,
82
+ required: false,
83
+ default: null,
84
+ },
85
+ /**
86
+ * Custom tooltip text for clipboard button.
87
+ */
88
+ clipboardTooltipText: {
89
+ type: String,
90
+ required: false,
91
+ default: null,
92
+ },
67
93
  },
68
94
  data() {
69
95
  return {
@@ -94,6 +120,12 @@ export default {
94
120
  avatarSize() {
95
121
  return this.size === 'sm' ? 16 : 24;
96
122
  },
123
+ clipboardButtonText() {
124
+ if (this.pathToCopy) return this.pathToCopy;
125
+
126
+ const items = Array.from(this.items, (item) => item.text);
127
+ return items.join('/');
128
+ },
97
129
  },
98
130
  watch: {
99
131
  items: {
@@ -230,16 +262,28 @@ export default {
230
262
  :size="size"
231
263
  :aria-current="getAriaCurrentAttr(index)"
232
264
  :class="[hideItemClass(item), itemClass]"
233
- ><gl-avatar
234
- v-if="item.avatarPath"
235
- :src="item.avatarPath"
236
- :size="avatarSize"
237
- aria-hidden="true"
238
- class="gl-breadcrumb-avatar-tile gl-border gl-mr-2 !gl-rounded-default"
239
- shape="rect"
240
- data-testid="avatar"
241
- /><span class="gl-align-middle">{{ item.text }}</span>
265
+ ><template #default>
266
+ <gl-avatar
267
+ v-if="item.avatarPath"
268
+ :src="item.avatarPath"
269
+ :size="avatarSize"
270
+ aria-hidden="true"
271
+ class="gl-breadcrumb-avatar-tile gl-border gl-mr-2 !gl-rounded-default"
272
+ shape="rect"
273
+ data-testid="avatar"
274
+ /><span class="gl-align-middle">{{ item.text }}</span>
275
+ </template>
242
276
  </gl-breadcrumb-item>
277
+
278
+ <li v-if="showClipboardButton" class="gl-breadcrumb-clipboard-button">
279
+ <clipboard-button
280
+ data-testid="copy-to-clipboard-button"
281
+ class="gl-ml-2"
282
+ :text="clipboardButtonText"
283
+ v-bind="clipboardTooltipText ? { title: clipboardTooltipText } : {}"
284
+ :size="dropdownSize"
285
+ />
286
+ </li>
243
287
  </ol>
244
288
  </nav>
245
289
  </template>
@@ -102,6 +102,9 @@ export { default as GlDashboardPanel } from './dashboards/dashboard_panel/dashbo
102
102
  // Experimental
103
103
  export { default as GlExperimentBadge } from './experimental/experiment_badge/experiment_badge.vue';
104
104
 
105
+ // Shared components
106
+ export { default as GlClipboardButton } from './shared_components/clipboard_button/clipboard_button.vue';
107
+
105
108
  // Utilities
106
109
  export { default as GlAnimatedNumber } from './utilities/animated_number/animated_number.vue';
107
110
  export { default as GlFriendlyWrap } from './utilities/friendly_wrap/friendly_wrap.vue';
@@ -0,0 +1,78 @@
1
+ <script>
2
+ import { GlTooltipDirective } from '../../../directives/tooltip/tooltip';
3
+ import GlButton from '../../base/button/button.vue';
4
+ import { translate } from '../../../utils/i18n';
5
+
6
+ export default {
7
+ name: 'ClipboardButton',
8
+ components: {
9
+ GlButton,
10
+ },
11
+ directives: {
12
+ GlTooltip: GlTooltipDirective,
13
+ },
14
+ props: {
15
+ /**
16
+ * The text to copy to clipboard
17
+ */
18
+ text: {
19
+ type: String,
20
+ required: true,
21
+ },
22
+ /**
23
+ * The tooltip text shown on hover
24
+ */
25
+ title: {
26
+ type: String,
27
+ required: false,
28
+ default: () => translate('ClipboardButton.title', 'Copy to clipboard'),
29
+ },
30
+ /**
31
+ * Button size
32
+ */
33
+ size: {
34
+ type: String,
35
+ required: false,
36
+ default: 'medium',
37
+ },
38
+ },
39
+ data() {
40
+ return {
41
+ localTitle: this.title,
42
+ titleTimeout: null,
43
+ };
44
+ },
45
+ methods: {
46
+ updateTooltip(title) {
47
+ this.localTitle = title;
48
+
49
+ clearTimeout(this.titleTimeout);
50
+
51
+ this.titleTimeout = setTimeout(() => {
52
+ this.localTitle = this.title;
53
+ }, 1000);
54
+ },
55
+ async handleClick() {
56
+ try {
57
+ await navigator.clipboard.writeText(this.text);
58
+ this.updateTooltip(translate('ClipboardButton.copied', 'Copied'));
59
+ } catch {
60
+ this.updateTooltip(translate('ClipboardButton.error', 'Copy failed'));
61
+ }
62
+ },
63
+ },
64
+ };
65
+ </script>
66
+
67
+ <template>
68
+ <gl-button
69
+ v-gl-tooltip.hover.focus.top
70
+ variant="default"
71
+ category="tertiary"
72
+ icon="copy-to-clipboard"
73
+ :size="size"
74
+ :title="localTitle"
75
+ :aria-label="localTitle"
76
+ @click="handleClick"
77
+ />
78
+ </template>
package/translations.js CHANGED
@@ -1,6 +1,9 @@
1
1
  /* eslint-disable import/no-default-export */
2
2
  export default {
3
3
  'ClearIconButton.title': 'Clear',
4
+ 'ClipboardButton.copied': 'Copied',
5
+ 'ClipboardButton.error': 'Copy failed',
6
+ 'ClipboardButton.title': 'Copy to clipboard',
4
7
  'CloseButton.title': 'Close',
5
8
  'GlAlert.closeButtonTitle': 'Dismiss',
6
9
  'GlBanner.closeButtonTitle': 'Dismiss',