@crustjs/style 0.0.1 → 0.0.3

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
@@ -21,6 +21,7 @@ import { style } from "@crustjs/style";
21
21
  console.log(style.bold("Build succeeded"));
22
22
  console.log(style.red("Error: missing argument"));
23
23
  console.log(style.dim("hint: use --help for usage"));
24
+ console.log(style.bold.red("Critical failure"));
24
25
  ```
25
26
 
26
27
  ## Primitive Styling
@@ -57,6 +58,63 @@ console.log(applyStyle("critical error", boldRed));
57
58
 
58
59
  Nested styles are handled safely — no style bleed across boundaries.
59
60
 
61
+ ## Dynamic Colors (Truecolor)
62
+
63
+ Use any RGB or hex color via 24-bit truecolor ANSI sequences:
64
+
65
+ ```ts
66
+ import { rgb, bgRgb, hex, bgHex } from "@crustjs/style";
67
+
68
+ // RGB values (0–255)
69
+ console.log(rgb("ocean", 0, 128, 255));
70
+ console.log(bgRgb("warning", 255, 128, 0));
71
+
72
+ // Hex colors (#RGB or #RRGGBB)
73
+ console.log(hex("error", "#ff0000"));
74
+ console.log(hex("short", "#f00"));
75
+ console.log(bgHex("highlight", "#ff8800"));
76
+ ```
77
+
78
+ ### Pair Factories
79
+
80
+ Create reusable `AnsiPair` objects for composition:
81
+
82
+ ```ts
83
+ import { rgbCode, bgRgbCode, hexCode, bgHexCode, applyStyle, composeStyles, boldCode } from "@crustjs/style";
84
+
85
+ const coral = rgbCode(255, 127, 80);
86
+ console.log(applyStyle("coral text", coral));
87
+
88
+ const boldCoral = composeStyles(boldCode, hexCode("#ff7f50"));
89
+ console.log(applyStyle("bold coral", boldCoral));
90
+ ```
91
+
92
+ ### Style Instance
93
+
94
+ Dynamic colors on `createStyle` instances respect mode and truecolor detection:
95
+
96
+ ```ts
97
+ import { createStyle } from "@crustjs/style";
98
+
99
+ const s = createStyle({ mode: "always" });
100
+ console.log(s.rgb("text", 255, 0, 0));
101
+ console.log(s.hex("text", "#ff0000"));
102
+ console.log(s.bgRgb("text", 0, 128, 255));
103
+ console.log(s.bgHex("text", "#0080ff"));
104
+ ```
105
+
106
+ In `"auto"` mode, dynamic colors are emitted only when the terminal supports truecolor (detected via `COLORTERM=truecolor|24bit` or `TERM` containing `truecolor`, `24bit`, or `-direct`). When truecolor is not detected, dynamic color methods return plain text while standard 16-color methods continue to work.
107
+
108
+ In `"never"` mode, all dynamic color methods return plain text. In `"always"` mode, truecolor sequences are always emitted.
109
+
110
+ ### Terminal Compatibility
111
+
112
+ Dynamic colors use truecolor (24-bit) ANSI sequences. There is no automatic fallback to 256 or 16 colors. On terminals that do not support truecolor:
113
+
114
+ - Colors may be approximated to the nearest supported color
115
+ - Colors may be silently ignored (text renders in default color)
116
+ - No runtime errors will occur
117
+
60
118
  ## Color Modes
61
119
 
62
120
  Control when ANSI codes are emitted using `createStyle`:
@@ -70,6 +128,7 @@ const auto = createStyle({ mode: "auto" });
70
128
  // Always emit ANSI codes
71
129
  const color = createStyle({ mode: "always" });
72
130
  console.log(color.red("always red"));
131
+ console.log(color.bold.red("always bold red"));
73
132
 
74
133
  // Never emit ANSI codes — returns plain text
75
134
  const plain = createStyle({ mode: "never" });
@@ -90,6 +149,12 @@ const testStyle = createStyle({
90
149
  mode: "auto",
91
150
  overrides: { isTTY: true, noColor: undefined },
92
151
  });
152
+
153
+ // Include truecolor overrides for dynamic color testing
154
+ const truecolorStyle = createStyle({
155
+ mode: "auto",
156
+ overrides: { isTTY: true, noColor: undefined, colorTerm: "truecolor" },
157
+ });
93
158
  ```
94
159
 
95
160
  ## Text Utilities
package/dist/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ declare namespace codes {
2
+ export { yellow, white, underline, strikethrough, reset, red, magenta, italic, inverse, hidden, green, gray, dim, cyan, brightYellow, brightWhite, brightRed, brightMagenta, brightGreen, brightCyan, brightBlue, bold, blue, black, bgYellow, bgWhite, bgRed, bgMagenta, bgGreen, bgCyan, bgBrightYellow, bgBrightWhite, bgBrightRed, bgBrightMagenta, bgBrightGreen, bgBrightCyan, bgBrightBlue, bgBrightBlack, bgBlue, bgBlack, AnsiPair };
3
+ }
1
4
  /**
2
5
  * An ANSI style pair consisting of an opening and closing escape sequence.
3
6
  *
@@ -36,29 +39,29 @@ declare const cyan: AnsiPair;
36
39
  declare const white: AnsiPair;
37
40
  /** Bright black (gray). */
38
41
  declare const gray: AnsiPair;
39
- declare const brightRed2: AnsiPair;
40
- declare const brightGreen2: AnsiPair;
41
- declare const brightYellow2: AnsiPair;
42
- declare const brightBlue2: AnsiPair;
43
- declare const brightMagenta2: AnsiPair;
44
- declare const brightCyan2: AnsiPair;
45
- declare const brightWhite2: AnsiPair;
46
- declare const bgBlack2: AnsiPair;
47
- declare const bgRed2: AnsiPair;
48
- declare const bgGreen2: AnsiPair;
49
- declare const bgYellow2: AnsiPair;
50
- declare const bgBlue2: AnsiPair;
51
- declare const bgMagenta2: AnsiPair;
52
- declare const bgCyan2: AnsiPair;
53
- declare const bgWhite2: AnsiPair;
54
- declare const bgBrightBlack2: AnsiPair;
55
- declare const bgBrightRed2: AnsiPair;
56
- declare const bgBrightGreen2: AnsiPair;
57
- declare const bgBrightYellow2: AnsiPair;
58
- declare const bgBrightBlue2: AnsiPair;
59
- declare const bgBrightMagenta2: AnsiPair;
60
- declare const bgBrightCyan2: AnsiPair;
61
- declare const bgBrightWhite2: AnsiPair;
42
+ declare const brightRed: AnsiPair;
43
+ declare const brightGreen: AnsiPair;
44
+ declare const brightYellow: AnsiPair;
45
+ declare const brightBlue: AnsiPair;
46
+ declare const brightMagenta: AnsiPair;
47
+ declare const brightCyan: AnsiPair;
48
+ declare const brightWhite: AnsiPair;
49
+ declare const bgBlack: AnsiPair;
50
+ declare const bgRed: AnsiPair;
51
+ declare const bgGreen: AnsiPair;
52
+ declare const bgYellow: AnsiPair;
53
+ declare const bgBlue: AnsiPair;
54
+ declare const bgMagenta: AnsiPair;
55
+ declare const bgCyan: AnsiPair;
56
+ declare const bgWhite: AnsiPair;
57
+ declare const bgBrightBlack: AnsiPair;
58
+ declare const bgBrightRed: AnsiPair;
59
+ declare const bgBrightGreen: AnsiPair;
60
+ declare const bgBrightYellow: AnsiPair;
61
+ declare const bgBrightBlue: AnsiPair;
62
+ declare const bgBrightMagenta: AnsiPair;
63
+ declare const bgBrightCyan: AnsiPair;
64
+ declare const bgBrightWhite: AnsiPair;
62
65
  /**
63
66
  * Options for {@link unorderedList}.
64
67
  */
@@ -279,6 +282,8 @@ interface TableOptions {
279
282
  * ```
280
283
  */
281
284
  declare function table(headers: string[], rows: string[][], options?: TableOptions): string;
285
+ declare const styleMethodPairs: Omit<typeof codes, "reset">;
286
+ type StyleMethodName = keyof typeof styleMethodPairs;
282
287
  /**
283
288
  * Color emission mode for the style engine.
284
289
  *
@@ -307,6 +312,18 @@ interface CapabilityOverrides {
307
312
  readonly noColor?: string | undefined;
308
313
  }
309
314
  /**
315
+ * Truecolor capability overrides for deterministic testing.
316
+ *
317
+ * These override environment variable checks used by
318
+ * {@link resolveTrueColor} to detect 24-bit color support.
319
+ */
320
+ interface TrueColorOverrides {
321
+ /** Override `process.env.COLORTERM`. */
322
+ readonly colorTerm?: string | undefined;
323
+ /** Override `process.env.TERM`. */
324
+ readonly term?: string | undefined;
325
+ }
326
+ /**
310
327
  * Configuration options for creating a style instance.
311
328
  *
312
329
  * @example
@@ -318,7 +335,7 @@ interface StyleOptions {
318
335
  /** Color emission mode. Defaults to `"auto"`. */
319
336
  readonly mode?: ColorMode;
320
337
  /** Capability overrides for deterministic testing. */
321
- readonly overrides?: CapabilityOverrides;
338
+ readonly overrides?: CapabilityOverrides & TrueColorOverrides;
322
339
  }
323
340
  /**
324
341
  * A style function that applies an ANSI style pair to text,
@@ -326,56 +343,47 @@ interface StyleOptions {
326
343
  */
327
344
  type StyleFn = (text: string) => string;
328
345
  /**
346
+ * Shared style method surface used by style instances and chainable style
347
+ * functions.
348
+ */
349
+ type StyleMethodMap = { readonly [K in StyleMethodName2] : ChainableStyleFn };
350
+ /**
351
+ * A callable style function that also exposes all style methods for chaining.
352
+ *
353
+ * @example
354
+ * ```ts
355
+ * style.bold.red("error");
356
+ * ```
357
+ */
358
+ interface ChainableStyleFn extends StyleMethodMap {
359
+ (text: string): string;
360
+ }
361
+ /**
362
+ * Style method name used by the chain builder implementation.
363
+ */
364
+ type StyleMethodName2 = StyleMethodName;
365
+ /**
329
366
  * A configured style instance with mode-aware styling functions.
330
367
  *
331
368
  * In `"never"` mode, all functions return plain text without ANSI codes.
332
369
  * In `"always"` mode, ANSI codes are always emitted.
333
370
  * In `"auto"` mode, behavior depends on terminal capability detection.
334
371
  */
335
- interface StyleInstance {
372
+ interface StyleInstance extends StyleMethodMap {
336
373
  /** Whether ANSI codes will be emitted by this instance. */
337
374
  readonly enabled: boolean;
375
+ /** Whether truecolor (24-bit) sequences will be emitted by this instance. */
376
+ readonly trueColorEnabled: boolean;
338
377
  /** Apply an arbitrary ANSI pair to text, respecting the color mode. */
339
378
  readonly apply: (text: string, pair: AnsiPair) => string;
340
- readonly bold: StyleFn;
341
- readonly dim: StyleFn;
342
- readonly italic: StyleFn;
343
- readonly underline: StyleFn;
344
- readonly inverse: StyleFn;
345
- readonly hidden: StyleFn;
346
- readonly strikethrough: StyleFn;
347
- readonly black: StyleFn;
348
- readonly red: StyleFn;
349
- readonly green: StyleFn;
350
- readonly yellow: StyleFn;
351
- readonly blue: StyleFn;
352
- readonly magenta: StyleFn;
353
- readonly cyan: StyleFn;
354
- readonly white: StyleFn;
355
- readonly gray: StyleFn;
356
- readonly brightRed: StyleFn;
357
- readonly brightGreen: StyleFn;
358
- readonly brightYellow: StyleFn;
359
- readonly brightBlue: StyleFn;
360
- readonly brightMagenta: StyleFn;
361
- readonly brightCyan: StyleFn;
362
- readonly brightWhite: StyleFn;
363
- readonly bgBlack: StyleFn;
364
- readonly bgRed: StyleFn;
365
- readonly bgGreen: StyleFn;
366
- readonly bgYellow: StyleFn;
367
- readonly bgBlue: StyleFn;
368
- readonly bgMagenta: StyleFn;
369
- readonly bgCyan: StyleFn;
370
- readonly bgWhite: StyleFn;
371
- readonly bgBrightBlack: StyleFn;
372
- readonly bgBrightRed: StyleFn;
373
- readonly bgBrightGreen: StyleFn;
374
- readonly bgBrightYellow: StyleFn;
375
- readonly bgBrightBlue: StyleFn;
376
- readonly bgBrightMagenta: StyleFn;
377
- readonly bgBrightCyan: StyleFn;
378
- readonly bgBrightWhite: StyleFn;
379
+ /** Apply a truecolor foreground RGB color to text. */
380
+ readonly rgb: (text: string, r: number, g: number, b: number) => string;
381
+ /** Apply a truecolor background RGB color to text. */
382
+ readonly bgRgb: (text: string, r: number, g: number, b: number) => string;
383
+ /** Apply a truecolor foreground hex color to text. */
384
+ readonly hex: (text: string, hexColor: string) => string;
385
+ /** Apply a truecolor background hex color to text. */
386
+ readonly bgHex: (text: string, hexColor: string) => string;
379
387
  }
380
388
  /**
381
389
  * Resolve whether ANSI color codes should be emitted.
@@ -405,6 +413,35 @@ interface StyleInstance {
405
413
  * ```
406
414
  */
407
415
  declare function resolveCapability(mode: ColorMode, overrides?: CapabilityOverrides): boolean;
416
+ /**
417
+ * Resolve whether the terminal supports truecolor (24-bit) ANSI sequences.
418
+ *
419
+ * Detection heuristics (checked in order):
420
+ * 1. `COLORTERM` environment variable is `"truecolor"` or `"24bit"`.
421
+ * 2. `TERM` environment variable contains `"24bit"`, `"truecolor"`, or `"-direct"`.
422
+ *
423
+ * In `"always"` mode, returns `true` unconditionally.
424
+ * In `"never"` mode, returns `false` unconditionally.
425
+ * In `"auto"` mode, requires base color to be enabled **and** truecolor
426
+ * to be detected.
427
+ *
428
+ * @param mode - The color emission mode.
429
+ * @param overrides - Optional overrides for deterministic testing.
430
+ * @returns `true` if truecolor sequences should be emitted.
431
+ *
432
+ * @example
433
+ * ```ts
434
+ * resolveTrueColor("auto"); // true if TTY + truecolor env detected
435
+ * resolveTrueColor("always"); // true
436
+ * resolveTrueColor("never"); // false
437
+ * resolveTrueColor("auto", {
438
+ * isTTY: true,
439
+ * noColor: undefined,
440
+ * colorTerm: "truecolor",
441
+ * }); // true
442
+ * ```
443
+ */
444
+ declare function resolveTrueColor(mode: ColorMode, overrides?: CapabilityOverrides & TrueColorOverrides): boolean;
408
445
  /** Apply black foreground color. */
409
446
  declare function black2(text: string): string;
410
447
  /** Apply red foreground color. */
@@ -424,51 +461,51 @@ declare function white2(text: string): string;
424
461
  /** Apply gray (bright black) foreground color. */
425
462
  declare function gray2(text: string): string;
426
463
  /** Apply bright red foreground color. */
427
- declare function brightRed3(text: string): string;
464
+ declare function brightRed2(text: string): string;
428
465
  /** Apply bright green foreground color. */
429
- declare function brightGreen3(text: string): string;
466
+ declare function brightGreen2(text: string): string;
430
467
  /** Apply bright yellow foreground color. */
431
- declare function brightYellow3(text: string): string;
468
+ declare function brightYellow2(text: string): string;
432
469
  /** Apply bright blue foreground color. */
433
- declare function brightBlue3(text: string): string;
470
+ declare function brightBlue2(text: string): string;
434
471
  /** Apply bright magenta foreground color. */
435
- declare function brightMagenta3(text: string): string;
472
+ declare function brightMagenta2(text: string): string;
436
473
  /** Apply bright cyan foreground color. */
437
- declare function brightCyan3(text: string): string;
474
+ declare function brightCyan2(text: string): string;
438
475
  /** Apply bright white foreground color. */
439
- declare function brightWhite3(text: string): string;
476
+ declare function brightWhite2(text: string): string;
440
477
  /** Apply black background color. */
441
- declare function bgBlack3(text: string): string;
478
+ declare function bgBlack2(text: string): string;
442
479
  /** Apply red background color. */
443
- declare function bgRed3(text: string): string;
480
+ declare function bgRed2(text: string): string;
444
481
  /** Apply green background color. */
445
- declare function bgGreen3(text: string): string;
482
+ declare function bgGreen2(text: string): string;
446
483
  /** Apply yellow background color. */
447
- declare function bgYellow3(text: string): string;
484
+ declare function bgYellow2(text: string): string;
448
485
  /** Apply blue background color. */
449
- declare function bgBlue3(text: string): string;
486
+ declare function bgBlue2(text: string): string;
450
487
  /** Apply magenta background color. */
451
- declare function bgMagenta3(text: string): string;
488
+ declare function bgMagenta2(text: string): string;
452
489
  /** Apply cyan background color. */
453
- declare function bgCyan3(text: string): string;
490
+ declare function bgCyan2(text: string): string;
454
491
  /** Apply white background color. */
455
- declare function bgWhite3(text: string): string;
492
+ declare function bgWhite2(text: string): string;
456
493
  /** Apply bright black background color. */
457
- declare function bgBrightBlack3(text: string): string;
494
+ declare function bgBrightBlack2(text: string): string;
458
495
  /** Apply bright red background color. */
459
- declare function bgBrightRed3(text: string): string;
496
+ declare function bgBrightRed2(text: string): string;
460
497
  /** Apply bright green background color. */
461
- declare function bgBrightGreen3(text: string): string;
498
+ declare function bgBrightGreen2(text: string): string;
462
499
  /** Apply bright yellow background color. */
463
- declare function bgBrightYellow3(text: string): string;
500
+ declare function bgBrightYellow2(text: string): string;
464
501
  /** Apply bright blue background color. */
465
- declare function bgBrightBlue3(text: string): string;
502
+ declare function bgBrightBlue2(text: string): string;
466
503
  /** Apply bright magenta background color. */
467
- declare function bgBrightMagenta3(text: string): string;
504
+ declare function bgBrightMagenta2(text: string): string;
468
505
  /** Apply bright cyan background color. */
469
- declare function bgBrightCyan3(text: string): string;
506
+ declare function bgBrightCyan2(text: string): string;
470
507
  /** Apply bright white background color. */
471
- declare function bgBrightWhite3(text: string): string;
508
+ declare function bgBrightWhite2(text: string): string;
472
509
  /**
473
510
  * Create a configured style instance with mode-aware styling functions.
474
511
  *
@@ -490,6 +527,7 @@ declare function bgBrightWhite3(text: string): string;
490
527
  * // Force color output
491
528
  * const color = createStyle({ mode: "always" });
492
529
  * console.log(color.red("error"));
530
+ * console.log(color.bold.red("critical"));
493
531
  *
494
532
  * // Disable all styling
495
533
  * const plain = createStyle({ mode: "never" });
@@ -519,6 +557,150 @@ declare function createStyle(options?: StyleOptions): StyleInstance;
519
557
  */
520
558
  declare const style: StyleInstance;
521
559
  /**
560
+ * Parse a hex color string into RGB channel values.
561
+ *
562
+ * Supports `#RGB` (shorthand) and `#RRGGBB` (full) formats.
563
+ * The `#` prefix is required.
564
+ *
565
+ * @param hex - The hex color string.
566
+ * @returns A tuple of `[r, g, b]` channel values (0–255).
567
+ * @throws {TypeError} If the string is not a valid hex color.
568
+ *
569
+ * @example
570
+ * ```ts
571
+ * parseHex("#ff0000"); // [255, 0, 0]
572
+ * parseHex("#f00"); // [255, 0, 0]
573
+ * ```
574
+ */
575
+ declare function parseHex(hex: string): [r: number, g: number, b: number];
576
+ /**
577
+ * Create an {@link AnsiPair} for a truecolor foreground RGB color.
578
+ *
579
+ * Uses the ANSI escape sequence `\x1b[38;2;R;G;Bm` with close `\x1b[39m`.
580
+ *
581
+ * @param r - Red channel (0–255).
582
+ * @param g - Green channel (0–255).
583
+ * @param b - Blue channel (0–255).
584
+ * @returns An ANSI pair for the specified foreground color.
585
+ * @throws {RangeError} If any channel value is invalid.
586
+ *
587
+ * @example
588
+ * ```ts
589
+ * const pair = rgbCode(255, 0, 0);
590
+ * applyStyle("error", pair); // red foreground
591
+ * ```
592
+ */
593
+ declare function rgbCode(r: number, g: number, b: number): AnsiPair;
594
+ /**
595
+ * Create an {@link AnsiPair} for a truecolor background RGB color.
596
+ *
597
+ * Uses the ANSI escape sequence `\x1b[48;2;R;G;Bm` with close `\x1b[49m`.
598
+ *
599
+ * @param r - Red channel (0–255).
600
+ * @param g - Green channel (0–255).
601
+ * @param b - Blue channel (0–255).
602
+ * @returns An ANSI pair for the specified background color.
603
+ * @throws {RangeError} If any channel value is invalid.
604
+ *
605
+ * @example
606
+ * ```ts
607
+ * const pair = bgRgbCode(255, 128, 0);
608
+ * applyStyle("warning", pair); // orange background
609
+ * ```
610
+ */
611
+ declare function bgRgbCode(r: number, g: number, b: number): AnsiPair;
612
+ /**
613
+ * Create an {@link AnsiPair} for a truecolor foreground hex color.
614
+ *
615
+ * @param hex - Hex color string (`#RGB` or `#RRGGBB`).
616
+ * @returns An ANSI pair for the specified foreground color.
617
+ * @throws {TypeError} If the hex string is invalid.
618
+ *
619
+ * @example
620
+ * ```ts
621
+ * const pair = hexCode("#ff0000");
622
+ * applyStyle("error", pair); // red foreground
623
+ * ```
624
+ */
625
+ declare function hexCode(hex: string): AnsiPair;
626
+ /**
627
+ * Create an {@link AnsiPair} for a truecolor background hex color.
628
+ *
629
+ * @param hex - Hex color string (`#RGB` or `#RRGGBB`).
630
+ * @returns An ANSI pair for the specified background color.
631
+ * @throws {TypeError} If the hex string is invalid.
632
+ *
633
+ * @example
634
+ * ```ts
635
+ * const pair = bgHexCode("#ff8800");
636
+ * applyStyle("warning", pair); // orange background
637
+ * ```
638
+ */
639
+ declare function bgHexCode(hex: string): AnsiPair;
640
+ /**
641
+ * Apply a truecolor foreground RGB color to text.
642
+ *
643
+ * @param text - The text to style.
644
+ * @param r - Red channel (0–255).
645
+ * @param g - Green channel (0–255).
646
+ * @param b - Blue channel (0–255).
647
+ * @returns The styled string.
648
+ * @throws {RangeError} If any channel value is invalid.
649
+ *
650
+ * @example
651
+ * ```ts
652
+ * rgb("error", 255, 0, 0); // red text
653
+ * rgb("ocean", 0, 128, 255); // blue text
654
+ * ```
655
+ */
656
+ declare function rgb(text: string, r: number, g: number, b: number): string;
657
+ /**
658
+ * Apply a truecolor background RGB color to text.
659
+ *
660
+ * @param text - The text to style.
661
+ * @param r - Red channel (0–255).
662
+ * @param g - Green channel (0–255).
663
+ * @param b - Blue channel (0–255).
664
+ * @returns The styled string.
665
+ * @throws {RangeError} If any channel value is invalid.
666
+ *
667
+ * @example
668
+ * ```ts
669
+ * bgRgb("warning", 255, 128, 0); // orange background
670
+ * ```
671
+ */
672
+ declare function bgRgb2(text: string, r: number, g: number, b: number): string;
673
+ /**
674
+ * Apply a truecolor foreground hex color to text.
675
+ *
676
+ * @param text - The text to style.
677
+ * @param hexColor - Hex color string (`#RGB` or `#RRGGBB`).
678
+ * @returns The styled string.
679
+ * @throws {TypeError} If the hex string is invalid.
680
+ *
681
+ * @example
682
+ * ```ts
683
+ * hex("error", "#ff0000"); // red text
684
+ * hex("ocean", "#0080ff"); // blue text
685
+ * hex("short", "#f00"); // red text (shorthand)
686
+ * ```
687
+ */
688
+ declare function hex(text: string, hexColor: string): string;
689
+ /**
690
+ * Apply a truecolor background hex color to text.
691
+ *
692
+ * @param text - The text to style.
693
+ * @param hexColor - Hex color string (`#RGB` or `#RRGGBB`).
694
+ * @returns The styled string.
695
+ * @throws {TypeError} If the hex string is invalid.
696
+ *
697
+ * @example
698
+ * ```ts
699
+ * bgHex("warning", "#ff8800"); // orange background
700
+ * ```
701
+ */
702
+ declare function bgHex2(text: string, hexColor: string): string;
703
+ /**
522
704
  * Apply **bold** (increased intensity) to text.
523
705
  *
524
706
  * @example
@@ -962,4 +1144,4 @@ declare function createMarkdownTheme(options?: CreateMarkdownThemeOptions): Mark
962
1144
  * ```
963
1145
  */
964
1146
  declare const defaultTheme: MarkdownTheme;
965
- export { yellow as yellowCode, yellow2 as yellow, wrapText, white as whiteCode, white2 as white, visibleWidth, unorderedList, underline as underlineCode, underline2 as underline, taskList, table, style, stripAnsi, strikethrough as strikethroughCode, strikethrough2 as strikethrough, resolveCapability, reset, red as redCode, red2 as red, padStart, padEnd, orderedList, magenta as magentaCode, magenta2 as magenta, italic as italicCode, italic2 as italic, inverse as inverseCode, inverse2 as inverse, hidden as hiddenCode, hidden2 as hidden, green as greenCode, green2 as green, gray as grayCode, gray2 as gray, dim as dimCode, dim2 as dim, defaultTheme, cyan as cyanCode, cyan2 as cyan, createStyle, createMarkdownTheme, composeStyles, center, buildDefaultMarkdownTheme, brightYellow2 as brightYellowCode, brightYellow3 as brightYellow, brightWhite2 as brightWhiteCode, brightWhite3 as brightWhite, brightRed2 as brightRedCode, brightRed3 as brightRed, brightMagenta2 as brightMagentaCode, brightMagenta3 as brightMagenta, brightGreen2 as brightGreenCode, brightGreen3 as brightGreen, brightCyan2 as brightCyanCode, brightCyan3 as brightCyan, brightBlue2 as brightBlueCode, brightBlue3 as brightBlue, bold as boldCode, bold2 as bold, blue as blueCode, blue2 as blue, black as blackCode, black2 as black, bgYellow2 as bgYellowCode, bgYellow3 as bgYellow, bgWhite2 as bgWhiteCode, bgWhite3 as bgWhite, bgRed2 as bgRedCode, bgRed3 as bgRed, bgMagenta2 as bgMagentaCode, bgMagenta3 as bgMagenta, bgGreen2 as bgGreenCode, bgGreen3 as bgGreen, bgCyan2 as bgCyanCode, bgCyan3 as bgCyan, bgBrightYellow2 as bgBrightYellowCode, bgBrightYellow3 as bgBrightYellow, bgBrightWhite2 as bgBrightWhiteCode, bgBrightWhite3 as bgBrightWhite, bgBrightRed2 as bgBrightRedCode, bgBrightRed3 as bgBrightRed, bgBrightMagenta2 as bgBrightMagentaCode, bgBrightMagenta3 as bgBrightMagenta, bgBrightGreen2 as bgBrightGreenCode, bgBrightGreen3 as bgBrightGreen, bgBrightCyan2 as bgBrightCyanCode, bgBrightCyan3 as bgBrightCyan, bgBrightBlue2 as bgBrightBlueCode, bgBrightBlue3 as bgBrightBlue, bgBrightBlack2 as bgBrightBlackCode, bgBrightBlack3 as bgBrightBlack, bgBlue2 as bgBlueCode, bgBlue3 as bgBlue, bgBlack2 as bgBlackCode, bgBlack3 as bgBlack, applyStyle, WrapOptions, UnorderedListOptions, ThemeSlotFn, TaskListOptions, TaskListItem, TableOptions, StyleOptions, StyleInstance, StyleFn, PartialMarkdownTheme, OrderedListOptions, MarkdownTheme, CreateMarkdownThemeOptions, ColumnAlignment, ColorMode, CapabilityOverrides, AnsiPair };
1147
+ export { yellow as yellowCode, yellow2 as yellow, wrapText, white as whiteCode, white2 as white, visibleWidth, unorderedList, underline as underlineCode, underline2 as underline, taskList, table, style, stripAnsi, strikethrough as strikethroughCode, strikethrough2 as strikethrough, rgbCode, rgb, resolveTrueColor, resolveCapability, reset, red as redCode, red2 as red, parseHex, padStart, padEnd, orderedList, magenta as magentaCode, magenta2 as magenta, italic as italicCode, italic2 as italic, inverse as inverseCode, inverse2 as inverse, hidden as hiddenCode, hidden2 as hidden, hexCode, hex, green as greenCode, green2 as green, gray as grayCode, gray2 as gray, dim as dimCode, dim2 as dim, defaultTheme, cyan as cyanCode, cyan2 as cyan, createStyle, createMarkdownTheme, composeStyles, center, buildDefaultMarkdownTheme, brightYellow as brightYellowCode, brightYellow2 as brightYellow, brightWhite as brightWhiteCode, brightWhite2 as brightWhite, brightRed as brightRedCode, brightRed2 as brightRed, brightMagenta as brightMagentaCode, brightMagenta2 as brightMagenta, brightGreen as brightGreenCode, brightGreen2 as brightGreen, brightCyan as brightCyanCode, brightCyan2 as brightCyan, brightBlue as brightBlueCode, brightBlue2 as brightBlue, bold as boldCode, bold2 as bold, blue as blueCode, blue2 as blue, black as blackCode, black2 as black, bgYellow as bgYellowCode, bgYellow2 as bgYellow, bgWhite as bgWhiteCode, bgWhite2 as bgWhite, bgRgbCode, bgRgb2 as bgRgb, bgRed as bgRedCode, bgRed2 as bgRed, bgMagenta as bgMagentaCode, bgMagenta2 as bgMagenta, bgHexCode, bgHex2 as bgHex, bgGreen as bgGreenCode, bgGreen2 as bgGreen, bgCyan as bgCyanCode, bgCyan2 as bgCyan, bgBrightYellow as bgBrightYellowCode, bgBrightYellow2 as bgBrightYellow, bgBrightWhite as bgBrightWhiteCode, bgBrightWhite2 as bgBrightWhite, bgBrightRed as bgBrightRedCode, bgBrightRed2 as bgBrightRed, bgBrightMagenta as bgBrightMagentaCode, bgBrightMagenta2 as bgBrightMagenta, bgBrightGreen as bgBrightGreenCode, bgBrightGreen2 as bgBrightGreen, bgBrightCyan as bgBrightCyanCode, bgBrightCyan2 as bgBrightCyan, bgBrightBlue as bgBrightBlueCode, bgBrightBlue2 as bgBrightBlue, bgBrightBlack as bgBrightBlackCode, bgBrightBlack2 as bgBrightBlack, bgBlue as bgBlueCode, bgBlue2 as bgBlue, bgBlack as bgBlackCode, bgBlack2 as bgBlack, applyStyle, WrapOptions, UnorderedListOptions, TrueColorOverrides, ThemeSlotFn, TaskListOptions, TaskListItem, TableOptions, StyleOptions, StyleInstance, StyleFn, PartialMarkdownTheme, OrderedListOptions, MarkdownTheme, CreateMarkdownThemeOptions, ColumnAlignment, ColorMode, CapabilityOverrides, AnsiPair };
package/dist/index.js CHANGED
@@ -1,5 +1,59 @@
1
1
  // @bun
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, {
6
+ get: all[name],
7
+ enumerable: true,
8
+ configurable: true,
9
+ set: (newValue) => all[name] = () => newValue
10
+ });
11
+ };
12
+
2
13
  // src/ansiCodes.ts
14
+ var exports_ansiCodes = {};
15
+ __export(exports_ansiCodes, {
16
+ yellow: () => yellow,
17
+ white: () => white,
18
+ underline: () => underline,
19
+ strikethrough: () => strikethrough,
20
+ reset: () => reset,
21
+ red: () => red,
22
+ magenta: () => magenta,
23
+ italic: () => italic,
24
+ inverse: () => inverse,
25
+ hidden: () => hidden,
26
+ green: () => green,
27
+ gray: () => gray,
28
+ dim: () => dim,
29
+ cyan: () => cyan,
30
+ brightYellow: () => brightYellow,
31
+ brightWhite: () => brightWhite,
32
+ brightRed: () => brightRed,
33
+ brightMagenta: () => brightMagenta,
34
+ brightGreen: () => brightGreen,
35
+ brightCyan: () => brightCyan,
36
+ brightBlue: () => brightBlue,
37
+ bold: () => bold,
38
+ blue: () => blue,
39
+ black: () => black,
40
+ bgYellow: () => bgYellow,
41
+ bgWhite: () => bgWhite,
42
+ bgRed: () => bgRed,
43
+ bgMagenta: () => bgMagenta,
44
+ bgGreen: () => bgGreen,
45
+ bgCyan: () => bgCyan,
46
+ bgBrightYellow: () => bgBrightYellow,
47
+ bgBrightWhite: () => bgBrightWhite,
48
+ bgBrightRed: () => bgBrightRed,
49
+ bgBrightMagenta: () => bgBrightMagenta,
50
+ bgBrightGreen: () => bgBrightGreen,
51
+ bgBrightCyan: () => bgBrightCyan,
52
+ bgBrightBlue: () => bgBrightBlue,
53
+ bgBrightBlack: () => bgBrightBlack,
54
+ bgBlue: () => bgBlue,
55
+ bgBlack: () => bgBlack
56
+ });
3
57
  function pair(open, close) {
4
58
  return { open: `\x1B[${open}m`, close: `\x1B[${close}m` };
5
59
  }
@@ -233,6 +287,32 @@ function resolveCapability(mode, overrides) {
233
287
  }
234
288
  return isTTY;
235
289
  }
290
+ function resolveTrueColor(mode, overrides) {
291
+ if (mode === "always") {
292
+ return true;
293
+ }
294
+ if (mode === "never") {
295
+ return false;
296
+ }
297
+ if (!resolveCapability(mode, overrides)) {
298
+ return false;
299
+ }
300
+ const hasColorTermOverride = overrides !== undefined && "colorTerm" in overrides;
301
+ const colorTerm = hasColorTermOverride ? overrides.colorTerm : process.env.COLORTERM;
302
+ const lowerColorTerm = colorTerm?.toLowerCase();
303
+ if (lowerColorTerm === "truecolor" || lowerColorTerm === "24bit") {
304
+ return true;
305
+ }
306
+ const hasTermOverride = overrides !== undefined && "term" in overrides;
307
+ const term = hasTermOverride ? overrides.term : process.env.TERM;
308
+ if (term !== undefined) {
309
+ const lower = term.toLowerCase();
310
+ if (lower.includes("24bit") || lower.includes("truecolor") || lower.endsWith("-direct")) {
311
+ return true;
312
+ }
313
+ }
314
+ return false;
315
+ }
236
316
  // src/styleEngine.ts
237
317
  function applyStyle(text, style) {
238
318
  if (text === "") {
@@ -348,58 +428,146 @@ function bgBrightCyan2(text) {
348
428
  function bgBrightWhite2(text) {
349
429
  return applyStyle(text, bgBrightWhite);
350
430
  }
431
+ // src/dynamicColors.ts
432
+ function validateChannel(value, channel) {
433
+ if (!Number.isInteger(value) || value < 0 || value > 255) {
434
+ throw new RangeError(`Invalid ${channel} value: ${String(value)}. Must be an integer between 0 and 255.`);
435
+ }
436
+ }
437
+ function validateRgb(r, g, b) {
438
+ validateChannel(r, "red");
439
+ validateChannel(g, "green");
440
+ validateChannel(b, "blue");
441
+ }
442
+ var HEX_SHORT = /^#([0-9a-f]{3})$/i;
443
+ var HEX_LONG = /^#([0-9a-f]{6})$/i;
444
+ function parseHex(hex) {
445
+ const shortMatch = HEX_SHORT.exec(hex);
446
+ if (shortMatch) {
447
+ const digits = shortMatch[1];
448
+ const r = digits.charAt(0);
449
+ const g = digits.charAt(1);
450
+ const b = digits.charAt(2);
451
+ return [
452
+ Number.parseInt(r + r, 16),
453
+ Number.parseInt(g + g, 16),
454
+ Number.parseInt(b + b, 16)
455
+ ];
456
+ }
457
+ const longMatch = HEX_LONG.exec(hex);
458
+ if (longMatch) {
459
+ const digits = longMatch[1];
460
+ return [
461
+ Number.parseInt(digits.slice(0, 2), 16),
462
+ Number.parseInt(digits.slice(2, 4), 16),
463
+ Number.parseInt(digits.slice(4, 6), 16)
464
+ ];
465
+ }
466
+ throw new TypeError(`Invalid hex color: "${hex}". Expected format: "#RGB" or "#RRGGBB".`);
467
+ }
468
+ function rgbCode(r, g, b) {
469
+ validateRgb(r, g, b);
470
+ return { open: `\x1B[38;2;${r};${g};${b}m`, close: "\x1B[39m" };
471
+ }
472
+ function bgRgbCode(r, g, b) {
473
+ validateRgb(r, g, b);
474
+ return { open: `\x1B[48;2;${r};${g};${b}m`, close: "\x1B[49m" };
475
+ }
476
+ function hexCode(hex) {
477
+ const [r, g, b] = parseHex(hex);
478
+ return rgbCode(r, g, b);
479
+ }
480
+ function bgHexCode(hex) {
481
+ const [r, g, b] = parseHex(hex);
482
+ return bgRgbCode(r, g, b);
483
+ }
484
+ function rgb(text, r, g, b) {
485
+ return applyStyle(text, rgbCode(r, g, b));
486
+ }
487
+ function bgRgb(text, r, g, b) {
488
+ return applyStyle(text, bgRgbCode(r, g, b));
489
+ }
490
+ function hex(text, hexColor) {
491
+ return applyStyle(text, hexCode(hexColor));
492
+ }
493
+ function bgHex(text, hexColor) {
494
+ return applyStyle(text, bgHexCode(hexColor));
495
+ }
496
+
497
+ // src/styleMethodRegistry.ts
498
+ function readStyleMethodPairs() {
499
+ const { reset: _reset, ...pairs } = exports_ansiCodes;
500
+ return pairs;
501
+ }
502
+ var styleMethodPairs = Object.freeze(readStyleMethodPairs());
503
+ var styleMethodNames = Object.freeze(Object.keys(styleMethodPairs));
504
+ function stylePairFor(name) {
505
+ return styleMethodPairs[name];
506
+ }
507
+
351
508
  // src/createStyle.ts
352
- function makeStyleFn(pair2, enabled) {
353
- if (enabled) {
354
- return (text) => applyStyle(text, pair2);
509
+ function applyChain(text, methodNames, enabled) {
510
+ if (!enabled || text === "") {
511
+ return text;
512
+ }
513
+ let result = text;
514
+ for (let i = methodNames.length - 1;i >= 0; i--) {
515
+ const methodName = methodNames[i];
516
+ if (methodName === undefined) {
517
+ continue;
518
+ }
519
+ result = applyStyle(result, stylePairFor(methodName));
520
+ }
521
+ return result;
522
+ }
523
+ function buildChainableStyleFactory(enabled) {
524
+ const cache = new Map;
525
+ function makeKey(methodNames) {
526
+ return methodNames.join("|");
527
+ }
528
+ function createChainableStyle(methodNames) {
529
+ const key = makeKey(methodNames);
530
+ const cached = cache.get(key);
531
+ if (cached) {
532
+ return cached;
533
+ }
534
+ const styleFn = (text) => applyChain(text, methodNames, enabled);
535
+ cache.set(key, styleFn);
536
+ for (const name of styleMethodNames) {
537
+ Object.defineProperty(styleFn, name, {
538
+ configurable: false,
539
+ enumerable: true,
540
+ get() {
541
+ return createChainableStyle([...methodNames, name]);
542
+ }
543
+ });
544
+ }
545
+ return Object.freeze(styleFn);
546
+ }
547
+ return createChainableStyle;
548
+ }
549
+ function buildStyleMethods(createChainableStyle) {
550
+ const methods = {};
551
+ for (const methodName of styleMethodNames) {
552
+ methods[methodName] = createChainableStyle([methodName]);
355
553
  }
356
- return (text) => text;
554
+ return methods;
357
555
  }
358
556
  function createStyle(options) {
359
557
  const mode = options?.mode ?? "auto";
360
558
  const enabled = resolveCapability(mode, options?.overrides);
559
+ const trueColorEnabled = resolveTrueColor(mode, options?.overrides);
560
+ const createChainableStyle = buildChainableStyleFactory(enabled);
561
+ const methods = buildStyleMethods(createChainableStyle);
361
562
  const instance = {
362
563
  enabled,
564
+ trueColorEnabled,
363
565
  apply: enabled ? (text, pair2) => applyStyle(text, pair2) : (text, _pair) => text,
364
- bold: makeStyleFn(bold, enabled),
365
- dim: makeStyleFn(dim, enabled),
366
- italic: makeStyleFn(italic, enabled),
367
- underline: makeStyleFn(underline, enabled),
368
- inverse: makeStyleFn(inverse, enabled),
369
- hidden: makeStyleFn(hidden, enabled),
370
- strikethrough: makeStyleFn(strikethrough, enabled),
371
- black: makeStyleFn(black, enabled),
372
- red: makeStyleFn(red, enabled),
373
- green: makeStyleFn(green, enabled),
374
- yellow: makeStyleFn(yellow, enabled),
375
- blue: makeStyleFn(blue, enabled),
376
- magenta: makeStyleFn(magenta, enabled),
377
- cyan: makeStyleFn(cyan, enabled),
378
- white: makeStyleFn(white, enabled),
379
- gray: makeStyleFn(gray, enabled),
380
- brightRed: makeStyleFn(brightRed, enabled),
381
- brightGreen: makeStyleFn(brightGreen, enabled),
382
- brightYellow: makeStyleFn(brightYellow, enabled),
383
- brightBlue: makeStyleFn(brightBlue, enabled),
384
- brightMagenta: makeStyleFn(brightMagenta, enabled),
385
- brightCyan: makeStyleFn(brightCyan, enabled),
386
- brightWhite: makeStyleFn(brightWhite, enabled),
387
- bgBlack: makeStyleFn(bgBlack, enabled),
388
- bgRed: makeStyleFn(bgRed, enabled),
389
- bgGreen: makeStyleFn(bgGreen, enabled),
390
- bgYellow: makeStyleFn(bgYellow, enabled),
391
- bgBlue: makeStyleFn(bgBlue, enabled),
392
- bgMagenta: makeStyleFn(bgMagenta, enabled),
393
- bgCyan: makeStyleFn(bgCyan, enabled),
394
- bgWhite: makeStyleFn(bgWhite, enabled),
395
- bgBrightBlack: makeStyleFn(bgBrightBlack, enabled),
396
- bgBrightRed: makeStyleFn(bgBrightRed, enabled),
397
- bgBrightGreen: makeStyleFn(bgBrightGreen, enabled),
398
- bgBrightYellow: makeStyleFn(bgBrightYellow, enabled),
399
- bgBrightBlue: makeStyleFn(bgBrightBlue, enabled),
400
- bgBrightMagenta: makeStyleFn(bgBrightMagenta, enabled),
401
- bgBrightCyan: makeStyleFn(bgBrightCyan, enabled),
402
- bgBrightWhite: makeStyleFn(bgBrightWhite, enabled)
566
+ rgb: trueColorEnabled ? (text, r, g, b) => rgb(text, r, g, b) : (text, _r, _g, _b) => text,
567
+ bgRgb: trueColorEnabled ? (text, r, g, b) => bgRgb(text, r, g, b) : (text, _r, _g, _b) => text,
568
+ hex: trueColorEnabled ? (text, hexColor) => hex(text, hexColor) : (text, _hexColor) => text,
569
+ bgHex: trueColorEnabled ? (text, hexColor) => bgHex(text, hexColor) : (text, _hexColor) => text,
570
+ ...methods
403
571
  };
404
572
  return Object.freeze(instance);
405
573
  }
@@ -636,10 +804,14 @@ export {
636
804
  stripAnsi,
637
805
  strikethrough as strikethroughCode,
638
806
  strikethrough2 as strikethrough,
807
+ rgbCode,
808
+ rgb,
809
+ resolveTrueColor,
639
810
  resolveCapability,
640
811
  reset,
641
812
  red as redCode,
642
813
  red2 as red,
814
+ parseHex,
643
815
  padStart,
644
816
  padEnd,
645
817
  orderedList,
@@ -651,6 +823,8 @@ export {
651
823
  inverse2 as inverse,
652
824
  hidden as hiddenCode,
653
825
  hidden2 as hidden,
826
+ hexCode,
827
+ hex,
654
828
  green as greenCode,
655
829
  green2 as green,
656
830
  gray as grayCode,
@@ -689,10 +863,14 @@ export {
689
863
  bgYellow2 as bgYellow,
690
864
  bgWhite as bgWhiteCode,
691
865
  bgWhite2 as bgWhite,
866
+ bgRgbCode,
867
+ bgRgb,
692
868
  bgRed as bgRedCode,
693
869
  bgRed2 as bgRed,
694
870
  bgMagenta as bgMagentaCode,
695
871
  bgMagenta2 as bgMagenta,
872
+ bgHexCode,
873
+ bgHex,
696
874
  bgGreen as bgGreenCode,
697
875
  bgGreen2 as bgGreen,
698
876
  bgCyan as bgCyanCode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crustjs/style",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Terminal styling foundation for the Crust CLI framework",
5
5
  "type": "module",
6
6
  "license": "MIT",