@financial-times/o-private-foundation 1.0.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.
Files changed (36) hide show
  1. package/README.md +108 -0
  2. package/demos/src/demo.mustache +0 -0
  3. package/demos/src/demo.scss +1 -0
  4. package/main.js +60 -0
  5. package/main.scss +32 -0
  6. package/origami.json +26 -0
  7. package/package.json +33 -0
  8. package/src/scss/_brand.scss +68 -0
  9. package/src/scss/_tokens.scss +15 -0
  10. package/src/scss/_variables.scss +1 -0
  11. package/src/scss/o-buttons/custom-themes.scss +631 -0
  12. package/src/scss/o-buttons/main.scss +255 -0
  13. package/src/scss/o-colors/_functions.scss +354 -0
  14. package/src/scss/o-colors/_palette.scss +2 -0
  15. package/src/scss/o-colors/_variables.scss +50 -0
  16. package/src/scss/o-colors/main.scss +6 -0
  17. package/src/scss/o-grid/_functions.scss +90 -0
  18. package/src/scss/o-grid/_mixins.scss +384 -0
  19. package/src/scss/o-grid/_variables.scss +105 -0
  20. package/src/scss/o-grid/main.scss +5 -0
  21. package/src/scss/o-icons/_mixins.scss +71 -0
  22. package/src/scss/o-icons/main.scss +1 -0
  23. package/src/scss/o-normalise/_mixins.scss +126 -0
  24. package/src/scss/o-normalise/_variables.scss +10 -0
  25. package/src/scss/o-normalise/main.scss +4 -0
  26. package/src/scss/o-spacing/_variables.scss +29 -0
  27. package/src/scss/o-spacing/main.scss +28 -0
  28. package/src/scss/o-typography/main.scss +428 -0
  29. package/src/scss/o-visual-effects/main.scss +4 -0
  30. package/src/scss/o-visual-effects/scss/_shadows.scss +31 -0
  31. package/src/scss/o-visual-effects/scss/_variables.scss +13 -0
  32. package/src/scss/tokens/core.scss +563 -0
  33. package/src/scss/tokens/internal.scss +456 -0
  34. package/src/scss/tokens/professional.scss +537 -0
  35. package/src/scss/tokens/sustainable-views.scss +493 -0
  36. package/src/scss/tokens/whitelabel.scss +465 -0
@@ -0,0 +1,631 @@
1
+ /// oPrivateButtonsContent but with a custom theme.
2
+ /// @param {Map} $opts [('type': 'null', 'size': null, 'icon': null, 'icon-only': false)] - The kind of button styles to output.
3
+ /// @param {Map} $theme-override - The button theme to output. Either a default theme 'inverse' or custom theme map with properties `name`, `color`, and optional `context` key.
4
+ @mixin oPrivateButtonsContentWithThemeOverride(
5
+ $opts: (
6
+ 'type': null,
7
+ 'size': null,
8
+ 'icon': null,
9
+ 'icon-only': false,
10
+ ),
11
+ $theme-override
12
+ ) {
13
+ $type: map-get($opts, 'type');
14
+ $type: if($type, $type, 'primary');
15
+ $generated-colors: _oPrivateButtonsGenerateColors($type, $theme-override);
16
+
17
+ @include _oPrivateButtonsBase($opts);
18
+ @include _oPrivateButtonsTheme($generated-colors);
19
+ }
20
+
21
+ /// Generate the colours for a button type and theme, either an existing theme
22
+ /// or a new theme map.
23
+ ///
24
+ /// @example
25
+ /// // $colors: _oPrivateButtonsGetColors('primary', ('color': 'white', 'context': 'slate'));
26
+ /// // (
27
+ /// // "color": black,
28
+ /// // "background": #ffffff,
29
+ /// // "border": transparent,
30
+ /// // "hover-background": #c9cacc,
31
+ /// // "hover-color": black,
32
+ /// // "focus-background": #c9cacc,
33
+ /// // "focus-color": black,
34
+ /// // "active-background": #9d9fa3,
35
+ /// // "active-color": black,
36
+ /// // "hover-border": transparent,
37
+ /// // "focus-border": transparent,
38
+ /// // "active-border": transparent
39
+ /// // )
40
+ ///
41
+ /// @param {String} $type
42
+ /// @param {String|Map} $theme
43
+ /// @return {Map} - Button colours.
44
+ @function _oPrivateButtonsGenerateColors($type, $theme: null) {
45
+ @if ($type != 'primary' and $type != 'secondary' and $type != 'ghost') {
46
+ @error 'Expected a button type of "secondary" or "primary" or "ghost".';
47
+ }
48
+
49
+ // Get button colour from custom theme map or brand config, see _brand.scss.
50
+ $color: map-get($theme, 'color');
51
+ $context-color: map-get($theme, 'context');
52
+
53
+ // Get button context, which is the background colour the button is placed on.
54
+ $page-background-usecase: oPrivateFoundationGet('o3-color-use-case-page-background');
55
+ $context-color: if($context-color, $context-color, $page-background-usecase);
56
+
57
+ // Get button colours depending on button type.
58
+ $color-map: ();
59
+ @if ($type == 'primary') {
60
+ $color-map: _oPrivateButtonsGetPrimaryButtonColors($color, $context-color);
61
+ }
62
+
63
+ @if ($type == 'secondary') {
64
+ $color-map: _oPrivateButtonsGetSecondaryButtonColors(
65
+ $color,
66
+ $context-color
67
+ );
68
+ }
69
+
70
+ @if ($type == 'ghost') {
71
+ $color-map: _oPrivateButtonsGetGhostButtonColors($color, $context-color);
72
+ }
73
+
74
+ // If a button state does not have a property configured, set it to the
75
+ // default button colour.
76
+ @each $property in ('color', 'background', 'border') {
77
+ @each $state in ('hover', 'focus', 'active') {
78
+ $state-color: map-get($color-map, '#{$state}-#{$property}');
79
+ @if (not $state-color) {
80
+ $color-map: map-merge(
81
+ $color-map,
82
+ (
83
+ '#{$state}-#{$property}': map-get($color-map, $property),
84
+ )
85
+ );
86
+ }
87
+ }
88
+ }
89
+ @return $color-map;
90
+ }
91
+
92
+ /// For a colour and context colour (the background colour behind the button),
93
+ /// generate primary button colours and overrides for each button state.
94
+ ///
95
+ /// @example
96
+ /// $colors: _oPrivateButtonsGetPrimaryButtonColors('lemon', 'slate');
97
+ /// // (
98
+ /// // "color": black,
99
+ /// // "background": #ffec1a,
100
+ /// // "border": transparent,
101
+ /// // "hover-background": #ccbd14,
102
+ /// // "hover-color": black,
103
+ /// // "focus-background": #ccbd14,
104
+ /// // "focus-color": black,
105
+ /// // "active-background": #a69911,
106
+ /// // "active-color": black
107
+ /// // )
108
+ ///
109
+ /// @param {String|Color} $color - The button colour e.g. 'teal' (from `o-colors` palette).
110
+ /// @param {String|Color} $context-color - The page colour behind the button (from `o-colors` palette).
111
+ /// @return {Map} - Colours for a primary button. Including overrides for each button state.
112
+ @function _oPrivateButtonsGetPrimaryButtonColors($color, $context-color) {
113
+ $color-arg: $color;
114
+ $context-color-arg: $context-color;
115
+ $default-background: if(
116
+ type-of($color) == 'string',
117
+ oPrivateFoundationGet($color),
118
+ $color
119
+ );
120
+ $context-color: if(
121
+ type-of($context-color) == 'string',
122
+ oPrivateFoundationGet($context-color),
123
+ $context-color
124
+ );
125
+ $default-context: $context-color == oPrivateFoundationGet('o3-color-use-case-page-background');
126
+
127
+ // The default button text colour is black/white on the default page background.
128
+ // If a different context has been given the text colour matches if possible,
129
+ // or is mixed to be darker/lighter for higher contrast.
130
+ // o-buttons does custom contrast checks
131
+ $default-base-color: oPrivateColorsGetTextColor(
132
+ $color,
133
+ 100,
134
+ $minimum-contrast: null
135
+ );
136
+ $default-color: if(
137
+ $default-context,
138
+ $default-base-color,
139
+ _oPrivateButtonsGetMixColor(
140
+ $color-a: $context-color,
141
+ $color-b: $default-base-color,
142
+ $contrast-color: $default-background,
143
+ $contrast-aim: 4.5,
144
+ $preferred-mix: 100,
145
+ $minimum-mix: 0,
146
+ )
147
+ );
148
+
149
+ // Derive the hover/focus/active background colour from the default
150
+ // background colour.
151
+ $hover-focus-background: null;
152
+ $active-background: null;
153
+
154
+ // If the background color may be tinted use tints, otherwise use a mix.
155
+ $is-tint: oPrivateColorsGetToneDetails($default-background);
156
+ @if ($is-tint) {
157
+ // The hover/focus background tint should be lower than the default
158
+ // button background. Preferably with a contrast ratio of at least 1.5,
159
+ // but should not have a tint value lower than ten e.g. teal-10.
160
+ $hover-focus-background: _oPrivateButtonsGetDarkerTint(
161
+ $tint: $default-background,
162
+ $contrast-aim: 1.5,
163
+ $minimum-tint-value: 10,
164
+ );
165
+
166
+ // The interactive background tint should be darker than the
167
+ // hover/focus background too.
168
+ $active-background: _oPrivateButtonsGetDarkerTint(
169
+ $tint: $hover-focus-background,
170
+ $contrast-aim: 1.5,
171
+ $minimum-tint-value: 0,
172
+ );
173
+ } @else {
174
+ // When lightening buttons with a mix use white. Except for the
175
+ // core brand where a slate button should be mixed with paper.
176
+ $light-mix: if(
177
+ oBrandIs('core') and $default-background == oPrivateFoundationGet('o3-color-palette-slate'),
178
+ oPrivateFoundationGet('o3-color-palette-paper'),
179
+ 'o3-color-palette-white'
180
+ );
181
+
182
+ // When darkening buttons with a mix use black. Except for the
183
+ // core and internal brands, where buttons on slate should be mixed
184
+ // with slate.
185
+ $dark-mix: if(
186
+ (oBrandIs('core') or oBrandIs('internal')) and
187
+ $context-color ==
188
+ oPrivateFoundationGet('o3-color-palette-slate'),
189
+ oPrivateFoundationGet('o3-color-palette-slate'),
190
+ 'o3-color-palette-black'
191
+ );
192
+
193
+ // Make the button darker for hover/focus states, and
194
+ // darker still for active states. Unless the button color has low
195
+ // luminance, in which case make the button lighter instead.
196
+ // E.g. white: 1, claret: 0.07451, slate: 0.02307
197
+ $color-luminance: oPrivateColorsColorLuminance($default-background);
198
+ $mix-color: if($color-luminance > 0.05, $dark-mix, $light-mix);
199
+
200
+ // Mix the background colour to make the hover/focus state darker or
201
+ // lighter. The contrast should be at least 1.5. If not try lowering
202
+ // the button colour until a minimum mix value we'll accept is reached.
203
+ $hover-focus-background: _oPrivateButtonsGetMixColor(
204
+ $color-a: $color,
205
+ $color-b: $mix-color,
206
+ $contrast-color: $color,
207
+ $contrast-aim: 1.5,
208
+ $preferred-mix: 80,
209
+ $minimum-mix: 60,
210
+ );
211
+
212
+ // The active background tint should have at least a contrast of 1.5
213
+ // against the hover/focus background colour.
214
+ $active-background: _oPrivateButtonsGetMixColor(
215
+ $color-a: $color,
216
+ $color-b: $mix-color,
217
+ $contrast-color: $hover-focus-background,
218
+ $contrast-aim: 1.5,
219
+ $preferred-mix: 70,
220
+ $minimum-mix: 50,
221
+ );
222
+ }
223
+
224
+ // Generate the hover/focus state text colour.
225
+ // The text colour is black/white on the default page background.
226
+ // If a different context has been given the text colour matches if possible,
227
+ // or is mixed to be darker/lighter for higher contrast.
228
+ $hover-focus-base-color: oPrivateColorsGetTextColor(
229
+ $hover-focus-background,
230
+ 100,
231
+ $minimum-contrast: null
232
+ );
233
+ $hover-focus-color: if(
234
+ $default-context,
235
+ $hover-focus-base-color,
236
+ _oPrivateButtonsGetMixColor(
237
+ $color-a: $context-color,
238
+ $color-b: $hover-focus-base-color,
239
+ $contrast-color: $hover-focus-background,
240
+ $contrast-aim: 4.5,
241
+ $preferred-mix: 100,
242
+ $minimum-mix: 0,
243
+ )
244
+ );
245
+
246
+ // Generate the active state text colour.
247
+ // The text colour is black/white on the default page background.
248
+ // If a different context has been given the text colour matches if possible,
249
+ // or is mixed to be darker/lighter for higher contrast.
250
+ $active-base-color: oPrivateColorsGetTextColor(
251
+ $active-background,
252
+ 100,
253
+ $minimum-contrast: null
254
+ );
255
+ $active-color: if(
256
+ $default-context,
257
+ $active-base-color,
258
+ _oPrivateButtonsGetMixColor(
259
+ $color-a: $context-color,
260
+ $color-b: $active-base-color,
261
+ $contrast-color: $active-background,
262
+ $contrast-aim: 4.5,
263
+ $preferred-mix: 100,
264
+ $minimum-mix: 0,
265
+ )
266
+ );
267
+
268
+ // Confirm the contrast of default state.
269
+ $contrast-error-message: 'Could not create an accessible primary button of colour "#{$color-arg}" for a background context "#{$context-color-arg}".';
270
+ $default-contrast-ratio: oPrivateColorsGetContrastRatio(
271
+ $default-color,
272
+ $default-background
273
+ );
274
+ @if ($default-contrast-ratio < 4.5) {
275
+ @error ($contrast-error-message + ' The default text and background colour do not pass WCAG AA contrast checks.');
276
+ }
277
+ // Confirm the focus/hover state contrast.
278
+ $hover-contrast-ratio: oPrivateColorsGetContrastRatio(
279
+ $hover-focus-color,
280
+ $hover-focus-background
281
+ );
282
+ @if ($hover-contrast-ratio < 4.5) {
283
+ @error ($contrast-error-message + ' The text and background colour of the hover and focus state do not pass WCAG AA contrast checks.');
284
+ }
285
+ // Confirm the active state contrast.
286
+ $active-contrast-ratio: oPrivateColorsGetContrastRatio(
287
+ $active-color,
288
+ $active-background
289
+ );
290
+ @if ($active-contrast-ratio < 4.5) {
291
+ @error ($contrast-error-message + ' The text and background colour of the active state do not pass WCAG AA contrast checks.');
292
+ }
293
+
294
+ @return (
295
+ 'color': $default-color,
296
+ 'background': $default-background,
297
+ 'border': transparent,
298
+ 'hover-background': $hover-focus-background,
299
+ 'hover-color': $hover-focus-color,
300
+ 'focus-background': $hover-focus-background,
301
+ 'focus-color': $hover-focus-color,
302
+ 'active-background': $active-background,
303
+ 'active-color': $active-color
304
+ );
305
+ }
306
+
307
+ /// For a colour and context colour (the background colour behind the button),
308
+ /// generate secondary button colours and overrides for each button state.
309
+ ///
310
+ /// @example
311
+ /// $colors: _oPrivateButtonsGetSecondaryButtonColors('lemon', 'slate');
312
+ /// // (
313
+ /// // "color": #ffec1a,
314
+ /// // "background": transparent,
315
+ /// // "border": #ffec1a,
316
+ /// // "hover-background": rgba(255, 236, 26, 0.15),
317
+ /// // "hover-color": #ffec1a,
318
+ /// // "focus-background": rgba(255, 236, 26, 0.15),
319
+ /// // "focus-color": #ffec1a,
320
+ /// // "active-background": #ffec1a,
321
+ /// // "active-color": black
322
+ /// // )
323
+ ///
324
+ /// @param {String|Color} $color - The button colour e.g. 'teal' (from `o-colors` palette).
325
+ /// @param {String|Color} $context-color - The page colour behind the button (from `o-colors` palette).
326
+ /// @return {Map} - Colours for a secondary button. Including overrides for each button state.
327
+ @function _oPrivateButtonsGetSecondaryButtonColors($color, $context-color) {
328
+ $default-color: if(
329
+ type-of($color) == 'string',
330
+ oPrivateFoundationGet($color),
331
+ $color
332
+ );
333
+ $default-background: transparent;
334
+ $default-background-opaque: if(
335
+ type-of($context-color) == 'string',
336
+ oPrivateFoundationGet($context-color),
337
+ $context-color
338
+ );
339
+
340
+ // Get hover/focus colors:
341
+ // The secondary button hover/focus background is transparent.
342
+ // It should be 15% opacity if the contrast ratio against the button
343
+ // copy is passes WCAG AA contrast checks, otherwise use 10%.
344
+ $hover-focus-background-mix: _oPrivateButtonsGetMix(
345
+ $color-a: $color,
346
+ $color-b: $context-color,
347
+ $contrast-color: $color,
348
+ $contrast-aim: 4.5,
349
+ $preferred-mix: 15,
350
+ $minimum-mix: 10,
351
+ );
352
+ // Use transparency so the button may be used on a different background
353
+ // context, and trust the user to test accessibility in their app.
354
+ // But use an opaque mix to test contrast with the known context.
355
+ $hover-focus-background: oPrivateColorsMix(
356
+ $color,
357
+ transparent,
358
+ $hover-focus-background-mix
359
+ );
360
+ $hover-focus-background-opaque: oPrivateColorsMix(
361
+ $color,
362
+ $context-color,
363
+ $hover-focus-background-mix
364
+ );
365
+ // If the hover/focus state doesn't have high enough contrast darken/lighten
366
+ // the button foreground colour until it does.
367
+ $hover-focus-color: _oPrivateButtonsGetMixColor(
368
+ $color-a: $color,
369
+ $color-b: oPrivateColorsGetTextColor($hover-focus-background-opaque, 100),
370
+ $contrast-color: $hover-focus-background-opaque,
371
+ $contrast-aim: 4.5,
372
+ $preferred-mix: 100,
373
+ $minimum-mix: 0,
374
+ );
375
+
376
+ // Get active colours.
377
+ $active-background: $default-color;
378
+ $active-color: oPrivateColorsGetTextColor($active-background, 100);
379
+
380
+ // Confirm the contrast of default state.
381
+ $contrast-error-message: 'Could not create an accessible secondary button of colour "#{$color}" for a background context "#{$context-color}".';
382
+ $default-contrast-ratio: oPrivateColorsGetContrastRatio(
383
+ $default-color,
384
+ $default-background-opaque
385
+ );
386
+ @if $default-contrast-ratio < 4.5 {
387
+ @error ($contrast-error-message + ' The default text and background colour do not pass WCAG AA contrast checks.');
388
+ }
389
+ // Confirm the focus/hover state contrast.
390
+ $hover-contrast-ratio: oPrivateColorsGetContrastRatio(
391
+ $hover-focus-color,
392
+ $hover-focus-background-opaque
393
+ );
394
+ @if $hover-contrast-ratio < 4.5 {
395
+ @error ($contrast-error-message + ' The text and background colour of the hover and focus state do not pass WCAG AA contrast checks.');
396
+ }
397
+ // Confirm the active state contrast.
398
+ $active-contrast-ratio: oPrivateColorsGetContrastRatio(
399
+ $active-color,
400
+ $active-background
401
+ );
402
+ @if $active-contrast-ratio < 4.5 {
403
+ @error ($contrast-error-message + ' The text and background colour of the active state do not pass WCAG AA contrast checks.');
404
+ }
405
+
406
+ @return (
407
+ 'color': $default-color,
408
+ 'background': $default-background,
409
+ 'border': $default-color,
410
+ 'hover-background': $hover-focus-background,
411
+ 'hover-color': $hover-focus-color,
412
+ 'focus-background': $hover-focus-background,
413
+ 'focus-color': $hover-focus-color,
414
+ 'active-background': $active-background,
415
+ 'active-color': $active-color
416
+ );
417
+ }
418
+
419
+ /// For a colour and context colour (the background colour behind the button),
420
+ /// generate ghost button colours and overrides for each button state.
421
+ ///
422
+ /// @example
423
+ /// $colors: _oPrivateButtonsGetGhostButtonColors('lemon', 'slate');
424
+ /// // (
425
+ /// // "color": #ffec1a,
426
+ /// // "background": transparent,
427
+ /// // "border": #ffec1a,
428
+ /// // "hover-background": rgba(255, 236, 26, 0.15),
429
+ /// // "hover-color": #ffec1a,
430
+ /// // "focus-background": rgba(255, 236, 26, 0.15),
431
+ /// // "focus-color": #ffec1a,
432
+ /// // "active-background": #ffec1a,
433
+ /// // "active-color": black
434
+ /// // )
435
+ ///
436
+ /// @param {String|Color} $color - The button colour e.g. 'teal' (from `o-colors` palette).
437
+ /// @param {String|Color} $context-color - The page colour behind the button (from `o-colors` palette).
438
+ /// @return {Map} - Colours for a ghost button. Including overrides for each button state.
439
+ @function _oPrivateButtonsGetGhostButtonColors($color, $context-color) {
440
+ $default-color: if(
441
+ type-of($color) == 'string',
442
+ oPrivateFoundationGet($color),
443
+ $color
444
+ );
445
+ $default-background: transparent;
446
+ $default-background-opaque: if(
447
+ type-of($context-color) == 'string',
448
+ oPrivateFoundationGet($context-color),
449
+ $context-color
450
+ );
451
+
452
+ // Get hover/focus colors:
453
+ // The secondary button hover/focus background is transparent.
454
+ // It should be 15% opacity if the contrast ratio against the button
455
+ // copy is passes WCAG AA contrast checks, otherwise use 10%.
456
+ $hover-focus-background-mix: _oPrivateButtonsGetMix(
457
+ $color-a: $color,
458
+ $color-b: $context-color,
459
+ $contrast-color: $color,
460
+ $contrast-aim: 4.5,
461
+ $preferred-mix: 15,
462
+ $minimum-mix: 10,
463
+ );
464
+ // Use transparency so the button may be used on a different background
465
+ // context, and trust the user to test accessibility in their app.
466
+ // But use an opaque mix to test contrast with the known context.
467
+ $hover-focus-background: oPrivateColorsMix(
468
+ $color,
469
+ transparent,
470
+ $hover-focus-background-mix
471
+ );
472
+ $hover-focus-background-opaque: oPrivateColorsMix(
473
+ $color,
474
+ $context-color,
475
+ $hover-focus-background-mix
476
+ );
477
+ // If the hover/focus state doesn't have high enough contrast darken/lighten
478
+ // the button foreground colour until it does.
479
+ $hover-focus-color: _oPrivateButtonsGetMixColor(
480
+ $color-a: $color,
481
+ $color-b: oPrivateColorsGetTextColor($hover-focus-background-opaque, 100),
482
+ $contrast-color: $hover-focus-background-opaque,
483
+ $contrast-aim: 4.5,
484
+ $preferred-mix: 100,
485
+ $minimum-mix: 0,
486
+ );
487
+
488
+ // Get active colours.
489
+ $active-background: $default-color;
490
+ $active-color: oPrivateColorsGetTextColor($active-background, 100);
491
+
492
+ // Confirm the contrast of default state.
493
+ $contrast-error-message: 'Could not create an accessible ghost button of colour "#{$color}" for a background context "#{$context-color}".';
494
+ $default-contrast-ratio: oPrivateColorsGetContrastRatio(
495
+ $default-color,
496
+ $default-background-opaque
497
+ );
498
+ @if $default-contrast-ratio < 4.5 {
499
+ @error ($contrast-error-message + ' The default text and background colour do not pass WCAG AA contrast checks.');
500
+ }
501
+ // Confirm the focus/hover state contrast.
502
+ $hover-contrast-ratio: oPrivateColorsGetContrastRatio(
503
+ $hover-focus-color,
504
+ $hover-focus-background-opaque
505
+ );
506
+ @if $hover-contrast-ratio < 4.5 {
507
+ @error ($contrast-error-message + ' The text and background colour of the hover and focus state do not pass WCAG AA contrast checks.');
508
+ }
509
+ // Confirm the active state contrast.
510
+ $active-contrast-ratio: oPrivateColorsGetContrastRatio(
511
+ $active-color,
512
+ $active-background
513
+ );
514
+ @if $active-contrast-ratio < 4.5 {
515
+ @error ($contrast-error-message + ' The text and background colour of the active state do not pass WCAG AA contrast checks.');
516
+ }
517
+
518
+ @return (
519
+ 'color': $default-color,
520
+ 'background': $default-background,
521
+ 'border': $default-background,
522
+ 'hover-background': $hover-focus-background,
523
+ 'hover-color': $hover-focus-color,
524
+ 'focus-background': $hover-focus-background,
525
+ 'focus-color': $hover-focus-color,
526
+ 'active-background': $active-background,
527
+ 'active-color': $active-color
528
+ );
529
+ }
530
+
531
+ /// Mix two colours, a and b, at the preferred mix percentage. If the contrast
532
+ /// of the mix does not meet the contrast ratio aimed for try a lower mix
533
+ /// percentage incrementally until either the contrast meets our aim or the
534
+ /// minimum mix percentage is reached.
535
+ ///
536
+ /// @param {Color|String} $color-a - the colour to mix
537
+ /// @param {Color|String} $color-b - the colour to mix
538
+ /// @param {Color} $contrast-color - the colour to compare the mix contrast ratio against
539
+ /// @param {Number} $contrast-aim - the desired contrast ratio between the mix and contrast colour
540
+ /// @param {Number} $preferred-mix - the preferable percentage to mix colours a and b
541
+ /// @param {Number} $minimum-mix - the minimum percentage to mix colours a and b by if the aimed for contrast ratio is not met
542
+ /// @param {Color} - A mix of colours a and b.
543
+ @function _oPrivateButtonsGetMixColor(
544
+ $color-a,
545
+ $color-b,
546
+ $contrast-color,
547
+ $contrast-aim,
548
+ $preferred-mix,
549
+ $minimum-mix
550
+ ) {
551
+ $mix: _oPrivateButtonsGetMix(
552
+ $color-a,
553
+ $color-b,
554
+ $contrast-color,
555
+ $contrast-aim,
556
+ $preferred-mix,
557
+ $minimum-mix
558
+ );
559
+ @return oPrivateColorsMix($color-a, $color-b, $mix);
560
+ }
561
+
562
+ /// The mix percentage used by `_oPrivateButtonsGetMixColor`.
563
+ /// @see _oPrivateButtonsGetMixColor
564
+ ///
565
+ /// @param {Color|String} $color-a - the colour to mix
566
+ /// @param {Color|String} $color-b - the colour to mix
567
+ /// @param {Color} $contrast-color - the colour to compare the mix contrast ratio against
568
+ /// @param {Number} $contrast-aim - the desired contrast ratio between the mix and contrast colour
569
+ /// @param {Number} $preferred-mix - the preferable percentage to mix colours a and b
570
+ /// @param {Number} $minimum-mix - the minimum percentage to mix colours a and b by if the aimed for contrast ratio is not met
571
+ /// @param {Number} - A mix percentage for colours a and b
572
+ @function _oPrivateButtonsGetMix(
573
+ $color-a,
574
+ $color-b,
575
+ $contrast-color,
576
+ $contrast-aim,
577
+ $preferred-mix,
578
+ $minimum-mix
579
+ ) {
580
+ $decrement: 5;
581
+ $value: $preferred-mix;
582
+ @while $value >= $minimum-mix {
583
+ $mix: oPrivateColorsMix($color-a, $color-b, $value);
584
+ $ratio: oPrivateColorsGetContrastRatio($mix, $contrast-color);
585
+ @if $ratio >= $contrast-aim {
586
+ @return $value;
587
+ }
588
+ $value: $value - $decrement;
589
+ }
590
+ @return $minimum-mix;
591
+ }
592
+
593
+ /// For a given tint colour return a darker tint which either meets the contrast
594
+ /// ratio we're aiming for or is the lowest tint we can use.
595
+ /// Start with a decrement of 10, then decrement by 5 onward.
596
+ ///
597
+ // This contrast ratio and decrement is arbitrary, chosen
598
+ // to recreate as close as possible colours chosen by the design
599
+ // team (each button state used to be specified manually).
600
+ @function _oPrivateButtonsGetDarkerTint(
601
+ $tint,
602
+ $contrast-aim,
603
+ $minimum-tint-value
604
+ ) {
605
+ // Current tint.
606
+ $tint-details: oPrivateColorsGetToneDetails($tint);
607
+ $tint-color: map-get($tint-details, 'color-name');
608
+ $tint-brightness: map-get($tint-details, 'brightness');
609
+ // Lower the tint value.
610
+ // Ensure the initial tint value isn't lower than the minimum value.
611
+ $initial-tint-decrement: 10;
612
+ $decrement: 5;
613
+ $initial-tint-value: $tint-brightness - $initial-tint-decrement;
614
+ $value: if(
615
+ $initial-tint-value > $minimum-tint-value,
616
+ $initial-tint-value,
617
+ $minimum-tint-value
618
+ );
619
+ // Return the new tint if the current decrement is of high enough contrast.
620
+ @while $value >= $minimum-tint-value {
621
+ $darker-tint: oPrivateColorsGetTone($tint-color, $value);
622
+ $ratio: oPrivateColorsGetContrastRatio($darker-tint, $tint);
623
+ @if $ratio >= $contrast-aim {
624
+ @return $darker-tint;
625
+ }
626
+ $value: $value - $decrement;
627
+ }
628
+ // No tint of a high enough contrast could be produced.
629
+ // Return the darkest tint we'll allow.
630
+ @return oPrivateColorsGetTone($tint-color, $minimum-tint-value);
631
+ }