From 4e518edfc3cf6fc88541a117ed5cf6ce9572ff19 Mon Sep 17 00:00:00 2001 From: Nate Baldwin Date: Wed, 12 Aug 2020 11:05:29 -0600 Subject: [PATCH] Custom output color names option (#81) * added option for color scales in * updated test for error * updated to allow ratios input as an object --- packages/contrast-colors/README.md | 47 ++++++++-- packages/contrast-colors/index.js | 35 ++++++- .../test/generateAdaptiveTheme.test.js | 93 +++++++++++++++++++ 3 files changed, 162 insertions(+), 13 deletions(-) diff --git a/packages/contrast-colors/README.md b/packages/contrast-colors/README.md index c70c45a7..a20553a7 100644 --- a/packages/contrast-colors/README.md +++ b/packages/contrast-colors/README.md @@ -36,20 +36,28 @@ let myTheme = generateAdaptiveTheme({ { name: 'gray', colorKeys: ['#cacaca'], - colorspace: 'HSL', - ratios: [1, 2, 3, 4.5, 8, 12] + ratios: { + 'GRAY_LOW_CONTRAST': 2, + 'GRAY_LARGE_TEXT': 3, + 'GRAY_TEXT': 4.5, + 'GRAY_HIGH_CONTRAST': 8 + } }, { name: 'blue', colorKeys: ['#5CDBFF', '#0000FF'], - colorspace: 'HSL', - ratios: [3, 4.5] + ratios: { + 'BLUE_LARGE_TEXT': 3, + 'BLUE_TEXT': 4.5 + } }, { name: 'red', colorKeys: ['#FF9A81', '#FF0000'], - colorspace: 'HSL', - ratios: [3, 4.5] + ratios: { + 'RED_LARGE_TEXT': 3, + 'RED_TEXT': 4.5 + } } ], baseScale: 'gray', @@ -74,13 +82,32 @@ myTheme(brightness, contrast); ``` #### `colorScales` *[array of objects]*: -Each object contains the necessary parameters for [generating colors by contrast](#generateContrastColors) with the exception of the `name` parameter. +Each object contains the necessary parameters for [generating colors by contrast](#generateContrastColors) with the exception of the `name` and `ratios` parameter. For `generateAdaptiveTheme`, [ratios can be an array or an object](#ratios-array-or-object). + +Example of `colorScales` object with all options: + +```js + { + name: 'blue', + colorKeys: ['#5CDBFF', '#0000FF'], + colorSpace: 'LCH', + ratios: { + 'blue--largeText': 3, + 'blue--normalText': 4.5 + } + } +``` #### `baseScale` *string (enum)*: String value matching the `name` of a `colorScales` object to be used as a [base scale](#generateBaseScale) (background color). This creates a scale of values from 0-100 in lightness, which is used for `brightness` parameter. Ie. `brightness: 90` returns the 90% lightness value of the base scale. #### `name` *string*: -Unique name for each color scale. This value will be used for the output color keys, ie `blue100: '#5CDBFF'` +Unique name for each color scale. This value refers to the entire color group _(eg "blue")_ and will be used for the output color keys, ie `blue100: '#5CDBFF'` + +#### `ratios` *array* or *object*: +List of numbers to be used as target contrast ratios. If entered as an array, swatch names are incremented in `100`s such as `blue100`, `blue200` based on the color scale [name](#name-string). + +Alternatively, `ratios` can be an object with custom keys to name each color, such as `['Blue_Large_Text', 'Blue_Normal_Text']`. #### `brightness` *number*: Optional value from 0-100 indicating the brightness of the base / background color. If undefined, `generateAdaptiveTheme` will return a function @@ -201,8 +228,8 @@ List of numbers to be used as target contrast ratios. #### `colorspace` *string*: The colorspace in which the key colors will be interpolated within. Below are the available options: -- [Lch](https://en.wikipedia.org/wiki/HCL_color_space) -- [Lab](https://en.wikipedia.org/wiki/CIELAB_color_space) +- [LCH](https://en.wikipedia.org/wiki/HCL_color_space) +- [LAB](https://en.wikipedia.org/wiki/CIELAB_color_space) - [CAM02](https://en.wikipedia.org/wiki/CIECAM02) - [HSL](https://en.wikipedia.org/wiki/HSL_and_HSV) - [HSLuv](https://en.wikipedia.org/wiki/HSLuv) diff --git a/packages/contrast-colors/index.js b/packages/contrast-colors/index.js index 16e49558..f708cbe4 100644 --- a/packages/contrast-colors/index.js +++ b/packages/contrast-colors/index.js @@ -13,6 +13,7 @@ governing permissions and limitations under the License. const d3 = require('./d3.js'); const { catmullRom2bezier, prepareCurve } = require('./curve.js'); +const { color } = require('./d3.js'); function smoothScale(ColorsArray, domains, space) { const points = space.channels.map(() => []); @@ -450,6 +451,16 @@ function generateAdaptiveTheme({colorScales, baseScale, brightness, contrast = 1 if (!Array.isArray(colorScales)) { throw new Error('colorScales must be an array of objects'); } + for (let i=0; i < colorScales.length; i ++) { + // if (colorScales[i].swatchNames) { // if the scale has custom swatch names + // let ratioLength = colorScales[i].ratios.length; + // let swatchNamesLength = colorScales[i].swatchNames.length; + + // if (ratioLength !== swatchNamesLength) { + // throw new Error('`${colorScales[i].name}`ratios and swatchNames must be equal length') + // } + // } + } if (brightness === undefined) { return function(brightness, contrast) { @@ -478,7 +489,18 @@ function generateAdaptiveTheme({colorScales, baseScale, brightness, contrast = 1 throw new Error('Color missing name'); } let name = colorScales[i].name; - let ratios = colorScales[i].ratios; + + let ratioInput = colorScales[i].ratios; + let ratios; + let swatchNames; + // assign ratios array whether input is array or object + if(Array.isArray(ratioInput)) { + ratios = ratioInput; + } else { + ratios = Object.values(ratioInput); + swatchNames = Object.keys(ratioInput); + } + let smooth = colorScales[i].smooth; let newArr = []; let colorObj = { @@ -509,8 +531,14 @@ function generateAdaptiveTheme({colorScales, baseScale, brightness, contrast = 1 }); for (let i=0; i < outputColors.length; i++) { - let rVal = ratioName(ratios)[i]; - let n = name.concat(rVal); + let n; + if(!swatchNames) { + let rVal = ratioName(ratios)[i]; + n = name.concat(rVal); + } + else { + n = swatchNames[i]; + } let obj = { name: n, @@ -520,6 +548,7 @@ function generateAdaptiveTheme({colorScales, baseScale, brightness, contrast = 1 newArr.push(obj) } arr.push(colorObj); + } return arr; diff --git a/packages/contrast-colors/test/generateAdaptiveTheme.test.js b/packages/contrast-colors/test/generateAdaptiveTheme.test.js index 7fa9366a..98c4ae1e 100644 --- a/packages/contrast-colors/test/generateAdaptiveTheme.test.js +++ b/packages/contrast-colors/test/generateAdaptiveTheme.test.js @@ -415,6 +415,99 @@ test('should generate dark theme with increased contrast', function() { }); +test('should generate colors with user-defined names', function() { + let theme = generateAdaptiveTheme({ + baseScale: 'gray', + colorScales: [ + { + name: "gray", + colorKeys: ['#cacaca'], + colorspace: 'HSL', + ratios: { + 'GRAY_1': -1.8, + 'GRAY_2': -1.2, + 'GRAY_3': 1, + 'GRAY_4': 1.2, + 'GRAY_5': 1.4, + 'GRAY_6': 2, + 'GRAY_7': 3, + 'GRAY_8': 4.5, + 'GRAY_9': 6, + 'GRAY_10': 8, + 'GRAY_11': 12, + 'GRAY_12': 21 + } + }, + { + name: "blue", + colorKeys: ['#0000ff'], + colorspace: 'LAB', + ratios: { + 'BLUE_LOW_CONTRAST': 2, + 'BLUE_LARGE_TEXT': 3, + 'BLUE_TEXT': 4.5, + 'BLUE_HIGH_CONTRAST': 8, + 'BLUE_HIGHEST_CONTRAST': 12 + } + }, + { + name: "red", + colorKeys: ['#ff0000'], + colorspace: 'RGB', + ratios: { + 'red--lowContrast': 2, + 'red--largeText': 3, + 'red--text': 4.5, + 'red--highContrast': 8, + 'red--highestContrast': 12 + } + } + ]}); + let themeLight = theme(20, 1.5);; + + expect(themeLight).toEqual([ + { background: "#303030" }, + { + name: 'gray', + values: [ + {name: "GRAY_1", contrast: -2.2, value: "#000000"}, + {name: "GRAY_2", contrast: -1.3, value: "#1c1c1c"}, + {name: "GRAY_3", contrast: 1, value: "#303030"}, + {name: "GRAY_4", contrast: 1.3, value: "#414141"}, + {name: "GRAY_5", contrast: 1.6, value: "#4f4f4f"}, + {name: "GRAY_6", contrast: 2.5, value: "#6b6b6b"}, + {name: "GRAY_7", contrast: 4, value: "#8e8e8e"}, + {name: "GRAY_8", contrast: 6.25, value: "#b3b3b3"}, + {name: "GRAY_9", contrast: 8.5, value: "#d0d0d0"}, + {name: "GRAY_10", contrast: 11.5, value: "#efefef"}, + {name: "GRAY_11", contrast: 17.5, value: "#ffffff"}, + {name: "GRAY_12", contrast: 31, value: "#ffffff"} + ] + }, + { + name: 'blue', + values: [ + {name: "BLUE_LOW_CONTRAST", contrast: 2.5, value: "#6f45ff"}, + {name: "BLUE_LARGE_TEXT", contrast: 4, value: "#9d73ff"}, + {name: "BLUE_TEXT", contrast: 6.25, value: "#c3a3ff"}, + {name: "BLUE_HIGH_CONTRAST", contrast: 11.5, value: "#f4edff"}, + {name: "BLUE_HIGHEST_CONTRAST", contrast: 17.5, value: "#ffffff"} + ] + }, + { + name: 'red', + values: [ + {name: "red--lowContrast", contrast: 2.5, value: "#da0000"}, + {name: "red--largeText", contrast: 4, value: "#ff4b4b"}, + {name: "red--text", contrast: 6.25, value: "#ff9494"}, + {name: "red--highContrast", contrast: 11.5, value: "#ffebeb"}, + {name: "red--highestContrast", contrast: 17.5, value: "#ffffff"} + ] + } + ]); +}); + + // Should throw errors test('should throw error, not valid base scale option', function() { expect(