@gitlab/ui 138.1.0 → 138.3.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": "138.1.0",
3
+ "version": "138.3.0",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -151,7 +151,7 @@
151
151
  "pikaday": "^1.8.0",
152
152
  "playwright": "^1.63.0",
153
153
  "playwright-core": "^1.63.0",
154
- "postcss": "8.5.28",
154
+ "postcss": "8.5.29",
155
155
  "postcss-loader": "8.2.1",
156
156
  "postcss-scss": "4.0.9",
157
157
  "react": "18.3.1",
@@ -168,7 +168,7 @@
168
168
  "start-server-and-test": "^2.1.5",
169
169
  "storybook": "^7.6.24",
170
170
  "storybook-dark-mode": "4.0.2",
171
- "style-dictionary": "^5.5.5",
171
+ "style-dictionary": "^5.6.0",
172
172
  "style-loader": "^4",
173
173
  "tailwindcss": "3.4.19",
174
174
  "vue": "2.7.16",
@@ -178,6 +178,6 @@
178
178
  "vue-router": "^3.6.5",
179
179
  "vue-template-compiler": "2.7.16",
180
180
  "vue-test-utils-compat": "^0.0.15",
181
- "webpack": "^5.100.1"
181
+ "webpack": "^5.111.1"
182
182
  }
183
183
  }
@@ -431,12 +431,6 @@
431
431
  @apply gl-bg-transparent;
432
432
  }
433
433
 
434
- &.disabled,
435
- &[disabled] {
436
- @apply gl-bg-transparent;
437
- @apply gl-shadow-none;
438
- }
439
-
440
434
  @media (forced-colors: active) {
441
435
  color: LinkText; // stylelint-disable-line scale-unlimited/declaration-strict-value
442
436
  }
@@ -472,10 +466,17 @@
472
466
  }
473
467
  }
474
468
 
469
+ // After the disabled rule above so it also wins on focus, active and selected
475
470
  &.disabled[class*="-tertiary"],
476
- &[disabled][class*="-tertiary"] {
471
+ &[disabled][class*="-tertiary"],
472
+ &.btn-link.disabled,
473
+ &.btn-link[disabled] {
477
474
  @apply gl-bg-transparent;
478
- @apply gl-shadow-none;
475
+
476
+ // Focusable disabled buttons (`accessibleDisabled`, loading) keep the focus ring
477
+ &:not(:focus-visible) {
478
+ @apply gl-shadow-none;
479
+ }
479
480
  }
480
481
  }
481
482
 
@@ -155,7 +155,8 @@ export default {
155
155
  },
156
156
  data() {
157
157
  return {
158
- breakpoint: GlBreakpointInstance.getBreakpointSize(),
158
+ // Set on mount to be safe for SSR
159
+ breakpoint: null,
159
160
  // If total pages count is below or equal to minTotalPagesToCollapse, collapsing is disabled
160
161
  minTotalPagesToCollapse: 4,
161
162
  };
@@ -272,7 +273,8 @@ export default {
272
273
  return '#';
273
274
  },
274
275
  },
275
- created() {
276
+ mounted() {
277
+ this.setBreakpoint();
276
278
  this.resizeDebounced = debounce(this.setBreakpoint, resizeDebounceTime);
277
279
  window.addEventListener('resize', this.resizeDebounced);
278
280
  },
@@ -98,6 +98,15 @@ export default {
98
98
  required: false,
99
99
  default: true,
100
100
  },
101
+ /**
102
+ * Disables the entire sorting control (both the sort-by dropdown and the
103
+ * sort direction toggle) while keeping it visible.
104
+ */
105
+ disabled: {
106
+ type: Boolean,
107
+ required: false,
108
+ default: false,
109
+ },
101
110
  },
102
111
  data() {
103
112
  return {
@@ -106,7 +115,14 @@ export default {
106
115
  };
107
116
  },
108
117
  computed: {
118
+ unavailableLabel() {
119
+ return translate('GlSorting.sortingUnavailable', 'Sorting is unavailable');
120
+ },
109
121
  sortingListboxLabel() {
122
+ if (this.disabled) {
123
+ return this.unavailableLabel;
124
+ }
125
+
110
126
  return translate('GlSorting.sortByLabel', 'Sort by:');
111
127
  },
112
128
  localSortDirection() {
@@ -119,19 +135,19 @@ export default {
119
135
  return this.selectedSortOption?.text ?? '';
120
136
  },
121
137
  isDirectionToggleDisabled() {
122
- return Boolean(this.selectedSortOption?.directionToggleDisabled);
138
+ return this.disabled || Boolean(this.selectedSortOption?.directionToggleDisabled);
123
139
  },
124
140
  sortDirectionText() {
125
- if (this.sortDirectionToolTip) return this.sortDirectionToolTip;
141
+ if (this.sortDirectionToolTip && !this.disabled) return this.sortDirectionToolTip;
126
142
 
127
143
  if (this.isDirectionToggleDisabled) {
128
144
  return this.selectedSortText
129
145
  ? translate(
130
146
  'GlSorting.sortDirectionUnavailableFor',
131
- 'Sort direction unavailable for %{sortField}',
147
+ 'Sorting is unavailable for %{sortField}',
132
148
  { sortField: this.selectedSortText },
133
149
  )
134
- : translate('GlSorting.sortDirectionUnavailable', 'Sort direction unavailable');
150
+ : this.unavailableLabel;
135
151
  }
136
152
 
137
153
  return this.isAscending
@@ -139,6 +155,11 @@ export default {
139
155
  : translate('GlSorting.sortDescending', 'Sort direction: descending');
140
156
  },
141
157
  },
158
+ watch: {
159
+ disabled(isDisabled) {
160
+ if (isDisabled) this.$refs.listbox.close();
161
+ },
162
+ },
142
163
  methods: {
143
164
  toggleSortDirection() {
144
165
  if (this.isDirectionToggleDisabled) return;
@@ -156,6 +177,8 @@ export default {
156
177
  this.$emit('sort-direction-change', newDirection);
157
178
  },
158
179
  onSortByChanged(event) {
180
+ if (this.disabled) return;
181
+
159
182
  /**
160
183
  * Emitted when the sort field is changed.
161
184
  *
@@ -174,6 +197,7 @@ export default {
174
197
  <template>
175
198
  <gl-button-group class="gl-sorting gl-flex">
176
199
  <gl-collapsible-listbox
200
+ ref="listbox"
177
201
  :toggle-text="text"
178
202
  :items="sortOptions"
179
203
  :selected="sortBy"
@@ -182,6 +206,7 @@ export default {
182
206
  :class="dropdownClass"
183
207
  placement="bottom-end"
184
208
  :block="block"
209
+ :disabled="disabled"
185
210
  :toggle-id="toggleId"
186
211
  :toggle-aria-labelled-by="`${sortingListboxId} ${toggleId}`"
187
212
  @select="onSortByChanged"
@@ -1,6 +1,7 @@
1
1
  <script>
2
2
  import { uniqueId } from 'lodash-es';
3
3
 
4
+ import { glToggleConfig } from '../../../config';
4
5
  import { toggleLabelPosition } from '../../../utils/constants';
5
6
  import GlIcon from '../icon/icon.vue';
6
7
  import GlLoadingIcon from '../loading_icon/loading_icon.vue';
@@ -43,6 +44,22 @@ export default {
43
44
  required: false,
44
45
  default: false,
45
46
  },
47
+ /**
48
+ * Keep the toggle focusable while `disabled` is `true`. Uses `aria-disabled` so the toggle stays in the tab order and is announced by assistive technology.
49
+ */
50
+ accessibleDisabled: {
51
+ type: Boolean,
52
+ required: false,
53
+ default: () => glToggleConfig.accessibleDisabledToggle,
54
+ },
55
+ /**
56
+ * Space-separated ids of elements that describe the toggle, in addition to its help text.
57
+ */
58
+ ariaDescribedby: {
59
+ type: String,
60
+ required: false,
61
+ default: undefined,
62
+ },
46
63
  /**
47
64
  * Whether the toggle is in the loading state.
48
65
  */
@@ -111,6 +128,12 @@ export default {
111
128
  helpId() {
112
129
  return this.shouldRenderHelp ? `toggle-help-${this.uuid}` : undefined;
113
130
  },
131
+ describedBy() {
132
+ return [this.helpId, this.ariaDescribedby].filter(Boolean).join(' ') || undefined;
133
+ },
134
+ isNativeDisabled() {
135
+ return this.disabled && !this.accessibleDisabled;
136
+ },
114
137
  isChecked() {
115
138
  return this.value ? 'true' : 'false';
116
139
  },
@@ -172,7 +195,7 @@ export default {
172
195
  role="switch"
173
196
  :aria-checked="isChecked"
174
197
  :aria-labelledby="labelId"
175
- :aria-describedby="helpId"
198
+ :aria-describedby="describedBy"
176
199
  :aria-disabled="disabled"
177
200
  :class="{
178
201
  'is-checked': value,
@@ -181,7 +204,7 @@ export default {
181
204
  }"
182
205
  class="gl-toggle gl-shrink-0"
183
206
  type="button"
184
- :disabled="disabled"
207
+ :disabled="isNativeDisabled"
185
208
  @click.prevent="toggleFeature"
186
209
  >
187
210
  <gl-loading-icon v-if="isLoading" color="dark" class="toggle-loading" />
@@ -80,6 +80,15 @@ export default {
80
80
  required: false,
81
81
  default: true,
82
82
  },
83
+ /**
84
+ * A name for the chart that screen readers announce. It is added as a hidden title, which
85
+ * ECharts reads into the description it generates. Ignored when `options` sets a title.
86
+ */
87
+ accessibleTitle: {
88
+ type: String,
89
+ required: false,
90
+ default: '',
91
+ },
83
92
  },
84
93
  data() {
85
94
  return {
@@ -96,6 +105,10 @@ export default {
96
105
  options = merge({}, options, { aria: { enabled: true } });
97
106
  }
98
107
 
108
+ if (this.accessibleTitle && !options.title) {
109
+ options = merge({}, options, { title: { text: this.accessibleTitle, show: false } });
110
+ }
111
+
99
112
  // Add space at the top to fit the toolbox
100
113
  if (options.toolbox?.show === true) {
101
114
  const top = (options.grid?.top || 0) + toolboxHeight;
@@ -111,6 +124,11 @@ export default {
111
124
  this.draw();
112
125
  }
113
126
  },
127
+ accessibleTitle() {
128
+ if (this.chart) {
129
+ this.draw();
130
+ }
131
+ },
114
132
  width() {
115
133
  this.setChartSize();
116
134
  },
package/src/config.js CHANGED
@@ -7,6 +7,7 @@ export const defaultConfig = {
7
7
  };
8
8
 
9
9
  export const glButtonConfig = {};
10
+ export const glToggleConfig = {};
10
11
 
11
12
  let configured = false;
12
13
 
@@ -18,9 +19,15 @@ let configured = false;
18
19
  * @property {undefined | Object} translations Generic translations for component labels to fall back to.
19
20
  * @property {undefined | Number} firstDayOfWeek Configured first day of the week, from 0 (Sunday) to 6 (Saturday).
20
21
  * @property {boolean} [accessibleDisabledButton] Temporary flag to enable the accessible disabled button.
22
+ * @property {boolean} [accessibleDisabledToggle] Temporary flag to enable the accessible disabled toggle.
21
23
  *
22
24
  */
23
- const setConfigs = ({ translations, firstDayOfWeek, accessibleDisabledButton = false } = {}) => {
25
+ const setConfigs = ({
26
+ translations,
27
+ firstDayOfWeek,
28
+ accessibleDisabledButton = false,
29
+ accessibleDisabledToggle = false,
30
+ } = {}) => {
24
31
  if (configured) {
25
32
  if (process.env.NODE_ENV === 'development') {
26
33
  throw new Error('GitLab UI can only be configured once!');
@@ -71,6 +78,14 @@ const setConfigs = ({ translations, firstDayOfWeek, accessibleDisabledButton = f
71
78
  accessibleDisabledButton,
72
79
  });
73
80
  }
81
+
82
+ // Temporary flag for the accessible disabled toggle. Once validated, aria-disabled becomes
83
+ // the default for disabled toggles and this flag is removed.
84
+ if (typeof accessibleDisabledToggle === 'boolean') {
85
+ Object.assign(glToggleConfig, {
86
+ accessibleDisabledToggle,
87
+ });
88
+ }
74
89
  };
75
90
 
76
91
  export default setConfigs;
package/translations.js CHANGED
@@ -43,8 +43,8 @@ export default {
43
43
  'GlSorting.sortAscending': 'Sort direction: ascending',
44
44
  'GlSorting.sortByLabel': 'Sort by:',
45
45
  'GlSorting.sortDescending': 'Sort direction: descending',
46
- 'GlSorting.sortDirectionUnavailable': 'Sort direction unavailable',
47
- 'GlSorting.sortDirectionUnavailableFor': 'Sort direction unavailable for %{sortField}',
46
+ 'GlSorting.sortDirectionUnavailableFor': 'Sorting is unavailable for %{sortField}',
47
+ 'GlSorting.sortingUnavailable': 'Sorting is unavailable',
48
48
  'GlTabs.GlScrollableTabs.scrollLeftLabel': 'Scroll left',
49
49
  'GlTabs.GlScrollableTabs.scrollRightLabel': 'Scroll right',
50
50
  'GlToken.closeButtonTitle': 'Remove',