UNPKG

termstyle-plus

Version:

The most comprehensive and powerful terminal styling library with extensive color support, gradients, animations, and special effects - TypeScript Edition

260 lines (224 loc) 8.38 kB
import { RGB, Colors, Styles, BoxStyle, NeonColor, Brighten as BrightenInterface } from './types'; class Brighten implements BrightenInterface { public readonly colors: Colors; public readonly bg: Colors; public readonly styles: Styles; [key: string]: any; constructor() { // Basic colors this.colors = { // Standard colors black: '\x1b[30m', red: '\x1b[31m', green: '\x1b[32m', yellow: '\x1b[33m', blue: '\x1b[34m', magenta: '\x1b[35m', cyan: '\x1b[36m', white: '\x1b[37m', // Bright colors brightBlack: '\x1b[90m', brightRed: '\x1b[91m', brightGreen: '\x1b[92m', brightYellow: '\x1b[93m', brightBlue: '\x1b[94m', brightMagenta: '\x1b[95m', brightCyan: '\x1b[96m', brightWhite: '\x1b[97m', // Extended colors orange: '\x1b[38;2;255;165;0m', pink: '\x1b[38;2;255;192;203m', purple: '\x1b[38;2;128;0;128m', brown: '\x1b[38;2;165;42;42m', gold: '\x1b[38;2;255;215;0m', silver: '\x1b[38;2;192;192;192m', lime: '\x1b[38;2;0;255;0m', teal: '\x1b[38;2;0;128;128m', indigo: '\x1b[38;2;75;0;130m', violet: '\x1b[38;2;238;130;238m', // Precious stones emerald: '\x1b[38;2;46;204;113m', ruby: '\x1b[38;2;224;17;95m', sapphire: '\x1b[38;2;15;82;186m', amethyst: '\x1b[38;2;153;102;204m', jade: '\x1b[38;2;0;168;107m', amber: '\x1b[38;2;255;191;0m', topaz: '\x1b[38;2;255;200;124m', pearl: '\x1b[38;2;240;234;214m', opal: '\x1b[38;2;177;231;236m', garnet: '\x1b[38;2;179;27;27m', // Nature colors forest: '\x1b[38;2;34;139;34m', sky: '\x1b[38;2;135;206;235m', ocean: '\x1b[38;2;0;119;190m', grass: '\x1b[38;2;124;252;0m', sunset: '\x1b[38;2;255;111;89m', dawn: '\x1b[38;2;255;179;167m', earth: '\x1b[38;2;150;75;0m', sand: '\x1b[38;2;194;178;128m', // Neon colors neonPink: '\x1b[38;2;255;0;255m', neonBlue: '\x1b[38;2;0;255;255m', neonGreen: '\x1b[38;2;57;255;20m', neonOrange: '\x1b[38;2;255;95;0m', neonYellow: '\x1b[38;2;255;255;0m', neonPurple: '\x1b[38;2;159;0;255m', // Pastel colors pastelPink: '\x1b[38;2;255;209;220m', pastelBlue: '\x1b[38;2;174;198;207m', pastelGreen: '\x1b[38;2;119;221;119m', pastelYellow: '\x1b[38;2;253;253;150m', pastelPurple: '\x1b[38;2;179;158;181m', pastelOrange: '\x1b[38;2;255;179;71m' }; // Backgrounds this.bg = {}; Object.entries(this.colors).forEach(([name, value]) => { const code = value.match(/\d+(?:;\d+)*/)?.[0]; if (code) { this.bg[name] = code.startsWith('38') ? `\x1b[48${code.slice(2)}m` : `\x1b[${parseInt(code) + 10}m`; } }); // Styles this.styles = { reset: '\x1b[0m', bold: '\x1b[1m', dim: '\x1b[2m', italic: '\x1b[3m', underline: '\x1b[4m', blink: '\x1b[5m', reverse: '\x1b[7m', hidden: '\x1b[8m', strikethrough: '\x1b[9m', doubleUnderline: '\x1b[21m', overline: '\x1b[53m' }; // Create color methods Object.keys(this.colors).forEach(color => { this[color] = (text: string): string => this.colors[color] + text + this.styles.reset; }); // Create background methods Object.keys(this.bg).forEach(color => { const methodName = `bg${color.charAt(0).toUpperCase() + color.slice(1)}`; this[methodName] = (text: string): string => this.bg[color] + text + this.styles.reset; }); // Create style methods Object.keys(this.styles).forEach(style => { if (style !== 'reset') { this[style] = (text: string): string => this.styles[style] + text + this.styles.reset; } }); } rgb(r: number, g: number, b: number): (text: string) => string { return (text: string): string => `\x1b[38;2;${r};${g};${b}m${text}${this.styles.reset}`; } bgRgb(r: number, g: number, b: number): (text: string) => string { return (text: string): string => `\x1b[48;2;${r};${g};${b}m${text}${this.styles.reset}`; } private hslToRgb(h: number, s: number, l: number): [number, number, number] { h /= 360; s /= 100; l /= 100; let r: number, g: number, b: number; if (s === 0) { r = g = b = l; } else { const hue2rgb = (p: number, q: number, t: number): number => { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1/6) return p + (q - p) * 6 * t; if (t < 1/2) return q; if (t < 2/3) return p + (q - p) * (2/3 - t) * 6; return p; }; const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = hue2rgb(p, q, h + 1/3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1/3); } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; } hsl(h: number, s: number, l: number): (text: string) => string { const [r, g, b] = this.hslToRgb(h, s, l); return this.rgb(r, g, b); } bgHsl(h: number, s: number, l: number): (text: string) => string { const [r, g, b] = this.hslToRgb(h, s, l); return this.bgRgb(r, g, b); } rainbow(text: string): string { const colors = [ 'red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet' ]; return text.split('').map((char, i) => { const color = colors[i % colors.length]; return this.colors[color] + char; }).join('') + this.styles.reset; } gradient(text: string, startColor: RGB, endColor: RGB): string { const chars = text.split(''); const steps = chars.length; return chars.map((char, i) => { const r = Math.floor(startColor.r + (endColor.r - startColor.r) * (i / steps)); const g = Math.floor(startColor.g + (endColor.g - startColor.g) * (i / steps)); const b = Math.floor(startColor.b + (endColor.b - startColor.b) * (i / steps)); return this.rgb(r, g, b)(char); }).join(''); } multiGradient(text: string, colors: RGB[]): string { const chars = text.split(''); const segments = colors.length - 1; const charsPerSegment = Math.ceil(chars.length / segments); return chars.map((char, i) => { const segment = Math.min(Math.floor(i / charsPerSegment), segments - 1); const startColor = colors[segment]; const endColor = colors[segment + 1]; const segmentPosition = (i % charsPerSegment) / charsPerSegment; const r = Math.floor(startColor.r + (endColor.r - startColor.r) * segmentPosition); const g = Math.floor(startColor.g + (endColor.g - startColor.g) * segmentPosition); const b = Math.floor(startColor.b + (endColor.b - startColor.b) * segmentPosition); return this.rgb(r, g, b)(char); }).join('') + this.styles.reset; } neon(text: string, color: NeonColor = 'blue'): string { const neonColors: { [key in NeonColor]: (text: string) => string } = { blue: this.neonBlue, pink: this.neonPink, green: this.neonGreen, orange: this.neonOrange, yellow: this.neonYellow, purple: this.neonPurple }; const colorFn = neonColors[color] || neonColors.blue; return this.bold(this.blink(colorFn(text))); } box(text: string, style: BoxStyle = 'single'): string { const styles: { [key in BoxStyle]: [string, string, string, string, string, string] } = { single: ['┌', '─', '┐', '│', '└', '┘'], double: ['╔', '═', '╗', '║', '╚', '╝'], round: ['╭', '─', '╮', '│', '╰', '╯'], bold: ['┏', '━', '┓', '┃', '┗', '┛'] }; const [tl, t, tr, v, bl, br] = styles[style] || styles.single; const width = text.length + 2; const top = `${tl}${t.repeat(width)}${tr}`; const middle = `${v} ${text} ${v}`; const bottom = `${bl}${t.repeat(width)}${br}`; return `${top}\n${middle}\n${bottom}`; } chain(...styles: string[]): (text: string) => string { return (text: string): string => styles.reduce((acc, style) => { if (typeof this[style] === 'function') { return this[style](acc); } return acc; }, text); } } // Create and export a singleton instance const brighten = new Brighten(); export default brighten;