From cff094a3e2cdffdc3709c18184691447646bb634 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Tue, 7 Feb 2023 03:09:28 -0500 Subject: [PATCH] Removes Color namespaces --- src/constants.ts | 24 +++ src/system/color.ts | 486 ++++++++++++++++++++++------------------------------ 2 files changed, 227 insertions(+), 283 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 672d99d..fbdf2ff 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -13,16 +13,40 @@ export const ImageMimetypes: Record = { export const enum CharCode { /** + * The `#` character. + */ + Hash = 35, + /** * The `/` character. */ Slash = 47, + Digit0 = 48, + Digit1 = 49, + Digit2 = 50, + Digit3 = 51, + Digit4 = 52, + Digit5 = 53, + Digit6 = 54, + Digit7 = 55, + Digit8 = 56, + Digit9 = 57, /** * The `\` character. */ Backslash = 92, A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, Z = 90, a = 97, + b = 98, + c = 99, + d = 100, + e = 101, + f = 102, z = 122, } diff --git a/src/system/color.ts b/src/system/color.ts index 207af33..13ca135 100644 --- a/src/system/color.ts +++ b/src/system/color.ts @@ -1,3 +1,5 @@ +import { CharCode } from '../constants'; + const cssColorRegex = /^(?:(#?)([0-9a-f]{3}|[0-9a-f]{6})|((?:rgb|hsl)a?)\((-?\d+%?)[,\s]+(-?\d+%?)[,\s]+(-?\d+%?)[,\s]*(-?[\d.]+%?)?\))$/i; @@ -95,75 +97,6 @@ export function toRgba(color: string) { } } -const enum CharCode { - /** - * The `#` character. - */ - Hash = 35, - Digit0 = 48, - Digit1 = 49, - Digit2 = 50, - Digit3 = 51, - Digit4 = 52, - Digit5 = 53, - Digit6 = 54, - Digit7 = 55, - Digit8 = 56, - Digit9 = 57, - A = 65, - B = 66, - C = 67, - D = 68, - E = 69, - F = 70, - G = 71, - H = 72, - I = 73, - J = 74, - K = 75, - L = 76, - M = 77, - N = 78, - O = 79, - P = 80, - Q = 81, - R = 82, - S = 83, - T = 84, - U = 85, - V = 86, - W = 87, - X = 88, - Y = 89, - Z = 90, - a = 97, - b = 98, - c = 99, - d = 100, - e = 101, - f = 102, - g = 103, - h = 104, - i = 105, - j = 106, - k = 107, - l = 108, - m = 109, - n = 110, - o = 111, - p = 112, - q = 113, - r = 114, - s = 115, - t = 116, - u = 117, - v = 118, - w = 119, - x = 120, - y = 121, - z = 122, -} - function mixColors(col1: Color, col2: Color, factor: number): Color { const xyz0 = col1.rgba; const xyz1 = col2.rgba; @@ -465,13 +398,13 @@ export class HSVA { export class Color { static fromHex(hex: string): Color { - return Color.Format.CSS.parseHex(hex) || Color.red; + return parseHex(hex) || Color.red; } static from(value: string | Color): Color { if (value instanceof Color) return value; - return Color.Format.CSS.parseString(value) || Color.red; + return parseString(value) || Color.red; } static equals(a: Color | null, b: Color | null): boolean { @@ -678,7 +611,7 @@ export class Color { private _toString?: string; toString(): string { if (!this._toString) { - this._toString = Color.Format.CSS.format(this); + this._toString = format(this); } return this._toString; } @@ -715,229 +648,216 @@ export class Color { static readonly transparent = new Color(new RGBA(0, 0, 0, 0)); } -export namespace Color { - export namespace Format { - export namespace CSS { - export function formatRGB(color: Color): string { - if (color.rgba.a === 1) { - return `rgb(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b})`; - } +export function formatRGB(color: Color): string { + if (color.rgba.a === 1) { + return `rgb(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b})`; + } - return Color.Format.CSS.formatRGBA(color); - } + return formatRGBA(color); +} - export function formatRGBA(color: Color): string { - return `rgba(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}, ${Number(color.rgba.a.toFixed(2))})`; - } +export function formatRGBA(color: Color): string { + return `rgba(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}, ${Number(color.rgba.a.toFixed(2))})`; +} - export function formatHSL(color: Color): string { - if (color.hsla.a === 1) { - return `hsl(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed( - 2, - )}%)`; - } +export function formatHSL(color: Color): string { + if (color.hsla.a === 1) { + return `hsl(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed(2)}%)`; + } - return Color.Format.CSS.formatHSLA(color); - } + return formatHSLA(color); +} - export function formatHSLA(color: Color): string { - return `hsla(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed( - 2, - )}%, ${color.hsla.a.toFixed(2)})`; - } +export function formatHSLA(color: Color): string { + return `hsla(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed( + 2, + )}%, ${color.hsla.a.toFixed(2)})`; +} - function _toTwoDigitHex(n: number): string { - const r = n.toString(16); - return r.length !== 2 ? `0${r}` : r; - } +function _toTwoDigitHex(n: number): string { + const r = n.toString(16); + return r.length !== 2 ? `0${r}` : r; +} - /** - * Formats the color as #RRGGBB - */ - export function formatHex(color: Color): string { - return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}`; - } +/** + * Formats the color as #RRGGBB + */ +export function formatHex(color: Color): string { + return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}`; +} - /** - * Formats the color as #RRGGBBAA - * If 'compact' is set, colors without transparancy will be printed as #RRGGBB - */ - export function formatHexA(color: Color, compact = false): string { - if (compact && color.rgba.a === 1) { - return Color.Format.CSS.formatHex(color); - } - - return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex( - color.rgba.b, - )}${_toTwoDigitHex(Math.round(color.rgba.a * 255))}`; - } +/** + * Formats the color as #RRGGBBAA + * If 'compact' is set, colors without transparancy will be printed as #RRGGBB + */ +export function formatHexA(color: Color, compact = false): string { + if (compact && color.rgba.a === 1) { + return formatHex(color); + } - /** - * The default format will use HEX if opaque and RGBA otherwise. - */ - export function format(color: Color): string { - if (color.isOpaque()) { - return Color.Format.CSS.formatHex(color); - } + return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex( + color.rgba.b, + )}${_toTwoDigitHex(Math.round(color.rgba.a * 255))}`; +} - return Color.Format.CSS.formatRGBA(color); - } +/** + * The default format will use HEX if opaque and RGBA otherwise. + */ +export function format(color: Color): string { + if (color.isOpaque()) { + return formatHex(color); + } - export function parseString(value: string): Color | null { - const length = value.length; - - // Invalid color - if (length === 0) { - return null; - } - - // Begin with a # - if (value.charCodeAt(0) === CharCode.Hash) { - return Color.Format.CSS.parseHex(value); - } - - const result = cssColorRegex.exec(value); - if (result == null) { - return null; - } - - const mode = result[3]; - let colors: number[]; - switch (mode) { - case 'rgb': - case 'hsl': - colors = [parseInt(result[4], 10), parseInt(result[5], 10), parseInt(result[6], 10), 1]; - break; - case 'rgba': - case 'hsla': - colors = [ - parseInt(result[4], 10), - parseInt(result[5], 10), - parseInt(result[6], 10), - parseFloat(result[7]), - ]; - break; - default: - return null; - } - - switch (mode) { - case 'rgb': - case 'rgba': - return new Color(new RGBA(colors[0], colors[1], colors[2], colors[3])); - case 'hsl': - case 'hsla': - return new Color(new HSLA(colors[0], colors[1], colors[2], colors[3])); - } - - return Color.red; - } + return formatRGBA(color); +} - /** - * Converts an Hex color value to a Color. - * returns r, g, and b are contained in the set [0, 255] - * @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA). - */ - export function parseHex(hex: string): Color | null { - const length = hex.length; - - if (length === 0) { - // Invalid color - return null; - } - - if (hex.charCodeAt(0) !== CharCode.Hash) { - // Does not begin with a # - return null; - } - - if (length === 7) { - // #RRGGBB format - const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2)); - const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4)); - const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6)); - return new Color(new RGBA(r, g, b, 1)); - } - - if (length === 9) { - // #RRGGBBAA format - const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2)); - const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4)); - const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6)); - const a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8)); - return new Color(new RGBA(r, g, b, a / 255)); - } - - if (length === 4) { - // #RGB format - const r = _parseHexDigit(hex.charCodeAt(1)); - const g = _parseHexDigit(hex.charCodeAt(2)); - const b = _parseHexDigit(hex.charCodeAt(3)); - return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b)); - } - - if (length === 5) { - // #RGBA format - const r = _parseHexDigit(hex.charCodeAt(1)); - const g = _parseHexDigit(hex.charCodeAt(2)); - const b = _parseHexDigit(hex.charCodeAt(3)); - const a = _parseHexDigit(hex.charCodeAt(4)); - return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b, (16 * a + a) / 255)); - } - - // Invalid color - return null; - } +export function parseString(value: string): Color | null { + const length = value.length; - function _parseHexDigit(charCode: CharCode): number { - switch (charCode) { - case CharCode.Digit0: - return 0; - case CharCode.Digit1: - return 1; - case CharCode.Digit2: - return 2; - case CharCode.Digit3: - return 3; - case CharCode.Digit4: - return 4; - case CharCode.Digit5: - return 5; - case CharCode.Digit6: - return 6; - case CharCode.Digit7: - return 7; - case CharCode.Digit8: - return 8; - case CharCode.Digit9: - return 9; - case CharCode.a: - return 10; - case CharCode.A: - return 10; - case CharCode.b: - return 11; - case CharCode.B: - return 11; - case CharCode.c: - return 12; - case CharCode.C: - return 12; - case CharCode.d: - return 13; - case CharCode.D: - return 13; - case CharCode.e: - return 14; - case CharCode.E: - return 14; - case CharCode.f: - return 15; - case CharCode.F: - return 15; - } - return 0; - } - } + // Invalid color + if (length === 0) { + return null; + } + + // Begin with a # + if (value.charCodeAt(0) === CharCode.Hash) { + return parseHex(value); } + + const result = cssColorRegex.exec(value); + if (result == null) { + return null; + } + + const mode = result[3]; + let colors: number[]; + switch (mode) { + case 'rgb': + case 'hsl': + colors = [parseInt(result[4], 10), parseInt(result[5], 10), parseInt(result[6], 10), 1]; + break; + case 'rgba': + case 'hsla': + colors = [parseInt(result[4], 10), parseInt(result[5], 10), parseInt(result[6], 10), parseFloat(result[7])]; + break; + default: + return null; + } + + switch (mode) { + case 'rgb': + case 'rgba': + return new Color(new RGBA(colors[0], colors[1], colors[2], colors[3])); + case 'hsl': + case 'hsla': + return new Color(new HSLA(colors[0], colors[1], colors[2], colors[3])); + } + + return Color.red; +} + +/** + * Converts an Hex color value to a Color. + * returns r, g, and b are contained in the set [0, 255] + * @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA). + */ +export function parseHex(hex: string): Color | null { + const length = hex.length; + + if (length === 0) { + // Invalid color + return null; + } + + if (hex.charCodeAt(0) !== CharCode.Hash) { + // Does not begin with a # + return null; + } + + if (length === 7) { + // #RRGGBB format + const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2)); + const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4)); + const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6)); + return new Color(new RGBA(r, g, b, 1)); + } + + if (length === 9) { + // #RRGGBBAA format + const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2)); + const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4)); + const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6)); + const a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8)); + return new Color(new RGBA(r, g, b, a / 255)); + } + + if (length === 4) { + // #RGB format + const r = _parseHexDigit(hex.charCodeAt(1)); + const g = _parseHexDigit(hex.charCodeAt(2)); + const b = _parseHexDigit(hex.charCodeAt(3)); + return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b)); + } + + if (length === 5) { + // #RGBA format + const r = _parseHexDigit(hex.charCodeAt(1)); + const g = _parseHexDigit(hex.charCodeAt(2)); + const b = _parseHexDigit(hex.charCodeAt(3)); + const a = _parseHexDigit(hex.charCodeAt(4)); + return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b, (16 * a + a) / 255)); + } + + // Invalid color + return null; +} + +function _parseHexDigit(charCode: CharCode): number { + switch (charCode) { + case CharCode.Digit0: + return 0; + case CharCode.Digit1: + return 1; + case CharCode.Digit2: + return 2; + case CharCode.Digit3: + return 3; + case CharCode.Digit4: + return 4; + case CharCode.Digit5: + return 5; + case CharCode.Digit6: + return 6; + case CharCode.Digit7: + return 7; + case CharCode.Digit8: + return 8; + case CharCode.Digit9: + return 9; + case CharCode.a: + return 10; + case CharCode.A: + return 10; + case CharCode.b: + return 11; + case CharCode.B: + return 11; + case CharCode.c: + return 12; + case CharCode.C: + return 12; + case CharCode.d: + return 13; + case CharCode.D: + return 13; + case CharCode.e: + return 14; + case CharCode.E: + return 14; + case CharCode.f: + return 15; + case CharCode.F: + return 15; + } + return 0; }