console-toolkit 1.2.8 → 1.2.10

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.
Files changed (156) hide show
  1. package/README.md +70 -25
  2. package/package.json +26 -6
  3. package/src/alphanumeric/arrows.d.ts +48 -0
  4. package/src/alphanumeric/arrows.js +23 -0
  5. package/src/alphanumeric/fractions.d.ts +65 -0
  6. package/src/alphanumeric/fractions.js +49 -0
  7. package/src/alphanumeric/number-formatters.d.ts +91 -0
  8. package/src/alphanumeric/number-formatters.js +45 -1
  9. package/src/alphanumeric/roman.d.ts +15 -0
  10. package/src/alphanumeric/roman.js +12 -0
  11. package/src/alphanumeric/unicode-cultural-numbers.d.ts +65 -0
  12. package/src/alphanumeric/unicode-cultural-numbers.js +1 -0
  13. package/src/alphanumeric/unicode-letters.d.ts +32 -0
  14. package/src/alphanumeric/unicode-letters.js +8 -0
  15. package/src/alphanumeric/unicode-numbers.d.ts +44 -0
  16. package/src/alphanumeric/unicode-numbers.js +21 -0
  17. package/src/alphanumeric/utils.d.ts +45 -0
  18. package/src/alphanumeric/utils.js +26 -0
  19. package/src/ansi/csi.d.ts +141 -0
  20. package/src/ansi/csi.js +51 -2
  21. package/src/ansi/index.d.ts +26 -0
  22. package/src/ansi/sgr-constants.d.ts +173 -0
  23. package/src/ansi/sgr-state.d.ts +91 -0
  24. package/src/ansi/sgr-state.js +45 -0
  25. package/src/ansi/sgr.d.ts +587 -0
  26. package/src/ansi/sgr.js +426 -6
  27. package/src/box.d.ts +160 -0
  28. package/src/box.js +113 -12
  29. package/src/charts/bars/block-frac-grouped.d.ts +12 -0
  30. package/src/charts/bars/block-frac-grouped.js +6 -0
  31. package/src/charts/bars/block-frac.d.ts +34 -0
  32. package/src/charts/bars/block-frac.js +13 -0
  33. package/src/charts/bars/block-grouped.d.ts +12 -0
  34. package/src/charts/bars/block-grouped.js +6 -0
  35. package/src/charts/bars/block.d.ts +43 -0
  36. package/src/charts/bars/block.js +13 -0
  37. package/src/charts/bars/draw-grouped.d.ts +41 -0
  38. package/src/charts/bars/draw-grouped.js +4 -0
  39. package/src/charts/bars/draw-stacked.d.ts +47 -0
  40. package/src/charts/bars/draw-stacked.js +4 -0
  41. package/src/charts/bars/frac-grouped.d.ts +32 -0
  42. package/src/charts/bars/frac-grouped.js +13 -0
  43. package/src/charts/bars/plain-grouped.d.ts +12 -0
  44. package/src/charts/bars/plain-grouped.js +6 -0
  45. package/src/charts/bars/plain.d.ts +75 -0
  46. package/src/charts/bars/plain.js +27 -0
  47. package/src/charts/columns/block-frac-grouped.d.ts +12 -0
  48. package/src/charts/columns/block-frac-grouped.js +6 -0
  49. package/src/charts/columns/block-frac.d.ts +39 -0
  50. package/src/charts/columns/block-frac.js +13 -0
  51. package/src/charts/columns/block-grouped.d.ts +12 -0
  52. package/src/charts/columns/block-grouped.js +6 -0
  53. package/src/charts/columns/block.d.ts +43 -0
  54. package/src/charts/columns/block.js +13 -0
  55. package/src/charts/columns/draw-grouped.d.ts +41 -0
  56. package/src/charts/columns/draw-grouped.js +4 -0
  57. package/src/charts/columns/draw-stacked.d.ts +39 -0
  58. package/src/charts/columns/draw-stacked.js +4 -0
  59. package/src/charts/columns/frac-grouped.d.ts +37 -0
  60. package/src/charts/columns/frac-grouped.js +13 -0
  61. package/src/charts/columns/plain-grouped.d.ts +12 -0
  62. package/src/charts/columns/plain-grouped.js +6 -0
  63. package/src/charts/columns/plain.d.ts +32 -0
  64. package/src/charts/columns/plain.js +13 -0
  65. package/src/charts/themes/default.d.ts +6 -0
  66. package/src/charts/themes/default.js +1 -0
  67. package/src/charts/themes/rainbow-reversed.d.ts +6 -0
  68. package/src/charts/themes/rainbow-reversed.js +2 -1
  69. package/src/charts/themes/rainbow.d.ts +6 -0
  70. package/src/charts/themes/rainbow.js +1 -0
  71. package/src/charts/utils.d.ts +79 -0
  72. package/src/charts/utils.js +32 -4
  73. package/src/draw-block-frac.d.ts +16 -0
  74. package/src/draw-block-frac.js +14 -0
  75. package/src/draw-block.d.ts +53 -0
  76. package/src/draw-block.js +25 -1
  77. package/src/meta.d.ts +84 -0
  78. package/src/meta.js +64 -0
  79. package/src/output/show.d.ts +55 -0
  80. package/src/output/show.js +28 -0
  81. package/src/output/updater.d.ts +114 -0
  82. package/src/output/updater.js +58 -4
  83. package/src/output/writer.d.ts +87 -0
  84. package/src/output/writer.js +57 -5
  85. package/src/panel.d.ts +402 -0
  86. package/src/panel.js +219 -5
  87. package/src/plot/bitmap.d.ts +80 -0
  88. package/src/plot/bitmap.js +33 -4
  89. package/src/plot/draw-line.d.ts +13 -0
  90. package/src/plot/draw-line.js +8 -0
  91. package/src/plot/draw-rect.d.ts +13 -0
  92. package/src/plot/draw-rect.js +38 -30
  93. package/src/plot/index.d.ts +39 -0
  94. package/src/plot/index.js +22 -0
  95. package/src/plot/to-quads.d.ts +10 -0
  96. package/src/plot/to-quads.js +5 -0
  97. package/src/spinner/index.d.ts +4 -0
  98. package/src/spinner/index.js +0 -2
  99. package/src/spinner/spin.d.ts +13 -0
  100. package/src/spinner/spin.js +13 -2
  101. package/src/spinner/spinner.d.ts +69 -0
  102. package/src/spinner/spinner.js +30 -2
  103. package/src/spinner/spinners.d.ts +34 -0
  104. package/src/spinner/spinners.js +23 -9
  105. package/src/strings/clip.d.ts +21 -0
  106. package/src/strings/clip.js +10 -0
  107. package/src/strings/parse.d.ts +23 -0
  108. package/src/strings/parse.js +7 -0
  109. package/src/strings/split.d.ts +38 -0
  110. package/src/strings/split.js +15 -0
  111. package/src/strings.d.ts +44 -0
  112. package/src/strings.js +34 -4
  113. package/src/style.d.ts +462 -0
  114. package/src/style.js +58 -4
  115. package/src/symbols.d.ts +167 -0
  116. package/src/symbols.js +91 -7
  117. package/src/table/draw-borders.d.ts +38 -0
  118. package/src/table/draw-borders.js +10 -2
  119. package/src/table/index.d.ts +8 -0
  120. package/src/table/index.js +1 -0
  121. package/src/table/table.d.ts +234 -0
  122. package/src/table/table.js +59 -1
  123. package/src/themes/blocks/unicode-half.d.ts +6 -0
  124. package/src/themes/blocks/unicode-half.js +1 -0
  125. package/src/themes/blocks/unicode-thin.d.ts +6 -0
  126. package/src/themes/blocks/unicode-thin.js +1 -0
  127. package/src/themes/lines/ascii-compact.d.ts +6 -0
  128. package/src/themes/lines/ascii-compact.js +1 -0
  129. package/src/themes/lines/ascii-dots.d.ts +6 -0
  130. package/src/themes/lines/ascii-dots.js +1 -0
  131. package/src/themes/lines/ascii-girder.d.ts +6 -0
  132. package/src/themes/lines/ascii-girder.js +1 -0
  133. package/src/themes/lines/ascii-github.d.ts +6 -0
  134. package/src/themes/lines/ascii-github.js +1 -0
  135. package/src/themes/lines/ascii-reddit.d.ts +6 -0
  136. package/src/themes/lines/ascii-reddit.js +1 -0
  137. package/src/themes/lines/ascii-rounded.d.ts +6 -0
  138. package/src/themes/lines/ascii-rounded.js +1 -0
  139. package/src/themes/lines/ascii.d.ts +6 -0
  140. package/src/themes/lines/ascii.js +1 -0
  141. package/src/themes/lines/unicode-bold.d.ts +6 -0
  142. package/src/themes/lines/unicode-bold.js +1 -0
  143. package/src/themes/lines/unicode-rounded.d.ts +6 -0
  144. package/src/themes/lines/unicode-rounded.js +1 -0
  145. package/src/themes/lines/unicode.d.ts +6 -0
  146. package/src/themes/lines/unicode.js +1 -0
  147. package/src/themes/utils.d.ts +33 -0
  148. package/src/themes/utils.js +7 -0
  149. package/src/turtle/draw-line-art.d.ts +19 -0
  150. package/src/turtle/draw-line-art.js +7 -0
  151. package/src/turtle/draw-unicode.d.ts +19 -0
  152. package/src/turtle/draw-unicode.js +8 -0
  153. package/src/turtle/index.d.ts +21 -0
  154. package/src/turtle/index.js +8 -0
  155. package/src/turtle/turtle.d.ts +269 -0
  156. package/src/turtle/turtle.js +124 -4
package/src/panel.js CHANGED
@@ -15,7 +15,15 @@ import split, {size} from './strings/split.js';
15
15
  import Box from './box.js';
16
16
  import {addAliases} from './meta.js';
17
17
 
18
+ /** A 2D array of cells, where each cell has a character symbol and an SGR state.
19
+ * Provides methods for manipulation, styling, geometric transforms, and conversion to Box/strings.
20
+ * @see {@link https://github.com/uhop/console-toolkit/wiki/Module:-panel}
21
+ */
18
22
  export class Panel {
23
+ /** Creates an empty Panel of the given dimensions.
24
+ * @param {number} width - Width in columns.
25
+ * @param {number} height - Height in rows.
26
+ */
19
27
  constructor(width, height) {
20
28
  this.box = new Array(height);
21
29
  for (let i = 0; i < height; ++i) {
@@ -23,14 +31,21 @@ export class Panel {
23
31
  }
24
32
  }
25
33
 
34
+ /** The width of the panel in columns. */
26
35
  get width() {
27
36
  return this.box.length && this.box[0].length;
28
37
  }
29
38
 
39
+ /** The height of the panel in rows. */
30
40
  get height() {
31
41
  return this.box.length;
32
42
  }
33
43
 
44
+ /** Creates a Panel from various input types (Panel, Box, string, string[], function).
45
+ * @param {import('./strings.js').StringsInput} s - Input data.
46
+ * @param {object} [options] - Options passed to Box.make() or put().
47
+ * @returns {Panel}
48
+ */
34
49
  static make(s, options) {
35
50
  main: for (;;) {
36
51
  switch (typeof s) {
@@ -52,6 +67,12 @@ export class Panel {
52
67
  return panel;
53
68
  }
54
69
 
70
+ /** Converts the panel to an array of strings with embedded ANSI escape sequences.
71
+ * @param {object} [options] - Options.
72
+ * @param {string} [options.emptySymbol=' '] - Character for empty cells.
73
+ * @param {object} [options.emptyState] - SGR state for empty cells.
74
+ * @returns {string[]}
75
+ */
55
76
  toStrings(options = {}) {
56
77
  if (!this.height || !this.width) return Box.makeBlank(this.width, this.height);
57
78
 
@@ -81,10 +102,21 @@ export class Panel {
81
102
  return s;
82
103
  }
83
104
 
105
+ /** Converts the panel to a Box.
106
+ * @param {object} [options] - Options passed to toStrings().
107
+ * @returns {import('./box.js').Box}
108
+ */
84
109
  toBox(options) {
85
110
  return new Box(this.toStrings(options), true);
86
111
  }
87
112
 
113
+ /** Extracts a rectangular region as a new Panel.
114
+ * @param {number} [x=0] - Left column.
115
+ * @param {number} [y=0] - Top row.
116
+ * @param {number} [width] - Width (defaults to panel width).
117
+ * @param {number} [height] - Height (defaults to panel height).
118
+ * @returns {Panel}
119
+ */
88
120
  extract(x, y, width, height) {
89
121
  // normalize arguments
90
122
 
@@ -131,10 +163,23 @@ export class Panel {
131
163
  return panel;
132
164
  }
133
165
 
166
+ /** Creates a deep copy of this panel.
167
+ * @returns {Panel}
168
+ */
134
169
  clone() {
135
170
  return this.extract();
136
171
  }
137
172
 
173
+ /** Copies cells from another panel into this panel.
174
+ * @param {number} x - Destination x.
175
+ * @param {number} y - Destination y.
176
+ * @param {number} width - Width to copy.
177
+ * @param {number} height - Height to copy.
178
+ * @param {Panel} panel - Source panel.
179
+ * @param {number} [x1=0] - Source x.
180
+ * @param {number} [y1=0] - Source y.
181
+ * @returns {this}
182
+ */
138
183
  copyFrom(x, y, width, height, panel, x1 = 0, y1 = 0) {
139
184
  // normalize arguments
140
185
 
@@ -169,6 +214,14 @@ export class Panel {
169
214
  return this;
170
215
  }
171
216
 
217
+ /** Places text onto this panel at the given position. Characters matching `emptySymbol` (default: '\x07' BELL) are treated as empty cells.
218
+ * @param {number} x - Left column.
219
+ * @param {number} y - Top row.
220
+ * @param {import('./strings.js').StringsInput} text - Content to place.
221
+ * @param {object} [options] - Put options.
222
+ * @param {string} [options.emptySymbol='\x07'] - Character treated as an empty cell.
223
+ * @returns {this}
224
+ */
172
225
  put(x, y, text, options = {}) {
173
226
  if (text instanceof Panel) return this.copyFrom(x, y, text.width, text.height, text);
174
227
 
@@ -228,6 +281,15 @@ export class Panel {
228
281
  return this;
229
282
  }
230
283
 
284
+ /** Applies a function to each cell in a rectangular region.
285
+ * @param {number|Function} x - Left column, or the function if called with a single argument.
286
+ * @param {number} [y] - Top row.
287
+ * @param {number} [width] - Width.
288
+ * @param {number} [height] - Height.
289
+ * @param {Function} [fn] - Function `(x, y, cell) => newCell`.
290
+ * @param {object} [options] - Options.
291
+ * @returns {this}
292
+ */
231
293
  applyFn(x, y, width, height, fn, options) {
232
294
  // normalize arguments
233
295
 
@@ -274,6 +336,16 @@ export class Panel {
274
336
  return this;
275
337
  }
276
338
 
339
+ /** Fills a rectangular region with a symbol and state.
340
+ * @param {number|string} x - Left column, or symbol if filling the entire panel.
341
+ * @param {number} [y] - Top row.
342
+ * @param {number} [width] - Width.
343
+ * @param {number} [height] - Height.
344
+ * @param {string} [symbol] - Fill character.
345
+ * @param {object|string|string[]} [state={}] - SGR state.
346
+ * @param {object} [options] - Options.
347
+ * @returns {this}
348
+ */
277
349
  fill(x, y, width, height, symbol, state = {}, options) {
278
350
  if (typeof x === 'string') {
279
351
  symbol = x;
@@ -293,6 +365,14 @@ export class Panel {
293
365
  return this.applyFn(x, y, width, height, () => ({symbol, state}), options);
294
366
  }
295
367
 
368
+ /** Fills all cells with the given state, using `emptySymbol` for empty cells' symbol.
369
+ * @param {number|object} x - Left column, or options if filling the entire panel.
370
+ * @param {number} [y] - Top row.
371
+ * @param {number} [width] - Width.
372
+ * @param {number} [height] - Height.
373
+ * @param {object} [options] - Options with `state` and `emptySymbol`.
374
+ * @returns {this}
375
+ */
296
376
  fillState(x, y, width, height, options) {
297
377
  if (typeof x === 'object') {
298
378
  options = x;
@@ -319,6 +399,14 @@ export class Panel {
319
399
  );
320
400
  }
321
401
 
402
+ /** Fills state only for non-empty cells in a region.
403
+ * @param {number|object} x - Left column, or options if filling the entire panel.
404
+ * @param {number} [y] - Top row.
405
+ * @param {number} [width] - Width.
406
+ * @param {number} [height] - Height.
407
+ * @param {object} [options] - Options with `state`.
408
+ * @returns {this}
409
+ */
322
410
  fillNonEmptyState(x, y, width, height, options) {
323
411
  if (typeof x === 'object') {
324
412
  options = x;
@@ -338,6 +426,14 @@ export class Panel {
338
426
  return this.applyFn(x, y, width, height, (x, y, cell) => cell && {symbol: cell.symbol, state}, options);
339
427
  }
340
428
 
429
+ /** Combines a state before existing cell states (applied state acts as a base that cells override).
430
+ * @param {number|object} x - Left column, or options if filling the entire panel.
431
+ * @param {number} [y] - Top row.
432
+ * @param {number} [width] - Width.
433
+ * @param {number} [height] - Height.
434
+ * @param {object} [options] - Options with `state`, `emptySymbol`, `emptyState`.
435
+ * @returns {this}
436
+ */
341
437
  combineStateBefore(x, y, width, height, options) {
342
438
  if (typeof x === 'object') {
343
439
  options = x;
@@ -367,6 +463,14 @@ export class Panel {
367
463
  );
368
464
  }
369
465
 
466
+ /** Combines a state after existing cell states (applied state overrides cell properties).
467
+ * @param {number|object} x - Left column, or options if filling the entire panel.
468
+ * @param {number} [y] - Top row.
469
+ * @param {number} [width] - Width.
470
+ * @param {number} [height] - Height.
471
+ * @param {object} [options] - Options with `state`, `emptySymbol`, `emptyState`.
472
+ * @returns {this}
473
+ */
370
474
  combineStateAfter(x, y, width, height, options) {
371
475
  if (typeof x === 'object') {
372
476
  options = x;
@@ -396,6 +500,14 @@ export class Panel {
396
500
  );
397
501
  }
398
502
 
503
+ /** Clears (nullifies) cells in a rectangular region.
504
+ * @param {number} [x=0] - Left column.
505
+ * @param {number} [y=0] - Top row.
506
+ * @param {number} [width] - Width.
507
+ * @param {number} [height] - Height.
508
+ * @param {object} [options] - Options.
509
+ * @returns {this}
510
+ */
399
511
  clear(x, y, width, height, options) {
400
512
  // normalize arguments
401
513
  if (typeof x != 'number') {
@@ -416,6 +528,10 @@ export class Panel {
416
528
  return this.applyFn(x, y, width, height, () => null, options);
417
529
  }
418
530
 
531
+ /** Pads the left side with `n` empty columns.
532
+ * @param {number} n
533
+ * @returns {this}
534
+ */
419
535
  padLeft(n) {
420
536
  if (n <= 0) return this;
421
537
 
@@ -427,6 +543,10 @@ export class Panel {
427
543
  return this;
428
544
  }
429
545
 
546
+ /** Pads the right side with `n` empty columns.
547
+ * @param {number} n
548
+ * @returns {this}
549
+ */
430
550
  padRight(n) {
431
551
  if (n <= 0) return this;
432
552
 
@@ -438,6 +558,11 @@ export class Panel {
438
558
  return this;
439
559
  }
440
560
 
561
+ /** Pads left and right sides with empty cells.
562
+ * @param {number} n - Left columns.
563
+ * @param {number} m - Right columns.
564
+ * @returns {this}
565
+ */
441
566
  padLeftRight(n, m) {
442
567
  if (n <= 0) return this.padRight(m);
443
568
  if (m <= 0) return this.padLeft(n);
@@ -449,6 +574,10 @@ export class Panel {
449
574
  return this;
450
575
  }
451
576
 
577
+ /** Pads the top with `n` empty rows.
578
+ * @param {number} n
579
+ * @returns {this}
580
+ */
452
581
  padTop(n) {
453
582
  if (n <= 0) return this;
454
583
 
@@ -459,6 +588,10 @@ export class Panel {
459
588
  return this;
460
589
  }
461
590
 
591
+ /** Pads the bottom with `n` empty rows.
592
+ * @param {number} n
593
+ * @returns {this}
594
+ */
462
595
  padBottom(n) {
463
596
  if (n <= 0) return this;
464
597
 
@@ -469,6 +602,11 @@ export class Panel {
469
602
  return this;
470
603
  }
471
604
 
605
+ /** Pads top and bottom with empty rows.
606
+ * @param {number} n - Top rows.
607
+ * @param {number} m - Bottom rows.
608
+ * @returns {this}
609
+ */
472
610
  padTopBottom(n, m) {
473
611
  if (n <= 0) return this.padBottom(m);
474
612
  if (m <= 0) return this.padTop(n);
@@ -484,6 +622,13 @@ export class Panel {
484
622
  return this;
485
623
  }
486
624
 
625
+ /** Pads the panel using CSS-style shorthand (top, right, bottom, left).
626
+ * @param {number} t - Top (or all sides if only argument).
627
+ * @param {number} [r] - Right.
628
+ * @param {number} [b] - Bottom.
629
+ * @param {number} [l] - Left.
630
+ * @returns {this}
631
+ */
487
632
  pad(t, r, b, l) {
488
633
  // use values according to CSS rules
489
634
  if (typeof r != 'number') {
@@ -498,6 +643,11 @@ export class Panel {
498
643
  return this.padLeftRight(l, r).padTopBottom(t, b);
499
644
  }
500
645
 
646
+ /** Removes `n` columns starting at column `x`.
647
+ * @param {number} x - Start column.
648
+ * @param {number} n - Number of columns to remove.
649
+ * @returns {this}
650
+ */
501
651
  removeColumns(x, n) {
502
652
  // normalize arguments
503
653
  if (x < 0) {
@@ -511,6 +661,11 @@ export class Panel {
511
661
  return this;
512
662
  }
513
663
 
664
+ /** Removes `n` rows starting at row `y`.
665
+ * @param {number} y - Start row.
666
+ * @param {number} n - Number of rows to remove.
667
+ * @returns {this}
668
+ */
514
669
  removeRows(y, n) {
515
670
  // normalize arguments
516
671
  if (y < 0) {
@@ -524,6 +679,11 @@ export class Panel {
524
679
  return this;
525
680
  }
526
681
 
682
+ /** Resizes the panel horizontally.
683
+ * @param {number} newWidth - New width.
684
+ * @param {'left'|'center'|'right'} [align='right'] - Alignment when adding/removing columns.
685
+ * @returns {this}
686
+ */
527
687
  resizeH(newWidth, align = 'right') {
528
688
  if (!this.width) return this.padRight(newWidth);
529
689
 
@@ -536,7 +696,7 @@ export class Panel {
536
696
  case 'c': {
537
697
  const half = Math.abs(diff) >> 1;
538
698
  return diff < 0
539
- ? this.removeColumns(0, half).removeColumns(newWidth, half + 1)
699
+ ? this.removeColumns(0, half).removeColumns(newWidth, -diff - half)
540
700
  : this.padLeft(half).padRight(diff - half);
541
701
  }
542
702
  }
@@ -544,6 +704,11 @@ export class Panel {
544
704
  return diff < 0 ? this.removeColumns(newWidth, -diff) : this.padRight(diff);
545
705
  }
546
706
 
707
+ /** Resizes the panel vertically.
708
+ * @param {number} newHeight - New height.
709
+ * @param {'top'|'center'|'bottom'} [align='bottom'] - Alignment when adding/removing rows.
710
+ * @returns {this}
711
+ */
547
712
  resizeV(newHeight, align = 'bottom') {
548
713
  if (!this.height) return this.padBottom(newHeight);
549
714
 
@@ -556,7 +721,7 @@ export class Panel {
556
721
  case 'c': {
557
722
  const half = Math.abs(diff) >> 1;
558
723
  return diff < 0
559
- ? this.removeRows(0, half).removeRows(newHeight, half + 1)
724
+ ? this.removeRows(0, half).removeRows(newHeight, -diff - half)
560
725
  : this.padTop(half).padBottom(diff - half);
561
726
  }
562
727
  }
@@ -564,6 +729,13 @@ export class Panel {
564
729
  return diff < 0 ? this.removeRows(newHeight, -diff) : this.padBottom(diff);
565
730
  }
566
731
 
732
+ /** Resizes the panel in both dimensions.
733
+ * @param {number} newWidth - New width.
734
+ * @param {number} newHeight - New height.
735
+ * @param {'left'|'center'|'right'} [horizontal='right'] - Horizontal alignment.
736
+ * @param {'top'|'center'|'bottom'} [vertical='bottom'] - Vertical alignment.
737
+ * @returns {this}
738
+ */
567
739
  resize(newWidth, newHeight, horizontal = 'right', vertical = 'bottom') {
568
740
  if (!this.height) return this.padBottom(newHeight).padRight(newWidth);
569
741
 
@@ -572,27 +744,45 @@ export class Panel {
572
744
  : this.resizeH(newWidth, horizontal).resizeV(newHeight, vertical);
573
745
  }
574
746
 
747
+ /** Inserts `n` empty columns at position `x`.
748
+ * @param {number} x - Insert position.
749
+ * @param {number} n - Number of columns.
750
+ * @returns {this}
751
+ */
575
752
  insertColumns(x, n) {
576
753
  // normalize arguments
577
754
  if (n <= 0) return this;
578
755
  if (x > this.width) x = this.width;
579
756
  else if (x < 0) x = 0;
580
757
 
581
- for (const row of this.box) row.splice(x, 0, ...new Array(n).fill(null));
758
+ const padding = new Array(n).fill(null);
759
+ for (const row of this.box) row.splice(x, 0, ...padding);
582
760
  return this;
583
761
  }
584
762
 
763
+ /** Inserts `n` empty rows at position `y`.
764
+ * @param {number} y - Insert position.
765
+ * @param {number} n - Number of rows.
766
+ * @returns {this}
767
+ */
585
768
  insertRows(y, n) {
586
769
  // normalize arguments
587
770
  if (n <= 0) return this;
588
771
  if (y > this.height) y = this.height;
589
772
  else if (y < 0) y = 0;
590
773
 
591
- this.box.splice(y, 0, ...new Array(n).fill(null));
592
- for (let i = 0; i < n; ++i) this.box[y + i] = new Array(this.width).fill(null);
774
+ const rows = new Array(n);
775
+ for (let i = 0; i < n; ++i) rows[i] = new Array(this.width).fill(null);
776
+ this.box.splice(y, 0, ...rows);
593
777
  return this;
594
778
  }
595
779
 
780
+ /** Appends another panel below this one.
781
+ * @param {Panel} panel - Panel to append.
782
+ * @param {object} [options] - Options.
783
+ * @param {'left'|'center'|'right'} [options.align='left'] - Horizontal alignment.
784
+ * @returns {this}
785
+ */
596
786
  addBottom(panel, {align = 'left'} = {}) {
597
787
  panel = panel.clone();
598
788
 
@@ -635,6 +825,12 @@ export class Panel {
635
825
  return this;
636
826
  }
637
827
 
828
+ /** Appends another panel to the right of this one.
829
+ * @param {Panel} panel - Panel to append.
830
+ * @param {object} [options] - Options.
831
+ * @param {'top'|'center'|'bottom'} [options.align='top'] - Vertical alignment.
832
+ * @returns {this}
833
+ */
638
834
  addRight(panel, {align = 'top'} = {}) {
639
835
  panel = panel.clone();
640
836
 
@@ -713,6 +909,9 @@ export class Panel {
713
909
  return this;
714
910
  }
715
911
 
912
+ /** Returns a new Panel that is the transpose of this one (rows become columns).
913
+ * @returns {Panel}
914
+ */
716
915
  transpose() {
717
916
  const panel = new Panel(this.height, this.width);
718
917
  for (let i = 0; i < this.height; ++i) {
@@ -725,6 +924,9 @@ export class Panel {
725
924
  return panel;
726
925
  }
727
926
 
927
+ /** Returns a new Panel rotated 90° clockwise.
928
+ * @returns {Panel}
929
+ */
728
930
  rotateRight() {
729
931
  const panel = new Panel(this.height, this.width);
730
932
  for (let i = 0; i < this.height; ++i) {
@@ -737,6 +939,9 @@ export class Panel {
737
939
  return panel;
738
940
  }
739
941
 
942
+ /** Returns a new Panel rotated 90° counter-clockwise.
943
+ * @returns {Panel}
944
+ */
740
945
  rotateLeft() {
741
946
  const panel = new Panel(this.height, this.width);
742
947
  for (let i = 0; i < this.height; ++i) {
@@ -749,11 +954,17 @@ export class Panel {
749
954
  return panel;
750
955
  }
751
956
 
957
+ /** Flips the panel horizontally (mirrors left-right) in place.
958
+ * @returns {this}
959
+ */
752
960
  flipH() {
753
961
  for (const row of this.box) row.reverse();
754
962
  return this;
755
963
  }
756
964
 
965
+ /** Flips the panel vertically (mirrors top-bottom) in place.
966
+ * @returns {this}
967
+ */
757
968
  flipV() {
758
969
  this.box.reverse();
759
970
  return this;
@@ -762,6 +973,9 @@ export class Panel {
762
973
 
763
974
  addAliases(Panel, {combineState: 'combineStateAfter', toPanel: 'clone'});
764
975
 
976
+ /** Alias for `Panel.make()`. Creates a Panel from various input types.
977
+ * @type {typeof Panel.make}
978
+ */
765
979
  export const toPanel = Panel.make;
766
980
 
767
981
  export default Panel;
@@ -0,0 +1,80 @@
1
+ import Box from '../box.js';
2
+
3
+ /** A bitmap for drawing pixels, stored as a compact bit-packed array.
4
+ * @see {@link https://github.com/uhop/console-toolkit/wiki/Module:-plot}
5
+ */
6
+ export class Bitmap {
7
+ /** Width in pixels. */
8
+ width: number;
9
+ /** Height in pixels. */
10
+ height: number;
11
+ /** Width of each internal block (default: 5). */
12
+ blockWidth: number;
13
+ /** Height of each internal block (default: 5). */
14
+ blockHeight: number;
15
+ /** Number of words per line. */
16
+ lineSize: number;
17
+ /** Number of lines. */
18
+ lineCount: number;
19
+ /** The underlying bit-packed array. */
20
+ bitmap: number[];
21
+
22
+ /**
23
+ * @param width - Width in pixels.
24
+ * @param height - Height in pixels.
25
+ * @param blockWidth - Width of each internal block (default: 5).
26
+ * @param blockHeight - Height of each internal block (default: 5).
27
+ */
28
+ constructor(width: number, height: number, blockWidth?: number, blockHeight?: number);
29
+
30
+ /** Verifies that (x, y) is within bounds.
31
+ * @param x - X coordinate.
32
+ * @param y - Y coordinate.
33
+ * @returns This Bitmap.
34
+ * @throws If out of bounds.
35
+ */
36
+ verifyPos(x: number, y: number): this;
37
+ /** Returns the word index for the given position.
38
+ * @param x - X coordinate.
39
+ * @param y - Y coordinate.
40
+ * @returns The word index.
41
+ */
42
+ getWordIndex(x: number, y: number): number;
43
+ /** Returns the bit mask for the given position.
44
+ * @param x - X coordinate.
45
+ * @param y - Y coordinate.
46
+ * @returns The bit mask.
47
+ */
48
+ getWordMask(x: number, y: number): number;
49
+
50
+ /** Gets the bit value at (x, y).
51
+ * @param x - X coordinate.
52
+ * @param y - Y coordinate.
53
+ * @returns Non-zero if the bit is set, 0 otherwise.
54
+ */
55
+ getBit(x: number, y: number): number;
56
+ /** Sets the bit value at (x, y).
57
+ * @param x - X coordinate.
58
+ * @param y - Y coordinate.
59
+ * @param value - Bit value (default: 1).
60
+ * @returns This Bitmap.
61
+ */
62
+ setBit(x: number, y: number, value?: number): this;
63
+ /** Alias for `setBit`. */
64
+ set: Bitmap['setBit'];
65
+
66
+ /** Clears the bitmap.
67
+ * @param value - If true, set all bits; if false, clear all (default: false).
68
+ * @returns This Bitmap.
69
+ */
70
+ clear(value?: boolean): this;
71
+
72
+ /** Converts the bitmap to a Box using the given characters.
73
+ * @param one - Character for set bits (default: full block).
74
+ * @param zero - Character for clear bits (default: space).
75
+ * @returns A Box representation.
76
+ */
77
+ toBox(one?: string, zero?: string): Box;
78
+ }
79
+
80
+ export default Bitmap;
@@ -2,20 +2,29 @@ import Box from '../box.js';
2
2
  import {addAlias} from '../meta.js';
3
3
  import {fullBlock} from '../symbols.js';
4
4
 
5
+ /** A bitmap image using a compact bit-packed representation.
6
+ * Supports setting/getting individual bits and converting to a Box for console display.
7
+ */
5
8
  export class Bitmap {
9
+ /** Creates a new Bitmap.
10
+ * @param {number} width - The width in pixels.
11
+ * @param {number} height - The height in pixels.
12
+ * @param {number} [blockWidth=5] - The width of each internal block (blockWidth * blockHeight <= 32).
13
+ * @param {number} [blockHeight=5] - The height of each internal block.
14
+ */
6
15
  constructor(width, height, blockWidth = 5, blockHeight = 5) {
7
16
  // parameters check
8
17
  width = Math.round(width);
9
18
  if (isNaN(width) || width <= 0) throw new Error(`Width should be a positive integer instead of "${width}"`);
10
19
  height = Math.round(height);
11
- if (isNaN(width) || height <= 0) throw new Error(`Height should be a positive integer instead of "${height}"`);
20
+ if (isNaN(height) || height <= 0) throw new Error(`Height should be a positive integer instead of "${height}"`);
12
21
  blockWidth = Math.round(blockWidth);
13
- if (isNaN(width) || blockWidth <= 0)
22
+ if (isNaN(blockWidth) || blockWidth <= 0)
14
23
  throw new Error(`Block width should be a positive integer instead of "${blockWidth}"`);
15
24
  blockHeight = Math.round(blockHeight);
16
- if (isNaN(width) || blockHeight <= 0)
25
+ if (isNaN(blockHeight) || blockHeight <= 0)
17
26
  throw new Error(`Block height should be a positive integer instead of "${blockHeight}"`);
18
- if (isNaN(width) || blockWidth * blockHeight > 32)
27
+ if (blockWidth * blockHeight > 32)
19
28
  throw new Error("Multiplication of 'blockWidth' and 'blockHeight' should be equal or less than 32");
20
29
 
21
30
  this.width = width;
@@ -49,6 +58,11 @@ export class Bitmap {
49
58
  return 1 << (shiftX + this.blockWidth * shiftY);
50
59
  }
51
60
 
61
+ /** Gets the value of a bit at the given position.
62
+ * @param {number} x - The x coordinate.
63
+ * @param {number} y - The y coordinate.
64
+ * @returns {number} Non-zero if the bit is set, 0 otherwise.
65
+ */
52
66
  getBit(x, y) {
53
67
  if (x < 0 || x >= this.width || y < 0 || y >= this.height) return 0;
54
68
  const index = this.getWordIndex(x, y),
@@ -56,6 +70,12 @@ export class Bitmap {
56
70
  return this.bitmap[index] & mask;
57
71
  }
58
72
 
73
+ /** Sets or clears a bit at the given position.
74
+ * @param {number} x - The x coordinate.
75
+ * @param {number} y - The y coordinate.
76
+ * @param {number} [value=1] - Positive to set, 0 to clear, negative to toggle.
77
+ * @returns {this}
78
+ */
59
79
  setBit(x, y, value = 1) {
60
80
  if (x < 0 || x >= this.width || y < 0 || y >= this.height) return this;
61
81
  const index = this.getWordIndex(x, y),
@@ -65,6 +85,10 @@ export class Bitmap {
65
85
  return this;
66
86
  }
67
87
 
88
+ /** Clears the entire bitmap.
89
+ * @param {boolean} [value=false] - If true, sets all bits; if false, clears all bits.
90
+ * @returns {this}
91
+ */
68
92
  clear(value) {
69
93
  this.bitmap.fill(value ? ~0 : 0);
70
94
  return this;
@@ -81,6 +105,11 @@ export class Bitmap {
81
105
  // return result;
82
106
  // }
83
107
 
108
+ /** Converts the bitmap to a Box for console display.
109
+ * @param {string} [one=fullBlock] - Character for set bits.
110
+ * @param {string} [zero=' '] - Character for unset bits.
111
+ * @returns {import('../box.js').Box} A Box representation of the bitmap.
112
+ */
84
113
  toBox(one = fullBlock, zero = ' ') {
85
114
  const result = [];
86
115
  for (let k = 0, kBase = 0; k < this.lineCount; ++k, kBase += this.blockHeight) {
@@ -0,0 +1,13 @@
1
+ import {Bitmap} from './bitmap.js';
2
+
3
+ /** Draws a line on a Bitmap using Bresenham's algorithm.
4
+ * @param bmp - The target bitmap.
5
+ * @param x0 - Start X.
6
+ * @param y0 - Start Y.
7
+ * @param x1 - End X.
8
+ * @param y1 - End Y.
9
+ * @param value - Bit value to set (default: 1).
10
+ */
11
+ export function drawLine(bmp: Bitmap, x0: number, y0: number, x1: number, y1: number, value?: number): void;
12
+
13
+ export default drawLine;
@@ -1,6 +1,14 @@
1
1
  // Drawing lines using Bresenham's line algorithm
2
2
  // The canonic version from https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
3
3
 
4
+ /** Draws a line on a Bitmap using Bresenham's line algorithm.
5
+ * @param {import('./bitmap.js').Bitmap} bmp - The bitmap to draw on.
6
+ * @param {number} x0 - Start x coordinate.
7
+ * @param {number} y0 - Start y coordinate.
8
+ * @param {number} x1 - End x coordinate.
9
+ * @param {number} y1 - End y coordinate.
10
+ * @param {number} [value=1] - Bit value: positive to set, 0 to clear, negative to toggle.
11
+ */
4
12
  export const drawLine = (bmp, x0, y0, x1, y1, value = 1) => {
5
13
  const dx = Math.abs(x1 - x0),
6
14
  sx = x0 < x1 ? 1 : -1,
@@ -0,0 +1,13 @@
1
+ import {Bitmap} from './bitmap.js';
2
+
3
+ /** Draws a filled rectangle on a Bitmap.
4
+ * @param bmp - The target bitmap.
5
+ * @param x0 - First corner x coordinate.
6
+ * @param y0 - First corner y coordinate.
7
+ * @param x1 - Opposite corner x coordinate.
8
+ * @param y1 - Opposite corner y coordinate.
9
+ * @param value - Bit value to set (default: 1).
10
+ */
11
+ export function drawRect(bmp: Bitmap, x0: number, y0: number, x1: number, y1: number, value?: number): void;
12
+
13
+ export default drawRect;