ansimax 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +152 -0
- package/README.es.md +150 -40
- package/README.md +150 -40
- package/dist/index.d.mts +78 -2
- package/dist/index.d.ts +78 -2
- package/dist/index.js +140 -15
- package/dist/index.mjs +139 -15
- package/examples/all-in-one.cjs +1 -1
- package/examples/all-in-one.mjs +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
ST: () => ST,
|
|
47
47
|
STYLE: () => STYLE,
|
|
48
48
|
animate: () => animate,
|
|
49
|
+
animateGradient: () => animateGradient,
|
|
49
50
|
ascii: () => ascii,
|
|
50
51
|
bell: () => bell,
|
|
51
52
|
bg256: () => bg256,
|
|
@@ -225,6 +226,11 @@ var cursor = {
|
|
|
225
226
|
var _exitHandlerRegistered = false;
|
|
226
227
|
var _isTestEnv = () => process.env["JEST_WORKER_ID"] !== void 0 || process.env["VITEST"] !== void 0 || process.env["NODE_ENV"] === "test";
|
|
227
228
|
var _installCursorRestoreImpl = () => {
|
|
229
|
+
try {
|
|
230
|
+
const current = process.getMaxListeners?.() ?? 10;
|
|
231
|
+
if (current < 20) process.setMaxListeners?.(20);
|
|
232
|
+
} catch {
|
|
233
|
+
}
|
|
228
234
|
const restore = () => {
|
|
229
235
|
try {
|
|
230
236
|
safeStreamWrite(process.stdout, cursor.show());
|
|
@@ -1109,6 +1115,37 @@ var compose = (...fns) => (text) => {
|
|
|
1109
1115
|
if (opens === "") return s;
|
|
1110
1116
|
return opens + s + reset();
|
|
1111
1117
|
};
|
|
1118
|
+
var _cubicBezier = (t, x1 = 0.25, y1 = 0.1, x2 = 0.25, y2 = 1) => {
|
|
1119
|
+
if (t <= 0) return 0;
|
|
1120
|
+
if (t >= 1) return 1;
|
|
1121
|
+
let s = t;
|
|
1122
|
+
for (let i = 0; i < 8; i++) {
|
|
1123
|
+
const s22 = s * s;
|
|
1124
|
+
const s32 = s22 * s;
|
|
1125
|
+
const oneMinusS = 1 - s;
|
|
1126
|
+
const oneMinusS2 = oneMinusS * oneMinusS;
|
|
1127
|
+
const fx = 3 * oneMinusS2 * s * x1 + 3 * oneMinusS * s22 * x2 + s32 - t;
|
|
1128
|
+
const dfx = 3 * oneMinusS2 * x1 + 6 * oneMinusS * s * (x2 - x1) + 3 * s22 * (1 - x2);
|
|
1129
|
+
if (Math.abs(dfx) < 1e-6) break;
|
|
1130
|
+
s -= fx / dfx;
|
|
1131
|
+
s = Math.min(1, Math.max(0, s));
|
|
1132
|
+
}
|
|
1133
|
+
const s2 = s * s;
|
|
1134
|
+
const s3 = s2 * s;
|
|
1135
|
+
return 3 * (1 - s) * (1 - s) * s * y1 + 3 * (1 - s) * s2 * y2 + s3;
|
|
1136
|
+
};
|
|
1137
|
+
var EASINGS = {
|
|
1138
|
+
"linear": (t) => t,
|
|
1139
|
+
"ease-in": (t) => t * t,
|
|
1140
|
+
"ease-out": (t) => 1 - (1 - t) * (1 - t),
|
|
1141
|
+
"ease-in-out": (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
|
|
1142
|
+
"cubic-bezier": (t) => _cubicBezier(t)
|
|
1143
|
+
};
|
|
1144
|
+
var resolveEasing = (e) => {
|
|
1145
|
+
if (typeof e === "function") return e;
|
|
1146
|
+
if (typeof e === "string" && EASINGS[e]) return EASINGS[e];
|
|
1147
|
+
return EASINGS.linear;
|
|
1148
|
+
};
|
|
1112
1149
|
var stripAnsi3 = stripAnsi;
|
|
1113
1150
|
var gradient = (text, stops, opts = {}) => {
|
|
1114
1151
|
const s = coerceText(text);
|
|
@@ -1120,13 +1157,15 @@ var gradient = (text, stops, opts = {}) => {
|
|
|
1120
1157
|
const c = colors[0];
|
|
1121
1158
|
return adaptiveFg(c.r, c.g, c.b) + s + reset();
|
|
1122
1159
|
}
|
|
1123
|
-
const { preserveAnsi = false } = opts;
|
|
1160
|
+
const { preserveAnsi = false, easing, phase = 0 } = opts;
|
|
1161
|
+
const easingFn = resolveEasing(easing);
|
|
1162
|
+
const phaseN = Number.isFinite(phase) ? (phase % 1 + 1) % 1 : 0;
|
|
1124
1163
|
if (!preserveAnsi || !s.includes("\x1B")) {
|
|
1125
|
-
return _gradientPlain(s, colors);
|
|
1164
|
+
return _gradientPlain(s, colors, easingFn, phaseN);
|
|
1126
1165
|
}
|
|
1127
|
-
return _gradientAnsiAware(s, colors);
|
|
1166
|
+
return _gradientAnsiAware(s, colors, easingFn, phaseN);
|
|
1128
1167
|
};
|
|
1129
|
-
var _gradientPlain = (text, colors) => {
|
|
1168
|
+
var _gradientPlain = (text, colors, easingFn, phase) => {
|
|
1130
1169
|
const chars = [...text];
|
|
1131
1170
|
const visible = chars.filter((c) => c !== " ").length;
|
|
1132
1171
|
if (visible === 0) return text;
|
|
@@ -1139,7 +1178,10 @@ var _gradientPlain = (text, colors) => {
|
|
|
1139
1178
|
out += ch;
|
|
1140
1179
|
continue;
|
|
1141
1180
|
}
|
|
1142
|
-
|
|
1181
|
+
let t = visible === 1 ? 0 : colorIdx / visibleMinus;
|
|
1182
|
+
t = (t + phase) % 1;
|
|
1183
|
+
t = easingFn(t);
|
|
1184
|
+
t = Math.min(1, Math.max(0, t));
|
|
1143
1185
|
const scaled = t * (colorCount - 1);
|
|
1144
1186
|
const lo = Math.floor(scaled);
|
|
1145
1187
|
const hi = Math.min(lo + 1, colorCount - 1);
|
|
@@ -1150,7 +1192,7 @@ var _gradientPlain = (text, colors) => {
|
|
|
1150
1192
|
return out;
|
|
1151
1193
|
};
|
|
1152
1194
|
var ANSI_TOKEN = /\x1b\[[0-9;?]*[a-zA-Z]/y;
|
|
1153
|
-
var _gradientAnsiAware = (text, colors) => {
|
|
1195
|
+
var _gradientAnsiAware = (text, colors, easingFn, phase) => {
|
|
1154
1196
|
const visible = stripAnsi3(text).split("").filter((c) => c !== " ").length;
|
|
1155
1197
|
if (visible === 0) return text;
|
|
1156
1198
|
let out = "";
|
|
@@ -1176,7 +1218,10 @@ var _gradientAnsiAware = (text, colors) => {
|
|
|
1176
1218
|
if (ch === " ") {
|
|
1177
1219
|
out += ch;
|
|
1178
1220
|
} else {
|
|
1179
|
-
|
|
1221
|
+
let t = visible === 1 ? 0 : colorIdx / visibleMinus;
|
|
1222
|
+
t = (t + phase) % 1;
|
|
1223
|
+
t = easingFn(t);
|
|
1224
|
+
t = Math.min(1, Math.max(0, t));
|
|
1180
1225
|
const scaled = t * (colorCount - 1);
|
|
1181
1226
|
const lo = Math.floor(scaled);
|
|
1182
1227
|
const hi = Math.min(lo + 1, colorCount - 1);
|
|
@@ -1190,6 +1235,76 @@ var _gradientAnsiAware = (text, colors) => {
|
|
|
1190
1235
|
};
|
|
1191
1236
|
var RAINBOW = ["#ff0000", "#ff7f00", "#ffff00", "#00ff00", "#0000ff", "#8b00ff"];
|
|
1192
1237
|
var rainbow = (text) => gradient(text, RAINBOW);
|
|
1238
|
+
var animateGradient = (text, stops, opts = {}) => {
|
|
1239
|
+
const {
|
|
1240
|
+
duration = 2e3,
|
|
1241
|
+
fps = 30,
|
|
1242
|
+
infinite = true,
|
|
1243
|
+
cycles = 1,
|
|
1244
|
+
direction = "forward",
|
|
1245
|
+
easing,
|
|
1246
|
+
preserveAnsi = false,
|
|
1247
|
+
signal,
|
|
1248
|
+
onFrame
|
|
1249
|
+
} = opts;
|
|
1250
|
+
const safeFps = Math.min(60, Math.max(1, Number.isFinite(fps) ? fps : 30));
|
|
1251
|
+
const safeDuration2 = Math.max(100, Number.isFinite(duration) ? duration : 2e3);
|
|
1252
|
+
const safeCycles = Math.max(1, Number.isFinite(cycles) ? cycles : 1);
|
|
1253
|
+
const frameInterval2 = 1e3 / safeFps;
|
|
1254
|
+
let stopped = false;
|
|
1255
|
+
let timer = null;
|
|
1256
|
+
let resolveDone = (
|
|
1257
|
+
/* istanbul ignore next */
|
|
1258
|
+
() => {
|
|
1259
|
+
}
|
|
1260
|
+
);
|
|
1261
|
+
const done = new Promise((res) => {
|
|
1262
|
+
resolveDone = res;
|
|
1263
|
+
});
|
|
1264
|
+
const stop = () => {
|
|
1265
|
+
if (stopped) return;
|
|
1266
|
+
stopped = true;
|
|
1267
|
+
if (timer != null) {
|
|
1268
|
+
clearInterval(timer);
|
|
1269
|
+
timer = null;
|
|
1270
|
+
}
|
|
1271
|
+
resolveDone();
|
|
1272
|
+
};
|
|
1273
|
+
if (signal) {
|
|
1274
|
+
if (signal.aborted) {
|
|
1275
|
+
stop();
|
|
1276
|
+
return { stop, done };
|
|
1277
|
+
}
|
|
1278
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
1279
|
+
}
|
|
1280
|
+
const startTime = Date.now();
|
|
1281
|
+
const renderFrame = () => {
|
|
1282
|
+
if (stopped) return;
|
|
1283
|
+
const elapsed = Date.now() - startTime;
|
|
1284
|
+
let phase = elapsed / safeDuration2 % 1;
|
|
1285
|
+
if (direction === "reverse") phase = 1 - phase;
|
|
1286
|
+
const frame = gradient(text, stops, { preserveAnsi, easing, phase });
|
|
1287
|
+
if (onFrame) {
|
|
1288
|
+
onFrame(frame, phase);
|
|
1289
|
+
} else {
|
|
1290
|
+
try {
|
|
1291
|
+
process.stdout.write("\r" + frame);
|
|
1292
|
+
} catch {
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
if (!infinite) {
|
|
1296
|
+
const completedCycles = Math.floor(elapsed / safeDuration2);
|
|
1297
|
+
if (completedCycles >= safeCycles) {
|
|
1298
|
+
stop();
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
renderFrame();
|
|
1303
|
+
if (!stopped) {
|
|
1304
|
+
timer = setInterval(renderFrame, frameInterval2);
|
|
1305
|
+
}
|
|
1306
|
+
return { stop, done };
|
|
1307
|
+
};
|
|
1193
1308
|
var PRESET_DEFS = {
|
|
1194
1309
|
sunset: ["#ff6b6b", "#feca57", "#48dbfb"],
|
|
1195
1310
|
ocean: ["#0575e6", "#021b79"],
|
|
@@ -4113,12 +4228,12 @@ var validateTheme = (t) => {
|
|
|
4113
4228
|
}
|
|
4114
4229
|
const obj = t;
|
|
4115
4230
|
if (typeof obj.name !== "string" || obj.name.length === 0) {
|
|
4116
|
-
throw new
|
|
4231
|
+
throw new TypeError('Theme must have a non-empty "name" string.');
|
|
4117
4232
|
}
|
|
4118
4233
|
for (const key of REQUIRED_COLOR_KEYS) {
|
|
4119
4234
|
const value = obj[key];
|
|
4120
4235
|
if (typeof value !== "string" || !HEX_RE4.test(value)) {
|
|
4121
|
-
throw new
|
|
4236
|
+
throw new TypeError(
|
|
4122
4237
|
`Invalid hex in theme "${obj.name}" \u2192 ${key}: ${JSON.stringify(value)}. Expected #RGB or #RRGGBB.`
|
|
4123
4238
|
);
|
|
4124
4239
|
}
|
|
@@ -4127,20 +4242,20 @@ var validateTheme = (t) => {
|
|
|
4127
4242
|
const value = obj[key];
|
|
4128
4243
|
if (value === void 0) continue;
|
|
4129
4244
|
if (typeof value !== "string" || !HEX_RE4.test(value)) {
|
|
4130
|
-
throw new
|
|
4245
|
+
throw new TypeError(
|
|
4131
4246
|
`Invalid hex in theme "${obj.name}" \u2192 ${key}: ${JSON.stringify(value)}.`
|
|
4132
4247
|
);
|
|
4133
4248
|
}
|
|
4134
4249
|
}
|
|
4135
4250
|
if (!Array.isArray(obj.gradient) || obj.gradient.length < 2) {
|
|
4136
|
-
throw new
|
|
4251
|
+
throw new TypeError(
|
|
4137
4252
|
`Theme "${obj.name}" must define a "gradient" array with at least 2 colors.`
|
|
4138
4253
|
);
|
|
4139
4254
|
}
|
|
4140
4255
|
for (let i = 0; i < obj.gradient.length; i++) {
|
|
4141
4256
|
const stop = obj.gradient[i];
|
|
4142
4257
|
if (typeof stop !== "string" || !HEX_RE4.test(stop)) {
|
|
4143
|
-
throw new
|
|
4258
|
+
throw new TypeError(
|
|
4144
4259
|
`Invalid hex in theme "${obj.name}" \u2192 gradient[${i}]: ${JSON.stringify(stop)}.`
|
|
4145
4260
|
);
|
|
4146
4261
|
}
|
|
@@ -4452,8 +4567,8 @@ var themes = {
|
|
|
4452
4567
|
use(name) {
|
|
4453
4568
|
const t = _globalRegistry.get(name);
|
|
4454
4569
|
if (!t) {
|
|
4455
|
-
throw new
|
|
4456
|
-
`Theme "${name}" not found. Available: ${[..._globalRegistry.keys()].join(", ")}`
|
|
4570
|
+
throw new RangeError(
|
|
4571
|
+
`Theme "${name}" not found. Available themes: ${[..._globalRegistry.keys()].join(", ")}`
|
|
4457
4572
|
);
|
|
4458
4573
|
}
|
|
4459
4574
|
const old = _globalActive;
|
|
@@ -4828,6 +4943,7 @@ var gradientRect = (opts = {}) => {
|
|
|
4828
4943
|
colors = ["#ff0000", "#0000ff"],
|
|
4829
4944
|
style = "horizontal",
|
|
4830
4945
|
angle,
|
|
4946
|
+
startAngle = 0,
|
|
4831
4947
|
dither = "none",
|
|
4832
4948
|
braille = false
|
|
4833
4949
|
} = opts;
|
|
@@ -4866,7 +4982,15 @@ var gradientRect = (opts = {}) => {
|
|
|
4866
4982
|
} else if (style === "horizontal") t = col / (safeW - 1);
|
|
4867
4983
|
else if (style === "vertical") t = row / (safeH - 1);
|
|
4868
4984
|
else if (style === "diagonal") t = (col + row) / (safeW + safeH - 2);
|
|
4869
|
-
else {
|
|
4985
|
+
else if (style === "conic") {
|
|
4986
|
+
const cx = safeW / 2, cy = safeH / 2;
|
|
4987
|
+
const dx = col - cx;
|
|
4988
|
+
const dy = row - cy;
|
|
4989
|
+
const startRad = (Number.isFinite(startAngle) ? startAngle : 0) * Math.PI / 180;
|
|
4990
|
+
let angleRad = Math.atan2(dy, dx) - startRad;
|
|
4991
|
+
angleRad = (angleRad % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI);
|
|
4992
|
+
t = angleRad / (2 * Math.PI);
|
|
4993
|
+
} else {
|
|
4870
4994
|
const cx = safeW / 2, cy = safeH / 2;
|
|
4871
4995
|
const dx = (col - cx) / cx;
|
|
4872
4996
|
const dy = (row - cy) / cy;
|
|
@@ -5318,6 +5442,7 @@ var index_default = ansimax;
|
|
|
5318
5442
|
ST,
|
|
5319
5443
|
STYLE,
|
|
5320
5444
|
animate,
|
|
5445
|
+
animateGradient,
|
|
5321
5446
|
ascii,
|
|
5322
5447
|
bell,
|
|
5323
5448
|
bg256,
|
package/dist/index.mjs
CHANGED
|
@@ -53,6 +53,11 @@ var cursor = {
|
|
|
53
53
|
var _exitHandlerRegistered = false;
|
|
54
54
|
var _isTestEnv = () => process.env["JEST_WORKER_ID"] !== void 0 || process.env["VITEST"] !== void 0 || process.env["NODE_ENV"] === "test";
|
|
55
55
|
var _installCursorRestoreImpl = () => {
|
|
56
|
+
try {
|
|
57
|
+
const current = process.getMaxListeners?.() ?? 10;
|
|
58
|
+
if (current < 20) process.setMaxListeners?.(20);
|
|
59
|
+
} catch {
|
|
60
|
+
}
|
|
56
61
|
const restore = () => {
|
|
57
62
|
try {
|
|
58
63
|
safeStreamWrite(process.stdout, cursor.show());
|
|
@@ -937,6 +942,37 @@ var compose = (...fns) => (text) => {
|
|
|
937
942
|
if (opens === "") return s;
|
|
938
943
|
return opens + s + reset();
|
|
939
944
|
};
|
|
945
|
+
var _cubicBezier = (t, x1 = 0.25, y1 = 0.1, x2 = 0.25, y2 = 1) => {
|
|
946
|
+
if (t <= 0) return 0;
|
|
947
|
+
if (t >= 1) return 1;
|
|
948
|
+
let s = t;
|
|
949
|
+
for (let i = 0; i < 8; i++) {
|
|
950
|
+
const s22 = s * s;
|
|
951
|
+
const s32 = s22 * s;
|
|
952
|
+
const oneMinusS = 1 - s;
|
|
953
|
+
const oneMinusS2 = oneMinusS * oneMinusS;
|
|
954
|
+
const fx = 3 * oneMinusS2 * s * x1 + 3 * oneMinusS * s22 * x2 + s32 - t;
|
|
955
|
+
const dfx = 3 * oneMinusS2 * x1 + 6 * oneMinusS * s * (x2 - x1) + 3 * s22 * (1 - x2);
|
|
956
|
+
if (Math.abs(dfx) < 1e-6) break;
|
|
957
|
+
s -= fx / dfx;
|
|
958
|
+
s = Math.min(1, Math.max(0, s));
|
|
959
|
+
}
|
|
960
|
+
const s2 = s * s;
|
|
961
|
+
const s3 = s2 * s;
|
|
962
|
+
return 3 * (1 - s) * (1 - s) * s * y1 + 3 * (1 - s) * s2 * y2 + s3;
|
|
963
|
+
};
|
|
964
|
+
var EASINGS = {
|
|
965
|
+
"linear": (t) => t,
|
|
966
|
+
"ease-in": (t) => t * t,
|
|
967
|
+
"ease-out": (t) => 1 - (1 - t) * (1 - t),
|
|
968
|
+
"ease-in-out": (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
|
|
969
|
+
"cubic-bezier": (t) => _cubicBezier(t)
|
|
970
|
+
};
|
|
971
|
+
var resolveEasing = (e) => {
|
|
972
|
+
if (typeof e === "function") return e;
|
|
973
|
+
if (typeof e === "string" && EASINGS[e]) return EASINGS[e];
|
|
974
|
+
return EASINGS.linear;
|
|
975
|
+
};
|
|
940
976
|
var stripAnsi3 = stripAnsi;
|
|
941
977
|
var gradient = (text, stops, opts = {}) => {
|
|
942
978
|
const s = coerceText(text);
|
|
@@ -948,13 +984,15 @@ var gradient = (text, stops, opts = {}) => {
|
|
|
948
984
|
const c = colors[0];
|
|
949
985
|
return adaptiveFg(c.r, c.g, c.b) + s + reset();
|
|
950
986
|
}
|
|
951
|
-
const { preserveAnsi = false } = opts;
|
|
987
|
+
const { preserveAnsi = false, easing, phase = 0 } = opts;
|
|
988
|
+
const easingFn = resolveEasing(easing);
|
|
989
|
+
const phaseN = Number.isFinite(phase) ? (phase % 1 + 1) % 1 : 0;
|
|
952
990
|
if (!preserveAnsi || !s.includes("\x1B")) {
|
|
953
|
-
return _gradientPlain(s, colors);
|
|
991
|
+
return _gradientPlain(s, colors, easingFn, phaseN);
|
|
954
992
|
}
|
|
955
|
-
return _gradientAnsiAware(s, colors);
|
|
993
|
+
return _gradientAnsiAware(s, colors, easingFn, phaseN);
|
|
956
994
|
};
|
|
957
|
-
var _gradientPlain = (text, colors) => {
|
|
995
|
+
var _gradientPlain = (text, colors, easingFn, phase) => {
|
|
958
996
|
const chars = [...text];
|
|
959
997
|
const visible = chars.filter((c) => c !== " ").length;
|
|
960
998
|
if (visible === 0) return text;
|
|
@@ -967,7 +1005,10 @@ var _gradientPlain = (text, colors) => {
|
|
|
967
1005
|
out += ch;
|
|
968
1006
|
continue;
|
|
969
1007
|
}
|
|
970
|
-
|
|
1008
|
+
let t = visible === 1 ? 0 : colorIdx / visibleMinus;
|
|
1009
|
+
t = (t + phase) % 1;
|
|
1010
|
+
t = easingFn(t);
|
|
1011
|
+
t = Math.min(1, Math.max(0, t));
|
|
971
1012
|
const scaled = t * (colorCount - 1);
|
|
972
1013
|
const lo = Math.floor(scaled);
|
|
973
1014
|
const hi = Math.min(lo + 1, colorCount - 1);
|
|
@@ -978,7 +1019,7 @@ var _gradientPlain = (text, colors) => {
|
|
|
978
1019
|
return out;
|
|
979
1020
|
};
|
|
980
1021
|
var ANSI_TOKEN = /\x1b\[[0-9;?]*[a-zA-Z]/y;
|
|
981
|
-
var _gradientAnsiAware = (text, colors) => {
|
|
1022
|
+
var _gradientAnsiAware = (text, colors, easingFn, phase) => {
|
|
982
1023
|
const visible = stripAnsi3(text).split("").filter((c) => c !== " ").length;
|
|
983
1024
|
if (visible === 0) return text;
|
|
984
1025
|
let out = "";
|
|
@@ -1004,7 +1045,10 @@ var _gradientAnsiAware = (text, colors) => {
|
|
|
1004
1045
|
if (ch === " ") {
|
|
1005
1046
|
out += ch;
|
|
1006
1047
|
} else {
|
|
1007
|
-
|
|
1048
|
+
let t = visible === 1 ? 0 : colorIdx / visibleMinus;
|
|
1049
|
+
t = (t + phase) % 1;
|
|
1050
|
+
t = easingFn(t);
|
|
1051
|
+
t = Math.min(1, Math.max(0, t));
|
|
1008
1052
|
const scaled = t * (colorCount - 1);
|
|
1009
1053
|
const lo = Math.floor(scaled);
|
|
1010
1054
|
const hi = Math.min(lo + 1, colorCount - 1);
|
|
@@ -1018,6 +1062,76 @@ var _gradientAnsiAware = (text, colors) => {
|
|
|
1018
1062
|
};
|
|
1019
1063
|
var RAINBOW = ["#ff0000", "#ff7f00", "#ffff00", "#00ff00", "#0000ff", "#8b00ff"];
|
|
1020
1064
|
var rainbow = (text) => gradient(text, RAINBOW);
|
|
1065
|
+
var animateGradient = (text, stops, opts = {}) => {
|
|
1066
|
+
const {
|
|
1067
|
+
duration = 2e3,
|
|
1068
|
+
fps = 30,
|
|
1069
|
+
infinite = true,
|
|
1070
|
+
cycles = 1,
|
|
1071
|
+
direction = "forward",
|
|
1072
|
+
easing,
|
|
1073
|
+
preserveAnsi = false,
|
|
1074
|
+
signal,
|
|
1075
|
+
onFrame
|
|
1076
|
+
} = opts;
|
|
1077
|
+
const safeFps = Math.min(60, Math.max(1, Number.isFinite(fps) ? fps : 30));
|
|
1078
|
+
const safeDuration2 = Math.max(100, Number.isFinite(duration) ? duration : 2e3);
|
|
1079
|
+
const safeCycles = Math.max(1, Number.isFinite(cycles) ? cycles : 1);
|
|
1080
|
+
const frameInterval2 = 1e3 / safeFps;
|
|
1081
|
+
let stopped = false;
|
|
1082
|
+
let timer = null;
|
|
1083
|
+
let resolveDone = (
|
|
1084
|
+
/* istanbul ignore next */
|
|
1085
|
+
() => {
|
|
1086
|
+
}
|
|
1087
|
+
);
|
|
1088
|
+
const done = new Promise((res) => {
|
|
1089
|
+
resolveDone = res;
|
|
1090
|
+
});
|
|
1091
|
+
const stop = () => {
|
|
1092
|
+
if (stopped) return;
|
|
1093
|
+
stopped = true;
|
|
1094
|
+
if (timer != null) {
|
|
1095
|
+
clearInterval(timer);
|
|
1096
|
+
timer = null;
|
|
1097
|
+
}
|
|
1098
|
+
resolveDone();
|
|
1099
|
+
};
|
|
1100
|
+
if (signal) {
|
|
1101
|
+
if (signal.aborted) {
|
|
1102
|
+
stop();
|
|
1103
|
+
return { stop, done };
|
|
1104
|
+
}
|
|
1105
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
1106
|
+
}
|
|
1107
|
+
const startTime = Date.now();
|
|
1108
|
+
const renderFrame = () => {
|
|
1109
|
+
if (stopped) return;
|
|
1110
|
+
const elapsed = Date.now() - startTime;
|
|
1111
|
+
let phase = elapsed / safeDuration2 % 1;
|
|
1112
|
+
if (direction === "reverse") phase = 1 - phase;
|
|
1113
|
+
const frame = gradient(text, stops, { preserveAnsi, easing, phase });
|
|
1114
|
+
if (onFrame) {
|
|
1115
|
+
onFrame(frame, phase);
|
|
1116
|
+
} else {
|
|
1117
|
+
try {
|
|
1118
|
+
process.stdout.write("\r" + frame);
|
|
1119
|
+
} catch {
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (!infinite) {
|
|
1123
|
+
const completedCycles = Math.floor(elapsed / safeDuration2);
|
|
1124
|
+
if (completedCycles >= safeCycles) {
|
|
1125
|
+
stop();
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
renderFrame();
|
|
1130
|
+
if (!stopped) {
|
|
1131
|
+
timer = setInterval(renderFrame, frameInterval2);
|
|
1132
|
+
}
|
|
1133
|
+
return { stop, done };
|
|
1134
|
+
};
|
|
1021
1135
|
var PRESET_DEFS = {
|
|
1022
1136
|
sunset: ["#ff6b6b", "#feca57", "#48dbfb"],
|
|
1023
1137
|
ocean: ["#0575e6", "#021b79"],
|
|
@@ -3941,12 +4055,12 @@ var validateTheme = (t) => {
|
|
|
3941
4055
|
}
|
|
3942
4056
|
const obj = t;
|
|
3943
4057
|
if (typeof obj.name !== "string" || obj.name.length === 0) {
|
|
3944
|
-
throw new
|
|
4058
|
+
throw new TypeError('Theme must have a non-empty "name" string.');
|
|
3945
4059
|
}
|
|
3946
4060
|
for (const key of REQUIRED_COLOR_KEYS) {
|
|
3947
4061
|
const value = obj[key];
|
|
3948
4062
|
if (typeof value !== "string" || !HEX_RE4.test(value)) {
|
|
3949
|
-
throw new
|
|
4063
|
+
throw new TypeError(
|
|
3950
4064
|
`Invalid hex in theme "${obj.name}" \u2192 ${key}: ${JSON.stringify(value)}. Expected #RGB or #RRGGBB.`
|
|
3951
4065
|
);
|
|
3952
4066
|
}
|
|
@@ -3955,20 +4069,20 @@ var validateTheme = (t) => {
|
|
|
3955
4069
|
const value = obj[key];
|
|
3956
4070
|
if (value === void 0) continue;
|
|
3957
4071
|
if (typeof value !== "string" || !HEX_RE4.test(value)) {
|
|
3958
|
-
throw new
|
|
4072
|
+
throw new TypeError(
|
|
3959
4073
|
`Invalid hex in theme "${obj.name}" \u2192 ${key}: ${JSON.stringify(value)}.`
|
|
3960
4074
|
);
|
|
3961
4075
|
}
|
|
3962
4076
|
}
|
|
3963
4077
|
if (!Array.isArray(obj.gradient) || obj.gradient.length < 2) {
|
|
3964
|
-
throw new
|
|
4078
|
+
throw new TypeError(
|
|
3965
4079
|
`Theme "${obj.name}" must define a "gradient" array with at least 2 colors.`
|
|
3966
4080
|
);
|
|
3967
4081
|
}
|
|
3968
4082
|
for (let i = 0; i < obj.gradient.length; i++) {
|
|
3969
4083
|
const stop = obj.gradient[i];
|
|
3970
4084
|
if (typeof stop !== "string" || !HEX_RE4.test(stop)) {
|
|
3971
|
-
throw new
|
|
4085
|
+
throw new TypeError(
|
|
3972
4086
|
`Invalid hex in theme "${obj.name}" \u2192 gradient[${i}]: ${JSON.stringify(stop)}.`
|
|
3973
4087
|
);
|
|
3974
4088
|
}
|
|
@@ -4280,8 +4394,8 @@ var themes = {
|
|
|
4280
4394
|
use(name) {
|
|
4281
4395
|
const t = _globalRegistry.get(name);
|
|
4282
4396
|
if (!t) {
|
|
4283
|
-
throw new
|
|
4284
|
-
`Theme "${name}" not found. Available: ${[..._globalRegistry.keys()].join(", ")}`
|
|
4397
|
+
throw new RangeError(
|
|
4398
|
+
`Theme "${name}" not found. Available themes: ${[..._globalRegistry.keys()].join(", ")}`
|
|
4285
4399
|
);
|
|
4286
4400
|
}
|
|
4287
4401
|
const old = _globalActive;
|
|
@@ -4656,6 +4770,7 @@ var gradientRect = (opts = {}) => {
|
|
|
4656
4770
|
colors = ["#ff0000", "#0000ff"],
|
|
4657
4771
|
style = "horizontal",
|
|
4658
4772
|
angle,
|
|
4773
|
+
startAngle = 0,
|
|
4659
4774
|
dither = "none",
|
|
4660
4775
|
braille = false
|
|
4661
4776
|
} = opts;
|
|
@@ -4694,7 +4809,15 @@ var gradientRect = (opts = {}) => {
|
|
|
4694
4809
|
} else if (style === "horizontal") t = col / (safeW - 1);
|
|
4695
4810
|
else if (style === "vertical") t = row / (safeH - 1);
|
|
4696
4811
|
else if (style === "diagonal") t = (col + row) / (safeW + safeH - 2);
|
|
4697
|
-
else {
|
|
4812
|
+
else if (style === "conic") {
|
|
4813
|
+
const cx = safeW / 2, cy = safeH / 2;
|
|
4814
|
+
const dx = col - cx;
|
|
4815
|
+
const dy = row - cy;
|
|
4816
|
+
const startRad = (Number.isFinite(startAngle) ? startAngle : 0) * Math.PI / 180;
|
|
4817
|
+
let angleRad = Math.atan2(dy, dx) - startRad;
|
|
4818
|
+
angleRad = (angleRad % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI);
|
|
4819
|
+
t = angleRad / (2 * Math.PI);
|
|
4820
|
+
} else {
|
|
4698
4821
|
const cx = safeW / 2, cy = safeH / 2;
|
|
4699
4822
|
const dx = (col - cx) / cx;
|
|
4700
4823
|
const dy = (row - cy) / cy;
|
|
@@ -5145,6 +5268,7 @@ export {
|
|
|
5145
5268
|
ST,
|
|
5146
5269
|
STYLE,
|
|
5147
5270
|
animate,
|
|
5271
|
+
animateGradient,
|
|
5148
5272
|
ascii,
|
|
5149
5273
|
bell,
|
|
5150
5274
|
bg256,
|
package/examples/all-in-one.cjs
CHANGED
|
@@ -118,7 +118,7 @@ async function main() {
|
|
|
118
118
|
console.log(components.section('🏷️ Badges & Status', { width: 60 }));
|
|
119
119
|
console.log();
|
|
120
120
|
console.log(' ',
|
|
121
|
-
components.badge('VERSION', 'v1.
|
|
121
|
+
components.badge('VERSION', 'v1.2.0'),
|
|
122
122
|
components.badge('BUILD', 'passing'),
|
|
123
123
|
components.badge('LICENSE', 'Apache 2.0'));
|
|
124
124
|
console.log();
|
package/examples/all-in-one.mjs
CHANGED
|
@@ -117,7 +117,7 @@ console.log();
|
|
|
117
117
|
console.log(components.section('🏷️ Badges & Status', { width: 60 }));
|
|
118
118
|
console.log();
|
|
119
119
|
console.log(' ',
|
|
120
|
-
components.badge('VERSION', 'v1.
|
|
120
|
+
components.badge('VERSION', 'v1.2.0'),
|
|
121
121
|
components.badge('BUILD', 'passing'),
|
|
122
122
|
components.badge('LICENSE', 'Apache 2.0'));
|
|
123
123
|
console.log();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ansimax",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Zero-dependency CLI rendering library: colors, gradients, animations, ASCII art, pixel art, components, and themes \u2014 all in TypeScript.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|