@reliverse/relico 1.4.1 → 2.2.7

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/README.md CHANGED
@@ -1,12 +1,8 @@
1
1
  # Reliverse Relico
2
2
 
3
- > @reliverse/dler-colors is a themeable, chainable, typed, truecolor-powered terminal styling toolkit — built for humans, not just terminals. It makes your CLI output beautiful, accessible, and expressive — with developer-first ergonomics, smart config, and blazing-fast performance.
3
+ > @reliverse/relico is a themeable, chainable, typed, truecolor-powered terminal styling toolkit — built for humans, not just terminals. It makes your CLI output beautiful, accessible, and expressive — with developer-first ergonomics, smart config, and blazing-fast performance.
4
4
 
5
- [sponsor](https://github.com/sponsors/blefnk) — [discord](https://discord.gg/Pb8uKbwpsJ) — [repo](https://github.com/reliverse/relico) — [npm](https://npmjs.com/@reliverse/dler-colors)
6
-
7
- ---
8
-
9
- ‼️Attention! The latest implementation of `@reliverse/relico` now lives in the framework repository for building libraries — `@reliverse/dler`. Please use [@reliverse/dler-colors](https://github.com/reliverse/dler/tree/main/packages/colors) instead of `@reliverse/relico`.
5
+ [sponsor](https://github.com/sponsors/blefnk) — [discord](https://discord.gg/Pb8uKbwpsJ) — [repo](https://github.com/reliverse/relico) — [npm](https://npmjs.com/@reliverse/relico)
10
6
 
11
7
  ## Why Relico?
12
8
 
@@ -28,7 +24,7 @@ Because terminal styling shouldn't feel like duct tape. **Relico** brings design
28
24
  ## Installation
29
25
 
30
26
  ```bash
31
- bun add @reliverse/dler-colors
27
+ bun add @reliverse/relico
32
28
  # bun • pnpm • yarn • npm
33
29
  ```
34
30
 
@@ -95,7 +91,7 @@ The readme will be updated soon.
95
91
  **If you're end-user OR developer, create `relico.config.ts` in your root**:
96
92
 
97
93
  ```ts
98
- import { defineConfig } from "@reliverse/dler-colors";
94
+ import { defineConfig } from "@reliverse/relico";
99
95
 
100
96
  export default defineConfig({
101
97
  colorLevel: 3, // 0 = off, 1 = basic, 2 = 256, 3 = truecolor
@@ -112,7 +108,7 @@ export default defineConfig({
112
108
  **If you're developer, initialize in your app (optional)**:
113
109
 
114
110
  ```ts
115
- import { initUserConfig, re } from "@reliverse/dler-colors";
111
+ import { initUserConfig, re } from "@reliverse/relico";
116
112
 
117
113
  // Use this to override Relico's
118
114
  // default settings for your app
@@ -124,7 +120,7 @@ console.log(re.info("Custom config loaded!"));
124
120
  ## API Sneak Peek
125
121
 
126
122
  ```ts
127
- import { re, rgb } from "@reliverse/dler-colors";
123
+ import { re, rgb } from "@reliverse/relico";
128
124
 
129
125
  console.log(re.red("Red!"));
130
126
  console.log(re.bold(re.green("Bold green")));
@@ -175,7 +171,7 @@ console.log(boldRed("This text is bold and red"));
175
171
  ### Want to Get Only Certain Colors?
176
172
 
177
173
  ```ts
178
- import type { DefaultColorKeys } from "@reliverse/dler-colors";
174
+ import type { DefaultColorKeys } from "@reliverse/relico";
179
175
  const brandColors: DefaultColorKeys[] = ["magentaBright", "maroon"];
180
176
  ```
181
177
 
@@ -184,7 +180,7 @@ const brandColors: DefaultColorKeys[] = ["magentaBright", "maroon"];
184
180
  Relico detects your terminal's capability:
185
181
 
186
182
  ```ts
187
- import { colorSupport } from "@reliverse/dler-colors";
183
+ import { colorSupport } from "@reliverse/relico";
188
184
 
189
185
  console.log(colorSupport.terminalName); // iTerm2, Windows Terminal, etc.
190
186
  console.log(colorSupport.level); // 0, 1, 2, or 3
@@ -200,7 +196,7 @@ console.log(colorSupport.level); // 0, 1, 2, or 3
200
196
  ### Custom RGB + Hex
201
197
 
202
198
  ```ts
203
- import { rgb, bgHex, hex } from "@reliverse/dler-colors";
199
+ import { rgb, bgHex, hex } from "@reliverse/relico";
204
200
 
205
201
  console.log(rgb(255, 105, 180)("Hot pink"));
206
202
  console.log(bgHex("#1e90ff")("Dodger blue background"));
@@ -209,7 +205,7 @@ console.log(bgHex("#1e90ff")("Dodger blue background"));
209
205
  ### Gradients & Rainbow
210
206
 
211
207
  ```ts
212
- import { gradient, multiGradient, rainbow } from "@reliverse/dler-colors";
208
+ import { gradient, multiGradient, rainbow } from "@reliverse/relico";
213
209
 
214
210
  console.log(rainbow("🎉 Woohoo!"));
215
211
  console.log(gradient("From red to blue", "#ff0000", "#0000ff"));
@@ -222,7 +218,7 @@ This function allows you to combine multiple color formatters into a single form
222
218
  ## Basic Usage
223
219
 
224
220
  ```typescript
225
- import { re, chain } from "@reliverse/dler-colors";
221
+ import { re, chain } from "@reliverse/relico";
226
222
 
227
223
  // Create a custom style that combines bold and red text
228
224
  const boldRed = chain(re.bold, re.red);
@@ -240,7 +236,7 @@ console.log(importantError("CRITICAL ERROR: System failure"));
240
236
  ## Creating Theme Combinations
241
237
 
242
238
  ```typescript
243
- import { re, chain } from "@reliverse/dler-colors";
239
+ import { re, chain } from "@reliverse/relico";
244
240
 
245
241
  // Create themed message styles
246
242
  const successStyle = chain(re.bold, re.green);
@@ -258,7 +254,7 @@ console.log(warnStyle("⚠ API rate limit approaching"));
258
254
  ## Custom RGB Combinations
259
255
 
260
256
  ```typescript
261
- import { re, rgb, bgRgb, chain } from "@reliverse/dler-colors";
257
+ import { re, rgb, bgRgb, chain } from "@reliverse/relico";
262
258
 
263
259
  // Create a custom color scheme with RGB values
264
260
  const customHeader = chain(
@@ -282,7 +278,7 @@ console.log(danger("Danger: High voltage detected!"));
282
278
  The `chain()` function automatically handles multiline text to prevent style leakage:
283
279
 
284
280
  ```typescript
285
- import { re, chain } from "@reliverse/dler-colors";
281
+ import { re, chain } from "@reliverse/relico";
286
282
 
287
283
  const highlight = chain(re.bgYellow, re.black, re.bold);
288
284
 
@@ -297,7 +293,7 @@ console.log(highlight(multilineText));
297
293
  ## Creating a Simple Logger
298
294
 
299
295
  ```typescript
300
- import { re, chain } from "@reliverse/dler-colors";
296
+ import { re, chain } from "@reliverse/relico";
301
297
 
302
298
  // Create logger styles
303
299
  const styles = {
@@ -320,7 +316,7 @@ const logger = {
320
316
  // Usage
321
317
  logger.info("Application started");
322
318
  logger.success("Data loaded successfully");
323
- logger.warning("Cache expired, refreshing data");
319
+ logger.warn("Cache expired, refreshing data");
324
320
  logger.error("Failed to connect to database");
325
321
  logger.debug("Request payload: " + JSON.stringify({id: 123}));
326
322
  ```
package/dist/mod.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ type ColorLevel = 0 | 1 | 2 | 3;
2
+ interface Rgb {
3
+ r: number;
4
+ g: number;
5
+ b: number;
6
+ }
7
+ type SgrOp = {
8
+ kind: "style";
9
+ open: number[];
10
+ } | {
11
+ kind: "fg-basic";
12
+ idx: number;
13
+ bright: boolean;
14
+ } | {
15
+ kind: "bg-basic";
16
+ idx: number;
17
+ bright: boolean;
18
+ } | {
19
+ kind: "fg-256";
20
+ code: number;
21
+ } | {
22
+ kind: "bg-256";
23
+ code: number;
24
+ } | {
25
+ kind: "fg-true";
26
+ rgb: Rgb;
27
+ } | {
28
+ kind: "bg-true";
29
+ rgb: Rgb;
30
+ };
31
+ type ApplyInput = string | number;
32
+ type FormatCallable = ((input: ApplyInput) => string) & {
33
+ readonly [OP_SYMBOL]: SgrOp[];
34
+ };
35
+ export type BaseColorName = "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray" | "orange" | "pink" | "purple" | "teal" | "lime" | "brown" | "navy" | "maroon" | "olive" | "silver";
36
+ export type ColorName = BaseColorName | BrightColorName | BgColorName;
37
+ export type BrightColorName = "blackBright" | "redBright" | "greenBright" | "yellowBright" | "blueBright" | "magentaBright" | "cyanBright" | "whiteBright" | "orangeBright" | "pinkBright" | "purpleBright" | "tealBright" | "limeBright" | "brownBright" | "navyBright" | "maroonBright" | "oliveBright" | "silverBright";
38
+ export type BgColorName = `bg${Capitalize<BaseColorName>}` | `bg${Capitalize<BrightColorName>}`;
39
+ export type ReStyleKey = "reset" | "bold" | "dim" | "italic" | "underline" | "inverse" | "hidden" | "strikethrough";
40
+ export type Re = FormatCallable & {
41
+ readonly [K in ReStyleKey]: Re;
42
+ } & {
43
+ readonly [K in ColorName]: Re;
44
+ } & {
45
+ readonly [K in BgColorName]: Re;
46
+ };
47
+ declare const OP_SYMBOL: unique symbol;
48
+ export declare const setColorLevel: (level: ColorLevel) => void;
49
+ export declare const re: Re;
50
+ export declare const chain: (...parts: FormatCallable[]) => Re;
51
+ type BunColorInput = {
52
+ r: number;
53
+ g: number;
54
+ b: number;
55
+ a?: number;
56
+ } | [number, number, number] | [number, number, number, number] | string | number | {
57
+ toString(): string;
58
+ };
59
+ export declare const color: (input: BunColorInput, isBg?: boolean) => Re;
60
+ export {};
package/dist/mod.js ADDED
@@ -0,0 +1,455 @@
1
+ const RESET = "\x1B[0m";
2
+ const OP_SYMBOL = /* @__PURE__ */ Symbol("re.ops");
3
+ const COLOR_LEVEL_OFF = 0;
4
+ const COLOR_LEVEL_BASIC = 1;
5
+ const COLOR_LEVEL_256 = 2;
6
+ const COLOR_LEVEL_TRUECOLOR = 3;
7
+ const MIN_BYTE = 0;
8
+ const MAX_BYTE = 255;
9
+ const WHITE_RGB = 255;
10
+ const ANSI_256_GRAYSCALE_MIN = 8;
11
+ const ANSI_256_GRAYSCALE_MAX = 248;
12
+ const ANSI_256_BASE_OFFSET = 16;
13
+ const ANSI_256_GRAYSCALE_BASE = 232;
14
+ const ANSI_256_GRAYSCALE_RANGE = 247;
15
+ const ANSI_256_GRAYSCALE_STEPS = 24;
16
+ const ANSI_256_BRIGHT_THRESHOLD = 231;
17
+ const ANSI_256_RGB_LEVELS = 5;
18
+ const ANSI_256_RGB_RED_MULTIPLIER = 36;
19
+ const ANSI_256_RGB_GREEN_MULTIPLIER = 6;
20
+ const SGR_FG_BASE = 30;
21
+ const SGR_BG_BASE = 40;
22
+ const SGR_FG_BRIGHT_BASE = 90;
23
+ const SGR_BG_BRIGHT_BASE = 100;
24
+ const SGR_RESET = 0;
25
+ const SGR_BOLD = 1;
26
+ const SGR_DIM = 2;
27
+ const SGR_ITALIC = 3;
28
+ const SGR_UNDERLINE = 4;
29
+ const SGR_INVERSE = 7;
30
+ const SGR_HIDDEN = 8;
31
+ const SGR_STRIKETHROUGH = 9;
32
+ const HEX_RADIX = 16;
33
+ const BRIGHT_SUFFIX_LENGTH = 6;
34
+ const BG_PREFIX_LENGTH = 2;
35
+ const BRIGHT_MIX_FACTOR = 0.25;
36
+ const BRIGHT_SUFFIX = "Bright";
37
+ const IS_BUN = typeof process !== "undefined" && process.versions?.bun !== void 0 && typeof Bun !== "undefined" && typeof Bun.color === "function";
38
+ let CURRENT_LEVEL = COLOR_LEVEL_TRUECOLOR;
39
+ export const setColorLevel = (level) => {
40
+ if (level !== COLOR_LEVEL_OFF && level !== COLOR_LEVEL_BASIC && level !== COLOR_LEVEL_256 && level !== COLOR_LEVEL_TRUECOLOR) {
41
+ throw new Error("Invalid color level");
42
+ }
43
+ CURRENT_LEVEL = level;
44
+ };
45
+ const clampByte = (n) => {
46
+ if (n <= MIN_BYTE || !Number.isFinite(n)) return MIN_BYTE;
47
+ if (n >= MAX_BYTE) return MAX_BYTE;
48
+ return Math.round(n);
49
+ };
50
+ const BASIC8 = Object.freeze([
51
+ Object.freeze({ r: 0, g: 0, b: 0 }),
52
+ Object.freeze({ r: 205, g: 0, b: 0 }),
53
+ Object.freeze({ r: 0, g: 205, b: 0 }),
54
+ Object.freeze({ r: 205, g: 205, b: 0 }),
55
+ Object.freeze({ r: 0, g: 0, b: 238 }),
56
+ Object.freeze({ r: 205, g: 0, b: 205 }),
57
+ Object.freeze({ r: 0, g: 205, b: 205 }),
58
+ Object.freeze({ r: 229, g: 229, b: 229 })
59
+ ]);
60
+ const sgrCache = /* @__PURE__ */ new Map();
61
+ const sgr = (codes) => {
62
+ if (codes.length === 1) {
63
+ const code = codes[0];
64
+ const cached2 = sgrCache.get(String(code));
65
+ if (cached2) return cached2;
66
+ const seq2 = `\x1B[${code}m`;
67
+ sgrCache.set(String(code), seq2);
68
+ return seq2;
69
+ }
70
+ const key = codes.join(";");
71
+ const cached = sgrCache.get(key);
72
+ if (cached) return cached;
73
+ const seq = `\x1B[${key}m`;
74
+ sgrCache.set(key, seq);
75
+ return seq;
76
+ };
77
+ const nearestBasicIndex = (rgb) => {
78
+ if (IS_BUN) {
79
+ const ansiStr = Bun.color(rgb, "ansi-16");
80
+ if (ansiStr) {
81
+ const match = ansiStr.match(/38;5;(\d+)/);
82
+ if (match?.[1]) {
83
+ return Number.parseInt(match[1], 10) & 7;
84
+ }
85
+ }
86
+ }
87
+ let best = 0;
88
+ let bestDist = Number.POSITIVE_INFINITY;
89
+ for (let i = 0; i < 8; i++) {
90
+ const c = BASIC8[i];
91
+ const dr = c.r - rgb.r;
92
+ const dg = c.g - rgb.g;
93
+ const db = c.b - rgb.b;
94
+ if (dr === 0 && dg === 0 && db === 0) return i;
95
+ const d = dr * dr + dg * dg + db * db;
96
+ if (d < bestDist) {
97
+ bestDist = d;
98
+ best = i;
99
+ }
100
+ }
101
+ return best;
102
+ };
103
+ const rgbToAnsi256 = (rgb) => {
104
+ if (IS_BUN) {
105
+ const ansiStr = Bun.color(rgb, "ansi-256");
106
+ if (ansiStr) {
107
+ const match = ansiStr.match(/38;5;(\d+)/);
108
+ if (match?.[1]) {
109
+ return Number.parseInt(match[1], 10);
110
+ }
111
+ }
112
+ }
113
+ if (rgb.r === rgb.g && rgb.g === rgb.b) {
114
+ if (rgb.r < ANSI_256_GRAYSCALE_MIN) return ANSI_256_BASE_OFFSET;
115
+ if (rgb.r > ANSI_256_GRAYSCALE_MAX) return ANSI_256_BRIGHT_THRESHOLD;
116
+ const step = Math.round(
117
+ (rgb.r - ANSI_256_GRAYSCALE_MIN) / ANSI_256_GRAYSCALE_RANGE * ANSI_256_GRAYSCALE_STEPS
118
+ );
119
+ return ANSI_256_GRAYSCALE_BASE + step;
120
+ }
121
+ const r = (rgb.r * ANSI_256_RGB_LEVELS + 127) / MAX_BYTE | 0;
122
+ const g = (rgb.g * ANSI_256_RGB_LEVELS + 127) / MAX_BYTE | 0;
123
+ const b = (rgb.b * ANSI_256_RGB_LEVELS + 127) / MAX_BYTE | 0;
124
+ return ANSI_256_BASE_OFFSET + r * ANSI_256_RGB_RED_MULTIPLIER + g * ANSI_256_RGB_GREEN_MULTIPLIER + b;
125
+ };
126
+ const NAMED_COLORS = {
127
+ black: "#000000",
128
+ red: "#ff0000",
129
+ green: "#00ff00",
130
+ yellow: "#ffff00",
131
+ blue: "#0000ff",
132
+ magenta: "#ff00ff",
133
+ cyan: "#00ffff",
134
+ white: "#ffffff",
135
+ gray: "#808080",
136
+ orange: "#ffa500",
137
+ pink: "#ffc0cb",
138
+ purple: "#800080",
139
+ teal: "#008080",
140
+ lime: "#00ff00",
141
+ brown: "#a52a2a",
142
+ navy: "#000080",
143
+ maroon: "#800000",
144
+ olive: "#808000",
145
+ silver: "#c0c0c0"
146
+ };
147
+ const rgbCache = /* @__PURE__ */ new Map();
148
+ for (const name of ["black", "white", "red", "green", "blue"]) {
149
+ const hex = NAMED_COLORS[name];
150
+ if (hex) {
151
+ const clean = hex.slice(1);
152
+ const r = Number.parseInt(clean.slice(0, 2), HEX_RADIX);
153
+ const g = Number.parseInt(clean.slice(2, 4), HEX_RADIX);
154
+ const b = Number.parseInt(clean.slice(4, 6), HEX_RADIX);
155
+ rgbCache.set(name, Object.freeze({ r, g, b }));
156
+ }
157
+ }
158
+ const mixWithWhite = (rgb, factor) => {
159
+ const invFactor = 1 - factor;
160
+ return {
161
+ r: clampByte(rgb.r * invFactor + WHITE_RGB * factor),
162
+ g: clampByte(rgb.g * invFactor + WHITE_RGB * factor),
163
+ b: clampByte(rgb.b * invFactor + WHITE_RGB * factor)
164
+ };
165
+ };
166
+ const fromNamed = (name) => {
167
+ const cached = rgbCache.get(name);
168
+ if (cached) return cached;
169
+ const hex = NAMED_COLORS[name];
170
+ if (!hex) return { r: 0, g: 0, b: 0 };
171
+ if (IS_BUN) {
172
+ const rgb = Bun.color(hex, "{rgb}");
173
+ if (rgb) {
174
+ rgbCache.set(name, rgb);
175
+ return rgb;
176
+ }
177
+ }
178
+ const clean = hex[0] === "#" ? hex.slice(1) : hex;
179
+ const len = clean.length;
180
+ let r, g, b;
181
+ if (len === 3) {
182
+ const rv = Number.parseInt(clean[0], HEX_RADIX);
183
+ const gv = Number.parseInt(clean[1], HEX_RADIX);
184
+ const bv = Number.parseInt(clean[2], HEX_RADIX);
185
+ r = rv << 4 | rv;
186
+ g = gv << 4 | gv;
187
+ b = bv << 4 | bv;
188
+ } else if (len === 6) {
189
+ r = Number.parseInt(clean.slice(0, 2), HEX_RADIX);
190
+ g = Number.parseInt(clean.slice(2, 4), HEX_RADIX);
191
+ b = Number.parseInt(clean.slice(4, 6), HEX_RADIX);
192
+ } else {
193
+ return { r: 0, g: 0, b: 0 };
194
+ }
195
+ if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {
196
+ return { r: 0, g: 0, b: 0 };
197
+ }
198
+ const result = Object.freeze({ r, g, b });
199
+ rgbCache.set(name, result);
200
+ return result;
201
+ };
202
+ const toBaseName = (compound) => {
203
+ if (!compound) return "black";
204
+ const base = compound.slice(0, -BRIGHT_SUFFIX_LENGTH);
205
+ if (!base) return "black";
206
+ return base[0]?.toLowerCase() + base.slice(1);
207
+ };
208
+ const parseColorName = (name) => {
209
+ if (!name) return { rgb: { r: 0, g: 0, b: 0 }, wantBright: false };
210
+ if (name.endsWith(BRIGHT_SUFFIX)) {
211
+ const base = toBaseName(name);
212
+ const rgb = fromNamed(base);
213
+ const rgbAdj = mixWithWhite(rgb, BRIGHT_MIX_FACTOR);
214
+ return { rgb: rgbAdj, wantBright: true };
215
+ }
216
+ return { rgb: fromNamed(name), wantBright: false };
217
+ };
218
+ const openForOp = (op) => {
219
+ if (CURRENT_LEVEL === COLOR_LEVEL_OFF) return "";
220
+ switch (op.kind) {
221
+ case "style":
222
+ return sgr(op.open);
223
+ case "fg-basic": {
224
+ const code = (op.bright ? SGR_FG_BRIGHT_BASE : SGR_FG_BASE) + op.idx;
225
+ return sgr([code]);
226
+ }
227
+ case "bg-basic": {
228
+ const code = (op.bright ? SGR_BG_BRIGHT_BASE : SGR_BG_BASE) + op.idx;
229
+ return sgr([code]);
230
+ }
231
+ case "fg-256": {
232
+ if (IS_BUN) {
233
+ const ansi = Bun.color(op.code, "ansi-256");
234
+ if (ansi) return ansi;
235
+ }
236
+ return `\x1B[38;5;${op.code}m`;
237
+ }
238
+ case "bg-256": {
239
+ if (IS_BUN) {
240
+ const fgAnsi = Bun.color(op.code, "ansi-256");
241
+ if (fgAnsi) return fgAnsi.replace("38;5;", "48;5;");
242
+ }
243
+ return `\x1B[48;5;${op.code}m`;
244
+ }
245
+ case "fg-true": {
246
+ if (IS_BUN) {
247
+ const ansi = Bun.color(op.rgb, "ansi-16m");
248
+ if (ansi) return ansi;
249
+ }
250
+ const { r, g, b } = op.rgb;
251
+ return `\x1B[38;2;${r};${g};${b}m`;
252
+ }
253
+ case "bg-true": {
254
+ if (IS_BUN) {
255
+ const fgAnsi = Bun.color(op.rgb, "ansi-16m");
256
+ if (fgAnsi) return fgAnsi.replace("38;2;", "48;2;");
257
+ }
258
+ const { r, g, b } = op.rgb;
259
+ return `\x1B[48;2;${r};${g};${b}m`;
260
+ }
261
+ default:
262
+ return "";
263
+ }
264
+ };
265
+ const opsToOpen = (ops) => {
266
+ if (CURRENT_LEVEL === COLOR_LEVEL_OFF) return "";
267
+ const len = ops.length;
268
+ if (len === 0) return "";
269
+ if (len === 1) return openForOp(ops[0]);
270
+ let result = "";
271
+ for (let i = 0; i < len; i++) {
272
+ result += openForOp(ops[i]);
273
+ }
274
+ return result;
275
+ };
276
+ const applyOpsToText = (ops, input) => {
277
+ const text = String(input);
278
+ const textLen = text.length;
279
+ if (CURRENT_LEVEL === COLOR_LEVEL_OFF || ops.length === 0 || textLen === 0) {
280
+ return text;
281
+ }
282
+ const open = opsToOpen(ops);
283
+ if (!open) return text;
284
+ const nlIdx = text.indexOf("\n");
285
+ if (nlIdx === -1) {
286
+ return `${open}${text}${RESET}`;
287
+ }
288
+ let result = "";
289
+ let start = 0;
290
+ while (start < textLen) {
291
+ const end = text.indexOf("\n", start);
292
+ if (end === -1) {
293
+ const line2 = text.slice(start);
294
+ if (line2) {
295
+ if (line2.endsWith("\r")) {
296
+ result += `${open}${line2.slice(0, -1)}\r${RESET}`;
297
+ } else {
298
+ result += `${open}${line2}${RESET}`;
299
+ }
300
+ }
301
+ break;
302
+ }
303
+ if (start > 0) result += "\n";
304
+ const line = text.slice(start, end);
305
+ if (line) {
306
+ if (line.endsWith("\r")) {
307
+ result += `${open}${line.slice(0, -1)}\r${RESET}`;
308
+ } else {
309
+ result += `${open}${line}${RESET}`;
310
+ }
311
+ } else {
312
+ result += `${open}${RESET}`;
313
+ }
314
+ start = end + 1;
315
+ }
316
+ return result;
317
+ };
318
+ const mkFgOpsFromRgb = (rgb, wantBright = false) => {
319
+ if (CURRENT_LEVEL === COLOR_LEVEL_BASIC) {
320
+ return [
321
+ { kind: "fg-basic", idx: nearestBasicIndex(rgb), bright: wantBright }
322
+ ];
323
+ }
324
+ if (CURRENT_LEVEL === COLOR_LEVEL_256) {
325
+ return [{ kind: "fg-256", code: rgbToAnsi256(rgb) }];
326
+ }
327
+ return [{ kind: "fg-true", rgb }];
328
+ };
329
+ const mkBgOpsFromRgb = (rgb, wantBright = false) => {
330
+ if (CURRENT_LEVEL === COLOR_LEVEL_BASIC) {
331
+ return [
332
+ { kind: "bg-basic", idx: nearestBasicIndex(rgb), bright: wantBright }
333
+ ];
334
+ }
335
+ if (CURRENT_LEVEL === COLOR_LEVEL_256) {
336
+ return [{ kind: "bg-256", code: rgbToAnsi256(rgb) }];
337
+ }
338
+ return [{ kind: "bg-true", rgb }];
339
+ };
340
+ const STYLE_TABLE = {
341
+ reset: Object.freeze({ kind: "style", open: [SGR_RESET] }),
342
+ bold: Object.freeze({ kind: "style", open: [SGR_BOLD] }),
343
+ dim: Object.freeze({ kind: "style", open: [SGR_DIM] }),
344
+ italic: Object.freeze({ kind: "style", open: [SGR_ITALIC] }),
345
+ underline: Object.freeze({ kind: "style", open: [SGR_UNDERLINE] }),
346
+ inverse: Object.freeze({ kind: "style", open: [SGR_INVERSE] }),
347
+ hidden: Object.freeze({ kind: "style", open: [SGR_HIDDEN] }),
348
+ strikethrough: Object.freeze({ kind: "style", open: [SGR_STRIKETHROUGH] })
349
+ };
350
+ const STYLE_KEYS = Object.freeze(
351
+ /* @__PURE__ */ new Set([
352
+ "reset",
353
+ "bold",
354
+ "dim",
355
+ "italic",
356
+ "underline",
357
+ "inverse",
358
+ "hidden",
359
+ "strikethrough"
360
+ ])
361
+ );
362
+ const COLOR_KEYS = Object.freeze(new Set(Object.keys(NAMED_COLORS)));
363
+ const BRIGHT_COLOR_KEYS = Object.freeze(
364
+ new Set(Object.keys(NAMED_COLORS).map((name) => `${name}Bright`))
365
+ );
366
+ const BG_COLOR_KEYS = Object.freeze(
367
+ new Set(
368
+ Object.keys(NAMED_COLORS).map(
369
+ (name) => `bg${name[0]?.toUpperCase()}${name.slice(1)}`
370
+ )
371
+ )
372
+ );
373
+ const BG_BRIGHT_COLOR_KEYS = Object.freeze(
374
+ new Set(
375
+ Object.keys(NAMED_COLORS).map(
376
+ (name) => `bg${name[0]?.toUpperCase()}${name.slice(1)}Bright`
377
+ )
378
+ )
379
+ );
380
+ const isColorKey = (key) => COLOR_KEYS.has(key) || BRIGHT_COLOR_KEYS.has(key);
381
+ const isBgKey = (key) => {
382
+ const len = key.length;
383
+ if (len <= BG_PREFIX_LENGTH || key[0] !== "b" || key[1] !== "g") {
384
+ return false;
385
+ }
386
+ return BG_COLOR_KEYS.has(key) || BG_BRIGHT_COLOR_KEYS.has(key);
387
+ };
388
+ const proxyCache = /* @__PURE__ */ new WeakMap();
389
+ const callableProxy = (ops) => {
390
+ const cached = proxyCache.get(ops);
391
+ if (cached) return cached;
392
+ const base = ((input) => applyOpsToText(ops, input));
393
+ Object.defineProperty(base, OP_SYMBOL, {
394
+ value: ops,
395
+ enumerable: false,
396
+ configurable: false,
397
+ writable: false
398
+ });
399
+ const proxy = new Proxy(base, {
400
+ apply(_target, _thisArg, argArray) {
401
+ return applyOpsToText(ops, argArray[0]);
402
+ },
403
+ get(_target, prop) {
404
+ if (prop === OP_SYMBOL) return ops;
405
+ const key = String(prop);
406
+ if (STYLE_KEYS.has(key)) {
407
+ const op = STYLE_TABLE[key];
408
+ const newOps = [...ops, op];
409
+ return callableProxy(newOps);
410
+ }
411
+ if (isBgKey(key)) {
412
+ const colorName = key[2]?.toLowerCase() + key.slice(3);
413
+ const { rgb, wantBright } = parseColorName(colorName);
414
+ const bgOps = mkBgOpsFromRgb(rgb, wantBright);
415
+ const newOps = [...ops, ...bgOps];
416
+ return callableProxy(newOps);
417
+ }
418
+ if (isColorKey(key)) {
419
+ const { rgb, wantBright } = parseColorName(key);
420
+ const fgOps = mkFgOpsFromRgb(rgb, wantBright);
421
+ const newOps = [...ops, ...fgOps];
422
+ return callableProxy(newOps);
423
+ }
424
+ return proxy;
425
+ }
426
+ });
427
+ proxyCache.set(ops, proxy);
428
+ return proxy;
429
+ };
430
+ export const re = callableProxy([]);
431
+ export const chain = (...parts) => {
432
+ if (parts.length === 0) return re;
433
+ if (parts.length === 1) return parts[0];
434
+ const collected = [];
435
+ for (let i = 0; i < parts.length; i++) {
436
+ const ops = parts[i][OP_SYMBOL];
437
+ if (ops?.length) {
438
+ collected.push(...ops);
439
+ }
440
+ }
441
+ return callableProxy(collected);
442
+ };
443
+ export const color = (input, isBg = false) => {
444
+ if (!IS_BUN) {
445
+ if (typeof input === "object" && "r" in input && "g" in input && "b" in input) {
446
+ const ops2 = isBg ? mkBgOpsFromRgb(input, false) : mkFgOpsFromRgb(input, false);
447
+ return callableProxy(ops2);
448
+ }
449
+ return re;
450
+ }
451
+ const rgb = Bun.color(input, "{rgb}");
452
+ if (!rgb) return re;
453
+ const ops = isBg ? mkBgOpsFromRgb(rgb, false) : mkFgOpsFromRgb(rgb, false);
454
+ return callableProxy(ops);
455
+ };
package/package.json CHANGED
@@ -1,25 +1,22 @@
1
1
  {
2
2
  "name": "@reliverse/relico",
3
- "author": "reliverse",
4
- "version": "1.4.1",
3
+ "version": "2.2.7",
4
+ "private": false,
5
5
  "type": "module",
6
6
  "description": "@reliverse/relico is a themeable, chainable, typed, truecolor-powered, modern terminal styling toolkit. Designed to make your CLI output colorful, accessible, and human-friendly. It gives you a flexible way to apply colors and styles — with reliability and a smart developer experience baked in. Built for humans, not just terminals.",
7
- "scripts": {
8
- "pub": "bun rse publish",
9
- "dev": "bun examples/core.ts",
10
- "perf": "bun bench && bun size",
11
- "latest": "bun rse update && bun install",
12
- "size": "bun examples/benchmarks/bundle-size.ts",
13
- "bench": "bun examples/benchmarks/performance.ts",
14
- "check": "bun tsc --noEmit && bun biome check --fix --unsafe"
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/mod.d.ts",
10
+ "default": "./dist/mod.js"
11
+ }
15
12
  },
16
- "devDependencies": {
17
- "@biomejs/biome": "2.2.2",
18
- "@reliverse/rse": "^1.7.27",
19
- "@total-typescript/ts-reset": "^0.6.1",
20
- "@types/bun": "^1.2.21",
21
- "@types/node": "^24.3.0",
22
- "typescript": "^5.9.2",
23
- "ultracite": "^5.2.17"
24
- }
25
- }
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "dependencies": {},
17
+ "files": [
18
+ "dist",
19
+ "package.json"
20
+ ],
21
+ "license": "MIT"
22
+ }