ansimax 1.0.0 → 1.1.1

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.
@@ -0,0 +1,96 @@
1
+ // ─────────────────────────────────────────────
2
+ // EXAMPLE 1 — CLI installer with hierarchical tasks
3
+ //
4
+ // Demonstrates a realistic project setup flow:
5
+ // - Banner intro with theme gradient
6
+ // - Hierarchical tasks (parent + subtasks with rollup)
7
+ // - Status indicators with custom icons
8
+ // - Box for final summary
9
+ //
10
+ // Run:
11
+ // npx ts-node examples/01-cli-installer.ts
12
+ // ─────────────────────────────────────────────
13
+
14
+ import {
15
+ ascii,
16
+ themes,
17
+ loader,
18
+ components,
19
+ configure,
20
+ sleep,
21
+ } from '../dist/index.js';
22
+
23
+ // Configure global defaults
24
+ configure({
25
+ theme: 'dracula',
26
+ animationSpeed: 'fast',
27
+ });
28
+
29
+ // Simulated work
30
+ const work = (ms: number, fail = false) => async (): Promise<string> => {
31
+ await sleep(ms);
32
+ if (fail) throw new Error('Simulated failure');
33
+ return 'ok';
34
+ };
35
+
36
+ const main = async (): Promise<void> => {
37
+ // ── Intro banner ──────────────────────────────
38
+ console.log();
39
+ console.log(themes.banner('CREATE-APP', { font: 'small' }));
40
+ console.log();
41
+ console.log(components.section(themes.primary('Initializing project'), { width: 60 }));
42
+ console.log();
43
+
44
+ // ── Hierarchical task list ────────────────────
45
+ const results = await loader.tasks([
46
+ {
47
+ text: 'Setup environment',
48
+ fn: work(300),
49
+ subtasks: [
50
+ { text: 'Detect Node version', fn: work(150) },
51
+ { text: 'Verify npm registry', fn: work(200) },
52
+ { text: 'Create project dir', fn: work(100) },
53
+ ],
54
+ },
55
+ {
56
+ text: 'Install dependencies',
57
+ fn: work(400),
58
+ subtasks: [
59
+ { text: 'Resolve package tree', fn: work(250) },
60
+ { text: 'Download tarballs', fn: work(500) },
61
+ { text: 'Build native modules', fn: work(300) },
62
+ ],
63
+ },
64
+ {
65
+ text: 'Run post-install hooks',
66
+ fn: work(200),
67
+ subtasks: [
68
+ { text: 'Generate types', fn: work(150) },
69
+ { text: 'Lint workspace', fn: work(180) },
70
+ ],
71
+ },
72
+ ]);
73
+
74
+ // ── Final summary box ─────────────────────────
75
+ console.log();
76
+ const succeeded = results.filter((r) => r.success).length;
77
+ const failed = results.length - succeeded;
78
+
79
+ const summary = [
80
+ components.status('success', `${succeeded} steps completed`),
81
+ failed > 0
82
+ ? components.status('error', `${failed} steps failed`)
83
+ : components.status('info', 'No errors'),
84
+ '',
85
+ themes.muted('Next steps:'),
86
+ ' ' + themes.accent('cd my-app && npm run dev'),
87
+ ].join('\n');
88
+
89
+ console.log(components.box(summary, { borderStyle: 'rounded', padding: 1 }));
90
+ console.log();
91
+ };
92
+
93
+ main().catch((err) => {
94
+ console.error(themes.error('✗ ' + err.message));
95
+ process.exit(1);
96
+ });
@@ -0,0 +1,121 @@
1
+ /**
2
+ * 01 — Quick Smoke Test
3
+ *
4
+ * Verifies all major named exports from `ansimax` are importable and callable.
5
+ * This is the FIRST test to run — if it fails, the package is broken.
6
+ *
7
+ * Run: npx tsx examples/01-quick-smoke.ts
8
+ */
9
+
10
+ import {
11
+ color,
12
+ gradient,
13
+ rainbow,
14
+ ascii,
15
+ loader,
16
+ animate,
17
+ frames,
18
+ components,
19
+ themes,
20
+ images,
21
+ trees,
22
+ tree,
23
+ configure,
24
+ getConfig,
25
+ // Utils
26
+ stripAnsi,
27
+ visibleLen,
28
+ hexToRgb,
29
+ rgbToHex,
30
+ clamp,
31
+ // ANSI primitives
32
+ cursor,
33
+ screen,
34
+ supportsColor,
35
+ } from '../src/index.js';
36
+
37
+ const pass = (msg: string): void => console.log(color.green('✓'), msg);
38
+ const info = (label: string, value: unknown): void =>
39
+ console.log(' ' + color.dim(label.padEnd(20)), value);
40
+
41
+ console.log();
42
+ console.log(color.bold(color.cyan('━━━ Ansimax v1.1.0 Smoke Test ━━━')));
43
+ console.log();
44
+
45
+ // 1. Colors
46
+ pass('color.red / color.green / color.blue');
47
+ info('color.red:', color.red('red text'));
48
+ info('color.green:', color.green('green text'));
49
+
50
+ // 2. Gradient
51
+ pass('gradient with multi-stop');
52
+ info('gradient:', gradient('rainbow text', ['#ff0000', '#00ff00', '#0000ff']));
53
+
54
+ // 3. Rainbow preset
55
+ pass('rainbow preset');
56
+ info('rainbow:', rainbow('hello rainbow!'));
57
+
58
+ // 4. Style modifiers
59
+ pass('color.bold / italic / underline');
60
+ info('bold:', color.bold('bold text'));
61
+ info('italic:', color.italic('italic text'));
62
+ info('underline:', color.underline('underlined text'));
63
+
64
+ // 5. Hex & RGB
65
+ pass('color.hex / color.rgb');
66
+ info('color.hex:', color.hex('#ff79c6')('Dracula pink'));
67
+ info('color.rgb:', color.rgb(189, 147, 249)('Dracula purple'));
68
+
69
+ // 6. ANSI utils
70
+ pass('stripAnsi / visibleLen');
71
+ const colored = color.red('hello');
72
+ info('stripAnsi:', JSON.stringify(stripAnsi(colored)));
73
+ info('visibleLen:', visibleLen(colored));
74
+
75
+ // 7. hexToRgb / rgbToHex
76
+ pass('hexToRgb / rgbToHex');
77
+ info('hexToRgb #ff79c6:', JSON.stringify(hexToRgb('#ff79c6')));
78
+ info('rgbToHex 189,147,249:', rgbToHex(189, 147, 249));
79
+
80
+ // 8. clamp
81
+ pass('clamp');
82
+ info('clamp(15, 0, 10):', clamp(15, 0, 10));
83
+
84
+ // 9. Capability detection
85
+ pass('supportsColor');
86
+ info('supportsColor():', supportsColor());
87
+
88
+ // 10. Module namespaces
89
+ pass('All namespaces accessible');
90
+ info('color:', typeof color);
91
+ info('ascii:', typeof ascii);
92
+ info('loader:', typeof loader);
93
+ info('animate:', typeof animate);
94
+ info('frames:', typeof frames);
95
+ info('components:', typeof components);
96
+ info('themes:', typeof themes);
97
+ info('images:', typeof images);
98
+ info('trees:', typeof trees);
99
+
100
+ // 11. tree() builder
101
+ pass('tree() builder');
102
+ const t = tree({ label: 'root', icon: '📦' });
103
+ t.addLeaf({ label: 'child1', icon: '📄' });
104
+ info('tree.render():', '\n' + t.render());
105
+
106
+ // 12. configure
107
+ pass('configure / getConfig');
108
+ const cfg = getConfig();
109
+ info('theme:', cfg.theme);
110
+ info('colorMode:', cfg.colorMode);
111
+
112
+ // 13. cursor / screen primitives
113
+ pass('cursor / screen primitives');
114
+ info('cursor.hide():', JSON.stringify(cursor.hide()));
115
+ info('cursor.show():', JSON.stringify(cursor.show()));
116
+ info('screen.clearLine():', JSON.stringify(screen.clearLine()));
117
+
118
+ console.log();
119
+ console.log(color.bold(color.green('✅ All smoke tests passed!')));
120
+ console.log(color.dim('You have a working ansimax installation.'));
121
+ console.log();
@@ -0,0 +1,108 @@
1
+ /**
2
+ * 02 — Colors & Gradients
3
+ * Tests verified against actual ansimax@1.1.0 exports.
4
+ *
5
+ * Run: npx tsx examples/02-colors-gradients.ts
6
+ */
7
+
8
+ import {
9
+ color,
10
+ gradient,
11
+ rainbow,
12
+ colorPresets,
13
+ presetNames,
14
+ compose,
15
+ chain,
16
+ registerPreset,
17
+ listPresets,
18
+ } from '../src/index.js';
19
+
20
+ console.log();
21
+ console.log(color.bold('━━━ Basic Colors ━━━'));
22
+ console.log();
23
+
24
+ const basic = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white'] as const;
25
+ console.log('Basic 8 colors:');
26
+ for (const c of basic) process.stdout.write(color[c](c.padEnd(8)) + ' ');
27
+ console.log('\n');
28
+
29
+ const bright = ['brightRed', 'brightGreen', 'brightYellow', 'brightBlue', 'brightMagenta', 'brightCyan'] as const;
30
+ console.log('Bright variants:');
31
+ for (const c of bright) process.stdout.write(color[c](c.padEnd(15)) + ' ');
32
+ console.log('\n');
33
+
34
+ const bg = ['bgRed', 'bgGreen', 'bgBlue', 'bgYellow', 'bgMagenta', 'bgCyan'] as const;
35
+ console.log('Backgrounds:');
36
+ for (const c of bg) process.stdout.write(color[c](` ${c} `) + ' ');
37
+ console.log('\n');
38
+
39
+ console.log('Modifiers:');
40
+ console.log(' ',
41
+ color.bold('bold'),
42
+ color.italic('italic'),
43
+ color.underline('underline'),
44
+ color.dim('dim'),
45
+ color.inverse('inverse'),
46
+ color.strikethrough('strikethrough'),
47
+ );
48
+ console.log();
49
+
50
+ console.log(color.bold('━━━ Hex / RGB / 256 ━━━'));
51
+ console.log();
52
+
53
+ const hexes = ['#ff79c6', '#bd93f9', '#8be9fd', '#50fa7b', '#ffb86c', '#ff5555'];
54
+ console.log('Hex colors:');
55
+ for (const hex of hexes) process.stdout.write(color.hex(hex)(hex) + ' ');
56
+ console.log('\n');
57
+
58
+ console.log('RGB:');
59
+ console.log(' ', color.rgb(255, 121, 198)('rgb(255, 121, 198)'));
60
+ console.log(' ', color.rgb(189, 147, 249)('rgb(189, 147, 249)'));
61
+ console.log();
62
+
63
+ console.log('256-color (palette indices):');
64
+ for (const n of [196, 208, 226, 46, 51, 21, 201]) {
65
+ process.stdout.write(color.color256(n)(`[${n}]`) + ' ');
66
+ }
67
+ console.log('\n');
68
+
69
+ console.log(color.bold('━━━ Gradients ━━━'));
70
+ console.log();
71
+
72
+ console.log('Multi-stop gradients:');
73
+ console.log(' ', gradient('Hello gradient world!', ['#ff0000', '#00ff00', '#0000ff']));
74
+ console.log(' ', gradient('Fire to ice', ['#ff6b6b', '#feca57', '#48dbfb']));
75
+ console.log(' ', gradient('Dracula theme', ['#ff79c6', '#bd93f9', '#8be9fd']));
76
+ console.log();
77
+
78
+ console.log(color.bold('━━━ Built-in colorPresets ━━━'));
79
+ console.log();
80
+ console.log(' Available:', presetNames.join(', '));
81
+ console.log();
82
+ console.log(' rainbow: ', rainbow('rainbow text!'));
83
+ console.log(' sunset: ', colorPresets.sunset!('sunset preset'));
84
+ console.log(' ocean: ', colorPresets.ocean!('ocean preset'));
85
+ console.log(' fire: ', colorPresets.fire!('fire preset'));
86
+ console.log(' neon: ', colorPresets.neon!('neon preset'));
87
+ console.log(' forest: ', colorPresets.forest!('forest preset'));
88
+ console.log(' aurora: ', colorPresets.aurora!('aurora preset'));
89
+ console.log(' candy: ', colorPresets.candy!('candy preset'));
90
+ console.log(' gold: ', colorPresets.gold!('gold preset'));
91
+ console.log();
92
+
93
+ console.log(color.bold('━━━ Custom presets ━━━'));
94
+ console.log();
95
+ registerPreset('my-pink', ['#ff6b6b', '#ff79c6', '#ffb6c1']);
96
+ console.log(' Registered. All presets now:', listPresets().join(', '));
97
+ console.log(' my-pink: ', colorPresets['my-pink']!('My custom pink preset!'));
98
+ console.log();
99
+
100
+ console.log(color.bold('━━━ Compose & Chain ━━━'));
101
+ console.log();
102
+ const fancy = compose(color.red, color.bold, color.underline);
103
+ console.log(' compose: ', fancy('red + bold + underline'));
104
+ console.log(' chain: ', chain().magenta().italic().underline().apply('chained styles'));
105
+ console.log();
106
+
107
+ console.log(color.bold(color.green('✓ Colors & gradients test complete')));
108
+ console.log();
@@ -0,0 +1,152 @@
1
+ // ─────────────────────────────────────────────
2
+ // EXAMPLE 2 — Real-time dashboard with live updates
3
+ //
4
+ // Demonstrates:
5
+ // - frames.live() for sticky bottom-of-screen UI
6
+ // - components.progressBar with gradient
7
+ // - components.table for data display
8
+ // - onResize listener for responsive layout
9
+ // - throttle for rate-limited updates
10
+ // - AbortSignal cleanup
11
+ //
12
+ // Run:
13
+ // npx ts-node examples/02-live-dashboard.ts
14
+ // ─────────────────────────────────────────────
15
+
16
+ import {
17
+ themes,
18
+ components,
19
+ frames,
20
+ onResize,
21
+ throttle,
22
+ termSize,
23
+ sleep,
24
+ cursor,
25
+ screen,
26
+ write,
27
+ } from '../dist/index.js';
28
+
29
+ interface Stat {
30
+ service: string;
31
+ status: 'up' | 'down' | 'pending';
32
+ latency: number;
33
+ load: number; // 0..100
34
+ }
35
+
36
+ // Simulated metrics that drift over time
37
+ const stats: Stat[] = [
38
+ { service: 'api-gateway', status: 'up', latency: 14, load: 32 },
39
+ { service: 'auth-service', status: 'up', latency: 22, load: 58 },
40
+ { service: 'database', status: 'pending', latency: 0, load: 0 },
41
+ { service: 'cdn-edge', status: 'up', latency: 8, load: 18 },
42
+ { service: 'cache-layer', status: 'up', latency: 3, load: 71 },
43
+ ];
44
+
45
+ const drift = (): void => {
46
+ for (const s of stats) {
47
+ if (s.status === 'pending') {
48
+ // Pending services come online randomly
49
+ if (Math.random() < 0.1) {
50
+ s.status = 'up';
51
+ s.latency = 10 + Math.floor(Math.random() * 30);
52
+ }
53
+ } else if (s.status === 'up') {
54
+ // Slight load + latency wander
55
+ s.load = Math.max(0, Math.min(100, s.load + (Math.random() - 0.5) * 8));
56
+ s.latency = Math.max(1, s.latency + (Math.random() - 0.5) * 3);
57
+ // Tiny chance of going down
58
+ if (Math.random() < 0.005) s.status = 'down';
59
+ }
60
+ }
61
+ };
62
+
63
+ const renderFrame = (): string => {
64
+ const { cols } = termSize();
65
+ const innerWidth = Math.max(40, Math.min(cols - 4, 80));
66
+
67
+ // ── Header with theme gradient ──
68
+ const title = themes.banner('STATUS', { font: 'small', perCharColor: false });
69
+
70
+ // ── Service rows ──
71
+ const rows: string[][] = [
72
+ ['Service', 'Status', 'Latency', 'Load'],
73
+ ...stats.map((s) => {
74
+ const statusIcon =
75
+ s.status === 'up' ? themes.accent('● up')
76
+ : s.status === 'down' ? themes.error('● down')
77
+ : themes.warning('● pending');
78
+
79
+ const latencyStr = s.status === 'up'
80
+ ? (s.latency < 20 ? themes.accent : s.latency < 50 ? themes.warning : themes.error)
81
+ (`${s.latency.toFixed(0)}ms`)
82
+ : themes.muted('—');
83
+
84
+ const loadBar = s.status === 'up'
85
+ ? components.progressBar(s.load, {
86
+ width: 20,
87
+ gradient: ['#00ff88', '#fdcb6e', '#ff6b6b'],
88
+ showPercentage: true,
89
+ })
90
+ : themes.muted('—');
91
+
92
+ return [s.service, statusIcon, latencyStr, loadBar];
93
+ }),
94
+ ];
95
+
96
+ const table = components.table(rows, { borderStyle: 'rounded', maxColWidth: innerWidth / 4 });
97
+
98
+ // ── Footer ──
99
+ const upCount = stats.filter((s) => s.status === 'up').length;
100
+ const downCount = stats.filter((s) => s.status === 'down').length;
101
+ const footer = themes.muted(
102
+ `${upCount} up · ${downCount} down · ${stats.length} total · ` +
103
+ `${cols}×${termSize().rows} terminal · Ctrl+C to exit`,
104
+ );
105
+
106
+ return [title, '', table, '', footer].join('\n');
107
+ };
108
+
109
+ const main = async (): Promise<void> => {
110
+ // Hide cursor while live UI runs
111
+ write(cursor.hide());
112
+
113
+ // Throttled resize redraw — coalesce rapid resize events into one render
114
+ const onAnyResize = throttle(() => {
115
+ // Frame engine will pick up the new size on its next tick
116
+ }, 100);
117
+ const offResize = onResize(onAnyResize);
118
+
119
+ // Start live engine at 4 fps (smooth but not CPU-hungry)
120
+ const live = frames.live({ fps: 4, autoStart: true });
121
+
122
+ // Drift loop
123
+ const ctrl = new AbortController();
124
+ process.on('SIGINT', () => {
125
+ ctrl.abort();
126
+ live.stop({ clear: false });
127
+ offResize();
128
+ write(cursor.show());
129
+ write('\n');
130
+ console.log(themes.muted('Dashboard stopped.'));
131
+ process.exit(0);
132
+ });
133
+
134
+ try {
135
+ while (!ctrl.signal.aborted) {
136
+ drift();
137
+ live.update(renderFrame());
138
+ await sleep(250, { signal: ctrl.signal });
139
+ }
140
+ } catch {
141
+ // Aborted — fall through to cleanup
142
+ } finally {
143
+ live.stop({ clear: false });
144
+ offResize();
145
+ write(cursor.show());
146
+ }
147
+ };
148
+
149
+ main().catch((err) => {
150
+ console.error(themes.error('✗ ' + (err as Error).message));
151
+ process.exit(1);
152
+ });
@@ -0,0 +1,81 @@
1
+ /**
2
+ * 03 — ASCII Banners & Boxes
3
+ * Real box styles: single, double, rounded, heavy, dashed, ascii
4
+ *
5
+ * Run: npx tsx examples/03-ascii-banners.ts
6
+ */
7
+
8
+ import { ascii, gradient, color, listFonts, hasFont } from '../src/index.js';
9
+
10
+ console.log();
11
+ console.log(color.bold('━━━ ASCII Banners ━━━'));
12
+ console.log();
13
+
14
+ console.log(color.dim('// Big font (default)'));
15
+ console.log(ascii.banner('HELLO'));
16
+
17
+ console.log(color.dim('// Small font'));
18
+ console.log(ascii.banner('HELLO', { font: 'small' }));
19
+
20
+ console.log(color.dim('// With gradient'));
21
+ console.log(ascii.banner('ANSIMAX', {
22
+ font: 'big',
23
+ colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9', '#8be9fd']),
24
+ }));
25
+
26
+ console.log(color.dim('// Aligned center'));
27
+ console.log(ascii.banner('CENTER', { align: 'center' }));
28
+
29
+ console.log(color.dim('// Available fonts:'));
30
+ console.log(' fonts:', listFonts().join(', '));
31
+ console.log(' has "big":', hasFont('big'));
32
+ console.log(' has "small":', hasFont('small'));
33
+ console.log(' has "unicorn":', hasFont('unicorn'));
34
+ console.log();
35
+
36
+ console.log(color.bold('━━━ Boxes (6 real styles) ━━━'));
37
+ console.log();
38
+
39
+ // REAL box styles: single, double, rounded, heavy, dashed, ascii
40
+ const boxStyles = ['single', 'double', 'rounded', 'heavy', 'dashed', 'ascii'] as const;
41
+ for (const style of boxStyles) {
42
+ console.log(color.dim(`// borderStyle: ${style}`));
43
+ console.log(ascii.box(`This is a ${style} box`, {
44
+ padding: 1,
45
+ borderStyle: style,
46
+ }));
47
+ }
48
+
49
+ console.log(color.dim('// Multi-line box'));
50
+ console.log(ascii.box(
51
+ 'Line 1\nLine 2 with a bit longer text\nLine 3',
52
+ { padding: 1, borderStyle: 'rounded' },
53
+ ));
54
+
55
+ console.log();
56
+ console.log(color.bold('━━━ Dividers ━━━'));
57
+ console.log();
58
+
59
+ console.log(ascii.divider({ char: '─', width: 50 }));
60
+ console.log(ascii.divider({ char: '═', width: 50 }));
61
+ console.log(ascii.divider({ char: '━', width: 50, label: 'Section' }));
62
+ console.log();
63
+
64
+ console.log(color.bold('━━━ Logo composer ━━━'));
65
+ console.log();
66
+
67
+ console.log(ascii.logo('LOGO', {
68
+ font: 'big',
69
+ colorFn: (t) => gradient(t, ['#ff6b6b', '#feca57', '#48dbfb']),
70
+ borderStyle: 'rounded',
71
+ }));
72
+
73
+ console.log();
74
+ console.log(color.bold('━━━ ascii.measure ━━━'));
75
+ console.log();
76
+ const dim = ascii.measure('Hello World', { font: 'big' });
77
+ console.log(` Banner dimensions: ${dim.width} × ${dim.height}`);
78
+ console.log();
79
+
80
+ console.log(color.bold(color.green('✓ ASCII test complete')));
81
+ console.log();