Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
@include _govuk-rebrand(
"background-color",
$from: $govuk-service-navigation-background,
$to: $_govuk-rebrand-template-background-colour
$to: govuk-colour("blue", $variant: tint-95)
);
}

Expand Down
61 changes: 54 additions & 7 deletions packages/govuk-frontend/src/govuk/helpers/_colour.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,76 @@
/// The `$legacy` parameter is deprecated and is non-operational, as the
/// legacy colour palette has been removed. The parameter will be removed in
/// the next major version.
/// @param {String | Colour} $variant - The variant of the colour to look up
/// @param {Map} $colours - The map of colours to look into
/// @return {Colour} Representation of named colour
///
/// @throw if `$colour` is not a colour from the colour palette
/// @access public

@function govuk-colour($colour, $legacy: false) {
@function govuk-colour($colour, $legacy: false, $variant: null, $colours: null) {
// Output a warning if $legacy is set to anything.
@if $legacy and _should-warn("legacy-colour-param") {
@warn _warning-text("legacy-colour-param", "The `$legacy` parameter of " +
"`govuk-colour` is deprecated and is non-operational. It will be " +
"removed in the next major version.");
}

@if type-of($colour) == "color" {
// stylelint-disable-next-line scss/function-quote-no-quoted-strings-inside
$colour: quote("#{$colour}");
@if $colours or $variant {
@return govuk-colour-variant($colour, $variant: $variant, $colours: $colours);
}

@if not map-has-key($govuk-colours, $colour) {
@error "Unknown colour `#{$colour}`";
@return govuk-colour-variant($colour, $govuk-colours);
}

/// Get the $variant of the given $colour among the given $colours
///
/// @param {String | Colour} $colour - Name of brand colour from the palette
/// (`$govuk-colour`)
/// @param {String } $variant [primary] - Name of the colour variant from the palette
/// @param {Map} $colours [$govuk-brand-colours] - A map of available colours
/// @return {Colour} Representation of the variant of the brand colour
///
/// @throw if `$variant` is not a variant from the colour
/// @access private
@function govuk-colour-variant($colour, $variant: null, $colours: null) {
// Handle positional arguments
@if type-of($variant) == "map" {
$colours: $variant;
}

$variant: $variant or primary;
$colours: $colours or $govuk-brand-colours;

// Sass parses unquoted colours as colours, so we need to turn them into
// strings before looking them up in the colour palette
// https://sass-lang.com/documentation/values/strings#unquoted
@if type-of($colour) != "string" {
$colour: "#{$colour}";
}

$colour-variants: map-get($colours, $colour);

@if not $colour-variants {
@error "Unknown colour `#{$colour}` (available colours: #{map-keys($colours)})";
}

// Some colours may not have variants, if that's the case, we can return the colour straight away
@if type-of($colour-variants) == "color" {
@return $colour-variants;
}

@if type-of($colour-variants) != "map" {
@error "Colour `#{$colour}` should either be a `map` or `color`, not a `#{type-of($colour-variants)}`";
}

$result: map-get($colour-variants, $variant);

@if not $result {
@error "Unknown variant `#{$variant}` for colour `#{$colour}` (available variants: #{map-keys($colour-variants)})";
}

@return map-get($govuk-colours, $colour);
@return $result;
}

/// Get the colour for a government organisation
Expand Down
243 changes: 243 additions & 0 deletions packages/govuk-frontend/src/govuk/helpers/colour.unit.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,249 @@ describe('@function govuk-colour', () => {
expect.anything()
)
})

describe('access to arbitrary colour maps', () => {
it('looks up in the provided colour map if receiving a colour map', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour(red, $colours: ("red": #ca3535));
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #ca3535;
}
`
})
})

it('allows to pass a variant when looking up arbitrary colour maps', async () => {
const sass = `
${sassBootstrap}

$colours: (
"red": (
"primary": #ca3535,
"tint-25": #d76868,
),
);

.foo {
color: govuk-colour(red, $variant: tint-25, $colours: $colours);
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #d76868;
}
`
})
})

it('looks up in `$govuk-brand-colours` if receiving only `$variant`', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour(red, $variant: tint-25);
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #d76868;
}
`
})
})
})
})

describe('@function govuk-colour-variant', () => {
const sassBootstrap = `
$colours: (
"blue": (
"primary": #1d70b8,
"tint-25": #5694ca,
),
"green": (
"primary": #11875a,
"tint-25": #4da583,
),
"red": (
"primary": #ca3535,
"tint-25": #d76868,
),
"white": #fff
);

@import "helpers/colour";
`

it('returns the variant of the colour if it exits', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour-variant('red', 'tint-25', $colours);
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #d76868;
}
`
})
})

it('accepts unquoted strings', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour-variant(red, tint-25, $colours);
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #d76868;
}
`
})
})

it("returns the colour if there's no variant", async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour-variant(white, $colours: $colours);
border-color: govuk-colour-variant(white, any-variant, $colours);
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #fff;
border-color: #fff;
}
`
})
})

describe('defaults', () => {
it('defaults the variant to "primary"', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour-variant(red, $colours: $colours);
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #ca3535;
}
`
})
})

it('defaults the colours to $govuk-brand-colours', async () => {
const sass = `
@import "helpers/colour";

.foo {
color: govuk-colour-variant(red, tint-25);
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #d76868;
}
`
})
})
})

describe('errors', () => {
it('throws an error if the colour is not found', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour-variant('unknown-colour', 'tint-25', $colours);
}
`

await expect(compileSassString(sass, sassConfig)).rejects.toThrow(
'Unknown colour `unknown-colour` (available colours: blue, green, red, white)'
)
})

it('throws an error if the found colour is not a Map or Color', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour-variant('a-colour', 'tint-25', ("a-colour": "not-a-map-or-colour"));
}
`

await expect(compileSassString(sass, sassConfig)).rejects.toThrow(
'Colour `a-colour` should either be a `map` or `color`, not a `string`'
)
})

it('throws an error if the variant is not found', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour-variant('red', 'unknown-variant', $colours);
}
`

await expect(compileSassString(sass, sassConfig)).rejects.toThrow(
'Unknown variant `unknown-variant` for colour `red` (available variants: primary, tint-25)'
)
})
})

describe('shorthand', () => {
it('allows using a positional argument for the list of colours', async () => {
const sass = `
${sassBootstrap}

.foo {
color: govuk-colour-variant(white, $colours);
}
`

await expect(compileSassString(sass, sassConfig)).resolves.toMatchObject({
css: outdent`
.foo {
color: #fff;
}
`
})
})
})
})

describe('@function govuk-organisation-colour', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,10 @@ $govuk-link-active-colour: govuk-colour("black") !default;
///
/// @type Colour
/// @access private
$_govuk-rebrand-template-background-colour: govuk-tint($govuk-brand-colour, 95%);
$_govuk-rebrand-template-background-colour: govuk-colour("blue", $variant: tint-95);

/// Border colour for areas on a light-blue background
///
/// @type Colour
/// @access private
$_govuk-rebrand-border-colour-on-blue-tint-95: govuk-tint($govuk-brand-colour, 50%);
$_govuk-rebrand-border-colour-on-blue-tint-95: govuk-colour("blue", $variant: tint-50);
Loading