@gitlab/ui 62.5.0 → 62.5.2

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
+ ## [62.5.2](https://gitlab.com/gitlab-org/gitlab-ui/compare/v62.5.1...v62.5.2) (2023-05-01)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **GlToggle:** set aria-disabled attribute ([a899eb7](https://gitlab.com/gitlab-org/gitlab-ui/commit/a899eb7acd23d089ddb43c3bcd66a0aae7fe3c6f))
7
+
8
+ ## [62.5.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v62.5.0...v62.5.1) (2023-04-28)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **utils:** Change color util to use relative luminance ([6245128](https://gitlab.com/gitlab-org/gitlab-ui/commit/6245128c7256e3d8db164b92e9580c79d47e9183))
14
+
1
15
  # [62.5.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v62.4.0...v62.5.0) (2023-04-25)
2
16
 
3
17
 
package/README.md CHANGED
@@ -121,25 +121,6 @@ should conform with the design system specs, and they should look correct in the
121
121
  the GitLab product. Please see [Debugging GitLab UI issues with GitLab product CSS](doc/debugging-gitlab-ui-with-gitlab-css.md)
122
122
  for information on how to debug issues with GitLab product CSS in GitLab UI.
123
123
 
124
- #### Running visual regression tests locally
125
-
126
- Visual difference tests form part of the test suite. Rendered output can vary
127
- from host to host (e.g., due to available fonts and how each platform renders
128
- them), so these can fail when run locally. The easiest way to work around this
129
- is to run a percent-based diff, and to increase the failure threshold with the
130
- `FAILURE_THRESHOLD_TYPE` and `FAILURE_THRESHOLD` environment variables:
131
-
132
- ```sh
133
- # Sets a 2% threshold
134
- FAILURE_THRESHOLD_TYPE='percent' FAILURE_THRESHOLD=.02 yarn test:visual
135
- ```
136
-
137
- `FAILURE_THRESHOLD_TYPE` defaults to `'pixel'` and `FAILURE_THRESHOLD` defaults to `1`. In the CI
138
- environment, we consider a 1 pixel difference as a false negative that should not fail the test.
139
-
140
- Under the hood, those variables are passed to
141
- [`jest-image-snapshot`](https://github.com/americanexpress/jest-image-snapshot)'s config
142
-
143
124
  ### End to end tests
144
125
 
145
126
  Components’ end to end tests live in the `cypress/e2e` folder. See our
@@ -145,7 +145,7 @@ var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=
145
145
  'gl-toggle': true,
146
146
  'is-checked': _vm.value,
147
147
  'is-disabled': _vm.disabled,
148
- },attrs:{"role":"switch","aria-checked":_vm.isChecked,"aria-labelledby":_vm.labelId,"aria-describedby":_vm.helpId,"type":"button"},on:{"click":function($event){$event.preventDefault();return _vm.toggleFeature.apply(null, arguments)}}},[(_vm.isLoading)?_c('gl-loading-icon',{staticClass:"toggle-loading",attrs:{"color":"light"}}):_c('span',{class:{ 'toggle-icon': true, disabled: _vm.disabled }},[_c('gl-icon',{attrs:{"name":_vm.icon,"size":16}})],1)],1),_vm._v(" "),(_vm.shouldRenderHelp)?_c('span',{staticClass:"gl-help-label",attrs:{"id":_vm.helpId,"data-testid":"toggle-help"}},[_vm._t("help",function(){return [_vm._v(_vm._s(_vm.help))]})],2):_vm._e()])};
148
+ },attrs:{"role":"switch","aria-checked":_vm.isChecked,"aria-labelledby":_vm.labelId,"aria-describedby":_vm.helpId,"aria-disabled":_vm.disabled,"type":"button"},on:{"click":function($event){$event.preventDefault();return _vm.toggleFeature.apply(null, arguments)}}},[(_vm.isLoading)?_c('gl-loading-icon',{staticClass:"toggle-loading",attrs:{"color":"light"}}):_c('span',{class:{ 'toggle-icon': true, disabled: _vm.disabled }},[_c('gl-icon',{attrs:{"name":_vm.icon,"size":16}})],1)],1),_vm._v(" "),(_vm.shouldRenderHelp)?_c('span',{staticClass:"gl-help-label",attrs:{"id":_vm.helpId,"data-testid":"toggle-help"}},[_vm._t("help",function(){return [_vm._v(_vm._s(_vm.help))]})],2):_vm._e()])};
149
149
  var __vue_staticRenderFns__ = [];
150
150
 
151
151
  /* style */
@@ -44,21 +44,38 @@ function hexToRgba(hex) {
44
44
  const [r, g, b] = rgbFromHex(hex);
45
45
  return `rgba(${r}, ${g}, ${b}, ${opacity})`;
46
46
  }
47
+ function toSrgb(value) {
48
+ const normalized = value / 255;
49
+ return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4;
50
+ }
51
+ function relativeLuminance(rgb) {
52
+ // WCAG 2.1 formula: https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
53
+ // -
54
+ // WCAG 3.0 will use APAC
55
+ // Using APAC would be the ultimate goal, but was dismissed by engineering as of now
56
+ // See https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/3418#note_1370107090
57
+ return 0.2126 * toSrgb(rgb[0]) + 0.7152 * toSrgb(rgb[1]) + 0.0722 * toSrgb(rgb[2]);
58
+ }
47
59
  function colorFromBackground(backgroundColor) {
48
- let r;
49
- let g;
50
- let b;
60
+ let color;
61
+ const lightColor = rgbFromHex('#FFFFFF');
62
+ const darkColor = rgbFromHex('#1f1e24');
51
63
  if (backgroundColor.startsWith('#')) {
52
- [r, g, b] = rgbFromHex(backgroundColor);
64
+ color = rgbFromHex(backgroundColor);
53
65
  } else if (backgroundColor.startsWith('rgba(')) {
54
- [r, g, b] = rgbFromString(backgroundColor, 5);
66
+ color = rgbFromString(backgroundColor, 5);
55
67
  } else if (backgroundColor.startsWith('rgb(')) {
56
- [r, g, b] = rgbFromString(backgroundColor, 4);
68
+ color = rgbFromString(backgroundColor, 4);
57
69
  }
58
- if (r + g + b <= 500) {
59
- return labelColorOptions.light;
60
- }
61
- return labelColorOptions.dark;
70
+ const luminance = relativeLuminance(color);
71
+ const lightLuminance = relativeLuminance(lightColor);
72
+ const darkLuminance = relativeLuminance(darkColor);
73
+ const contrastLight = (lightLuminance + 0.05) / (luminance + 0.05);
74
+ const contrastDark = (luminance + 0.05) / (darkLuminance + 0.05);
75
+
76
+ // Using a threshold contrast of 2.4 instead of 3
77
+ // as this will solve weird color combinations in the mid tones
78
+ return contrastLight >= 2.4 || contrastLight > contrastDark ? labelColorOptions.light : labelColorOptions.dark;
62
79
  }
63
80
  function uid() {
64
81
  return Math.random().toString(36).substring(2);
@@ -156,4 +173,4 @@ function filterVisible(els) {
156
173
  return (els || []).filter(isVisible);
157
174
  }
158
175
 
159
- export { colorFromBackground, debounceByAnimationFrame, filterVisible, focusFirstFocusableElement, hexToRgba, isDev, isElementFocusable, isElementTabbable, logWarning, rgbFromHex, rgbFromString, stopEvent, throttle, uid };
176
+ export { colorFromBackground, debounceByAnimationFrame, filterVisible, focusFirstFocusableElement, hexToRgba, isDev, isElementFocusable, isElementTabbable, logWarning, relativeLuminance, rgbFromHex, rgbFromString, stopEvent, throttle, toSrgb, uid };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitlab/ui",
3
- "version": "62.5.0",
3
+ "version": "62.5.2",
4
4
  "description": "GitLab UI Components",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -29,13 +29,13 @@
29
29
  "clean": "rm -r dist storybook scss_to_js/scss_variables.* src/scss/utilities.scss",
30
30
  "cy:run": "cypress run --browser firefox",
31
31
  "start": "yarn storybook",
32
- "storybook": "yarn storybook-prep && node ./bin/run_storybook.js --ci --host localhost --port 9001 -c .storybook",
33
- "storybook-vue3": "yarn storybook-prep && VUE_VERSION=3 node ./bin/run_storybook.js --ci --host localhost --port 9001 -c .storybook",
32
+ "storybook": "yarn storybook-prep && storybook dev --ci --host localhost --port 9001 -c .storybook",
33
+ "storybook-vue3": "yarn storybook-prep && VUE_VERSION=3 storybook dev --ci --host localhost --port 9001 -c .storybook",
34
34
  "storybook-prep": "run-s generate-utilities build-scss-variables copy-fonts",
35
- "storybook-static": "yarn storybook-prep && build-storybook -c .storybook -o storybook",
35
+ "storybook-static": "yarn storybook-prep && storybook build -c .storybook -o storybook",
36
36
  "pretest:unit": "yarn build-scss-variables",
37
37
  "test": "run-s test:unit test:visual",
38
- "test:integration": "NODE_ENV=test start-server-and-test start http://localhost:9001 cy:run",
38
+ "test:integration": "NODE_ENV=test start-server-and-test start http://localhost:9001/iframe.html cy:run",
39
39
  "test:unit": "NODE_ENV=test jest --testPathIgnorePatterns storyshots.spec.js",
40
40
  "test:unit:watch": "yarn test:unit --watch",
41
41
  "test:unit:debug": "NODE_ENV=test node --inspect node_modules/.bin/jest --testPathIgnorePatterns storyshot.spec.js --watch --runInBand",
@@ -45,7 +45,7 @@
45
45
  "test:visual": "./bin/run-visual-tests.sh 'jest ./tests/storyshots.spec.js'",
46
46
  "test:visual:minimal": "node ./bin/run_minimal_visual_tests.js",
47
47
  "test:visual:update": "./bin/run-visual-tests.sh 'JEST_IMAGE_SNAPSHOT_TRACK_OBSOLETE=1 jest ./tests/storyshots.spec.js --updateSnapshot'",
48
- "test:visual:internal": "NODE_ENV=test IS_VISUAL_TEST=true start-test http-get://localhost:9001",
48
+ "test:visual:internal": "NODE_ENV=test IS_VISUAL_TEST=true start-test http-get://localhost:9001/iframe.html",
49
49
  "prettier": "prettier --check '**/*.{js,vue}'",
50
50
  "prettier:fix": "prettier --write '**/*.{js,vue}'",
51
51
  "eslint": "eslint --max-warnings 0 --ext .js,.vue .",
@@ -78,8 +78,6 @@
78
78
  "vue": "^2.6.10"
79
79
  },
80
80
  "resolutions": {
81
- "@storybook/vue/webpack": "^5.9.0",
82
- "@storybook/vue3/vue-loader": "^17.0.0",
83
81
  "chokidar": "^3.5.2",
84
82
  "sane": "^5.0.1"
85
83
  },
@@ -87,24 +85,26 @@
87
85
  "@arkweid/lefthook": "0.7.7",
88
86
  "@babel/core": "^7.21.4",
89
87
  "@babel/preset-env": "^7.21.4",
90
- "@gitlab/eslint-plugin": "18.3.2",
88
+ "@babel/preset-react": "^7.18.6",
89
+ "@gitlab/eslint-plugin": "19.0.0",
91
90
  "@gitlab/fonts": "^1.2.0",
92
91
  "@gitlab/stylelint-config": "4.1.0",
93
- "@gitlab/svgs": "3.40.0",
92
+ "@gitlab/svgs": "3.42.0",
94
93
  "@rollup/plugin-commonjs": "^11.1.0",
95
94
  "@rollup/plugin-node-resolve": "^7.1.3",
96
95
  "@rollup/plugin-replace": "^2.3.2",
97
- "@storybook/addon-a11y": "6.5.16",
98
- "@storybook/addon-docs": "6.5.16",
99
- "@storybook/addon-essentials": "6.5.16",
100
- "@storybook/addon-storyshots": "6.5.16",
101
- "@storybook/addon-storyshots-puppeteer": "6.5.16",
102
- "@storybook/addon-viewport": "6.5.16",
103
- "@storybook/builder-webpack5": "^6.5.16",
104
- "@storybook/manager-webpack5": "^6.5.16",
105
- "@storybook/theming": "6.5.16",
106
- "@storybook/vue": "6.5.16",
107
- "@storybook/vue3": "6.5.16",
96
+ "@storybook/addon-a11y": "7.0.7",
97
+ "@storybook/addon-docs": "7.0.7",
98
+ "@storybook/addon-essentials": "7.0.7",
99
+ "@storybook/addon-storyshots": "7.0.7",
100
+ "@storybook/addon-storyshots-puppeteer": "7.0.7",
101
+ "@storybook/addon-viewport": "7.0.7",
102
+ "@storybook/builder-webpack5": "7.0.7",
103
+ "@storybook/theming": "7.0.7",
104
+ "@storybook/vue": "7.0.7",
105
+ "@storybook/vue-webpack5": "7.0.7",
106
+ "@storybook/vue3": "7.0.7",
107
+ "@storybook/vue3-webpack5": "7.0.7",
108
108
  "@vue/compat": "^3.2.40",
109
109
  "@vue/compiler-sfc": "^3.2.40",
110
110
  "@vue/test-utils": "1.3.0",
@@ -115,15 +115,13 @@
115
115
  "babel-jest": "29.0.1",
116
116
  "babel-loader": "^8.0.5",
117
117
  "babel-plugin-require-context-hook": "^1.0.0",
118
- "babel-preset-vue": "^2.0.2",
119
118
  "bootstrap": "4.6.2",
120
- "cypress": "12.10.0",
119
+ "cypress": "12.11.0",
121
120
  "emoji-regex": "^10.0.0",
122
- "eslint": "8.38.0",
121
+ "eslint": "8.39.0",
123
122
  "eslint-import-resolver-jest": "3.0.2",
124
123
  "eslint-plugin-cypress": "2.13.2",
125
124
  "eslint-plugin-storybook": "0.6.11",
126
- "file-loader": "^4.2.0",
127
125
  "glob": "^7.2.0",
128
126
  "identity-obj-proxy": "^3.0.0",
129
127
  "inquirer-select-directory": "^1.2.0",
@@ -142,6 +140,8 @@
142
140
  "prettier": "2.6.2",
143
141
  "puppeteer": "15.5.0",
144
142
  "raw-loader": "^0.5.1",
143
+ "react": "^18.2.0",
144
+ "react-dom": "^18.2.0",
145
145
  "rollup": "^2.53.1",
146
146
  "rollup-plugin-babel": "^4.4.0",
147
147
  "rollup-plugin-postcss": "^3.1.1",
@@ -153,7 +153,8 @@
153
153
  "sass-loader": "^10.2.0",
154
154
  "sass-true": "^6.1.0",
155
155
  "start-server-and-test": "^1.10.6",
156
- "storybook-dark-mode": "^1.0.8",
156
+ "storybook": "7.0.7",
157
+ "storybook-dark-mode": "3.0.0",
157
158
  "stylelint": "14.9.1",
158
159
  "stylelint-config-prettier": "9.0.4",
159
160
  "stylelint-prettier": "2.0.0",
@@ -4,9 +4,7 @@ indicate an issue’s status, a member’s role, or if a branch is protected.
4
4
 
5
5
  ## Usage
6
6
 
7
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
8
7
  ```html
9
-
10
8
  <gl-badge>Hello, world!</gl-badge>
11
9
  ```
12
10
 
@@ -19,9 +19,7 @@ with the necessary classes added to make it look like a button, it shares the sa
19
19
  Icon-only buttons must have an accessible name.
20
20
  You can provide one with the `aria-label` attribute, which is read out by screen readers.
21
21
 
22
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
23
22
  ```html
24
-
25
23
  <gl-button icon="close" aria-label="Close" />
26
24
  ```
27
25
 
@@ -71,8 +71,6 @@ const availableTokens = [
71
71
  Pass the list of tokens to the search component. Optionally, you can use `v-model` to receive
72
72
  realtime updates:
73
73
 
74
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
75
74
  ```html
76
-
77
75
  <gl-filtered-search :available-tokens="tokens" v-model="value" terms-as-tokens />
78
76
  ```
@@ -10,9 +10,7 @@ is to `v-bind` to the
10
10
  [`PageInfo`](https://docs.gitlab.com/ee/api/graphql/reference/#pageinfo) type
11
11
  returned by the endpoint:
12
12
 
13
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
14
13
  ```html
15
-
16
14
  <gl-keyset-pagination v-bind="pageInfo" />
17
15
  ```
18
16
 
@@ -27,9 +25,7 @@ can't be translated.
27
25
 
28
26
  Example:
29
27
 
30
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
31
28
  ```html
32
-
33
29
  <gl-keyset-pagination v-bind="pageInfo" :prev-text="__('Prev')" :next-text="__('Next')" />
34
30
  ```
35
31
 
@@ -40,9 +40,7 @@ selector to the root element that contains the markdown-generated HTML.
40
40
 
41
41
  Set the `compact` property to true in `GlMarkdown` to apply the compact markdown styles.
42
42
 
43
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
44
43
  ```html
45
-
46
44
  <gl-markdown compact></gl-compact>
47
45
  ```
48
46
 
@@ -4,9 +4,7 @@ to make sure this is the right dropdown component for you.
4
4
 
5
5
  ### Basic usage
6
6
 
7
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
8
7
  ```html
9
-
10
8
  <gl-disclosure-dropdown-dropdown toggle-text="Actions" :items="items" />
11
9
  ```
12
10
 
@@ -50,10 +50,10 @@ describe('toggle', () => {
50
50
  });
51
51
 
52
52
  describe.each`
53
- state | disabled | disabledClassExpected | changeEventPayload
54
- ${'enabled'} | ${false} | ${false} | ${[[true]]}
55
- ${'disabled'} | ${true} | ${true} | ${undefined}
56
- `('when $state', ({ disabled, disabledClassExpected, changeEventPayload }) => {
53
+ state | disabled | disabledClassExpected | changeEventPayload | ariaDisabledValue
54
+ ${'enabled'} | ${false} | ${false} | ${[[true]]} | ${undefined}
55
+ ${'disabled'} | ${true} | ${true} | ${undefined} | ${'true'}
56
+ `('when $state', ({ disabled, disabledClassExpected, changeEventPayload, ariaDisabledValue }) => {
57
57
  beforeEach(() => {
58
58
  createWrapper({ disabled });
59
59
  });
@@ -67,6 +67,10 @@ describe('toggle', () => {
67
67
 
68
68
  expect(wrapper.emitted('change')).toEqual(changeEventPayload);
69
69
  });
70
+
71
+ it(`sets aria-disabled attribute to ${ariaDisabledValue}`, () => {
72
+ expect(findButton().attributes('aria-disabled')).toBe(ariaDisabledValue);
73
+ });
70
74
  });
71
75
 
72
76
  describe.each`
@@ -172,6 +172,7 @@ export default {
172
172
  :aria-checked="isChecked"
173
173
  :aria-labelledby="labelId"
174
174
  :aria-describedby="helpId"
175
+ :aria-disabled="disabled"
175
176
  :class="{
176
177
  'gl-toggle': true,
177
178
  'is-checked': value,
@@ -21,17 +21,13 @@ wbr {
21
21
  By default, `GlFriendlyWrap` wraps text with slashes (`/`) as the break-symbol, which is especially
22
22
  useful when displaying paths or URLs:
23
23
 
24
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
25
24
  ```html
26
-
27
25
  <gl-friendly-wrap text="/some/file/path" />
28
26
  ```
29
27
 
30
28
  The code above renders to the following HTML:
31
29
 
32
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
33
30
  ```html
34
-
35
31
  <span class="text-break">/<wbr>some/<wbr>file/<wbr>path</span>
36
32
  ```
37
33
 
@@ -48,9 +44,7 @@ Multiple custom break-symbols can be defined via the `GlFriendlyWrap` prop:
48
44
 
49
45
  Which renders to:
50
46
 
51
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
52
47
  ```html
53
-
54
48
  <span class="text-break">some;<wbr>text-<wbr>that.<wbr>needs;<wbr>to-<wbr>be.<wbr>wrapped</span>
55
49
  ```
56
50
 
@@ -67,8 +61,6 @@ Symbols can be words too:
67
61
 
68
62
  Which renders to:
69
63
 
70
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
71
64
  ```html
72
-
73
65
  <span class="text-break">it goes on and<wbr> on and<wbr> on and<wbr> on</span>
74
66
  ```
@@ -34,9 +34,7 @@ consistent formatting.
34
34
 
35
35
  This renders to the following HTML:
36
36
 
37
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
38
37
  ```html
39
-
40
38
  <span><span>Item 1</span>, <span>Item 2</span>, <span>Item 3</span></span>
41
39
  ```
42
40
 
@@ -54,9 +52,7 @@ A custom separator can be defined via the `separator` prop:
54
52
 
55
53
  This renders to the following HTML:
56
54
 
57
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
58
55
  ```html
59
-
60
56
  <span><span>Item 1</span>/<span>Item 2</span>/<span>Item 3</span></span>
61
57
  ```
62
58
 
@@ -74,9 +70,7 @@ A custom last separator can be defined via the `lastSeparator` prop:
74
70
 
75
71
  This renders to the following HTML:
76
72
 
77
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
78
73
  ```html
79
-
80
74
  <span><span>Item 1</span>, <span>Item 2</span>, and <span>Item 3</span></span>
81
75
  ```
82
76
 
@@ -91,8 +85,6 @@ A custom last separator used on two items will only place `lastSeparator` betwee
91
85
 
92
86
  This renders to the following HTML:
93
87
 
94
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
95
88
  ```html
96
-
97
89
  <span><span>Item 1</span> and <span>Item 2</span></span>
98
90
  ```
@@ -130,9 +130,7 @@ export default {
130
130
 
131
131
  The example above renders to this HTML:
132
132
 
133
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
134
133
  ```html
135
-
136
134
  <div>Written by <span>Some author</span></div>
137
135
  ```
138
136
 
@@ -4,9 +4,7 @@ The `GlTruncate` component lets you truncate the long texts with ellipsis.
4
4
 
5
5
  ## Usage
6
6
 
7
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
8
7
  ```html
9
-
10
8
  <gl-truncate :text="text" :position="position" />
11
9
  ```
12
10
 
@@ -46,9 +46,7 @@ const config = { ALLOWED_TAGS: ['b'] };
46
46
  const config = { ALLOWED_TAGS: [] };
47
47
  ```
48
48
 
49
- <!-- Empty initial line is a workaround for https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2102 -->
50
49
  ```html
51
-
52
50
  <div v-safe-html:[config]="rawHtml"></div>
53
51
  ```
54
52
 
@@ -49,23 +49,45 @@ export function hexToRgba(hex, opacity = 1) {
49
49
  return `rgba(${r}, ${g}, ${b}, ${opacity})`;
50
50
  }
51
51
 
52
+ export function toSrgb(value) {
53
+ const normalized = value / 255;
54
+ return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4;
55
+ }
56
+
57
+ export function relativeLuminance(rgb) {
58
+ // WCAG 2.1 formula: https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
59
+ // -
60
+ // WCAG 3.0 will use APAC
61
+ // Using APAC would be the ultimate goal, but was dismissed by engineering as of now
62
+ // See https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/3418#note_1370107090
63
+ return 0.2126 * toSrgb(rgb[0]) + 0.7152 * toSrgb(rgb[1]) + 0.0722 * toSrgb(rgb[2]);
64
+ }
65
+
52
66
  export function colorFromBackground(backgroundColor) {
53
- let r;
54
- let g;
55
- let b;
67
+ let color;
68
+ const lightColor = rgbFromHex('#FFFFFF');
69
+ const darkColor = rgbFromHex('#1f1e24');
56
70
 
57
71
  if (backgroundColor.startsWith('#')) {
58
- [r, g, b] = rgbFromHex(backgroundColor);
72
+ color = rgbFromHex(backgroundColor);
59
73
  } else if (backgroundColor.startsWith('rgba(')) {
60
- [r, g, b] = rgbFromString(backgroundColor, 5);
74
+ color = rgbFromString(backgroundColor, 5);
61
75
  } else if (backgroundColor.startsWith('rgb(')) {
62
- [r, g, b] = rgbFromString(backgroundColor, 4);
76
+ color = rgbFromString(backgroundColor, 4);
63
77
  }
64
78
 
65
- if (r + g + b <= 500) {
66
- return labelColorOptions.light;
67
- }
68
- return labelColorOptions.dark;
79
+ const luminance = relativeLuminance(color);
80
+ const lightLuminance = relativeLuminance(lightColor);
81
+ const darkLuminance = relativeLuminance(darkColor);
82
+
83
+ const contrastLight = (lightLuminance + 0.05) / (luminance + 0.05);
84
+ const contrastDark = (luminance + 0.05) / (darkLuminance + 0.05);
85
+
86
+ // Using a threshold contrast of 2.4 instead of 3
87
+ // as this will solve weird color combinations in the mid tones
88
+ return contrastLight >= 2.4 || contrastLight > contrastDark
89
+ ? labelColorOptions.light
90
+ : labelColorOptions.dark;
69
91
  }
70
92
 
71
93
  export function uid() {