Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ansi colors and add .ansi256ToAnsi(), .rgbToAnsi() and .hexToAnsi() #71

Merged
merged 4 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions index.d.ts
Expand Up @@ -16,6 +16,8 @@ export interface ColorBase {
*/
readonly close: string;

ansi(code: number): string;

ansi256(code: number): string;

ansi16m(red: number, green: number, blue: number): string;
Expand Down Expand Up @@ -153,6 +155,29 @@ export interface ConvertColor {
@param hex - A hexadecimal string containing RGB data.
*/
hexToAnsi256(hex: string): number;

/**
Convert from the ANSI 256 color space to the ANSI 16 color space.

@param code - A number representing the ANSI 256 color.
*/
ansi256ToAnsi(code: number): number;

/**
Convert from the RGB color space to the ANSI 16 color space.

@param red - (`0...255`)
@param green - (`0...255`)
@param blue - (`0...255`)
*/
rgbToAnsi(red: number, green: number, blue: number): number;

/**
Convert from the RGB HEX color space to the ANSI 16 color space.

@param hex - A hexadecimal string containing RGB data.
*/
hexToAnsi(hex: string): number;
}

declare const ansiStyles: {
Expand Down
56 changes: 56 additions & 0 deletions index.js
@@ -1,5 +1,7 @@
const ANSI_BACKGROUND_OFFSET = 10;

const wrapAnsi16 = (offset = 0) => code => `\u001B[${code + offset}m`;

const wrapAnsi256 = (offset = 0) => code => `\u001B[${38 + offset};5;${code}m`;

const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
Expand Down Expand Up @@ -93,8 +95,10 @@ function assembleStyles() {
styles.color.close = '\u001B[39m';
styles.bgColor.close = '\u001B[49m';

styles.color.ansi = wrapAnsi16();
styles.color.ansi256 = wrapAnsi256();
styles.color.ansi16m = wrapAnsi16m();
styles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
styles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);

Expand Down Expand Up @@ -149,6 +153,58 @@ function assembleStyles() {
hexToAnsi256: {
value: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),
enumerable: false
},
ansi256ToAnsi: {
value: code => {
if (code < 8) {
return 30 + code;
}

if (code < 16) {
return 90 + (code - 8);
}

let red;
let green;
let blue;

if (code >= 232) {
red = (((code - 232) * 10) + 8) / 255;
green = red;
blue = red;
} else {
code -= 16;

const remainder = code % 36;

red = Math.floor(code / 36) / 5;
green = Math.floor(remainder / 6) / 5;
blue = (remainder % 6) / 5;
}

const value = Math.max(red, green, blue) * 2;

if (value === 0) {
return 30;
}

let result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));

if (value === 2) {
result += 60;
}

return result;
},
enumerable: false
},
rgbToAnsi: {
value: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),
enumerable: false
},
hexToAnsi: {
value: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),
enumerable: false
}
});

Expand Down
11 changes: 8 additions & 3 deletions readme.md
Expand Up @@ -25,6 +25,7 @@ console.log(`${styles.green.open}Hello world!${styles.green.close}`);
// may be degraded to fit the new color palette. This means terminals
// that do not support 16 million colors will best-match the
// original color.
console.log(`${styles.color.ansi(styles.rgbToAnsi(199, 20, 250))}Hello World${styles.color.close}`)
console.log(`${styles.color.ansi256(styles.rgbToAnsi256(199, 20, 250))}Hello World${styles.color.close}`)
console.log(`${styles.color.ansi16m(...styles.hexToRgb('#abcdef'))}Hello World${styles.color.close}`)
```
Expand Down Expand Up @@ -112,21 +113,25 @@ console.log(styles.codes.get(36));
//=> 39
```

## [256 / 16 million (TrueColor) support](https://gist.github.com/XVilka/8346728)
## 16 / 256 / 16 million (TrueColor) support

`ansi-styles` allows converting between various color formats and ANSI escapes, with support for 256 and 16 million colors.
`ansi-styles` allows converting between various color formats and ANSI escapes, with support for 16, 256 and [16 million colors](https://gist.github.com/XVilka/8346728).

The following color spaces from `color-convert` are supported:
The following color spaces are supported:

- `rgb`
- `hex`
- `ansi256`
- `ansi`

To use these, call the associated conversion function with the intended output, for example:

```js
import styles from 'ansi-styles';

styles.color.ansi(styles.rgbToAnsi(100, 200, 15)); // RGB to 16 color ansi foreground code
styles.bgColor.ansi(styles.hexToAnsi('#C0FFEE')); // HEX to 16 color ansi foreground code

styles.color.ansi256(styles.rgbToAnsi256(100, 200, 15)); // RGB to 256 color ansi foreground code
styles.bgColor.ansi256(styles.hexToAnsi256('#C0FFEE')); // HEX to 256 color ansi foreground code

Expand Down
10 changes: 10 additions & 0 deletions test/test.js
Expand Up @@ -19,6 +19,16 @@ test('groups should not be enumerable', t => {
t.false(Object.keys(ansiStyles).includes('modifier'));
});

test('support conversion to ansi (16 colors)', t => {
t.is(ansiStyles.color.ansi(ansiStyles.rgbToAnsi(255, 255, 255)), '\u001B[97m');
t.is(ansiStyles.color.ansi(ansiStyles.hexToAnsi('#990099')), '\u001B[35m');
t.is(ansiStyles.color.ansi(ansiStyles.hexToAnsi('#FF00FF')), '\u001B[95m');

t.is(ansiStyles.bgColor.ansi(ansiStyles.rgbToAnsi(255, 255, 255)), '\u001B[107m');
t.is(ansiStyles.bgColor.ansi(ansiStyles.hexToAnsi('#990099')), '\u001B[45m');
t.is(ansiStyles.bgColor.ansi(ansiStyles.hexToAnsi('#FF00FF')), '\u001B[105m');
});

test('support conversion to ansi (256 colors)', t => {
t.is(ansiStyles.color.ansi256(ansiStyles.rgbToAnsi256(255, 255, 255)), '\u001B[38;5;231m');
t.is(ansiStyles.color.ansi256(ansiStyles.hexToAnsi256('#990099')), '\u001B[38;5;127m');
Expand Down