First commit.

Signed-off-by: Chen Xiao <abigwc@gmail.com>
This commit is contained in:
Chen Xiao
2026-05-08 14:43:16 +08:00
commit 0b64e2de94
10989 changed files with 2253791 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
/* IMPORT */
import Color from '~/color';
import change from '~/methods/change';
import type {CHANNELS, Channels} from '~/types';
/* MAIN */
const adjust = ( color: string | Channels, channels: Partial<CHANNELS> ): string => {
const ch = Color.parse ( color );
const changes: Partial<CHANNELS> = {};
for ( const c in channels ) {
if ( !channels[c] ) continue;
changes[c] = ch[c] + channels[c];
}
return change ( color, changes );
};
/* EXPORT */
export default adjust;
+24
View File
@@ -0,0 +1,24 @@
/* IMPORT */
import _ from '~/utils';
import Color from '~/color';
import type {CHANNEL, Channels} from '~/types';
/* MAIN */
const adjustChannel = ( color: string | Channels, channel: CHANNEL, amount: number ): string => {
const channels = Color.parse ( color );
const amountCurrent = channels[channel];
const amountNext = _.channel.clamp[channel]( amountCurrent + amount );
if ( amountCurrent !== amountNext ) channels[channel] = amountNext;
return Color.stringify ( channels );
};
/* EXPORT */
export default adjustChannel;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import channel from '~/methods/channel';
import type {Channels} from '~/types';
/* MAIN */
const alpha = ( color: string | Channels ): number => {
return channel ( color, 'a' );
};
/* EXPORT */
export default alpha;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import channel from '~/methods/channel';
import type {Channels} from '~/types';
/* MAIN */
const blue = ( color: string | Channels ): number => {
return channel ( color, 'b' );
};
/* EXPORT */
export default blue;
+26
View File
@@ -0,0 +1,26 @@
/* IMPORT */
import _ from '~/utils';
import Color from '~/color';
import type {CHANNELS, Channels} from '~/types';
/* MAIN */
const change = ( color: string | Channels, channels: Partial<CHANNELS> ): string => {
const ch = Color.parse ( color );
for ( const c in channels ) {
ch[c] = _.channel.clamp[c]( channels[c] );
}
return Color.stringify ( ch );
};
/* EXPORT */
export default change;
+18
View File
@@ -0,0 +1,18 @@
/* IMPORT */
import _ from '~/utils';
import Color from '~/color';
import type {CHANNEL, Channels} from '~/types';
/* MAIN */
const channel = ( color: string | Channels, channel: CHANNEL ): number => {
return _.lang.round ( Color.parse ( color )[channel] );
};
/* EXPORT */
export default channel;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import adjustChannel from '~/methods/adjust_channel';
import type {Channels} from '~/types';
/* MAIN */
const complement = ( color: string | Channels ): string => {
return adjustChannel ( color, 'h', 180 );
};
/* EXPORT */
export default complement;
+23
View File
@@ -0,0 +1,23 @@
/* IMPORT */
import _ from '~/utils';
import luminance from '~/methods/luminance';
/* MAIN */
const contrast = ( color1: string, color2: string ): number => {
const luminance1 = luminance ( color1 );
const luminance2 = luminance ( color2 );
const max = Math.max ( luminance1, luminance2 );
const min = Math.min ( luminance1, luminance2 );
const ratio = ( max + Number.EPSILON ) / ( min + Number.EPSILON );
return _.lang.round ( _.lang.clamp ( ratio, 1, 10 ) );
};
/* EXPORT */
export default contrast;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import adjustChannel from '~/methods/adjust_channel';
import type {Channels} from '~/types';
/* MAIN */
const darken = ( color: string | Channels, amount: number ): string => {
return adjustChannel ( color, 'l', -amount );
};
/* EXPORT */
export default darken;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import adjustChannel from '~/methods/adjust_channel';
import type {Channels} from '~/types';
/* MAIN */
const desaturate = ( color: string | Channels, amount: number ): string => {
return adjustChannel ( color, 's', -amount );
};
/* EXPORT */
export default desaturate;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import change from '~/methods/change';
import type {Channels} from '~/types';
/* MAIN */
const grayscale = ( color: string | Channels ): string => {
return change ( color, { s: 0 } );
};
/* EXPORT */
export default grayscale;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import channel from '~/methods/channel';
import type {Channels} from '~/types';
/* MAIN */
const green = ( color: string | Channels ): number => {
return channel ( color, 'g' );
};
/* EXPORT */
export default green;
+25
View File
@@ -0,0 +1,25 @@
/* IMPORT */
import _ from '~/utils';
import ChannelsReusable from '~/channels/reusable';
import Color from '~/color';
/* MAIN */
const hsla = ( h: number, s: number, l: number, a: number = 1 ): string => {
const channels = ChannelsReusable.set ({
h: _.channel.clamp.h ( h ),
s: _.channel.clamp.s ( s ),
l: _.channel.clamp.l ( l ),
a: _.channel.clamp.a ( a )
});
return Color.stringify ( channels );
};
/* EXPORT */
export default hsla;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import channel from '~/methods/channel';
import type {Channels} from '~/types';
/* MAIN */
const hue = ( color: string | Channels ): number => {
return channel ( color, 'h' );
};
/* EXPORT */
export default hue;
+92
View File
@@ -0,0 +1,92 @@
/* IMPORT */
import hex from '~/methods/rgba'; // Alias
import rgb from '~/methods/rgba'; // Alias
import rgba from '~/methods/rgba';
import hsl from '~/methods/hsla'; // Alias
import hsla from '~/methods/hsla';
import toKeyword from '~/methods/to_keyword';
import toHex from '~/methods/to_hex';
import toRgba from '~/methods/to_rgba';
import toHsla from '~/methods/to_hsla';
import channel from '~/methods/channel';
import red from '~/methods/red';
import green from '~/methods/green';
import blue from '~/methods/blue';
import hue from '~/methods/hue';
import saturation from '~/methods/saturation';
import lightness from '~/methods/lightness';
import alpha from '~/methods/alpha';
import opacity from '~/methods/alpha'; // Alias
import contrast from '~/methods/contrast';
import luminance from '~/methods/luminance';
import isDark from '~/methods/is_dark';
import isLight from '~/methods/is_light';
import isTransparent from '~/methods/is_transparent';
import isValid from '~/methods/is_valid';
import saturate from '~/methods/saturate';
import desaturate from '~/methods/desaturate';
import lighten from '~/methods/lighten';
import darken from '~/methods/darken';
import opacify from '~/methods/opacify';
import fadeIn from '~/methods/opacify'; // Alias
import transparentize from '~/methods/transparentize';
import fadeOut from '~/methods/transparentize'; // Alias
import complement from '~/methods/complement';
import grayscale from '~/methods/grayscale';
import adjust from '~/methods/adjust';
import change from '~/methods/change';
import invert from '~/methods/invert';
import mix from '~/methods/mix';
import scale from '~/methods/scale';
/* EXPORT */
export {
/* CREATE */
hex,
rgb,
rgba,
hsl,
hsla,
/* CONVERT */
toKeyword,
toHex,
toRgba,
toHsla,
/* GET - CHANNEL */
channel,
red,
green,
blue,
hue,
saturation,
lightness,
alpha,
opacity,
/* GET - MORE */
contrast,
luminance,
isDark,
isLight,
isTransparent,
isValid,
/* EDIT - CHANNEL */
saturate,
desaturate,
lighten,
darken,
opacify,
fadeIn,
transparentize,
fadeOut,
complement,
grayscale,
/* EDIT - MORE */
adjust,
change,
invert,
mix,
scale
};
+24
View File
@@ -0,0 +1,24 @@
/* IMPORT */
import Color from '~/color';
import mix from '~/methods/mix';
import type {Channels} from '~/types';
/* MAIN */
const invert = ( color: string | Channels, weight: number = 100 ): string => {
const inverse = Color.parse ( color );
inverse.r = 255 - inverse.r;
inverse.g = 255 - inverse.g;
inverse.b = 255 - inverse.b;
return mix ( inverse, color, weight );
};
/* EXPORT */
export default invert;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import isLight from '~/methods/is_light';
import type {Channels} from '~/types';
/* MAIN */
const isDark = ( color: string | Channels ): boolean => {
return !isLight ( color );
};
/* EXPORT */
export default isDark;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import luminance from '~/methods/luminance';
import type {Channels} from '~/types';
/* MAIN */
const isLight = ( color: string | Channels ): boolean => {
return luminance ( color ) >= .5;
};
/* EXPORT */
export default isLight;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import alpha from '~/methods/alpha';
import type {Channels} from '~/types';
/* MAIN */
const isTransparent = ( color: string | Channels ): boolean => {
return !alpha ( color );
};
/* EXPORT */
export default isTransparent;
+26
View File
@@ -0,0 +1,26 @@
/* IMPORT */
import Color from '~/color';
/* MAIN */
const isValid = ( color: string ): boolean => {
try {
Color.parse ( color );
return true;
} catch {
return false;
}
};
/* EXPORT */
export default isValid;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import adjustChannel from '~/methods/adjust_channel';
import type {Channels} from '~/types';
/* MAIN */
const lighten = ( color: string | Channels, amount: number ): string => {
return adjustChannel ( color, 'l', amount );
};
/* EXPORT */
export default lighten;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import channel from '~/methods/channel';
import type {Channels} from '~/types';
/* MAIN */
const lightness = ( color: string | Channels ): number => {
return channel ( color, 'l' );
};
/* EXPORT */
export default lightness;
+23
View File
@@ -0,0 +1,23 @@
/* IMPORT */
import _ from '~/utils';
import Color from '~/color';
import type {Channels} from '~/types';
/* MAIN */
//SOURCE: https://planetcalc.com/7779
const luminance = ( color: string | Channels ): number => {
const {r, g, b} = Color.parse ( color );
const luminance = .2126 * _.channel.toLinear ( r ) + .7152 * _.channel.toLinear ( g ) + .0722 * _.channel.toLinear ( b );
return _.lang.round ( luminance );
};
/* EXPORT */
export default luminance;
+33
View File
@@ -0,0 +1,33 @@
/* IMPORT */
import Color from '~/color';
import rgba from '~/methods/rgba';
import type {Channels} from '~/types';
/* MAIN */
//SOURCE: https://github.com/sass/dart-sass/blob/7457d2e9e7e623d9844ffd037a070cf32d39c348/lib/src/functions/color.dart#L718-L756
const mix = ( color1: string | Channels, color2: string | Channels, weight: number = 50 ): string => {
const {r: r1, g: g1, b: b1, a: a1} = Color.parse ( color1 );
const {r: r2, g: g2, b: b2, a: a2} = Color.parse ( color2 );
const weightScale = weight / 100;
const weightNormalized = ( weightScale * 2 ) - 1;
const alphaDelta = a1 - a2;
const weight1combined = ( ( weightNormalized * alphaDelta ) === -1 ) ? weightNormalized : ( weightNormalized + alphaDelta ) / ( 1 + weightNormalized * alphaDelta );
const weight1 = ( weight1combined + 1 ) / 2;
const weight2 = 1 - weight1;
const r = ( r1 * weight1 ) + ( r2 * weight2 );
const g = ( g1 * weight1 ) + ( g2 * weight2 );
const b = ( b1 * weight1 ) + ( b2 * weight2 );
const a = ( a1 * weightScale ) + ( a2 * ( 1 - weightScale ) );
return rgba ( r, g, b, a );
};
/* EXPORT */
export default mix;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import adjustChannel from '~/methods/adjust_channel';
import type {Channels} from '~/types';
/* MAIN */
const opacify = ( color: string | Channels, amount: number ): string => {
return adjustChannel ( color, 'a', amount );
};
/* EXPORT */
export default opacify;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import channel from '~/methods/channel';
import type {Channels} from '~/types';
/* MAIN */
const red = ( color: string | Channels ): number => {
return channel ( color, 'r' );
};
/* EXPORT */
export default red;
+36
View File
@@ -0,0 +1,36 @@
/* IMPORT */
import _ from '~/utils';
import ChannelsReusable from '~/channels/reusable';
import Color from '~/color';
import change from '~/methods/change';
import type {Channels} from '~/types';
/* TYPES */
type IRgba = {
( color: string | Channels, opacity: number ): string,
( r: number, g: number, b: number, a?: number ): string
};
/* MAIN */
const rgba: IRgba = ( r: string | Channels | number, g: number, b: number = 0, a: number = 1 ): string => { //TSC: `b` shouldn't have a default value
if ( typeof r !== 'number' ) return change ( r, { a: g } );
const channels = ChannelsReusable.set ({
r: _.channel.clamp.r ( r ),
g: _.channel.clamp.g ( g ),
b: _.channel.clamp.b ( b ),
a: _.channel.clamp.a ( a )
});
return Color.stringify ( channels );
};
/* EXPORT */
export default rgba;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import adjustChannel from '~/methods/adjust_channel';
import type {Channels} from '~/types';
/* MAIN */
const saturate = ( color: string | Channels, amount: number ): string => {
return adjustChannel ( color, 's', amount );
};
/* EXPORT */
export default saturate;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import channel from '~/methods/channel';
import type {Channels} from '~/types';
/* MAIN */
const saturation = ( color: string | Channels ): number => {
return channel ( color, 's' );
};
/* EXPORT */
export default saturation;
+29
View File
@@ -0,0 +1,29 @@
/* IMPORT */
import _ from '~/utils';
import Color from '~/color';
import adjust from '~/methods/adjust';
import type {CHANNELS, Channels} from '~/types';
/* MAIN */
const scale = ( color: string | Channels, channels: Partial<CHANNELS> ): string => {
const ch = Color.parse ( color );
const adjustments: Partial<CHANNELS> = {};
const delta = ( amount: number, weight: number, max: number ) => weight > 0 ? ( max - amount ) * weight / 100 : amount * weight / 100;
for ( const c in channels ) {
adjustments[c] = delta ( ch[c], channels[c], _.channel.max[c] );
}
return adjust ( color, adjustments );
};
/* EXPORT */
export default scale;
+16
View File
@@ -0,0 +1,16 @@
/* IMPORT */
import Color from '~/color';
/* MAIN */
const toHex = ( color: string ): string => {
return Color.format.hex.stringify ( Color.parse ( color ) );
};
/* EXPORT */
export default toHex;
+16
View File
@@ -0,0 +1,16 @@
/* IMPORT */
import Color from '~/color';
/* MAIN */
const toHsla = ( color: string ): string => {
return Color.format.hsla.stringify ( Color.parse ( color ) );
};
/* EXPORT */
export default toHsla;
+16
View File
@@ -0,0 +1,16 @@
/* IMPORT */
import Color from '~/color';
/* MAIN */
const toKeyword = ( color: string ): string | undefined => {
return Color.format.keyword.stringify ( Color.parse ( color ) );
};
/* EXPORT */
export default toKeyword;
+16
View File
@@ -0,0 +1,16 @@
/* IMPORT */
import Color from '~/color';
/* MAIN */
const toRgba = ( color: string ): string => {
return Color.format.rgba.stringify ( Color.parse ( color ) );
};
/* EXPORT */
export default toRgba;
+17
View File
@@ -0,0 +1,17 @@
/* IMPORT */
import adjustChannel from '~/methods/adjust_channel';
import type {Channels} from '~/types';
/* MAIN */
const transparentize = ( color: string | Channels, amount: number ): string => {
return adjustChannel ( color, 'a', -amount );
};
/* EXPORT */
export default transparentize;