Comparing version
{ | ||
"name": "palx", | ||
"version": "1.0.0-beta.1", | ||
"description": "Color palette generator and helper", | ||
"main": "index.js", | ||
"version": "1.0.0", | ||
"description": "Automatic UI Color Palette Generator", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"build": "webpack -p", | ||
"start": "webpack-dev-server", | ||
"start": "micro -p 3000 server/index.js", | ||
"dev": "nodemon --exec 'npm start'", | ||
"test": "ava -v" | ||
@@ -19,12 +19,14 @@ }, | ||
"ava": "^0.15.2", | ||
"babel-loader": "^6.2.4", | ||
"babel-preset-es2015": "^6.9.0", | ||
"babel-preset-stage-0": "^6.5.0", | ||
"h0": "^1.0.0-beta.4", | ||
"webpack": "^1.13.1", | ||
"webpack-dev-server": "^1.14.1" | ||
"axs": "^1.0.0-b3", | ||
"nodemon": "^1.11.0", | ||
"objss": "^1.0.0-1", | ||
"react": "^15.4.0", | ||
"react-dom": "^15.4.0", | ||
"reline": "^1.0.0-beta.3", | ||
"repng": "^1.0.0-b4" | ||
}, | ||
"dependencies": { | ||
"chroma-js": "^1.2.1" | ||
"chroma-js": "^1.2.1", | ||
"micro": "^6.1.0" | ||
} | ||
} |
# Palx | ||
Automatic UI Color Palette Generator | ||
https://palx.jxnblk.com | ||
```js | ||
@@ -8,16 +12,14 @@ npm i palx | ||
Provide a single color value and Palx returns a full-spectrum color palette, | ||
well suited for UI design and data visualizations that work harmoniously with brand colors. | ||
```js | ||
const palx = require('palx') | ||
const colors = palx({ | ||
blue: '#07c', | ||
red: '#f40' | ||
}) | ||
colors.blue // '#07c' | ||
colors.red // '#f40' | ||
colors.rotate(30).blue | ||
palx('#07c') | ||
// Returns a color object with | ||
// 12 hues and a gray spread across | ||
// 10 luminance steps | ||
``` | ||
MIT License |
241
src/index.js
/* | ||
* API | ||
* | ||
* const colors = palx({ blue: '#07c' }) | ||
* | ||
* colors.blue | ||
* colors.rotate(30).blue | ||
* colors.darken(.5).blue | ||
* | ||
* colors.dark1.blue | ||
* | ||
*/ | ||
const chroma = require('chroma-js') | ||
const hueName = require('./hue-name') | ||
const createRotate = baseColors => keys => { | ||
const rotate = (n) => { | ||
const obj = {} | ||
Object.keys(baseColors).forEach(key => { | ||
Object.defineProperty(obj, key, { | ||
get: () => { | ||
const [ h, s, l ] = chroma(baseColors[key]).hsl() | ||
const hue = (360 + h + n) % 360 | ||
return chroma.hsl(hue, s, l).hex() | ||
} | ||
const lums = [ | ||
9, | ||
8, | ||
7, | ||
6, | ||
5, | ||
4, | ||
3, | ||
2, | ||
1, | ||
0 | ||
] | ||
.map(n => n + .5) | ||
.map(n => n / 10) | ||
const createHues = (length = 12) => { | ||
const hueLength = length | ||
const hueStep = 360 / hueLength | ||
return base => { | ||
const hues = Array.from({ length: hueLength }) | ||
.map((n, i) => { | ||
return Math.floor((base + (i * hueStep)) % 360) | ||
}) | ||
}) | ||
return obj | ||
return hues | ||
} | ||
} | ||
return rotate | ||
const desat = n => hex => { | ||
const [ h, s, l ] = chroma(hex).hsl() | ||
return chroma.hsl(h, n, l).hex() | ||
} | ||
const getName = hue => { | ||
const mins = { | ||
red: 0, | ||
orange: 30, | ||
yellow: 60, | ||
green: 90, | ||
cyan: 170, | ||
blue: 200, | ||
purple: 260, | ||
magenta: 320, | ||
} | ||
const createBlack = hex => { | ||
const d = desat(1/8)(hex) | ||
return chroma(d).luminance(.05).hex() | ||
} | ||
const isMatch = n => min => { | ||
return n >= min | ||
} | ||
const createShades = hex => { | ||
return lums.map(lum => { | ||
return chroma(hex).luminance(lum).hex() | ||
}) | ||
} | ||
const matcher = isMatch(hue) | ||
// Mappers | ||
const toHex = ({ key, value }) => ({ key, value: value.hex() }) | ||
const name = Object.keys(mins).reduce((a, b) => { | ||
return (matcher(mins[b]) ? b : a) | ||
}, null) | ||
const keyword = hex => { | ||
const [ hue, sat ] = chroma(hex).hsl() | ||
if (sat < .5) { | ||
return 'gray' | ||
} | ||
const name = hueName(hue) | ||
return name | ||
} | ||
const createColorFunction = func => baseColors => keys => { | ||
const fn = (n) => { | ||
const obj = {} | ||
// Figure out how to hoist this up | ||
Object.keys(baseColors).forEach(key => { | ||
Object.defineProperty(obj, key, { | ||
get: () => { | ||
return chroma(baseColors[key])[func](n).css() | ||
} | ||
}) | ||
}) | ||
return obj | ||
} | ||
return fn | ||
// Reducer | ||
const toObj = (a = {}, color) => { | ||
const key = a[color.key] ? color.key + '2' : color.key | ||
a[key] = color.value | ||
return a | ||
} | ||
const createDarken = createColorFunction('darken') | ||
const createLighten = createColorFunction('brighten') | ||
const createSaturate = createColorFunction('saturate') | ||
const createDesaturate = createColorFunction('desaturate') | ||
const createAlpha = createColorFunction('alpha') | ||
const palx = (hex, options = {}) => { | ||
const color = chroma(hex) | ||
const colors = [] | ||
const [ hue, sat, lte ] = color.hsl() | ||
const palx = ( | ||
input = {}, | ||
{ | ||
// Options | ||
hues = 6, | ||
lightnessScale = [ | ||
0, | ||
4 * 1 / 8, | ||
4 * 1 / 4, | ||
4 * 3 / 8, | ||
4 * 1 / 2, | ||
4 * 5 / 8, | ||
4 * 3 / 4, | ||
4 * 7 / 8, | ||
4 * 1 | ||
], | ||
saturationScale = [ | ||
0, | ||
2 * 1 / 8, | ||
2 * 1 / 4, | ||
2 * 3 / 8, | ||
2 * 1 / 2, | ||
2 * 5 / 8, | ||
2 * 3 / 4, | ||
2 * 7 / 8, | ||
2 * 1 | ||
], | ||
alphaScale = [ | ||
0, | ||
1 / 8, | ||
1 / 4, | ||
3 / 8, | ||
1 / 2, | ||
5 / 8, | ||
3 / 4, | ||
7 / 8, | ||
1 | ||
] | ||
} = {} | ||
) => { | ||
const keys = Object.keys(input) | ||
const [ k1 ] = keys | ||
const base = chroma(input[k1]) | ||
const hueShift = 360 / hues | ||
const hues = createHues(12)(hue) | ||
const baseColors = {} | ||
const colors = { | ||
get base () { | ||
return base.hex() | ||
}, | ||
keys: [] | ||
} | ||
// Add hues | ||
for (var i = 0; i < hues; i++) { | ||
const [ h, s, l ] = base.hsl() | ||
const angle = i * hueShift | ||
const hue = (h + angle) % 360 | ||
const color = chroma.hsl(hue, s, l) | ||
// const { name } = colorNamer(color.hex()).roygbiv[0] | ||
const name = getName(hue) | ||
colors.keys.push(name) | ||
if (!baseColors[name] && keys.indexOf(name) < 0) { | ||
baseColors[name] = color.hex() | ||
Object.defineProperty(colors, name, { | ||
get: () => baseColors[name] | ||
}) | ||
} | ||
} | ||
keys.forEach(key => { | ||
baseColors[key] = chroma(input[key]).hex() | ||
Object.defineProperty(colors, key, { | ||
get: () => { | ||
return baseColors[key] | ||
} | ||
}) | ||
colors.push({ | ||
key: 'black', | ||
value: createBlack('' + color.hex()) | ||
}) | ||
colors.rotate = createRotate(baseColors)(keys) | ||
colors.darken = createDarken(baseColors)(keys) | ||
colors.lighten = createLighten(baseColors)(keys) | ||
colors.saturate = createSaturate(baseColors)(keys) | ||
colors.desaturate = createDesaturate(baseColors)(keys) | ||
colors.alpha = createAlpha(baseColors)(keys) | ||
alphaScale.forEach((a, i) => { | ||
colors['alpha' + i] = colors.alpha(a) | ||
colors.push({ | ||
key: 'gray', | ||
value: createShades(desat(1/8)('' + color.hex())) | ||
}) | ||
saturationScale.forEach((s, i) => { | ||
colors['saturate' + i] = colors.saturate(s) | ||
hues.forEach(h => { | ||
const c = chroma.hsl(h, sat, lte) | ||
const key = keyword(c) | ||
colors.push({ | ||
key, | ||
value: createShades('' + c.hex()) | ||
}) | ||
}) | ||
saturationScale.forEach((s, i) => { | ||
colors['desaturate' + i] = colors.desaturate(s) | ||
}) | ||
const obj = Object.assign({ | ||
base: hex, | ||
}, colors.reduce(toObj, {})) | ||
lightnessScale.forEach((l, i) => { | ||
colors['darken' + i] = colors.darken(l) | ||
}) | ||
lightnessScale.forEach((l, i) => { | ||
colors['lighten' + i] = colors.lighten(l) | ||
}) | ||
return colors | ||
return obj | ||
} | ||
@@ -195,0 +100,0 @@ |
import test from 'ava' | ||
import chroma from 'chroma-js' | ||
import pal from '../src' | ||
import palx from '../src' | ||
const src = { | ||
blue: '#07c', | ||
red: '#f40' | ||
} | ||
let colors | ||
test('is a function', t => { | ||
t.is(typeof pal, 'function') | ||
}) | ||
test('returns an object', t => { | ||
colors = pal(src) | ||
test('returns a color object', t => { | ||
const colors = palx('#07c') | ||
t.is(typeof colors, 'object') | ||
}) | ||
test('returns the base color hex', t => { | ||
t.notThrows(() => { | ||
chroma(colors.blue) | ||
chroma(colors.red) | ||
}) | ||
t.is(chroma(src.blue).hex(), colors.base) | ||
t.is(chroma(src.blue).hex(), colors.blue) | ||
t.is(chroma(src.red).hex(), colors.red) | ||
}) | ||
test('returns a rotate function', t => { | ||
t.is(typeof colors.rotate, 'function') | ||
t.is(typeof colors.rotate(60), 'object') | ||
}) | ||
test('rotates a color', t => { | ||
let rotated | ||
t.notThrows(() => { | ||
rotated = colors.rotate(60).blue | ||
chroma(rotated) | ||
}) | ||
const [ h ] = chroma(src.blue).hsl() | ||
t.is(typeof rotated, 'string') | ||
t.is(h + 60, chroma(rotated).hsl()[0]) | ||
}) | ||
test('returns a darken function', t => { | ||
t.is(typeof colors.darken, 'function') | ||
t.is(typeof colors.darken(.5), 'object') | ||
}) | ||
test('darkens a color', t => { | ||
let dark | ||
t.notThrows(() => { | ||
dark = colors.darken(.5).blue | ||
chroma(dark) | ||
}) | ||
t.is(typeof dark, 'string') | ||
t.is(chroma(src.blue).darken(.5).css(), dark) | ||
}) | ||
test('returns a lighten function', t => { | ||
t.is(typeof colors.lighten, 'function') | ||
t.is(typeof colors.lighten(.5), 'object') | ||
}) | ||
test('lightens a color', t => { | ||
let light | ||
t.notThrows(() => { | ||
light = colors.lighten(.5).blue | ||
chroma(light) | ||
}) | ||
t.is(typeof light, 'string') | ||
t.is(chroma(src.blue).brighten(.5).css(), light) | ||
}) | ||
test('returns an alpha function', t => { | ||
t.is(typeof colors.alpha, 'function') | ||
t.is(typeof colors.alpha(.5), 'object') | ||
}) | ||
test('makes a color transparent', t => { | ||
let alpha | ||
t.notThrows(() => { | ||
alpha = colors.alpha(.5).blue | ||
chroma(alpha) | ||
}) | ||
t.is(typeof alpha, 'string') | ||
t.is(chroma(src.blue).alpha(.5).css(), alpha) | ||
}) | ||
test('returns a saturate function', t => { | ||
t.is(typeof colors.saturate, 'function') | ||
t.is(typeof colors.saturate(.5), 'object') | ||
}) | ||
test('saturates a color', t => { | ||
let sat | ||
t.notThrows(() => { | ||
sat = colors.saturate(.5).blue | ||
chroma(sat) | ||
}) | ||
t.is(typeof sat, 'string') | ||
t.is(chroma(src.blue).saturate(.5).css(), sat) | ||
}) | ||
test('returns a desaturate function', t => { | ||
t.is(typeof colors.desaturate, 'function') | ||
t.is(typeof colors.desaturate(.5), 'object') | ||
}) | ||
test('desaturates a color', t => { | ||
let desat | ||
t.notThrows(() => { | ||
desat = colors.desaturate(.5).blue | ||
chroma(desat) | ||
}) | ||
t.is(typeof desat, 'string') | ||
t.is(chroma(src.blue).desaturate(.5).css(), desat) | ||
}) | ||
test('returns an alpha0-8 objects', t => { | ||
t.is(typeof colors.alpha0, 'object') | ||
t.is(typeof colors.alpha1, 'object') | ||
t.is(typeof colors.alpha2, 'object') | ||
t.is(typeof colors.alpha3, 'object') | ||
t.is(typeof colors.alpha4, 'object') | ||
t.is(typeof colors.alpha5, 'object') | ||
t.is(typeof colors.alpha6, 'object') | ||
t.is(typeof colors.alpha7, 'object') | ||
t.is(typeof colors.alpha8, 'object') | ||
}) | ||
test('returns an darken0-8 objects', t => { | ||
t.is(typeof colors.darken0, 'object') | ||
t.is(typeof colors.darken1, 'object') | ||
t.is(typeof colors.darken2, 'object') | ||
t.is(typeof colors.darken3, 'object') | ||
t.is(typeof colors.darken4, 'object') | ||
t.is(typeof colors.darken5, 'object') | ||
t.is(typeof colors.darken6, 'object') | ||
t.is(typeof colors.darken7, 'object') | ||
t.is(typeof colors.darken8, 'object') | ||
}) | ||
test('returns an lighten0-8 objects', t => { | ||
t.is(typeof colors.lighten0, 'object') | ||
t.is(typeof colors.lighten1, 'object') | ||
t.is(typeof colors.lighten2, 'object') | ||
t.is(typeof colors.lighten3, 'object') | ||
t.is(typeof colors.lighten4, 'object') | ||
t.is(typeof colors.lighten5, 'object') | ||
t.is(typeof colors.lighten6, 'object') | ||
t.is(typeof colors.lighten7, 'object') | ||
t.is(typeof colors.lighten8, 'object') | ||
}) | ||
test('adds five hues', t => { | ||
console.log(colors) | ||
}) |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
35
288.89%876
45.03%1
-50%25
8.7%21652
-58.39%2
100%8
14.29%2
100%1
Infinity%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added