khroma
Version:
A collection of functions for manipulating CSS colors, inspired by SASS.
83 lines (47 loc) • 1.97 kB
text/typescript
/* IMPORT */
import _ from '~/utils';
import ChannelsReusable from '~/channels/reusable';
import type {Channels} from '~/types';
/* MAIN */
const HSL = {
/* VARIABLES */
re: /^hsla?\(\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(?:deg|grad|rad|turn)?)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)\s*?(?:,|\s)\s*?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?%)(?:\s*?(?:,|\/)\s*?\+?(-?(?:\d+(?:\.\d+)?|(?:\.\d+))(?:e-?\d+)?(%)?))?\s*?\)$/i,
hueRe: /^(.+?)(deg|grad|rad|turn)$/i,
/* HELPERS */
_hue2deg: ( hue: string ): number => {
const match = hue.match ( HSL.hueRe );
if ( match ) {
const [, number, unit] = match;
switch ( unit ) {
case 'grad': return _.channel.clamp.h ( parseFloat ( number ) * .9 );
case 'rad': return _.channel.clamp.h ( parseFloat ( number ) * 180 / Math.PI );
case 'turn': return _.channel.clamp.h ( parseFloat ( number ) * 360 );
}
}
return _.channel.clamp.h ( parseFloat ( hue ) );
},
/* API */
parse: ( color: string ): Channels | void => {
const charCode = color.charCodeAt ( 0 );
if ( charCode !== 104 && charCode !== 72 ) return; // 'h'/'H'
const match = color.match ( HSL.re );
if ( !match ) return;
const [, h, s, l, a, isAlphaPercentage] = match;
return ChannelsReusable.set ({
h: HSL._hue2deg ( h ),
s: _.channel.clamp.s ( parseFloat ( s ) ),
l: _.channel.clamp.l ( parseFloat ( l ) ),
a: a ? _.channel.clamp.a ( isAlphaPercentage ? parseFloat ( a ) / 100 : parseFloat ( a ) ) : 1
}, color );
},
stringify: ( channels: Channels ): string => {
const {h, s, l, a} = channels;
if ( a < 1 ) { // HSLA
return `hsla(${_.lang.round ( h )}, ${_.lang.round ( s )}%, ${_.lang.round ( l )}%, ${a})`;
} else { // HSL
return `hsl(${_.lang.round ( h )}, ${_.lang.round ( s )}%, ${_.lang.round ( l )}%)`;
}
}
};
/* EXPORT */
export default HSL;