feat: add gradient and theme features with corresponding tests and documentation

This commit is contained in:
HarshaVardhan 2026-02-01 17:12:54 -05:00
parent aa06bb5ac3
commit c017dd5b04
8 changed files with 505 additions and 13 deletions

61
source/index.js Normal file → Executable file
View file

@ -3,6 +3,8 @@ import supportsColor from '#supports-color';
import { // eslint-disable-line import/order
stringReplaceAll,
stringEncaseCRLFWithFirstIndex,
createGradientStyler,
applyGradient,
} from './utilities.js';
const {stdout: stdoutColor, stderr: stderrColor} = supportsColor;
@ -71,6 +73,18 @@ styles.visible = {
},
};
styles.theme = {
value(theme) {
const themed = createBuilder(this, this[STYLER], this[IS_EMPTY]);
for (const [key, value] of Object.entries(theme)) {
Object.defineProperty(themed, key, {value});
}
return themed;
},
};
const getModelAnsi = (model, level, type, ...arguments_) => {
if (model === 'rgb') {
if (level === 'ansi16m') {
@ -116,6 +130,12 @@ for (const model of usedModels) {
};
}
styles.gradient = {
get() {
return (...colors) => createBuilder(this, createGradientStyler(colors), this[IS_EMPTY]);
},
};
const proto = Object.defineProperties(() => {}, {
...styles,
level: {
@ -176,7 +196,39 @@ const applyStyle = (self, string) => {
return string;
}
const {openAll, closeAll} = styler;
// Find gradient styler in the chain
let gradientStyler = null;
let current = styler;
while (current) {
if (current.gradient) {
gradientStyler = current;
break;
}
current = current.parent;
}
let openAll;
let closeAll;
if (gradientStyler) {
// Build openAll/closeAll excluding gradient stylers
openAll = '';
closeAll = '';
current = styler;
while (current) {
if (!current.gradient) {
openAll = current.open + openAll;
closeAll += current.close;
}
current = current.parent;
}
} else {
({openAll, closeAll} = styler);
}
if (string.includes('\u001B')) {
while (styler !== undefined) {
// Replace any instances already present with a re-opening code
@ -188,6 +240,13 @@ const applyStyle = (self, string) => {
}
}
// Apply gradient if present
if (gradientStyler) {
string = applyGradient(string, gradientStyler.colors, self.level);
}
// We can move both next actions out of loop, because remaining actions in loop won't have
// We can move both next actions out of loop, because remaining actions in loop won't have
// any/visible effect on parts we add here. Close the styling before a linebreak and reopen
// after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92