@gitlab/ui 137.1.2 → 137.2.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.
- package/dist/components/charts/chart/chart.js +81 -20
- package/dist/components/charts/gauge/gauge.js +3 -13
- package/dist/components/charts/heatmap/heatmap.js +33 -13
- package/dist/components/charts/legend/legend.js +13 -1
- package/dist/index.css +2 -2
- package/dist/index.css.map +1 -1
- package/dist/tokens/build/js/tokens.dark.js +196 -191
- package/dist/tokens/build/js/tokens.js +218 -213
- package/dist/tokens/color_mode.js +17 -0
- package/dist/utils/charts/color_mode.js +95 -0
- package/dist/utils/charts/css_values.js +105 -0
- package/dist/utils/charts/theme.js +72 -7
- package/dist/utils/constants.js +5 -5
- package/package.json +6 -6
- package/src/components/base/alert/alert.scss +13 -48
- package/src/components/charts/chart/chart.vue +68 -22
- package/src/components/charts/gauge/gauge.vue +1 -12
- package/src/components/charts/heatmap/heatmap.vue +34 -10
- package/src/components/charts/legend/legend.vue +13 -1
- package/src/scss/themes.scss +23 -5
- package/src/tokens/build/css/tokens.css +20 -15
- package/src/tokens/build/css/tokens.dark.css +32 -27
- package/src/tokens/build/docs/tokens-tailwind-docs.dark.json +199 -199
- package/src/tokens/build/docs/tokens-tailwind-docs.json +198 -198
- package/src/tokens/build/figma/constants.dark.json +33 -33
- package/src/tokens/build/figma/constants.json +33 -33
- package/src/tokens/build/figma/mode.dark.json +66 -16
- package/src/tokens/build/figma/mode.json +54 -4
- package/src/tokens/build/js/tokens.dark.js +195 -190
- package/src/tokens/build/js/tokens.js +217 -212
- package/src/tokens/build/json/tokens.dark.json +378 -218
- package/src/tokens/build/json/tokens.json +388 -228
- package/src/tokens/build/scss/_tokens.dark.scss +32 -27
- package/src/tokens/build/scss/_tokens.scss +20 -15
- package/src/tokens/build/scss/_tokens_custom_properties.scss +5 -0
- package/src/tokens/color_mode.js +16 -0
- package/src/tokens/constant/color.neutral.tokens.json +33 -33
- package/src/tokens/contextual/alert.tokens.json +80 -35
- package/src/tokens/semantic/action.tokens.json +3 -3
- package/src/tokens/semantic/feedback.tokens.json +6 -6
- package/src/utils/charts/color_mode.js +83 -0
- package/src/utils/charts/css_values.js +59 -0
- package/src/utils/charts/theme.js +72 -5
- package/src/utils/constants.js +5 -5
|
@@ -30,10 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"background": {
|
|
32
32
|
"color": {
|
|
33
|
-
"$value": {
|
|
34
|
-
"default": "{feedback.neutral.background.color}",
|
|
35
|
-
"dark": "{background.color.subtle}"
|
|
36
|
-
},
|
|
33
|
+
"$value": "{feedback.neutral.background.color}",
|
|
37
34
|
"$type": "color",
|
|
38
35
|
"$description": "Used for the background color of a neutral alert.",
|
|
39
36
|
"$extensions": {
|
|
@@ -45,6 +42,16 @@
|
|
|
45
42
|
}
|
|
46
43
|
},
|
|
47
44
|
"border": {
|
|
45
|
+
"color": {
|
|
46
|
+
"$value": "{feedback.neutral.border.color}",
|
|
47
|
+
"$type": "color",
|
|
48
|
+
"$description": "Used for the border color of a neutral alert.",
|
|
49
|
+
"$extensions": {
|
|
50
|
+
"com.figma.scopes": [
|
|
51
|
+
"STROKE_COLOR"
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
48
55
|
"top": {
|
|
49
56
|
"color": {
|
|
50
57
|
"$value": {
|
|
@@ -52,13 +59,14 @@
|
|
|
52
59
|
"dark": "{color.neutral.400}"
|
|
53
60
|
},
|
|
54
61
|
"$type": "color",
|
|
55
|
-
"$description": "Used for the border
|
|
62
|
+
"$description": "Used for the border color of a neutral alert.",
|
|
56
63
|
"$extensions": {
|
|
57
64
|
"com.figma.scopes": [
|
|
58
65
|
"STROKE_COLOR"
|
|
59
66
|
]
|
|
60
67
|
}
|
|
61
|
-
}
|
|
68
|
+
},
|
|
69
|
+
"$deprecated": true
|
|
62
70
|
},
|
|
63
71
|
"bottom": {
|
|
64
72
|
"color": {
|
|
@@ -70,7 +78,8 @@
|
|
|
70
78
|
"STROKE_COLOR"
|
|
71
79
|
]
|
|
72
80
|
}
|
|
73
|
-
}
|
|
81
|
+
},
|
|
82
|
+
"$deprecated": true
|
|
74
83
|
}
|
|
75
84
|
}
|
|
76
85
|
},
|
|
@@ -79,7 +88,7 @@
|
|
|
79
88
|
"color": {
|
|
80
89
|
"$value": {
|
|
81
90
|
"default": "{text.color.heading}",
|
|
82
|
-
"dark": "{color.blue.
|
|
91
|
+
"dark": "{color.blue.200}"
|
|
83
92
|
},
|
|
84
93
|
"$type": "color",
|
|
85
94
|
"$description": "Used for the title color of an info alert.",
|
|
@@ -92,10 +101,7 @@
|
|
|
92
101
|
},
|
|
93
102
|
"background": {
|
|
94
103
|
"color": {
|
|
95
|
-
"$value": {
|
|
96
|
-
"default": "{feedback.info.background.color}",
|
|
97
|
-
"dark": "{background.color.subtle}"
|
|
98
|
-
},
|
|
104
|
+
"$value": "{feedback.info.background.color}",
|
|
99
105
|
"$type": "color",
|
|
100
106
|
"$description": "Used for the background color of an info alert.",
|
|
101
107
|
"$extensions": {
|
|
@@ -107,6 +113,16 @@
|
|
|
107
113
|
}
|
|
108
114
|
},
|
|
109
115
|
"border": {
|
|
116
|
+
"color": {
|
|
117
|
+
"$value": "{feedback.info.border.color}",
|
|
118
|
+
"$type": "color",
|
|
119
|
+
"$description": "Used for the border color of an info alert.",
|
|
120
|
+
"$extensions": {
|
|
121
|
+
"com.figma.scopes": [
|
|
122
|
+
"STROKE_COLOR"
|
|
123
|
+
]
|
|
124
|
+
}
|
|
125
|
+
},
|
|
110
126
|
"top": {
|
|
111
127
|
"color": {
|
|
112
128
|
"$value": {
|
|
@@ -120,14 +136,16 @@
|
|
|
120
136
|
"STROKE_COLOR"
|
|
121
137
|
]
|
|
122
138
|
}
|
|
123
|
-
}
|
|
139
|
+
},
|
|
140
|
+
"$deprecated": true
|
|
124
141
|
},
|
|
125
142
|
"bottom": {
|
|
126
143
|
"color": {
|
|
127
144
|
"$value": "{color.alpha.0}",
|
|
128
145
|
"$type": "color",
|
|
129
146
|
"$description": "Used for the border bottom color of an info alert."
|
|
130
|
-
}
|
|
147
|
+
},
|
|
148
|
+
"$deprecated": true
|
|
131
149
|
}
|
|
132
150
|
}
|
|
133
151
|
},
|
|
@@ -136,7 +154,7 @@
|
|
|
136
154
|
"color": {
|
|
137
155
|
"$value": {
|
|
138
156
|
"default": "{text.color.heading}",
|
|
139
|
-
"dark": "{color.green.
|
|
157
|
+
"dark": "{color.green.200}"
|
|
140
158
|
},
|
|
141
159
|
"$type": "color",
|
|
142
160
|
"$description": "Used for the title color of a success alert.",
|
|
@@ -149,10 +167,7 @@
|
|
|
149
167
|
},
|
|
150
168
|
"background": {
|
|
151
169
|
"color": {
|
|
152
|
-
"$value": {
|
|
153
|
-
"default": "{feedback.success.background.color}",
|
|
154
|
-
"dark": "{background.color.subtle}"
|
|
155
|
-
},
|
|
170
|
+
"$value": "{feedback.success.background.color}",
|
|
156
171
|
"$type": "color",
|
|
157
172
|
"$description": "Used for the background color of a success alert.",
|
|
158
173
|
"$extensions": {
|
|
@@ -164,6 +179,16 @@
|
|
|
164
179
|
}
|
|
165
180
|
},
|
|
166
181
|
"border": {
|
|
182
|
+
"color": {
|
|
183
|
+
"$value": "{feedback.success.border.color}",
|
|
184
|
+
"$type": "color",
|
|
185
|
+
"$description": "Used for the border color of a success alert.",
|
|
186
|
+
"$extensions": {
|
|
187
|
+
"com.figma.scopes": [
|
|
188
|
+
"STROKE_COLOR"
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
},
|
|
167
192
|
"top": {
|
|
168
193
|
"color": {
|
|
169
194
|
"$value": {
|
|
@@ -177,7 +202,8 @@
|
|
|
177
202
|
"STROKE_COLOR"
|
|
178
203
|
]
|
|
179
204
|
}
|
|
180
|
-
}
|
|
205
|
+
},
|
|
206
|
+
"$deprecated": true
|
|
181
207
|
},
|
|
182
208
|
"bottom": {
|
|
183
209
|
"color": {
|
|
@@ -189,7 +215,8 @@
|
|
|
189
215
|
"STROKE_COLOR"
|
|
190
216
|
]
|
|
191
217
|
}
|
|
192
|
-
}
|
|
218
|
+
},
|
|
219
|
+
"$deprecated": true
|
|
193
220
|
}
|
|
194
221
|
}
|
|
195
222
|
},
|
|
@@ -198,7 +225,7 @@
|
|
|
198
225
|
"color": {
|
|
199
226
|
"$value": {
|
|
200
227
|
"default": "{text.color.heading}",
|
|
201
|
-
"dark": "{color.orange.
|
|
228
|
+
"dark": "{color.orange.200}"
|
|
202
229
|
},
|
|
203
230
|
"$type": "color",
|
|
204
231
|
"$description": "Used for the title color of a warning alert.",
|
|
@@ -211,10 +238,7 @@
|
|
|
211
238
|
},
|
|
212
239
|
"background": {
|
|
213
240
|
"color": {
|
|
214
|
-
"$value": {
|
|
215
|
-
"default": "{feedback.warning.background.color}",
|
|
216
|
-
"dark": "{background.color.subtle}"
|
|
217
|
-
},
|
|
241
|
+
"$value": "{feedback.warning.background.color}",
|
|
218
242
|
"$type": "color",
|
|
219
243
|
"$description": "Used for the background color of a warning alert.",
|
|
220
244
|
"$extensions": {
|
|
@@ -226,6 +250,16 @@
|
|
|
226
250
|
}
|
|
227
251
|
},
|
|
228
252
|
"border": {
|
|
253
|
+
"color": {
|
|
254
|
+
"$value": "{feedback.warning.border.color}",
|
|
255
|
+
"$type": "color",
|
|
256
|
+
"$description": "Used for the border color of a warning alert.",
|
|
257
|
+
"$extensions": {
|
|
258
|
+
"com.figma.scopes": [
|
|
259
|
+
"STROKE_COLOR"
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
},
|
|
229
263
|
"top": {
|
|
230
264
|
"color": {
|
|
231
265
|
"$value": {
|
|
@@ -239,7 +273,8 @@
|
|
|
239
273
|
"STROKE_COLOR"
|
|
240
274
|
]
|
|
241
275
|
}
|
|
242
|
-
}
|
|
276
|
+
},
|
|
277
|
+
"$deprecated": true
|
|
243
278
|
},
|
|
244
279
|
"bottom": {
|
|
245
280
|
"color": {
|
|
@@ -251,7 +286,8 @@
|
|
|
251
286
|
"STROKE_COLOR"
|
|
252
287
|
]
|
|
253
288
|
}
|
|
254
|
-
}
|
|
289
|
+
},
|
|
290
|
+
"$deprecated": true
|
|
255
291
|
}
|
|
256
292
|
}
|
|
257
293
|
},
|
|
@@ -260,7 +296,7 @@
|
|
|
260
296
|
"color": {
|
|
261
297
|
"$value": {
|
|
262
298
|
"default": "{text.color.heading}",
|
|
263
|
-
"dark": "{color.red.
|
|
299
|
+
"dark": "{color.red.200}"
|
|
264
300
|
},
|
|
265
301
|
"$type": "color",
|
|
266
302
|
"$description": "Used for the title color of a danger alert.",
|
|
@@ -273,10 +309,7 @@
|
|
|
273
309
|
},
|
|
274
310
|
"background": {
|
|
275
311
|
"color": {
|
|
276
|
-
"$value": {
|
|
277
|
-
"default": "{feedback.danger.background.color}",
|
|
278
|
-
"dark": "{background.color.subtle}"
|
|
279
|
-
},
|
|
312
|
+
"$value": "{feedback.danger.background.color}",
|
|
280
313
|
"$type": "color",
|
|
281
314
|
"$description": "Used for the background color of a danger alert.",
|
|
282
315
|
"$extensions": {
|
|
@@ -288,6 +321,16 @@
|
|
|
288
321
|
}
|
|
289
322
|
},
|
|
290
323
|
"border": {
|
|
324
|
+
"color": {
|
|
325
|
+
"$value": "{feedback.danger.border.color}",
|
|
326
|
+
"$type": "color",
|
|
327
|
+
"$description": "Used for the border color of a danger alert.",
|
|
328
|
+
"$extensions": {
|
|
329
|
+
"com.figma.scopes": [
|
|
330
|
+
"STROKE_COLOR"
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
},
|
|
291
334
|
"top": {
|
|
292
335
|
"color": {
|
|
293
336
|
"$value": {
|
|
@@ -301,7 +344,8 @@
|
|
|
301
344
|
"STROKE_COLOR"
|
|
302
345
|
]
|
|
303
346
|
}
|
|
304
|
-
}
|
|
347
|
+
},
|
|
348
|
+
"$deprecated": true
|
|
305
349
|
},
|
|
306
350
|
"bottom": {
|
|
307
351
|
"color": {
|
|
@@ -313,7 +357,8 @@
|
|
|
313
357
|
"STROKE_COLOR"
|
|
314
358
|
]
|
|
315
359
|
}
|
|
316
|
-
}
|
|
360
|
+
},
|
|
361
|
+
"$deprecated": true
|
|
317
362
|
}
|
|
318
363
|
}
|
|
319
364
|
}
|
|
@@ -542,7 +542,7 @@
|
|
|
542
542
|
"color": {
|
|
543
543
|
"default": {
|
|
544
544
|
"$value": {
|
|
545
|
-
"default": "{color.red.
|
|
545
|
+
"default": "{color.red.600}",
|
|
546
546
|
"dark": "{color.red.200}"
|
|
547
547
|
},
|
|
548
548
|
"$type": "color",
|
|
@@ -556,7 +556,7 @@
|
|
|
556
556
|
},
|
|
557
557
|
"hover": {
|
|
558
558
|
"$value": {
|
|
559
|
-
"default": "{color.red.
|
|
559
|
+
"default": "{color.red.800}",
|
|
560
560
|
"dark": "{color.red.100}"
|
|
561
561
|
},
|
|
562
562
|
"$type": "color",
|
|
@@ -581,7 +581,7 @@
|
|
|
581
581
|
},
|
|
582
582
|
"active": {
|
|
583
583
|
"$value": {
|
|
584
|
-
"default": "{color.red.
|
|
584
|
+
"default": "{color.red.950}",
|
|
585
585
|
"dark": "{color.red.100}"
|
|
586
586
|
},
|
|
587
587
|
"$type": "color",
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
"color": {
|
|
131
131
|
"$value": {
|
|
132
132
|
"default": "{color.neutral.600}",
|
|
133
|
-
"dark": "{color.neutral.
|
|
133
|
+
"dark": "{color.neutral.200}"
|
|
134
134
|
},
|
|
135
135
|
"$type": "color",
|
|
136
136
|
"$description": "Used for the icon of a neutral feedback item when there isn't a specific meaning or urgency.",
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
"color": {
|
|
195
195
|
"$value": {
|
|
196
196
|
"default": "{color.blue.600}",
|
|
197
|
-
"dark": "{color.blue.
|
|
197
|
+
"dark": "{color.blue.200}"
|
|
198
198
|
},
|
|
199
199
|
"$type": "color",
|
|
200
200
|
"$description": "Used for the icon of an informational feedback item when highlighting new information or a change that doesn't require immediate action.",
|
|
@@ -258,7 +258,7 @@
|
|
|
258
258
|
"color": {
|
|
259
259
|
"$value": {
|
|
260
260
|
"default": "{color.green.600}",
|
|
261
|
-
"dark": "{color.green.
|
|
261
|
+
"dark": "{color.green.200}"
|
|
262
262
|
},
|
|
263
263
|
"$type": "color",
|
|
264
264
|
"$description": "Used for the icon of a success feedback item when confirming the successful completion of a user-initiated action.",
|
|
@@ -322,7 +322,7 @@
|
|
|
322
322
|
"color": {
|
|
323
323
|
"$value": {
|
|
324
324
|
"default": "{color.orange.600}",
|
|
325
|
-
"dark": "{color.orange.
|
|
325
|
+
"dark": "{color.orange.200}"
|
|
326
326
|
},
|
|
327
327
|
"$type": "color",
|
|
328
328
|
"$description": "Used for the icon of a warning feedback item when notifying about a potential issue or sensitive information.",
|
|
@@ -386,7 +386,7 @@
|
|
|
386
386
|
"color": {
|
|
387
387
|
"$value": {
|
|
388
388
|
"default": "{color.red.600}",
|
|
389
|
-
"dark": "{color.red.
|
|
389
|
+
"dark": "{color.red.200}"
|
|
390
390
|
},
|
|
391
391
|
"$type": "color",
|
|
392
392
|
"$description": "Used for the icon of a danger feedback item when notifying about a critical issue that has just occurred and requires immediate attention.",
|
|
@@ -450,7 +450,7 @@
|
|
|
450
450
|
"color": {
|
|
451
451
|
"$value": {
|
|
452
452
|
"default": "{color.purple.600}",
|
|
453
|
-
"dark": "{color.purple.
|
|
453
|
+
"dark": "{color.purple.200}"
|
|
454
454
|
},
|
|
455
455
|
"$type": "color",
|
|
456
456
|
"$description": "Used for the icon of a brand-related feedback item when highlighting information that pertains to GitLab.",
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { DARK_ROOT_CLASS, DARK_SCOPE_CLASS, LIGHT_SCOPE_CLASS } from '../../tokens/color_mode';
|
|
2
|
+
|
|
3
|
+
const SCOPE_CLASSES = [DARK_SCOPE_CLASS, LIGHT_SCOPE_CLASS, DARK_ROOT_CLASS];
|
|
4
|
+
|
|
5
|
+
const SCOPE_SELECTOR = SCOPE_CLASSES.map((scopeClass) => `.${scopeClass}`).join(', ');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Whether the given element sits in dark mode.
|
|
9
|
+
*
|
|
10
|
+
* Colour mode is not a document-wide fact. Tokens are declared for the root dark class and for a
|
|
11
|
+
* dark scope class, so any subtree can be flipped independently, and a light scope can flip one
|
|
12
|
+
* back inside a dark document. The nearest scope wins, which is what `closest` gives us.
|
|
13
|
+
*
|
|
14
|
+
* This lives under `charts` rather than in the general utilities because charts are the only thing
|
|
15
|
+
* in the package that needs it. Everywhere else, colour follows tokens and CSS re-resolves them on
|
|
16
|
+
* its own. Charts cannot always do that: ECharts parses colours numerically for its visual maps,
|
|
17
|
+
* and canvas cannot read custom properties at all, so those values have to be chosen in JavaScript
|
|
18
|
+
* and re-chosen when the mode changes.
|
|
19
|
+
*/
|
|
20
|
+
export const isDarkMode = (element) => {
|
|
21
|
+
const scope = element?.closest?.(SCOPE_SELECTOR);
|
|
22
|
+
|
|
23
|
+
return Boolean(scope) && !scope.classList.contains(LIGHT_SCOPE_CLASS);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Keyed by subscription so that each subscribed element's last known mode is tracked separately.
|
|
27
|
+
const subscriptions = new Map();
|
|
28
|
+
let observer = null;
|
|
29
|
+
|
|
30
|
+
// Most class mutations (hover states, dropdowns opening and closing) have nothing to do with the
|
|
31
|
+
// colour mode. Only mutations that added or removed a scope class can change it, so anything else
|
|
32
|
+
// can be dismissed with this cheap check instead of re-checking every subscriber.
|
|
33
|
+
const touchesColorMode = ({ target, oldValue }) =>
|
|
34
|
+
SCOPE_CLASSES.some(
|
|
35
|
+
(scopeClass) => target.classList?.contains(scopeClass) || oldValue?.includes(scopeClass),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const notify = () => {
|
|
39
|
+
subscriptions.forEach(({ element, subscriber, mode }, key) => {
|
|
40
|
+
const current = isDarkMode(element);
|
|
41
|
+
|
|
42
|
+
if (current !== mode) {
|
|
43
|
+
subscriptions.set(key, { element, subscriber, mode: current });
|
|
44
|
+
subscriber(current);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Calls back when the colour mode of `element` changes, and returns a function that unsubscribes.
|
|
51
|
+
*
|
|
52
|
+
* Most colour can be left to CSS, which re-resolves custom properties on its own. This exists for
|
|
53
|
+
* the places that cannot: colours ECharts parses numerically, such as the interpolated stops of a
|
|
54
|
+
* continuous `visualMap`, and colours handed to a canvas context. Both need a concrete value picked
|
|
55
|
+
* in JavaScript, so both need telling when the mode flips.
|
|
56
|
+
*
|
|
57
|
+
* Because a scope class can live on any ancestor, this watches the whole document for class
|
|
58
|
+
* changes, then re-checks each subscribed element and only calls back when its own mode changed.
|
|
59
|
+
*/
|
|
60
|
+
export const onColorModeChange = (element, subscriber) => {
|
|
61
|
+
if (!subscriptions.size && typeof MutationObserver !== 'undefined') {
|
|
62
|
+
observer = new MutationObserver((mutations) => {
|
|
63
|
+
if (mutations.some((mutation) => touchesColorMode(mutation))) notify();
|
|
64
|
+
});
|
|
65
|
+
observer.observe(document.documentElement, {
|
|
66
|
+
attributeFilter: ['class'],
|
|
67
|
+
attributeOldValue: true,
|
|
68
|
+
subtree: true,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const key = Symbol('colorModeSubscription');
|
|
73
|
+
subscriptions.set(key, { element, subscriber, mode: isDarkMode(element) });
|
|
74
|
+
|
|
75
|
+
return () => {
|
|
76
|
+
subscriptions.delete(key);
|
|
77
|
+
|
|
78
|
+
if (!subscriptions.size) {
|
|
79
|
+
observer?.disconnect();
|
|
80
|
+
observer = null;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { mapValues } from 'lodash-es';
|
|
2
|
+
|
|
3
|
+
const CSS_VAR = /^var\(\s*(--[\w-]+)\s*(?:,\s*([\s\S]*?)\s*)?\)$/;
|
|
4
|
+
|
|
5
|
+
const resolveString = (value, styles) => {
|
|
6
|
+
if (value.toLowerCase() === 'currentcolor') {
|
|
7
|
+
return styles.color;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const match = CSS_VAR.exec(value);
|
|
11
|
+
if (!match) {
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const [, name, fallback] = match;
|
|
16
|
+
const resolved = styles.getPropertyValue(name).trim();
|
|
17
|
+
|
|
18
|
+
if (resolved) {
|
|
19
|
+
return resolved;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return fallback ? resolveString(fallback, styles) : value;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Deeply replaces `var(--token)` and `currentcolor` strings with the values they resolve to for the
|
|
27
|
+
* given element.
|
|
28
|
+
*
|
|
29
|
+
* The SVG renderer needs none of this: it emits both forms into the DOM, where the browser resolves
|
|
30
|
+
* them and keeps them live across a colour-mode change. Canvas has no such context. `fillStyle` is
|
|
31
|
+
* a plain string setter, so an unparseable `var(--token)` is dropped on the floor and leaves the
|
|
32
|
+
* previous fill in place, while `currentcolor` has no element to inherit from and is defined to
|
|
33
|
+
* resolve to opaque black. Either way a canvas-rendered chart silently loses its themed colours.
|
|
34
|
+
*
|
|
35
|
+
* Resolution is relative to `element` rather than the document root so that `.gl-dark-scope`
|
|
36
|
+
* ancestors are honoured.
|
|
37
|
+
*
|
|
38
|
+
* Values are resolved once, so callers are responsible for resolving again when the colour mode
|
|
39
|
+
* changes.
|
|
40
|
+
*/
|
|
41
|
+
export const resolveCssValues = (input, element) => {
|
|
42
|
+
const styles = window.getComputedStyle(element);
|
|
43
|
+
|
|
44
|
+
const walk = (value) => {
|
|
45
|
+
if (typeof value === 'string') {
|
|
46
|
+
return resolveString(value, styles);
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
return value.map((item) => walk(item));
|
|
50
|
+
}
|
|
51
|
+
// Themes carry functions (formatters) which must pass through untouched.
|
|
52
|
+
if (value !== null && typeof value === 'object') {
|
|
53
|
+
return mapValues(value, walk);
|
|
54
|
+
}
|
|
55
|
+
return value;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return walk(input);
|
|
59
|
+
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
+
GL_COLOR_NEUTRAL_0,
|
|
2
3
|
GL_COLOR_NEUTRAL_50,
|
|
3
4
|
GL_COLOR_NEUTRAL_100,
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
GL_COLOR_NEUTRAL_800,
|
|
6
|
+
GL_COLOR_NEUTRAL_950,
|
|
6
7
|
GL_COLOR_DATA_AQUA_50,
|
|
7
8
|
GL_COLOR_DATA_AQUA_100,
|
|
8
9
|
GL_COLOR_DATA_AQUA_200,
|
|
@@ -58,6 +59,7 @@ import {
|
|
|
58
59
|
GL_COLOR_DATA_ORANGE_800,
|
|
59
60
|
GL_COLOR_DATA_ORANGE_950,
|
|
60
61
|
GL_COLOR_DATA_ORANGE_900,
|
|
62
|
+
GL_FONT_FAMILY_REGULAR,
|
|
61
63
|
} from '../../tokens/build/js/tokens';
|
|
62
64
|
import {
|
|
63
65
|
scrollHandleSvgPath,
|
|
@@ -66,20 +68,45 @@ import {
|
|
|
66
68
|
clearAllSvgPath,
|
|
67
69
|
downloadSvgPath,
|
|
68
70
|
} from '../svgs/svg_paths';
|
|
71
|
+
import { defaultFontSize } from './config';
|
|
69
72
|
|
|
70
73
|
const GL_BORDER_RADIUS_BASE = '0.25rem';
|
|
71
74
|
|
|
72
75
|
export const themeName = 'gitlab';
|
|
73
76
|
|
|
77
|
+
/**
|
|
78
|
+
* Sequential scales step away from the surface so that higher values gain contrast against it:
|
|
79
|
+
* darker on a light surface, lighter on a dark one. The lowest step is neutral rather than blue, so
|
|
80
|
+
* that "no data" reads as absence instead of as the bottom of the data range.
|
|
81
|
+
*
|
|
82
|
+
* https://design.gitlab.com/data-visualization/color#sequential-data
|
|
83
|
+
*/
|
|
74
84
|
export const heatmapHues = [
|
|
75
85
|
GL_COLOR_NEUTRAL_100,
|
|
76
|
-
|
|
77
|
-
GL_COLOR_DATA_BLUE_400,
|
|
86
|
+
GL_COLOR_DATA_BLUE_500,
|
|
78
87
|
GL_COLOR_DATA_BLUE_600,
|
|
79
88
|
GL_COLOR_DATA_BLUE_800,
|
|
89
|
+
GL_COLOR_DATA_BLUE_950,
|
|
80
90
|
];
|
|
81
91
|
|
|
82
|
-
export const
|
|
92
|
+
export const heatmapHuesDark = [
|
|
93
|
+
GL_COLOR_NEUTRAL_800,
|
|
94
|
+
GL_COLOR_DATA_BLUE_600,
|
|
95
|
+
GL_COLOR_DATA_BLUE_500,
|
|
96
|
+
GL_COLOR_DATA_BLUE_400,
|
|
97
|
+
GL_COLOR_DATA_BLUE_200,
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The plate behind the cells, and the separators between them. Separators match the surface so that
|
|
102
|
+
* neighbouring cells, which are only guaranteed to contrast with the surface and not with each
|
|
103
|
+
* other, stay distinguishable.
|
|
104
|
+
*
|
|
105
|
+
* https://design.gitlab.com/data-visualization/color#visual-separators
|
|
106
|
+
*/
|
|
107
|
+
export const heatmapSurface = { plate: GL_COLOR_NEUTRAL_100, separator: GL_COLOR_NEUTRAL_0 };
|
|
108
|
+
export const heatmapSurfaceDark = { plate: GL_COLOR_NEUTRAL_800, separator: GL_COLOR_NEUTRAL_950 };
|
|
109
|
+
|
|
83
110
|
export const gaugeSafeHues = [GL_COLOR_DATA_BLUE_500, GL_COLOR_DATA_BLUE_900];
|
|
84
111
|
export const gaugeWarningHue = GL_COLOR_DATA_ORANGE_500;
|
|
85
112
|
|
|
@@ -159,12 +186,33 @@ export const colorPaletteDark = [
|
|
|
159
186
|
|
|
160
187
|
export const colorFromDarkPalette = (index) => colorPaletteDark[index % colorPaletteDark.length];
|
|
161
188
|
|
|
189
|
+
// ECharts lays out text by assigning a CSS font shorthand to a canvas context and calling
|
|
190
|
+
// `measureText`, even under the SVG renderer. Canvas does not substitute CSS custom properties,
|
|
191
|
+
// and an unparseable shorthand is rejected wholesale, leaving text measured at the canvas default
|
|
192
|
+
// of 10px sans-serif. So the chart font stack must be concrete: drop the leading
|
|
193
|
+
// `var(--default-regular-font, 'GitLab Sans')` consumer override, whose own fallback is the
|
|
194
|
+
// 'GitLab Sans' that follows it.
|
|
195
|
+
export const defaultFontFamily = GL_FONT_FAMILY_REGULAR.filter(
|
|
196
|
+
(family) => !family.startsWith('var('),
|
|
197
|
+
).join(', ');
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Chart font sizes are concrete pixel numbers rather than the rem-based font.size tokens they
|
|
201
|
+
* mirror. zrender measures text on a detached canvas, which always resolves 1rem as 16px however
|
|
202
|
+
* the document root is set, so rem sizes render scaled while being laid out at the wrong width.
|
|
203
|
+
*
|
|
204
|
+
* `defaultFontSize` (12, font.size.100) is set per component in the theme below, because ECharts
|
|
205
|
+
* pins fontSize in its own component defaults (axis labels at 12, title at 18, gauge detail at 30)
|
|
206
|
+
* and those shadow `textStyle`.
|
|
207
|
+
*/
|
|
208
|
+
|
|
162
209
|
const axes = {
|
|
163
210
|
axisLabel: {
|
|
164
211
|
margin: 8,
|
|
165
212
|
show: true,
|
|
166
213
|
color: 'var(--gl-chart-axis-text-color)',
|
|
167
214
|
hideOverlap: true,
|
|
215
|
+
fontSize: defaultFontSize,
|
|
168
216
|
},
|
|
169
217
|
axisLine: {
|
|
170
218
|
show: false,
|
|
@@ -188,6 +236,7 @@ const axes = {
|
|
|
188
236
|
nameGap: 30,
|
|
189
237
|
nameTextStyle: {
|
|
190
238
|
fontWeight: 'bold',
|
|
239
|
+
fontSize: defaultFontSize,
|
|
191
240
|
},
|
|
192
241
|
splitLine: {
|
|
193
242
|
lineStyle: {
|
|
@@ -208,6 +257,24 @@ export const createTheme = (options = {}) => ({
|
|
|
208
257
|
backgroundColor: 'transparent',
|
|
209
258
|
textStyle: {
|
|
210
259
|
color: 'var(--gl-text-color-default)',
|
|
260
|
+
fontFamily: defaultFontFamily,
|
|
261
|
+
fontSize: defaultFontSize,
|
|
262
|
+
},
|
|
263
|
+
title: {
|
|
264
|
+
textStyle: {
|
|
265
|
+
fontSize: 18, // font.size.500-fixed, 1.125rem
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
gauge: {
|
|
269
|
+
axisLabel: {
|
|
270
|
+
fontSize: 14, // font.size.300, 0.875rem, the default body size
|
|
271
|
+
color: 'var(--gl-chart-axis-text-color)',
|
|
272
|
+
},
|
|
273
|
+
detail: {
|
|
274
|
+
fontSize: 30,
|
|
275
|
+
fontWeight: 'bold',
|
|
276
|
+
color: 'var(--gl-text-color-default)',
|
|
277
|
+
},
|
|
211
278
|
},
|
|
212
279
|
markLine: {
|
|
213
280
|
silent: true,
|
package/src/utils/constants.js
CHANGED
|
@@ -393,9 +393,9 @@ export const loadingIconVariants = {
|
|
|
393
393
|
|
|
394
394
|
export const themes = [
|
|
395
395
|
{ class: null, value: 'default', title: 'Default' },
|
|
396
|
-
{ class: '
|
|
397
|
-
{ class: '
|
|
398
|
-
{ class: '
|
|
399
|
-
{ class: '
|
|
400
|
-
{ class: '
|
|
396
|
+
{ class: 'ui-indigo', value: 'indigo', title: 'Indigo' },
|
|
397
|
+
{ class: 'ui-blue', value: 'blue', title: 'Blue' },
|
|
398
|
+
{ class: 'ui-green', value: 'green', title: 'Green' },
|
|
399
|
+
{ class: 'ui-red', value: 'red', title: 'Red' },
|
|
400
|
+
{ class: 'ui-gray', value: 'gray', title: 'Gray' },
|
|
401
401
|
];
|