ansimax 1.1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,274 @@
1
+ # Changelog
2
+
3
+ All notable changes to **ansimax** are documented in this file.
4
+ This project follows [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [1.1.1] — bug fixes + improved examples
7
+
8
+ Patch release with two bug fixes from real-world testing of v1.1.0, plus
9
+ a cleaner set of examples covering every public API.
10
+
11
+ ### Fixed
12
+
13
+ - **`box()` no longer crashes with object padding.** Previously, calling
14
+ `box(text, { padding: { x: 2, y: 1 } })` threw `RangeError: Invalid
15
+ array length` because the code assumed `padding` was always a number.
16
+ Now non-numeric padding falls back to the default (`1`) gracefully.
17
+ The fix also covers `NaN`, `Infinity`, strings, and other malformed
18
+ input.
19
+ - **`components.menu()` cursor restoration on abrupt exit.** Previously,
20
+ killing the process while a menu was active (Ctrl+C, kill signal)
21
+ left the terminal cursor hidden because the cleanup handler only ran
22
+ through the normal menu lifecycle. Now `SIGINT`, `SIGTERM`, and
23
+ `exit` events trigger an emergency cursor restoration, so the terminal
24
+ is always left in a sane state.
25
+
26
+ ### Changed — Examples
27
+
28
+ - Replaced all examples in `/examples` with a clean set covering every
29
+ public API:
30
+ - `01-quick-smoke.ts` — verifies major imports
31
+ - `02-colors-gradients.ts` — color fns, gradients, `colorPresets`
32
+ - `03-ascii-banners.ts` — banners + 6 box styles + dividers
33
+ - `04-trees.ts` — builder + plain-data + 4 styles + algorithms
34
+ - `05-components.ts` — tables, badges, status, timeline, etc.
35
+ - `06-pixel-art.ts` — sprites + canvas + transforms
36
+ - `07-animations.ts` — typewriter, fade, slide, pulse, wave, glitch
37
+ - `08-loaders.ts` — spinners + tasks + countdown
38
+ - `09-themes.ts` — 8 themes + listeners + isolation
39
+ - `10-everything.ts` — comprehensive showcase
40
+ - `all-in-one.mjs` — ESM (`import`) version, no TypeScript
41
+ - `all-in-one.cjs` — CommonJS (`require`) version, no TypeScript
42
+ - All examples now import from `'ansimax'` (npm registry) instead of
43
+ `'../src/index.js'`, making them copy-pasteable into user projects.
44
+ - READMEs updated with animations + loaders preview GIFs in the
45
+ header, and an `all-ansimax.gif` showcase near the footer.
46
+
47
+ ### Notes
48
+
49
+ - No API changes — `1.1.1` is a drop-in replacement for `1.1.0`.
50
+ - No new dependencies — still zero runtime deps.
51
+ - All 1848 tests still pass.
52
+
53
+ ---
54
+
55
+ ## [1.1.0] — comprehensive hardening + new features
56
+
57
+ A massive robustness pass across every module, plus a new `trees` module,
58
+ new API surfaces, and broader test coverage (~1700+ tests across 16 suites).
59
+
60
+ **Backwards compatibility:** 100% preserved. All existing APIs work
61
+ identically — only defensive validation, new features, and bug fixes.
62
+
63
+ ---
64
+
65
+ ### Added — Trees (`trees/index.ts`) — NEW MODULE
66
+
67
+ Hierarchical text renderer inspired by Rich's `Tree`.
68
+
69
+ - **Builder API** — `tree('root').add('child').add('grandchild')`. `addLeaf()` returns the parent for fluent sibling-adds.
70
+ - **Plain-data API** — `renderTree({ label, children: [...] })` accepts any plain JS object.
71
+ - **4 visual styles** — `'normal'`, `'rounded'` (╰─), `'heavy'` (┣━), `'ascii'` (`+--`). Per-node `style` override mixes styles in one tree.
72
+ - **Per-node colors** — `color: ColorFn` colorizes the label.
73
+ - **Depth-based palette** — `palette: [color1, color2, ...]` cycles colors per depth level. Per-node `color` overrides.
74
+ - **Guide-line colors** — `guideColor` colorizes the `├──`/`│`/`└──` chars separately from labels.
75
+ - **Per-node icons** — `icon: '📁'` renders before the label.
76
+ - **Multi-line labels** — extra lines align with proper continuation glyph. CRLF normalized to LF.
77
+ - **Collapsed subtrees** — `collapse: N` hides the first N children, shows `[+N hidden]`.
78
+ - **Max depth truncation** — `maxDepth` truncates deep trees, shows `[+N more]` markers.
79
+ - **Indent option** — pad the entire tree with N leading spaces.
80
+ - **`renderTreeStream(root, opts)`** — generator that yields one rendered line at a time.
81
+ - **`measureTree(root, opts)`** — `{ width, height }` for layout decisions.
82
+ - **`walkTree(root, visitor)`** — depth-first traversal with cycle detection.
83
+ - **`findInTree(root, predicate)`** — locate first matching node.
84
+ - **`countNodes(root)`** — total node count.
85
+ - **`mapTree(root, fn)`** — transform every node, returns new tree (input untouched).
86
+ - **`filterTree(root, predicate, opts?)`** — keep matching nodes with optional `prune` mode.
87
+ - **Cycle detection** — `walkTree` / `mapTree` throw a clear error on circular references instead of stack overflow.
88
+ - **Strict validation** — non-string labels coerced, null/array root rejected.
89
+
90
+ ### Added — Configuration (`configure.ts`)
91
+
92
+ - **`onConfigKeyChange(key, listener)`** — subscribe to changes of a specific config key only. Listener fires with `(newValue, oldValue)`.
93
+ - **`pauseListeners()`/`resumeListeners()`** — batch multiple updates without flooding subscribers; resume flushes a single notification.
94
+ - **`withConfig(overrides, fn)`** — temporarily override config for a sync or async block, restoring previous state automatically (even on throw).
95
+ - **`strict` mode** — `configure(opts, { strict: true })` rejects unknown keys with `RangeError`; useful for catching typos in config files.
96
+ - **`DEFAULTS` exported** — `Object.freeze`d, accessible to consumers as `CONFIG_DEFAULTS`.
97
+ - **No-op detection** — `configure({})` or setting unchanged values no longer fires listeners.
98
+ - **Soft theme fallback** — uses `themes.tryUse` instead of `themes.use` so configure() doesn't throw on themes registered later.
99
+ - **Validation hardening** — `null`/array opts rejected, empty-string `theme`/`locale`/`asciiFont` rejected.
100
+
101
+ ### Added — Colors (`colors/index.ts`)
102
+
103
+ - **Adaptive escape cache** — `_fgEscCache` / `_bgEscCache` packed-RGB keyed, bounded LRU (512 entries). Gradient animations now 10–50× faster on repeated colors.
104
+ - **`clearColorCache()`** exported for tests and post-level-change cleanup.
105
+ - **`registerPreset(name, stops)`** — register custom gradient presets accessible via `color.<name>`.
106
+ - **`listPresets()`** — runtime list of available presets.
107
+ - **Reserved-preset guard** — registering presets with names like `bold`, `red`, `gradient` throws with a clear conflict message.
108
+ - **Text coercion** — `color.red(42)` now returns `"\x1b[31m42\x1b[0m"` (chalk/kleur compatibility).
109
+ - **NaN/Infinity-safe RGB** — `Infinity → 255`, `-Infinity → 0`, `NaN → 0` in `clampRgb`/`clamp256`.
110
+ - **`compose` filters non-functions** — `compose(red, null, bold)` works (null silently ignored).
111
+ - **`compose` swallows extractor errors** — user fns that throw on `extractOpen` skipped.
112
+ - **`gradient` single-stop colors statically** — consistent with CSS `linear-gradient` UX.
113
+ - **`gradient` defensive** — null/undefined/empty stops return text unchanged. Non-string text coerced. Grapheme iteration preserves emoji.
114
+ - **Bare `\x1b` literal in gradient** — malformed ANSI doesn't corrupt output.
115
+
116
+ ### Added — Themes (`themes/index.ts`)
117
+
118
+ - **Per-instance isolation** — `createTheme()` instances have their own registry. Registering a theme on one no longer leaks into others. Critical for multi-tenant SSR.
119
+ - **`tryUse(name)`** — tolerant theme switch returning `boolean` instead of throwing.
120
+ - **`onChange(listener)`** — subscribe to theme changes, returns unsubscribe. Errors swallowed.
121
+ - **`unregister(name)`** — remove themes, throws if removing the active one.
122
+ - **Background color helpers** — `bgPrimary`, `bgSecondary`, `bgAccent`, `bgSuccess`, `bgWarning`, `bgError`, `bgInfo`, `bgMuted`, `bgSurface`.
123
+ - **`success` color with fallback** — built-ins define it; user themes without `success` fall back to `accent`.
124
+ - **`style(name)` dynamic accessor** — `theme.style('primary')(text)` for config-driven styling. Identity fn for unknown names (no throw).
125
+ - **HEX_RE consistent** — `#` optional, matches colors module.
126
+ - **Strict validation** — `register()` rejects non-string/empty names, null/array defs, non-array gradient, short gradient (< 2 stops).
127
+ - **`BannerOpts` interface** — explicit type instead of fragile `Omit<Parameters<...>>` derivation.
128
+
129
+ ### Added — Animations (`animations/index.ts`)
130
+
131
+ - **Crash-safe cursor restore** — `exit/SIGINT/SIGTERM` handlers force-restore cursor even on uncaught exceptions.
132
+ - **Reference-counted `hideCursor`/`showCursor`** — concurrent animations don't reveal the cursor early.
133
+ - **`animate.delay(ms)` helper** — compatible with `sequence`/`chain`. Pause respecting signal.
134
+ - **`animate.parallel({ timeout })`** — race steps against a timeout to prevent hangs.
135
+ - **`animate.parallel` swallows per-step errors** — one failing step doesn't reject the whole Promise.all.
136
+ - **Signal propagation** — parallel steps receive the parent signal.
137
+ - **`wave` with single color** — renders statically with that color (better UX than skip).
138
+ - **`wave` with empty palette** — renders plain.
139
+ - **`reveal` with `steps` option** — scales with text length by default (`Math.min(60, Math.max(10, len*2))`).
140
+ - **`pulse`/`glitch` final write use `safeWriteAsync`** — backpressure-aware.
141
+ - **`safeWriteAsync`/`safeWrite`** wrappers swallow stream errors.
142
+ - **Hooks errors swallowed** — `onFrame`/`onDone`/`onAbort` errors don't break the loop.
143
+
144
+ ### Added — ASCII (`ascii/index.ts`)
145
+
146
+ - **Strict input validation** — `ensureString()` throws `TypeError` with clear messages for non-string text.
147
+ - **`ensureFontMap` validates type** — rejects null/array/non-object font maps.
148
+ - **`hasFont(name)`** — check if a font is registered without throwing.
149
+ - **`measure(text, font?, letterSpacing?)`** — get `{ width, height }` without paying full render cost.
150
+ - **`stream(text, { signal })`** — pre-aborted yields nothing; aborted mid-stream stops at next poll.
151
+ - **Cache key uses `\u0001` separator** — eliminates collision risk from font names containing `|`.
152
+ - **Grapheme iteration** in `renderFont` — preserves surrogate pairs and emoji.
153
+ - **`box`/`divider`/`logo` defensive** against -Infinity from `Math.max([])`, width 0, empty text.
154
+ - **`colorEachVisibleChar` bare `\x1b` literal** — non-CSI escapes emitted instead of consumed.
155
+
156
+ ### Added — Loaders (`loaders/index.ts`)
157
+
158
+ - **`spin` coerces non-string text/prefix/suffix**.
159
+ - **`spin` clamps NaN interval** to default 80.
160
+ - **`progress` clamps NaN/Infinity percent** to 0.
161
+ - **`progress` empty-char fallback**.
162
+ - **`countdown(NaN)` → 0**, negative → 0.
163
+ - **`tasks(non-array)` → `[]`** instead of crash.
164
+
165
+ ### Added — Frames (`frames/index.ts`)
166
+
167
+ - **Reference-counted cursor** — concurrent `play()` + `live()` + animations safe.
168
+ - **`registerCrashHandlers()`** — restore cursor on exit/SIGINT/SIGTERM.
169
+ - **`resetFramesCursorCount()`** exported for tests.
170
+ - **`play(non-array)`** — no-op controller instead of crash.
171
+ - **`play({ repeat: 0 })`** — explicit infinite loop.
172
+ - **`play({ repeat: -N })`** — negative now falls back to 1 (was infinite — dangerous on bad input).
173
+ - **`fps` capped at 60** — prevents CPU saturation with `fps: 9999`.
174
+ - **`generate` swallows per-frame errors** — one bad frame doesn't poison the sequence.
175
+ - **`generate` coerces non-string returns**.
176
+ - **`morph(steps=1)` clamps to 2** — avoids division by zero.
177
+ - **All presets defensive** — width=0 OK, NaN fallback, empty char fallback.
178
+ - **`live` with stop() idempotent** — multiple stops safe via `wasRunning` flag.
179
+
180
+ ### Added — Components (`components/index.ts`)
181
+
182
+ - **`progressBar(NaN/Infinity)` → 0%** — defensive numeric inputs.
183
+ - **`progressBar` with single-stop gradient** — colors statically (consistent with `gradient()` UX).
184
+ - **`badge` SGR codes validated** — NaN fg/bg falls back to defaults.
185
+ - **`table(non-array)` → `''`**, filters non-array rows, coerces non-string cells.
186
+ - **`columns(cols<1)` clamps to default** — no longer throws.
187
+ - **`columns(non-array)` → `''`**.
188
+ - **`timeline(non-array)` → `''`**, coerces event labels.
189
+ - **`section(NaN width)` falls back to terminal cols**.
190
+ - **`status({ icon: '' })` omits icon** — coherent with `icon: null`.
191
+ - **`menu([])` returns `MENU_CANCELLED`** instead of throwing (safer for runtime data).
192
+ - **`menu(non-array)` → `MENU_CANCELLED`**.
193
+ - **`menu` cleanup symmetric** — every path that hides cursor also restores it.
194
+ - **`menu` `safeResolve` prevents double-resolve** races.
195
+
196
+ ### Added — Images (`images/index.ts`)
197
+
198
+ - **All numeric inputs clamped** — `MAX_DIMENSION = 10000` prevents OOM on `Infinity`.
199
+ - **`renderPixelArt(non-array)` → `''`** instead of crash.
200
+ - **`ensurePixelGrid`** filters malformed rows.
201
+ - **`flipHorizontal`/`flipVertical`/`rotate90` defensive** — non-array input returns `[]`.
202
+ - **`gradientRect` validates colors array** — clear errors for empty/all-invalid.
203
+ - **`gradientRect` single-stop renders solid fill** — better UX.
204
+ - **`gradientRect(Infinity width)` clamps** to MAX_DIMENSION.
205
+ - **`createCanvas(NaN/0)` → 1×1**.
206
+ - **`createCanvas(Infinity)`** clamps to MAX_DIMENSION.
207
+ - **`canvas.set/get` reject non-finite coords** as no-op.
208
+ - **`canvas.drawRect/Circle/Sprite` defensive** against NaN, negative dims, non-array sprites.
209
+ - **`canvas.pixels` getter returns deep clone** — callers can't mutate canvas state.
210
+ - **`canvas.print` with try/catch** — stream torn down doesn't crash.
211
+ - **ANSI cache LRU bounded** at 1024 entries — survives massive color counts.
212
+ - **`Pixel` and `PixelGrid` exported** for typed consumers.
213
+
214
+ ### Added — Utils (`utils/ansi.ts`)
215
+
216
+ - **`OSC`, `ST`, `BEL` constants** exported.
217
+ - **`setTitle(text)`** — set terminal window title (OSC 2). Control chars stripped.
218
+ - **`link(text, url)`** — clickable hyperlink (OSC 8). Supported in iTerm2, Terminal.app, WezTerm, Kitty, modern xterm.
219
+ - **`bell()`** — terminal bell.
220
+ - **`cursor.position()`** — query position (CSI 6n).
221
+ - **`cursor.nextLine()`/`prevLine()`** — line-aware navigation.
222
+ - **`screen.clearAll()`** — alias for `clear()`.
223
+ - **`DEFAULT_TERM_COLS = 80`, `DEFAULT_TERM_ROWS = 24`** exported.
224
+ - **`writeAsync({ timeout })`** option — prevents infinite hangs on broken streams.
225
+ - **`OutputBuffer.pushIf(cond, str)`** — conditional append.
226
+ - **`detectColorSupport`** improved — TERM truecolor/24bit detection, 256 substring match, rxvt support, try/catch around `os.release()`.
227
+ - **All numeric inputs clamped** — `cursor.up(NaN)` → min=1, `fgRgb(Infinity, ...)` → 0.
228
+ - **`ensureString` coercion** — all writes accept any input.
229
+ - **`sleep(NaN/negative)` clamped** to 0.
230
+
231
+ ### Added — Utils (`utils/helpers.ts`)
232
+
233
+ - **`once(fn)`** — invoke a function exactly once.
234
+ - **`escapeRegex(str)`** — escape regex metacharacters.
235
+ - **`safeJson(value, indent?)`** — JSON.stringify handling BigInt and circular references.
236
+ - **`padBoth(str, width, ch?)`** — pad both sides equally, Unicode-aware.
237
+ - **`nextTick(cb)`** — `setImmediate` fallback to `setTimeout(0)`.
238
+ - **`memoize` with `{ keyFn }` option** — multi-argument memoization.
239
+ - **`onResize` with implicit throttle (50ms default)** — coalesces rapid resize events.
240
+ - **`debounce` with `maxWait` option** — guarantees invocation within window.
241
+ - **`diffLines` with `type: 'added' | 'removed' | 'changed'`** — richer damage tracking.
242
+ - **`gradientColor` auto-clamps `t`** — values outside [0,1] clamped automatically. NaN → 0.
243
+ - **`stripAnsi`/`visibleLen` defensive** against non-string inputs.
244
+ - **`termSize` validates** cols/rows > 0.
245
+
246
+ ---
247
+
248
+ ### Test infrastructure
249
+
250
+ - **~1700+ tests across 16 suites**, all green.
251
+ - Coverage: ~98% statements, ~95% branches, ~99% functions, ~99% lines.
252
+ - All test files use `FORCE_COLOR=3` + `resetColorSupportCache()` in `beforeEach` for isolation.
253
+ - New test isolation helpers exported: `resetCursorRefCount`, `resetFramesCursorCount`, `resetLoaderCursorCount`, `clearAnsiCache`, `clearThemeColorCache`, `clearColorCache`, `clearRenderCache`, `resetConfig`.
254
+
255
+ ### Examples
256
+
257
+ 6 production-grade examples in `/examples`:
258
+
259
+ - `01-cli-installer.ts` — npm-create style installer (banner + hierarchical tasks + status icons + summary box).
260
+ - `02-live-dashboard.ts` — real-time dashboard (frames.live + service table + gradient bars + onResize + SIGINT cleanup).
261
+ - `03-pixel-art-game.ts` — bouncing rocket sprite (canvas + alpha blending + sunset gradient + FPS counter + drift-corrected loop).
262
+ - `04-interactive-deploy.ts` — interactive menu + multi-select + loader.multi + createTheme + onConfigChange.
263
+ - `05-tree-visualizations.ts` — filesystem + dependency + JSON + decision trees (4 scenarios, walk + measure bonus).
264
+ - `06-everything-together.ts` — comprehensive showcase touching every module (NEW).
265
+
266
+ ---
267
+
268
+ ## [1.0.0] — initial release
269
+
270
+ - Core modules: `color`, `animate`, `ascii`, `loader`, `frames`, `components`, `themes`, `images`, `configure`.
271
+ - TypeScript types exported.
272
+ - Adaptive color rendering (NO_COLOR / FORCE_COLOR / TTY detection).
273
+ - AbortSignal support across all blocking APIs.
274
+ - 750+ tests, 85%+ coverage.
package/README.es.md CHANGED
@@ -7,7 +7,7 @@
7
7
  _Colores • Gradientes • Animaciones • ASCII Art • Pixel Art • Árboles • Componentes • Temas_
8
8
 
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
10
- [![npm](https://img.shields.io/badge/npm-v1.1.0-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
10
+ [![npm](https://img.shields.io/badge/npm-v1.1.1-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
11
11
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg?style=flat-square)](tsconfig.json)
12
12
  [![Coverage](https://img.shields.io/badge/coverage-98%25-brightgreen.svg?style=flat-square)](#testing)
13
13
  [![Tests](https://img.shields.io/badge/tests-1700%2B%20passing-brightgreen.svg?style=flat-square)](#testing)
@@ -20,6 +20,27 @@ _Colores • Gradientes • Animaciones • ASCII Art • Pixel Art • Árboles
20
20
 
21
21
  ---
22
22
 
23
+ <div align="center">
24
+
25
+ ### 🎬 Vista previa
26
+
27
+ <table>
28
+ <tr>
29
+ <td align="center">
30
+ <strong>Animaciones</strong><br/>
31
+ <img src="media/animations.gif" alt="Demo de animaciones de Ansimax" width="420"/>
32
+ </td>
33
+ <td align="center">
34
+ <strong>Loaders</strong><br/>
35
+ <img src="media/loaders.gif" alt="Demo de loaders de Ansimax" width="420"/>
36
+ </td>
37
+ </tr>
38
+ </table>
39
+
40
+ </div>
41
+
42
+ ---
43
+
23
44
  ## 🌟 ¿Qué es Ansimax?
24
45
 
25
46
  Ansimax es una **librería de renderizado todo-en-uno** para construir interfaces de terminal hermosas en Node.js. Un solo paquete reemplaza un stack de más de 8 dependencias — colores, gradientes, ASCII art, spinners, barras de progreso, tablas, menús, árboles, temas, pixel art — combinadas en una única API coherente de TypeScript con **cero dependencias en runtime**.
@@ -248,7 +269,7 @@ components.table([
248
269
  ['loaders', color.green('● listo'), '100%'],
249
270
  ], { borderStyle: 'rounded' });
250
271
 
251
- components.badge('VERSION', 'v1.1.0');
272
+ components.badge('VERSION', 'v1.1.1');
252
273
  components.badge('BUILD', 'passing');
253
274
  ```
254
275
 
@@ -336,21 +357,33 @@ tenantA.register('custom', miDef); // no se filtra a tenantB
336
357
 
337
358
  ## 📚 Ejemplos
338
359
 
339
- Siete ejemplos de calidad de producción se publican en el paquete npm y son ejecutables directamente. Los encuentras en [`/examples`](./examples) después de instalar:
360
+ Once ejemplos de calidad de producción se publican en el paquete npm y son ejecutables directamente. Los encuentras en [`/examples`](./examples) después de instalar:
340
361
 
341
362
  | Archivo | Qué demuestra |
342
363
  |---|---|
343
- | `trees-basic.ts` | Ejemplo mínimo de árbolesAPI builder + algoritmos |
344
- | `01-cli-installer.ts` | Instalador estilo npm-create banner + tareas jerárquicas + íconos de estado + caja resumen |
345
- | `02-live-dashboard.ts` | Dashboard en tiempo real — `frames.live` + tabla de servicios + barras con gradiente + `onResize` + limpieza SIGINT |
346
- | `03-pixel-art-game.ts` | Sprite de cohete rebotando — canvas + alpha blending + gradiente + contador de FPS + loop con corrección de drift |
347
- | `04-interactive-deploy.ts` | Menú + multi-select + `loader.multi` + `createTheme` + `onConfigChange` |
348
- | `05-tree-visualizations.ts` | Árboles de filesystem + dependencias + JSON + decisión (`walk` + `measure` extra) |
349
- | `06-everything-together.ts` | Showcase completo cada módulo ejercitado en un demo cohesivo |
364
+ | `01-quick-smoke.ts` | Test rápido de humoverifica que cada import principal funciona |
365
+ | `02-colors-gradients.ts` | Toda función de color, tipos de gradiente, presets, compose, API chain |
366
+ | `03-ascii-banners.ts` | Banners (`big`/`small`), 6 estilos de caja, divisores, compositor de logos |
367
+ | `04-trees.ts` | Tree builder + API data-plana, 4 estilos, palettes, algoritmos (walk/find/map/filter) |
368
+ | `05-components.ts` | Tablas, badges, status, secciones, columnas, timelines, barras de progreso |
369
+ | `06-pixel-art.ts` | Sprites, canvas personalizado, gradient rects con dither, transforms (flip/rotate) |
370
+ | `07-animations.ts` | typewriter, fadeIn/Out, slide, pulse, wave, glitch, reveal |
371
+ | `08-loaders.ts` | Estilos de spinner, progreso animado, tareas jerárquicas, cuenta regresiva |
372
+ | `09-themes.ts` | Los 8 temas integrados, listeners, registro de temas personalizados, aislamiento por instancia |
373
+ | `10-everything.ts` | Showcase completo — cada módulo ejercitado en un demo cohesivo |
374
+ | `all-in-one.mjs` | Demo completo en **ESM** (JS puro con `import`) — sin necesidad de TypeScript |
375
+ | `all-in-one.cjs` | Demo completo en **CommonJS** (JS puro con `require`) — sin necesidad de TypeScript |
350
376
 
351
377
  Ejecuta cualquier ejemplo con:
352
378
  ```bash
353
- npx tsx examples/06-everything-together.ts
379
+ # Ejemplos en TypeScript
380
+ npx tsx examples/10-everything.ts
381
+
382
+ # JS puro — ESM
383
+ node examples/all-in-one.mjs
384
+
385
+ # JS puro — CommonJS
386
+ node examples/all-in-one.cjs
354
387
  ```
355
388
 
356
389
  ---
@@ -604,7 +637,7 @@ ansimax/
604
637
  │ ├── trees/ Builder de árboles + algoritmos
605
638
  │ ├── utils/ Primitivas ANSI + helpers
606
639
  │ └── configure.ts Config global + subscribers
607
- ├── examples/ 7 ejemplos de calidad de producción
640
+ ├── examples/ 10 ejemplos (TS) + 2 (JS — ESM y CJS) — todas las funciones cubiertas
608
641
  └── __tests__/ 16 test suites, 1700+ tests
609
642
  ```
610
643
 
@@ -612,6 +645,17 @@ ansimax/
612
645
 
613
646
  ## 📝 Changelog
614
647
 
648
+ ### v1.1.1 — Fixes de bugs + ejemplos limpios
649
+
650
+ Release patch que arregla dos bugs encontrados en testing real de v1.1.0, más una carpeta de ejemplos refrescada.
651
+
652
+ - 🐛 **Fix de crash en `box()`** con `padding: { x, y }` — ahora cae graciosamente al default para padding no-numérico (también maneja NaN, Infinity, strings)
653
+ - 🐛 **Fix de leak de cursor en `components.menu()`** al salir abruptamente (Ctrl+C, SIGTERM) — handlers de cleanup de emergencia ahora restauran el cursor incluso cuando el proceso se mata mid-menu
654
+ - 📚 **Nuevos ejemplos** — 10 ejemplos en TypeScript + 2 variantes en JS puro (`all-in-one.mjs` para ESM, `all-in-one.cjs` para CommonJS)
655
+ - 📖 **READMEs actualizados** — GIFs de preview en el header, GIF de showcase completo en el footer
656
+
657
+ Sin cambios en la API — drop-in replacement para `1.1.0`.
658
+
615
659
  ### v1.1.0 — Hardening exhaustivo + nuevas features
616
660
 
617
661
  Una pasada masiva de robustez sobre todo módulo, más un nuevo módulo `trees`. **100% retrocompatible** — toda API existente funciona idéntica.
@@ -676,6 +720,18 @@ Si Ansimax te ahorra tiempo, por favor dale estrella al repo en [GitHub](https:/
676
720
 
677
721
  ---
678
722
 
723
+ ## 🎬 Showcase completo
724
+
725
+ <div align="center">
726
+
727
+ <img src="media/all-ansimax.gif" alt="Showcase completo de Ansimax — todo en acción" width="720"/>
728
+
729
+ _Todas las funciones en acción — typewriter, gradientes, banners ASCII, árboles, tablas, spinners, temas y pixel art_
730
+
731
+ </div>
732
+
733
+ ---
734
+
679
735
  ## 📜 Licencia
680
736
 
681
737
  [Apache License 2.0](LICENSE) © 2026 Brashkie
@@ -694,4 +750,4 @@ Ansimax está licenciada bajo **Apache License, Version 2.0** — una licencia p
694
750
 
695
751
  Si Ansimax te ayuda a hacer mejores CLIs, ¡dale ⭐ en [GitHub](https://github.com/Brashkie/ansimax)!
696
752
 
697
- </div>
753
+ </div>
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  _Colors • Gradients • Animations • ASCII Art • Pixel Art • Trees • Components • Themes_
8
8
 
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
10
- [![npm](https://img.shields.io/badge/npm-v1.1.0-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
10
+ [![npm](https://img.shields.io/badge/npm-v1.1.1-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
11
11
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg?style=flat-square)](tsconfig.json)
12
12
  [![Coverage](https://img.shields.io/badge/coverage-98%25-brightgreen.svg?style=flat-square)](#testing)
13
13
  [![Tests](https://img.shields.io/badge/tests-1700%2B%20passing-brightgreen.svg?style=flat-square)](#testing)
@@ -20,6 +20,27 @@ _Colors • Gradients • Animations • ASCII Art • Pixel Art • Trees • C
20
20
 
21
21
  ---
22
22
 
23
+ <div align="center">
24
+
25
+ ### 🎬 Preview
26
+
27
+ <table>
28
+ <tr>
29
+ <td align="center">
30
+ <strong>Animations</strong><br/>
31
+ <img src="media/animations.gif" alt="Ansimax animations demo" width="420"/>
32
+ </td>
33
+ <td align="center">
34
+ <strong>Loaders</strong><br/>
35
+ <img src="media/loaders.gif" alt="Ansimax loaders demo" width="420"/>
36
+ </td>
37
+ </tr>
38
+ </table>
39
+
40
+ </div>
41
+
42
+ ---
43
+
23
44
  ## 🌟 What is Ansimax?
24
45
 
25
46
  Ansimax is a **batteries-included rendering library** for building beautiful terminal UIs in Node.js. One package replaces a stack of 8+ dependencies — colors, gradients, ASCII art, spinners, progress bars, tables, menus, trees, themes, pixel art — combined into a single coherent TypeScript API with **zero runtime dependencies**.
@@ -248,7 +269,7 @@ components.table([
248
269
  ['loaders', color.green('● ready'), '100%'],
249
270
  ], { borderStyle: 'rounded' });
250
271
 
251
- components.badge('VERSION', 'v1.1.0');
272
+ components.badge('VERSION', 'v1.1.1');
252
273
  components.badge('BUILD', 'passing');
253
274
  ```
254
275
 
@@ -336,21 +357,33 @@ tenantA.register('custom', myDef); // doesn't leak to tenantB
336
357
 
337
358
  ## 📚 Examples
338
359
 
339
- Seven production-grade examples ship in the npm package and are runnable directly. Find them in [`/examples`](./examples) once you install:
360
+ Eleven production-grade examples ship in the npm package and are runnable directly. Find them in [`/examples`](./examples) once you install:
340
361
 
341
362
  | File | What it demonstrates |
342
363
  |---|---|
343
- | `trees-basic.ts` | Minimal trees examplebuilder API + algorithms |
344
- | `01-cli-installer.ts` | npm-create style installer banner + hierarchical tasks + status icons + summary box |
345
- | `02-live-dashboard.ts` | Real-time dashboard — `frames.live` + service table + gradient bars + `onResize` + SIGINT cleanup |
346
- | `03-pixel-art-game.ts` | Bouncing rocket sprite — canvas + alpha blending + gradient + FPS counter + drift-corrected loop |
347
- | `04-interactive-deploy.ts` | Menu + multi-select + `loader.multi` + `createTheme` + `onConfigChange` |
348
- | `05-tree-visualizations.ts` | Filesystem + dependency + JSON + decision trees (`walk` + `measure` bonus) |
349
- | `06-everything-together.ts` | Comprehensive showcase every module exercised in one cohesive demo |
364
+ | `01-quick-smoke.ts` | Quick smoke testverifies every major import works |
365
+ | `02-colors-gradients.ts` | Every color fn, gradient types, presets, compose, chain API |
366
+ | `03-ascii-banners.ts` | Banners (`big`/`small`), 6 box styles, dividers, logo composer |
367
+ | `04-trees.ts` | Tree builder + plain-data API, 4 styles, palettes, algorithms (walk/find/map/filter) |
368
+ | `05-components.ts` | Tables, badges, status, sections, columns, timelines, progress bars |
369
+ | `06-pixel-art.ts` | Sprites, custom canvas, gradient rects with dither, transforms (flip/rotate) |
370
+ | `07-animations.ts` | typewriter, fadeIn/Out, slide, pulse, wave, glitch, reveal |
371
+ | `08-loaders.ts` | spinner styles, animated progress, hierarchical tasks, countdown |
372
+ | `09-themes.ts` | All 8 built-in themes, listeners, custom theme registration, per-instance isolation |
373
+ | `10-everything.ts` | Comprehensive showcase — every module exercised in one cohesive demo |
374
+ | `all-in-one.mjs` | Full demo in **ESM** (plain JS with `import`) — no TypeScript needed |
375
+ | `all-in-one.cjs` | Full demo in **CommonJS** (plain JS with `require`) — no TypeScript needed |
350
376
 
351
377
  Run any example with:
352
378
  ```bash
353
- npx tsx examples/06-everything-together.ts
379
+ # TypeScript examples
380
+ npx tsx examples/10-everything.ts
381
+
382
+ # Plain JS — ESM
383
+ node examples/all-in-one.mjs
384
+
385
+ # Plain JS — CommonJS
386
+ node examples/all-in-one.cjs
354
387
  ```
355
388
 
356
389
  ---
@@ -604,7 +637,7 @@ ansimax/
604
637
  │ ├── trees/ Tree builder + algorithms
605
638
  │ ├── utils/ ANSI primitives + helpers
606
639
  │ └── configure.ts Global config + subscribers
607
- ├── examples/ 7 production-grade examples
640
+ ├── examples/ 10 examples (TS) + 2 (JS — ESM & CJS) — all features covered
608
641
  └── __tests__/ 16 test suites, 1700+ tests
609
642
  ```
610
643
 
@@ -612,6 +645,17 @@ ansimax/
612
645
 
613
646
  ## 📝 Changelog
614
647
 
648
+ ### v1.1.1 — Bug fixes + cleaner examples
649
+
650
+ Patch release fixing two bugs from real-world v1.1.0 testing, plus a refreshed examples folder.
651
+
652
+ - 🐛 **Fixed `box()` crash** with `padding: { x, y }` — now gracefully falls back to default for non-numeric padding (also handles NaN, Infinity, strings)
653
+ - 🐛 **Fixed `components.menu()` cursor leak** on abrupt exit (Ctrl+C, SIGTERM) — emergency cleanup handlers now restore the cursor even when the process is killed mid-menu
654
+ - 📚 **New examples** — 10 TypeScript examples + 2 plain JS variants (`all-in-one.mjs` for ESM, `all-in-one.cjs` for CommonJS)
655
+ - 📖 **READMEs updated** — preview GIFs in the header, comprehensive showcase GIF in the footer
656
+
657
+ No API changes — drop-in replacement for `1.1.0`.
658
+
615
659
  ### v1.1.0 — Comprehensive hardening + new features
616
660
 
617
661
  A massive robustness pass across every module, plus a new `trees` module. **100% backward compatible** — every existing API works identically.
@@ -676,6 +720,18 @@ If Ansimax saves you time, please star the repo on [GitHub](https://github.com/B
676
720
 
677
721
  ---
678
722
 
723
+ ## 🎬 Full showcase
724
+
725
+ <div align="center">
726
+
727
+ <img src="media/all-ansimax.gif" alt="Ansimax full showcase — everything in action" width="720"/>
728
+
729
+ _All features in action — typewriter, gradients, ASCII banners, trees, tables, spinners, themes, and pixel art_
730
+
731
+ </div>
732
+
733
+ ---
734
+
679
735
  ## 📜 License
680
736
 
681
737
  [Apache License 2.0](LICENSE) © 2026 Brashkie
package/dist/index.js CHANGED
@@ -2264,7 +2264,8 @@ var banner = (text, opts = {}) => {
2264
2264
  var box = (text, opts = {}) => {
2265
2265
  const safe = ensureString2(text, "box(text)");
2266
2266
  const { padding = 1, borderStyle = "rounded", width = null } = opts;
2267
- const safePadding = Math.max(0, Math.floor(padding));
2267
+ const padNum = typeof padding === "number" && Number.isFinite(padding) ? padding : 1;
2268
+ const safePadding = Math.max(0, Math.floor(padNum));
2268
2269
  const b = BOX_STYLES[borderStyle] ?? BOX_STYLES.rounded;
2269
2270
  const lines = safe.split("\n");
2270
2271
  const inner = width != null ? lines.map((l) => padEnd(truncateAnsi(l, width, ""), width)) : lines;
@@ -3677,7 +3678,32 @@ var menu = (items, opts = {}) => {
3677
3678
  }
3678
3679
  cursorHidden = false;
3679
3680
  }
3681
+ try {
3682
+ process.off("SIGINT", emergencyCleanup);
3683
+ process.off("SIGTERM", emergencyCleanup);
3684
+ process.off("exit", emergencyCleanup);
3685
+ } catch {
3686
+ }
3680
3687
  };
3688
+ const emergencyCleanup = () => {
3689
+ if (cursorHidden) {
3690
+ try {
3691
+ out.write(cursor.show());
3692
+ } catch {
3693
+ }
3694
+ cursorHidden = false;
3695
+ }
3696
+ try {
3697
+ if (inp.setRawMode) inp.setRawMode(false);
3698
+ } catch {
3699
+ }
3700
+ };
3701
+ try {
3702
+ process.once("SIGINT", emergencyCleanup);
3703
+ process.once("SIGTERM", emergencyCleanup);
3704
+ process.once("exit", emergencyCleanup);
3705
+ } catch {
3706
+ }
3681
3707
  try {
3682
3708
  emit(cursor.hide());
3683
3709
  cursorHidden = true;
package/dist/index.mjs CHANGED
@@ -2092,7 +2092,8 @@ var banner = (text, opts = {}) => {
2092
2092
  var box = (text, opts = {}) => {
2093
2093
  const safe = ensureString2(text, "box(text)");
2094
2094
  const { padding = 1, borderStyle = "rounded", width = null } = opts;
2095
- const safePadding = Math.max(0, Math.floor(padding));
2095
+ const padNum = typeof padding === "number" && Number.isFinite(padding) ? padding : 1;
2096
+ const safePadding = Math.max(0, Math.floor(padNum));
2096
2097
  const b = BOX_STYLES[borderStyle] ?? BOX_STYLES.rounded;
2097
2098
  const lines = safe.split("\n");
2098
2099
  const inner = width != null ? lines.map((l) => padEnd(truncateAnsi(l, width, ""), width)) : lines;
@@ -3505,7 +3506,32 @@ var menu = (items, opts = {}) => {
3505
3506
  }
3506
3507
  cursorHidden = false;
3507
3508
  }
3509
+ try {
3510
+ process.off("SIGINT", emergencyCleanup);
3511
+ process.off("SIGTERM", emergencyCleanup);
3512
+ process.off("exit", emergencyCleanup);
3513
+ } catch {
3514
+ }
3508
3515
  };
3516
+ const emergencyCleanup = () => {
3517
+ if (cursorHidden) {
3518
+ try {
3519
+ out.write(cursor.show());
3520
+ } catch {
3521
+ }
3522
+ cursorHidden = false;
3523
+ }
3524
+ try {
3525
+ if (inp.setRawMode) inp.setRawMode(false);
3526
+ } catch {
3527
+ }
3528
+ };
3529
+ try {
3530
+ process.once("SIGINT", emergencyCleanup);
3531
+ process.once("SIGTERM", emergencyCleanup);
3532
+ process.once("exit", emergencyCleanup);
3533
+ } catch {
3534
+ }
3509
3535
  try {
3510
3536
  emit(cursor.hide());
3511
3537
  cursorHidden = true;