blessed-components 0.0.1 → 1.0.0
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 +16 -43
- package/ROADMAP.md +695 -302
- package/dist/index.cjs +57 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +51 -0
- package/dist/index.js.map +1 -1
- package/dist/progress-bar/blessed.cjs +60 -0
- package/dist/progress-bar/blessed.cjs.map +1 -0
- package/dist/progress-bar/blessed.d.cts +129 -0
- package/dist/progress-bar/blessed.d.ts +129 -0
- package/dist/progress-bar/blessed.js +54 -0
- package/dist/progress-bar/blessed.js.map +1 -0
- package/dist/progress-bar/index.cjs +33 -0
- package/dist/progress-bar/index.cjs.map +1 -0
- package/dist/progress-bar/index.d.cts +181 -0
- package/dist/progress-bar/index.d.ts +181 -0
- package/dist/progress-bar/index.js +31 -0
- package/dist/progress-bar/index.js.map +1 -0
- package/package.json +28 -12
- package/src/components/progress-bar/README.md +193 -0
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,61 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var blessed = require('blessed');
|
|
4
|
+
|
|
5
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
|
+
|
|
7
|
+
var blessed__default = /*#__PURE__*/_interopDefault(blessed);
|
|
8
|
+
|
|
9
|
+
// src/adapters/blessed/progress-bar.ts
|
|
10
|
+
|
|
11
|
+
// src/components/progress-bar/index.ts
|
|
12
|
+
function renderProgressBar({
|
|
13
|
+
characters = { empty: "\u2591", filled: "\u2588" },
|
|
14
|
+
formatValue = ({ percentage }) => `${percentage}%`,
|
|
15
|
+
label,
|
|
16
|
+
max = 100,
|
|
17
|
+
min = 0,
|
|
18
|
+
value,
|
|
19
|
+
width
|
|
20
|
+
}) {
|
|
21
|
+
if (!Number.isInteger(width) || width < 1) {
|
|
22
|
+
throw new RangeError("ProgressBar width must be a positive integer.");
|
|
23
|
+
}
|
|
24
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
|
|
25
|
+
throw new RangeError("ProgressBar max must be greater than min.");
|
|
26
|
+
}
|
|
27
|
+
if (!Number.isFinite(value)) {
|
|
28
|
+
throw new RangeError("ProgressBar value must be finite.");
|
|
29
|
+
}
|
|
30
|
+
const clampedValue = Math.min(max, Math.max(min, value));
|
|
31
|
+
const percentage = Math.round((clampedValue - min) / (max - min) * 100);
|
|
32
|
+
const filledWidth = Math.round(percentage / 100 * width);
|
|
33
|
+
const track = characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);
|
|
34
|
+
const prefix = label === void 0 ? "" : `${label} `;
|
|
35
|
+
const valueText = formatValue({ percentage, value: clampedValue });
|
|
36
|
+
return `${prefix}${track} ${valueText}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/adapters/blessed/progress-bar.ts
|
|
40
|
+
function progressBar({ box, data, parent }) {
|
|
41
|
+
const element = blessed__default.default.box({
|
|
42
|
+
...box,
|
|
43
|
+
content: renderProgressBar(data),
|
|
44
|
+
parent,
|
|
45
|
+
tags: false
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
element,
|
|
49
|
+
destroy() {
|
|
50
|
+
element.destroy();
|
|
51
|
+
},
|
|
52
|
+
setData(nextData) {
|
|
53
|
+
element.setContent(renderProgressBar(nextData));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
exports.progressBar = progressBar;
|
|
59
|
+
exports.renderProgressBar = renderProgressBar;
|
|
3
60
|
//# sourceMappingURL=index.cjs.map
|
|
4
61
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
|
|
1
|
+
{"version":3,"sources":["../src/components/progress-bar/index.ts","../src/adapters/blessed/progress-bar.ts"],"names":["blessed"],"mappings":";;;;;;;;;;;AA6LO,SAAS,iBAAA,CAAkB;AAAA,EAChC,UAAA,GAAa,EAAE,KAAA,EAAO,QAAA,EAAK,QAAQ,QAAA,EAAI;AAAA,EACvC,cAAc,CAAC,EAAE,UAAA,EAAW,KAAM,GAAG,UAAU,CAAA,CAAA,CAAA;AAAA,EAC/C,KAAA;AAAA,EACA,GAAA,GAAM,GAAA;AAAA,EACN,GAAA,GAAM,CAAA;AAAA,EACN,KAAA;AAAA,EACA;AACF,CAAA,EAAqC;AACnC,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA,IAAK,QAAQ,CAAA,EAAG;AACzC,IAAA,MAAM,IAAI,WAAW,+CAA+C,CAAA;AAAA,EACtE;AAEA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA,IAAO,GAAA,EAAK;AAChE,IAAA,MAAM,IAAI,WAAW,2CAA2C,CAAA;AAAA,EAClE;AAEA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,WAAW,mCAAmC,CAAA;AAAA,EAC1D;AAEA,EAAA,MAAM,YAAA,GAAe,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAC,CAAA;AACvD,EAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAA,CAAQ,eAAe,GAAA,KAAQ,GAAA,GAAM,OAAQ,GAAG,CAAA;AACxE,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAO,UAAA,GAAa,MAAO,KAAK,CAAA;AACzD,EAAA,MAAM,KAAA,GACJ,UAAA,CAAW,MAAA,CAAO,MAAA,CAAO,WAAW,IAAI,UAAA,CAAW,KAAA,CAAM,MAAA,CAAO,KAAA,GAAQ,WAAW,CAAA;AACrF,EAAA,MAAM,MAAA,GAAS,KAAA,KAAU,MAAA,GAAY,EAAA,GAAK,GAAG,KAAK,CAAA,CAAA,CAAA;AAClD,EAAA,MAAM,YAAY,WAAA,CAAY,EAAE,UAAA,EAAY,KAAA,EAAO,cAAc,CAAA;AAEjE,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,KAAK,IAAI,SAAS,CAAA,CAAA;AACvC;;;AClFO,SAAS,WAAA,CAAY,EAAE,GAAA,EAAK,IAAA,EAAM,QAAO,EAA0C;AACxF,EAAA,MAAM,OAAA,GAAUA,yBAAQ,GAAA,CAAI;AAAA,IAC1B,GAAG,GAAA;AAAA,IACH,OAAA,EAAS,kBAAkB,IAAI,CAAA;AAAA,IAC/B,MAAA;AAAA,IACA,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,OAAA,CAAQ,OAAA,EAAQ;AAAA,IAClB,CAAA;AAAA,IACA,QAAQ,QAAA,EAAU;AAChB,MAAA,OAAA,CAAQ,UAAA,CAAW,iBAAA,CAAkB,QAAQ,CAAC,CAAA;AAAA,IAChD;AAAA,GACF;AACF","file":"index.cjs","sourcesContent":["/**\n * Options accepted by {@link renderProgressBar}.\n *\n * The renderer maps `value` from the inclusive numeric range defined by\n * `min` and `max` into a fixed-width terminal track. Values outside the range\n * are clamped before rendering.\n *\n * @example Basic percentage bar\n *\n * ```ts\n * renderProgressBar({\n * value: 50,\n * width: 10,\n * });\n * // \"█████░░░░░ 50%\"\n * ```\n *\n * @example Custom range and label\n *\n * ```ts\n * renderProgressBar({\n * label: 'Workers',\n * min: 0,\n * max: 8,\n * value: 6,\n * width: 8,\n * });\n * // \"Workers ██████░░ 75%\"\n * ```\n */\nexport interface RenderProgressBarOptions {\n /**\n * Characters used to render filled and empty cells.\n *\n * Each character should occupy one terminal cell. Multi-cell or combining\n * characters can make the visible track wider than `width`.\n *\n * @defaultValue `{ filled: '█', empty: '░' }`\n */\n characters?: ProgressBarCharacters;\n\n /**\n * Formats the value text appended after the track.\n *\n * The callback receives the clamped numeric value and its rounded\n * percentage. Returning an empty string leaves the trailing separator in\n * place; callers that need a track-only representation should account for\n * that when composing output.\n *\n * @defaultValue `({ percentage }) => `${percentage}%``\n */\n formatValue?: (context: ProgressBarValueContext) => string;\n\n /**\n * Optional text rendered before the track.\n *\n * Dynamic values must be escaped by the caller if the returned string will\n * later be inserted into a Blessed element with tags enabled. The bundled\n * Blessed adapter disables tags.\n */\n label?: string;\n\n /**\n * Upper bound of the numeric range.\n *\n * Must be finite and greater than `min`.\n *\n * @defaultValue `100`\n */\n max?: number;\n\n /**\n * Lower bound of the numeric range.\n *\n * Must be finite and lower than `max`.\n *\n * @defaultValue `0`\n */\n min?: number;\n\n /**\n * Current numeric value.\n *\n * The value must be finite. Values below `min` or above `max` are clamped\n * before the percentage and formatted value are calculated.\n */\n value: number;\n\n /**\n * Number of characters reserved for the progress track.\n *\n * This excludes the optional label, spaces, and formatted value. It must be\n * a positive integer.\n */\n width: number;\n}\n\n/**\n * Character pair used to draw a progress track.\n *\n * Use ASCII characters when the target terminal cannot display Unicode block\n * glyphs reliably.\n *\n * @example\n *\n * ```ts\n * const asciiCharacters: ProgressBarCharacters = {\n * filled: '#',\n * empty: '-',\n * };\n * ```\n */\nexport interface ProgressBarCharacters {\n /** Character repeated for unfilled track cells. */\n empty: string;\n\n /** Character repeated for filled track cells. */\n filled: string;\n}\n\n/**\n * Normalized value information passed to a progress value formatter.\n */\nexport interface ProgressBarValueContext {\n /**\n * Rounded progress in the inclusive range from `0` to `100`.\n */\n percentage: number;\n\n /**\n * Numeric value after it has been clamped to the configured range.\n */\n value: number;\n}\n\n/**\n * Renders a deterministic, single-line progress bar.\n *\n * This function is framework-independent and does not import Blessed. Import\n * it from `blessed-components/progress-bar` when only string rendering is\n * needed; that subpath keeps the Blessed adapter out of the module graph.\n *\n * The result has this structure:\n *\n * ```text\n * [label + space][fixed-width track][space][formatted value]\n * ```\n *\n * @param options - Numeric range, track width, characters, and text formatting.\n * @returns A plain terminal string. No ANSI sequences or Blessed tags are added.\n *\n * @throws `RangeError`\n * Thrown when `width` is not a positive integer.\n *\n * @throws `RangeError`\n * Thrown when `min` or `max` is not finite, or when `max` is not greater than\n * `min`.\n *\n * @throws `RangeError`\n * Thrown when `value` is not finite.\n *\n * @example Unicode output\n *\n * ```ts\n * import { renderProgressBar } from 'blessed-components/progress-bar';\n *\n * const output = renderProgressBar({\n * label: 'Quality',\n * value: 78,\n * width: 16,\n * });\n *\n * // \"Quality ████████████░░░░ 78%\"\n * ```\n *\n * @example ASCII output with a custom value\n *\n * ```ts\n * const output = renderProgressBar({\n * characters: { filled: '#', empty: '-' },\n * formatValue: ({ value }) => `${value} files`,\n * label: 'Uploaded',\n * value: 25,\n * width: 8,\n * });\n *\n * // \"Uploaded ##------ 25 files\"\n * ```\n */\nexport function renderProgressBar({\n characters = { empty: '░', filled: '█' },\n formatValue = ({ percentage }) => `${percentage}%`,\n label,\n max = 100,\n min = 0,\n value,\n width,\n}: RenderProgressBarOptions): string {\n if (!Number.isInteger(width) || width < 1) {\n throw new RangeError('ProgressBar width must be a positive integer.');\n }\n\n if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {\n throw new RangeError('ProgressBar max must be greater than min.');\n }\n\n if (!Number.isFinite(value)) {\n throw new RangeError('ProgressBar value must be finite.');\n }\n\n const clampedValue = Math.min(max, Math.max(min, value));\n const percentage = Math.round(((clampedValue - min) / (max - min)) * 100);\n const filledWidth = Math.round((percentage / 100) * width);\n const track =\n characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);\n const prefix = label === undefined ? '' : `${label} `;\n const valueText = formatValue({ percentage, value: clampedValue });\n\n return `${prefix}${track} ${valueText}`;\n}\n","import blessed from 'blessed';\n\nimport {\n type RenderProgressBarOptions,\n renderProgressBar,\n} from '../../components/progress-bar/index.js';\n\n/**\n * Blessed box options supported by the ProgressBar adapter.\n *\n * `parent`, `content`, and `tags` are managed by {@link progressBar}:\n *\n * - `parent` comes from {@link ProgressBarOptions.parent}.\n * - `content` comes from {@link renderProgressBar}.\n * - `tags` is always disabled so labels and formatter output remain literal.\n */\nexport type ProgressBarBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;\n\n/**\n * Options accepted by the Blessed {@link progressBar} adapter.\n */\nexport interface ProgressBarOptions {\n /**\n * Optional Blessed box configuration.\n *\n * Position, dimensions, style, visibility, and other regular box options\n * can be supplied here.\n */\n box?: ProgressBarBoxOptions;\n\n /**\n * Data passed to the pure {@link renderProgressBar} renderer.\n */\n data: RenderProgressBarOptions;\n\n /**\n * Blessed node that receives the created box as a child.\n *\n * Usually this is a `Screen` or another `BoxElement`.\n */\n parent: blessed.Widgets.Node;\n}\n\n/**\n * Imperative handle returned by {@link progressBar}.\n *\n * The handle owns one Blessed `BoxElement`. It does not own the parent screen\n * and never calls `screen.render()`, allowing callers to batch several updates\n * into one terminal render.\n */\nexport interface ProgressBarHandle {\n /**\n * Underlying Blessed box.\n *\n * Use this for standard Blessed operations such as positioning, showing,\n * hiding, or applying styles.\n */\n readonly element: blessed.Widgets.BoxElement;\n\n /**\n * Destroys and detaches the owned box from its parent.\n *\n * This does not destroy the parent or screen. Do not use the handle after\n * calling this method.\n */\n destroy(): void;\n\n /**\n * Re-renders component content using new data.\n *\n * The underlying element is preserved. This method does not call\n * `screen.render()`; call it explicitly when updates should become visible.\n *\n * @param data - Complete renderer data replacing the previous data.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderProgressBar}.\n */\n setData(data: RenderProgressBarOptions): void;\n}\n\n/**\n * Creates a display-only ProgressBar backed by a Blessed `BoxElement`.\n *\n * Import this adapter from `blessed-components/progress-bar/blessed`. Use\n * {@link renderProgressBar} from `blessed-components/progress-bar` when a\n * Blessed element is unnecessary.\n *\n * The adapter:\n *\n * - renders initial content through {@link renderProgressBar};\n * - disables Blessed tags to keep dynamic text literal;\n * - updates the existing element through {@link ProgressBarHandle.setData};\n * - leaves screen rendering under caller control;\n * - detaches its element through {@link ProgressBarHandle.destroy}.\n *\n * @param options - Parent node, renderer data, and optional box settings.\n * @returns A handle for the created element, updates, and cleanup.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderProgressBar}.\n *\n * @example\n *\n * ```ts\n * import blessed from 'blessed';\n * import { progressBar } from 'blessed-components/progress-bar/blessed';\n *\n * const screen = blessed.screen({ smartCSR: true });\n * const upload = progressBar({\n * parent: screen,\n * box: {\n * top: 0,\n * left: 0,\n * width: 40,\n * height: 1,\n * },\n * data: {\n * label: 'Uploaded',\n * value: 25,\n * width: 20,\n * },\n * });\n *\n * screen.render();\n *\n * upload.setData({\n * label: 'Uploaded',\n * value: 75,\n * width: 20,\n * });\n * screen.render();\n *\n * upload.destroy();\n * screen.destroy();\n * ```\n */\nexport function progressBar({ box, data, parent }: ProgressBarOptions): ProgressBarHandle {\n const element = blessed.box({\n ...box,\n content: renderProgressBar(data),\n parent,\n tags: false,\n });\n\n return {\n element,\n destroy() {\n element.destroy();\n },\n setData(nextData) {\n element.setContent(renderProgressBar(nextData));\n },\n };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
1
|
+
export { ProgressBarBoxOptions, ProgressBarHandle, ProgressBarOptions, progressBar } from './progress-bar/blessed.cjs';
|
|
2
|
+
export { ProgressBarCharacters, ProgressBarValueContext, RenderProgressBarOptions, renderProgressBar } from './progress-bar/index.cjs';
|
|
3
|
+
import 'blessed';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export {
|
|
1
|
+
export { ProgressBarBoxOptions, ProgressBarHandle, ProgressBarOptions, progressBar } from './progress-bar/blessed.js';
|
|
2
|
+
export { ProgressBarCharacters, ProgressBarValueContext, RenderProgressBarOptions, renderProgressBar } from './progress-bar/index.js';
|
|
3
|
+
import 'blessed';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,54 @@
|
|
|
1
|
+
import blessed from 'blessed';
|
|
1
2
|
|
|
3
|
+
// src/adapters/blessed/progress-bar.ts
|
|
4
|
+
|
|
5
|
+
// src/components/progress-bar/index.ts
|
|
6
|
+
function renderProgressBar({
|
|
7
|
+
characters = { empty: "\u2591", filled: "\u2588" },
|
|
8
|
+
formatValue = ({ percentage }) => `${percentage}%`,
|
|
9
|
+
label,
|
|
10
|
+
max = 100,
|
|
11
|
+
min = 0,
|
|
12
|
+
value,
|
|
13
|
+
width
|
|
14
|
+
}) {
|
|
15
|
+
if (!Number.isInteger(width) || width < 1) {
|
|
16
|
+
throw new RangeError("ProgressBar width must be a positive integer.");
|
|
17
|
+
}
|
|
18
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
|
|
19
|
+
throw new RangeError("ProgressBar max must be greater than min.");
|
|
20
|
+
}
|
|
21
|
+
if (!Number.isFinite(value)) {
|
|
22
|
+
throw new RangeError("ProgressBar value must be finite.");
|
|
23
|
+
}
|
|
24
|
+
const clampedValue = Math.min(max, Math.max(min, value));
|
|
25
|
+
const percentage = Math.round((clampedValue - min) / (max - min) * 100);
|
|
26
|
+
const filledWidth = Math.round(percentage / 100 * width);
|
|
27
|
+
const track = characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);
|
|
28
|
+
const prefix = label === void 0 ? "" : `${label} `;
|
|
29
|
+
const valueText = formatValue({ percentage, value: clampedValue });
|
|
30
|
+
return `${prefix}${track} ${valueText}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/adapters/blessed/progress-bar.ts
|
|
34
|
+
function progressBar({ box, data, parent }) {
|
|
35
|
+
const element = blessed.box({
|
|
36
|
+
...box,
|
|
37
|
+
content: renderProgressBar(data),
|
|
38
|
+
parent,
|
|
39
|
+
tags: false
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
element,
|
|
43
|
+
destroy() {
|
|
44
|
+
element.destroy();
|
|
45
|
+
},
|
|
46
|
+
setData(nextData) {
|
|
47
|
+
element.setContent(renderProgressBar(nextData));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { progressBar, renderProgressBar };
|
|
2
53
|
//# sourceMappingURL=index.js.map
|
|
3
54
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
1
|
+
{"version":3,"sources":["../src/components/progress-bar/index.ts","../src/adapters/blessed/progress-bar.ts"],"names":[],"mappings":";;;;;AA6LO,SAAS,iBAAA,CAAkB;AAAA,EAChC,UAAA,GAAa,EAAE,KAAA,EAAO,QAAA,EAAK,QAAQ,QAAA,EAAI;AAAA,EACvC,cAAc,CAAC,EAAE,UAAA,EAAW,KAAM,GAAG,UAAU,CAAA,CAAA,CAAA;AAAA,EAC/C,KAAA;AAAA,EACA,GAAA,GAAM,GAAA;AAAA,EACN,GAAA,GAAM,CAAA;AAAA,EACN,KAAA;AAAA,EACA;AACF,CAAA,EAAqC;AACnC,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA,IAAK,QAAQ,CAAA,EAAG;AACzC,IAAA,MAAM,IAAI,WAAW,+CAA+C,CAAA;AAAA,EACtE;AAEA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA,IAAO,GAAA,EAAK;AAChE,IAAA,MAAM,IAAI,WAAW,2CAA2C,CAAA;AAAA,EAClE;AAEA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,WAAW,mCAAmC,CAAA;AAAA,EAC1D;AAEA,EAAA,MAAM,YAAA,GAAe,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAC,CAAA;AACvD,EAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAA,CAAQ,eAAe,GAAA,KAAQ,GAAA,GAAM,OAAQ,GAAG,CAAA;AACxE,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAO,UAAA,GAAa,MAAO,KAAK,CAAA;AACzD,EAAA,MAAM,KAAA,GACJ,UAAA,CAAW,MAAA,CAAO,MAAA,CAAO,WAAW,IAAI,UAAA,CAAW,KAAA,CAAM,MAAA,CAAO,KAAA,GAAQ,WAAW,CAAA;AACrF,EAAA,MAAM,MAAA,GAAS,KAAA,KAAU,MAAA,GAAY,EAAA,GAAK,GAAG,KAAK,CAAA,CAAA,CAAA;AAClD,EAAA,MAAM,YAAY,WAAA,CAAY,EAAE,UAAA,EAAY,KAAA,EAAO,cAAc,CAAA;AAEjE,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,KAAK,IAAI,SAAS,CAAA,CAAA;AACvC;;;AClFO,SAAS,WAAA,CAAY,EAAE,GAAA,EAAK,IAAA,EAAM,QAAO,EAA0C;AACxF,EAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,CAAI;AAAA,IAC1B,GAAG,GAAA;AAAA,IACH,OAAA,EAAS,kBAAkB,IAAI,CAAA;AAAA,IAC/B,MAAA;AAAA,IACA,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,OAAA,CAAQ,OAAA,EAAQ;AAAA,IAClB,CAAA;AAAA,IACA,QAAQ,QAAA,EAAU;AAChB,MAAA,OAAA,CAAQ,UAAA,CAAW,iBAAA,CAAkB,QAAQ,CAAC,CAAA;AAAA,IAChD;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/**\n * Options accepted by {@link renderProgressBar}.\n *\n * The renderer maps `value` from the inclusive numeric range defined by\n * `min` and `max` into a fixed-width terminal track. Values outside the range\n * are clamped before rendering.\n *\n * @example Basic percentage bar\n *\n * ```ts\n * renderProgressBar({\n * value: 50,\n * width: 10,\n * });\n * // \"█████░░░░░ 50%\"\n * ```\n *\n * @example Custom range and label\n *\n * ```ts\n * renderProgressBar({\n * label: 'Workers',\n * min: 0,\n * max: 8,\n * value: 6,\n * width: 8,\n * });\n * // \"Workers ██████░░ 75%\"\n * ```\n */\nexport interface RenderProgressBarOptions {\n /**\n * Characters used to render filled and empty cells.\n *\n * Each character should occupy one terminal cell. Multi-cell or combining\n * characters can make the visible track wider than `width`.\n *\n * @defaultValue `{ filled: '█', empty: '░' }`\n */\n characters?: ProgressBarCharacters;\n\n /**\n * Formats the value text appended after the track.\n *\n * The callback receives the clamped numeric value and its rounded\n * percentage. Returning an empty string leaves the trailing separator in\n * place; callers that need a track-only representation should account for\n * that when composing output.\n *\n * @defaultValue `({ percentage }) => `${percentage}%``\n */\n formatValue?: (context: ProgressBarValueContext) => string;\n\n /**\n * Optional text rendered before the track.\n *\n * Dynamic values must be escaped by the caller if the returned string will\n * later be inserted into a Blessed element with tags enabled. The bundled\n * Blessed adapter disables tags.\n */\n label?: string;\n\n /**\n * Upper bound of the numeric range.\n *\n * Must be finite and greater than `min`.\n *\n * @defaultValue `100`\n */\n max?: number;\n\n /**\n * Lower bound of the numeric range.\n *\n * Must be finite and lower than `max`.\n *\n * @defaultValue `0`\n */\n min?: number;\n\n /**\n * Current numeric value.\n *\n * The value must be finite. Values below `min` or above `max` are clamped\n * before the percentage and formatted value are calculated.\n */\n value: number;\n\n /**\n * Number of characters reserved for the progress track.\n *\n * This excludes the optional label, spaces, and formatted value. It must be\n * a positive integer.\n */\n width: number;\n}\n\n/**\n * Character pair used to draw a progress track.\n *\n * Use ASCII characters when the target terminal cannot display Unicode block\n * glyphs reliably.\n *\n * @example\n *\n * ```ts\n * const asciiCharacters: ProgressBarCharacters = {\n * filled: '#',\n * empty: '-',\n * };\n * ```\n */\nexport interface ProgressBarCharacters {\n /** Character repeated for unfilled track cells. */\n empty: string;\n\n /** Character repeated for filled track cells. */\n filled: string;\n}\n\n/**\n * Normalized value information passed to a progress value formatter.\n */\nexport interface ProgressBarValueContext {\n /**\n * Rounded progress in the inclusive range from `0` to `100`.\n */\n percentage: number;\n\n /**\n * Numeric value after it has been clamped to the configured range.\n */\n value: number;\n}\n\n/**\n * Renders a deterministic, single-line progress bar.\n *\n * This function is framework-independent and does not import Blessed. Import\n * it from `blessed-components/progress-bar` when only string rendering is\n * needed; that subpath keeps the Blessed adapter out of the module graph.\n *\n * The result has this structure:\n *\n * ```text\n * [label + space][fixed-width track][space][formatted value]\n * ```\n *\n * @param options - Numeric range, track width, characters, and text formatting.\n * @returns A plain terminal string. No ANSI sequences or Blessed tags are added.\n *\n * @throws `RangeError`\n * Thrown when `width` is not a positive integer.\n *\n * @throws `RangeError`\n * Thrown when `min` or `max` is not finite, or when `max` is not greater than\n * `min`.\n *\n * @throws `RangeError`\n * Thrown when `value` is not finite.\n *\n * @example Unicode output\n *\n * ```ts\n * import { renderProgressBar } from 'blessed-components/progress-bar';\n *\n * const output = renderProgressBar({\n * label: 'Quality',\n * value: 78,\n * width: 16,\n * });\n *\n * // \"Quality ████████████░░░░ 78%\"\n * ```\n *\n * @example ASCII output with a custom value\n *\n * ```ts\n * const output = renderProgressBar({\n * characters: { filled: '#', empty: '-' },\n * formatValue: ({ value }) => `${value} files`,\n * label: 'Uploaded',\n * value: 25,\n * width: 8,\n * });\n *\n * // \"Uploaded ##------ 25 files\"\n * ```\n */\nexport function renderProgressBar({\n characters = { empty: '░', filled: '█' },\n formatValue = ({ percentage }) => `${percentage}%`,\n label,\n max = 100,\n min = 0,\n value,\n width,\n}: RenderProgressBarOptions): string {\n if (!Number.isInteger(width) || width < 1) {\n throw new RangeError('ProgressBar width must be a positive integer.');\n }\n\n if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {\n throw new RangeError('ProgressBar max must be greater than min.');\n }\n\n if (!Number.isFinite(value)) {\n throw new RangeError('ProgressBar value must be finite.');\n }\n\n const clampedValue = Math.min(max, Math.max(min, value));\n const percentage = Math.round(((clampedValue - min) / (max - min)) * 100);\n const filledWidth = Math.round((percentage / 100) * width);\n const track =\n characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);\n const prefix = label === undefined ? '' : `${label} `;\n const valueText = formatValue({ percentage, value: clampedValue });\n\n return `${prefix}${track} ${valueText}`;\n}\n","import blessed from 'blessed';\n\nimport {\n type RenderProgressBarOptions,\n renderProgressBar,\n} from '../../components/progress-bar/index.js';\n\n/**\n * Blessed box options supported by the ProgressBar adapter.\n *\n * `parent`, `content`, and `tags` are managed by {@link progressBar}:\n *\n * - `parent` comes from {@link ProgressBarOptions.parent}.\n * - `content` comes from {@link renderProgressBar}.\n * - `tags` is always disabled so labels and formatter output remain literal.\n */\nexport type ProgressBarBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;\n\n/**\n * Options accepted by the Blessed {@link progressBar} adapter.\n */\nexport interface ProgressBarOptions {\n /**\n * Optional Blessed box configuration.\n *\n * Position, dimensions, style, visibility, and other regular box options\n * can be supplied here.\n */\n box?: ProgressBarBoxOptions;\n\n /**\n * Data passed to the pure {@link renderProgressBar} renderer.\n */\n data: RenderProgressBarOptions;\n\n /**\n * Blessed node that receives the created box as a child.\n *\n * Usually this is a `Screen` or another `BoxElement`.\n */\n parent: blessed.Widgets.Node;\n}\n\n/**\n * Imperative handle returned by {@link progressBar}.\n *\n * The handle owns one Blessed `BoxElement`. It does not own the parent screen\n * and never calls `screen.render()`, allowing callers to batch several updates\n * into one terminal render.\n */\nexport interface ProgressBarHandle {\n /**\n * Underlying Blessed box.\n *\n * Use this for standard Blessed operations such as positioning, showing,\n * hiding, or applying styles.\n */\n readonly element: blessed.Widgets.BoxElement;\n\n /**\n * Destroys and detaches the owned box from its parent.\n *\n * This does not destroy the parent or screen. Do not use the handle after\n * calling this method.\n */\n destroy(): void;\n\n /**\n * Re-renders component content using new data.\n *\n * The underlying element is preserved. This method does not call\n * `screen.render()`; call it explicitly when updates should become visible.\n *\n * @param data - Complete renderer data replacing the previous data.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderProgressBar}.\n */\n setData(data: RenderProgressBarOptions): void;\n}\n\n/**\n * Creates a display-only ProgressBar backed by a Blessed `BoxElement`.\n *\n * Import this adapter from `blessed-components/progress-bar/blessed`. Use\n * {@link renderProgressBar} from `blessed-components/progress-bar` when a\n * Blessed element is unnecessary.\n *\n * The adapter:\n *\n * - renders initial content through {@link renderProgressBar};\n * - disables Blessed tags to keep dynamic text literal;\n * - updates the existing element through {@link ProgressBarHandle.setData};\n * - leaves screen rendering under caller control;\n * - detaches its element through {@link ProgressBarHandle.destroy}.\n *\n * @param options - Parent node, renderer data, and optional box settings.\n * @returns A handle for the created element, updates, and cleanup.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderProgressBar}.\n *\n * @example\n *\n * ```ts\n * import blessed from 'blessed';\n * import { progressBar } from 'blessed-components/progress-bar/blessed';\n *\n * const screen = blessed.screen({ smartCSR: true });\n * const upload = progressBar({\n * parent: screen,\n * box: {\n * top: 0,\n * left: 0,\n * width: 40,\n * height: 1,\n * },\n * data: {\n * label: 'Uploaded',\n * value: 25,\n * width: 20,\n * },\n * });\n *\n * screen.render();\n *\n * upload.setData({\n * label: 'Uploaded',\n * value: 75,\n * width: 20,\n * });\n * screen.render();\n *\n * upload.destroy();\n * screen.destroy();\n * ```\n */\nexport function progressBar({ box, data, parent }: ProgressBarOptions): ProgressBarHandle {\n const element = blessed.box({\n ...box,\n content: renderProgressBar(data),\n parent,\n tags: false,\n });\n\n return {\n element,\n destroy() {\n element.destroy();\n },\n setData(nextData) {\n element.setContent(renderProgressBar(nextData));\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var blessed = require('blessed');
|
|
4
|
+
|
|
5
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
|
+
|
|
7
|
+
var blessed__default = /*#__PURE__*/_interopDefault(blessed);
|
|
8
|
+
|
|
9
|
+
// src/adapters/blessed/progress-bar.ts
|
|
10
|
+
|
|
11
|
+
// src/components/progress-bar/index.ts
|
|
12
|
+
function renderProgressBar({
|
|
13
|
+
characters = { empty: "\u2591", filled: "\u2588" },
|
|
14
|
+
formatValue = ({ percentage }) => `${percentage}%`,
|
|
15
|
+
label,
|
|
16
|
+
max = 100,
|
|
17
|
+
min = 0,
|
|
18
|
+
value,
|
|
19
|
+
width
|
|
20
|
+
}) {
|
|
21
|
+
if (!Number.isInteger(width) || width < 1) {
|
|
22
|
+
throw new RangeError("ProgressBar width must be a positive integer.");
|
|
23
|
+
}
|
|
24
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
|
|
25
|
+
throw new RangeError("ProgressBar max must be greater than min.");
|
|
26
|
+
}
|
|
27
|
+
if (!Number.isFinite(value)) {
|
|
28
|
+
throw new RangeError("ProgressBar value must be finite.");
|
|
29
|
+
}
|
|
30
|
+
const clampedValue = Math.min(max, Math.max(min, value));
|
|
31
|
+
const percentage = Math.round((clampedValue - min) / (max - min) * 100);
|
|
32
|
+
const filledWidth = Math.round(percentage / 100 * width);
|
|
33
|
+
const track = characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);
|
|
34
|
+
const prefix = label === void 0 ? "" : `${label} `;
|
|
35
|
+
const valueText = formatValue({ percentage, value: clampedValue });
|
|
36
|
+
return `${prefix}${track} ${valueText}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// src/adapters/blessed/progress-bar.ts
|
|
40
|
+
function progressBar({ box, data, parent }) {
|
|
41
|
+
const element = blessed__default.default.box({
|
|
42
|
+
...box,
|
|
43
|
+
content: renderProgressBar(data),
|
|
44
|
+
parent,
|
|
45
|
+
tags: false
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
element,
|
|
49
|
+
destroy() {
|
|
50
|
+
element.destroy();
|
|
51
|
+
},
|
|
52
|
+
setData(nextData) {
|
|
53
|
+
element.setContent(renderProgressBar(nextData));
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
exports.progressBar = progressBar;
|
|
59
|
+
//# sourceMappingURL=blessed.cjs.map
|
|
60
|
+
//# sourceMappingURL=blessed.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/progress-bar/index.ts","../../src/adapters/blessed/progress-bar.ts"],"names":["blessed"],"mappings":";;;;;;;;;;;AA6LO,SAAS,iBAAA,CAAkB;AAAA,EAChC,UAAA,GAAa,EAAE,KAAA,EAAO,QAAA,EAAK,QAAQ,QAAA,EAAI;AAAA,EACvC,cAAc,CAAC,EAAE,UAAA,EAAW,KAAM,GAAG,UAAU,CAAA,CAAA,CAAA;AAAA,EAC/C,KAAA;AAAA,EACA,GAAA,GAAM,GAAA;AAAA,EACN,GAAA,GAAM,CAAA;AAAA,EACN,KAAA;AAAA,EACA;AACF,CAAA,EAAqC;AACnC,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA,IAAK,QAAQ,CAAA,EAAG;AACzC,IAAA,MAAM,IAAI,WAAW,+CAA+C,CAAA;AAAA,EACtE;AAEA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA,IAAO,GAAA,EAAK;AAChE,IAAA,MAAM,IAAI,WAAW,2CAA2C,CAAA;AAAA,EAClE;AAEA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,WAAW,mCAAmC,CAAA;AAAA,EAC1D;AAEA,EAAA,MAAM,YAAA,GAAe,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAC,CAAA;AACvD,EAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAA,CAAQ,eAAe,GAAA,KAAQ,GAAA,GAAM,OAAQ,GAAG,CAAA;AACxE,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAO,UAAA,GAAa,MAAO,KAAK,CAAA;AACzD,EAAA,MAAM,KAAA,GACJ,UAAA,CAAW,MAAA,CAAO,MAAA,CAAO,WAAW,IAAI,UAAA,CAAW,KAAA,CAAM,MAAA,CAAO,KAAA,GAAQ,WAAW,CAAA;AACrF,EAAA,MAAM,MAAA,GAAS,KAAA,KAAU,MAAA,GAAY,EAAA,GAAK,GAAG,KAAK,CAAA,CAAA,CAAA;AAClD,EAAA,MAAM,YAAY,WAAA,CAAY,EAAE,UAAA,EAAY,KAAA,EAAO,cAAc,CAAA;AAEjE,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,KAAK,IAAI,SAAS,CAAA,CAAA;AACvC;;;AClFO,SAAS,WAAA,CAAY,EAAE,GAAA,EAAK,IAAA,EAAM,QAAO,EAA0C;AACxF,EAAA,MAAM,OAAA,GAAUA,yBAAQ,GAAA,CAAI;AAAA,IAC1B,GAAG,GAAA;AAAA,IACH,OAAA,EAAS,kBAAkB,IAAI,CAAA;AAAA,IAC/B,MAAA;AAAA,IACA,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,OAAA,CAAQ,OAAA,EAAQ;AAAA,IAClB,CAAA;AAAA,IACA,QAAQ,QAAA,EAAU;AAChB,MAAA,OAAA,CAAQ,UAAA,CAAW,iBAAA,CAAkB,QAAQ,CAAC,CAAA;AAAA,IAChD;AAAA,GACF;AACF","file":"blessed.cjs","sourcesContent":["/**\n * Options accepted by {@link renderProgressBar}.\n *\n * The renderer maps `value` from the inclusive numeric range defined by\n * `min` and `max` into a fixed-width terminal track. Values outside the range\n * are clamped before rendering.\n *\n * @example Basic percentage bar\n *\n * ```ts\n * renderProgressBar({\n * value: 50,\n * width: 10,\n * });\n * // \"█████░░░░░ 50%\"\n * ```\n *\n * @example Custom range and label\n *\n * ```ts\n * renderProgressBar({\n * label: 'Workers',\n * min: 0,\n * max: 8,\n * value: 6,\n * width: 8,\n * });\n * // \"Workers ██████░░ 75%\"\n * ```\n */\nexport interface RenderProgressBarOptions {\n /**\n * Characters used to render filled and empty cells.\n *\n * Each character should occupy one terminal cell. Multi-cell or combining\n * characters can make the visible track wider than `width`.\n *\n * @defaultValue `{ filled: '█', empty: '░' }`\n */\n characters?: ProgressBarCharacters;\n\n /**\n * Formats the value text appended after the track.\n *\n * The callback receives the clamped numeric value and its rounded\n * percentage. Returning an empty string leaves the trailing separator in\n * place; callers that need a track-only representation should account for\n * that when composing output.\n *\n * @defaultValue `({ percentage }) => `${percentage}%``\n */\n formatValue?: (context: ProgressBarValueContext) => string;\n\n /**\n * Optional text rendered before the track.\n *\n * Dynamic values must be escaped by the caller if the returned string will\n * later be inserted into a Blessed element with tags enabled. The bundled\n * Blessed adapter disables tags.\n */\n label?: string;\n\n /**\n * Upper bound of the numeric range.\n *\n * Must be finite and greater than `min`.\n *\n * @defaultValue `100`\n */\n max?: number;\n\n /**\n * Lower bound of the numeric range.\n *\n * Must be finite and lower than `max`.\n *\n * @defaultValue `0`\n */\n min?: number;\n\n /**\n * Current numeric value.\n *\n * The value must be finite. Values below `min` or above `max` are clamped\n * before the percentage and formatted value are calculated.\n */\n value: number;\n\n /**\n * Number of characters reserved for the progress track.\n *\n * This excludes the optional label, spaces, and formatted value. It must be\n * a positive integer.\n */\n width: number;\n}\n\n/**\n * Character pair used to draw a progress track.\n *\n * Use ASCII characters when the target terminal cannot display Unicode block\n * glyphs reliably.\n *\n * @example\n *\n * ```ts\n * const asciiCharacters: ProgressBarCharacters = {\n * filled: '#',\n * empty: '-',\n * };\n * ```\n */\nexport interface ProgressBarCharacters {\n /** Character repeated for unfilled track cells. */\n empty: string;\n\n /** Character repeated for filled track cells. */\n filled: string;\n}\n\n/**\n * Normalized value information passed to a progress value formatter.\n */\nexport interface ProgressBarValueContext {\n /**\n * Rounded progress in the inclusive range from `0` to `100`.\n */\n percentage: number;\n\n /**\n * Numeric value after it has been clamped to the configured range.\n */\n value: number;\n}\n\n/**\n * Renders a deterministic, single-line progress bar.\n *\n * This function is framework-independent and does not import Blessed. Import\n * it from `blessed-components/progress-bar` when only string rendering is\n * needed; that subpath keeps the Blessed adapter out of the module graph.\n *\n * The result has this structure:\n *\n * ```text\n * [label + space][fixed-width track][space][formatted value]\n * ```\n *\n * @param options - Numeric range, track width, characters, and text formatting.\n * @returns A plain terminal string. No ANSI sequences or Blessed tags are added.\n *\n * @throws `RangeError`\n * Thrown when `width` is not a positive integer.\n *\n * @throws `RangeError`\n * Thrown when `min` or `max` is not finite, or when `max` is not greater than\n * `min`.\n *\n * @throws `RangeError`\n * Thrown when `value` is not finite.\n *\n * @example Unicode output\n *\n * ```ts\n * import { renderProgressBar } from 'blessed-components/progress-bar';\n *\n * const output = renderProgressBar({\n * label: 'Quality',\n * value: 78,\n * width: 16,\n * });\n *\n * // \"Quality ████████████░░░░ 78%\"\n * ```\n *\n * @example ASCII output with a custom value\n *\n * ```ts\n * const output = renderProgressBar({\n * characters: { filled: '#', empty: '-' },\n * formatValue: ({ value }) => `${value} files`,\n * label: 'Uploaded',\n * value: 25,\n * width: 8,\n * });\n *\n * // \"Uploaded ##------ 25 files\"\n * ```\n */\nexport function renderProgressBar({\n characters = { empty: '░', filled: '█' },\n formatValue = ({ percentage }) => `${percentage}%`,\n label,\n max = 100,\n min = 0,\n value,\n width,\n}: RenderProgressBarOptions): string {\n if (!Number.isInteger(width) || width < 1) {\n throw new RangeError('ProgressBar width must be a positive integer.');\n }\n\n if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {\n throw new RangeError('ProgressBar max must be greater than min.');\n }\n\n if (!Number.isFinite(value)) {\n throw new RangeError('ProgressBar value must be finite.');\n }\n\n const clampedValue = Math.min(max, Math.max(min, value));\n const percentage = Math.round(((clampedValue - min) / (max - min)) * 100);\n const filledWidth = Math.round((percentage / 100) * width);\n const track =\n characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);\n const prefix = label === undefined ? '' : `${label} `;\n const valueText = formatValue({ percentage, value: clampedValue });\n\n return `${prefix}${track} ${valueText}`;\n}\n","import blessed from 'blessed';\n\nimport {\n type RenderProgressBarOptions,\n renderProgressBar,\n} from '../../components/progress-bar/index.js';\n\n/**\n * Blessed box options supported by the ProgressBar adapter.\n *\n * `parent`, `content`, and `tags` are managed by {@link progressBar}:\n *\n * - `parent` comes from {@link ProgressBarOptions.parent}.\n * - `content` comes from {@link renderProgressBar}.\n * - `tags` is always disabled so labels and formatter output remain literal.\n */\nexport type ProgressBarBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;\n\n/**\n * Options accepted by the Blessed {@link progressBar} adapter.\n */\nexport interface ProgressBarOptions {\n /**\n * Optional Blessed box configuration.\n *\n * Position, dimensions, style, visibility, and other regular box options\n * can be supplied here.\n */\n box?: ProgressBarBoxOptions;\n\n /**\n * Data passed to the pure {@link renderProgressBar} renderer.\n */\n data: RenderProgressBarOptions;\n\n /**\n * Blessed node that receives the created box as a child.\n *\n * Usually this is a `Screen` or another `BoxElement`.\n */\n parent: blessed.Widgets.Node;\n}\n\n/**\n * Imperative handle returned by {@link progressBar}.\n *\n * The handle owns one Blessed `BoxElement`. It does not own the parent screen\n * and never calls `screen.render()`, allowing callers to batch several updates\n * into one terminal render.\n */\nexport interface ProgressBarHandle {\n /**\n * Underlying Blessed box.\n *\n * Use this for standard Blessed operations such as positioning, showing,\n * hiding, or applying styles.\n */\n readonly element: blessed.Widgets.BoxElement;\n\n /**\n * Destroys and detaches the owned box from its parent.\n *\n * This does not destroy the parent or screen. Do not use the handle after\n * calling this method.\n */\n destroy(): void;\n\n /**\n * Re-renders component content using new data.\n *\n * The underlying element is preserved. This method does not call\n * `screen.render()`; call it explicitly when updates should become visible.\n *\n * @param data - Complete renderer data replacing the previous data.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderProgressBar}.\n */\n setData(data: RenderProgressBarOptions): void;\n}\n\n/**\n * Creates a display-only ProgressBar backed by a Blessed `BoxElement`.\n *\n * Import this adapter from `blessed-components/progress-bar/blessed`. Use\n * {@link renderProgressBar} from `blessed-components/progress-bar` when a\n * Blessed element is unnecessary.\n *\n * The adapter:\n *\n * - renders initial content through {@link renderProgressBar};\n * - disables Blessed tags to keep dynamic text literal;\n * - updates the existing element through {@link ProgressBarHandle.setData};\n * - leaves screen rendering under caller control;\n * - detaches its element through {@link ProgressBarHandle.destroy}.\n *\n * @param options - Parent node, renderer data, and optional box settings.\n * @returns A handle for the created element, updates, and cleanup.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderProgressBar}.\n *\n * @example\n *\n * ```ts\n * import blessed from 'blessed';\n * import { progressBar } from 'blessed-components/progress-bar/blessed';\n *\n * const screen = blessed.screen({ smartCSR: true });\n * const upload = progressBar({\n * parent: screen,\n * box: {\n * top: 0,\n * left: 0,\n * width: 40,\n * height: 1,\n * },\n * data: {\n * label: 'Uploaded',\n * value: 25,\n * width: 20,\n * },\n * });\n *\n * screen.render();\n *\n * upload.setData({\n * label: 'Uploaded',\n * value: 75,\n * width: 20,\n * });\n * screen.render();\n *\n * upload.destroy();\n * screen.destroy();\n * ```\n */\nexport function progressBar({ box, data, parent }: ProgressBarOptions): ProgressBarHandle {\n const element = blessed.box({\n ...box,\n content: renderProgressBar(data),\n parent,\n tags: false,\n });\n\n return {\n element,\n destroy() {\n element.destroy();\n },\n setData(nextData) {\n element.setContent(renderProgressBar(nextData));\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import blessed from 'blessed';
|
|
2
|
+
import { RenderProgressBarOptions } from './index.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Blessed box options supported by the ProgressBar adapter.
|
|
6
|
+
*
|
|
7
|
+
* `parent`, `content`, and `tags` are managed by {@link progressBar}:
|
|
8
|
+
*
|
|
9
|
+
* - `parent` comes from {@link ProgressBarOptions.parent}.
|
|
10
|
+
* - `content` comes from {@link renderProgressBar}.
|
|
11
|
+
* - `tags` is always disabled so labels and formatter output remain literal.
|
|
12
|
+
*/
|
|
13
|
+
type ProgressBarBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;
|
|
14
|
+
/**
|
|
15
|
+
* Options accepted by the Blessed {@link progressBar} adapter.
|
|
16
|
+
*/
|
|
17
|
+
interface ProgressBarOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Optional Blessed box configuration.
|
|
20
|
+
*
|
|
21
|
+
* Position, dimensions, style, visibility, and other regular box options
|
|
22
|
+
* can be supplied here.
|
|
23
|
+
*/
|
|
24
|
+
box?: ProgressBarBoxOptions;
|
|
25
|
+
/**
|
|
26
|
+
* Data passed to the pure {@link renderProgressBar} renderer.
|
|
27
|
+
*/
|
|
28
|
+
data: RenderProgressBarOptions;
|
|
29
|
+
/**
|
|
30
|
+
* Blessed node that receives the created box as a child.
|
|
31
|
+
*
|
|
32
|
+
* Usually this is a `Screen` or another `BoxElement`.
|
|
33
|
+
*/
|
|
34
|
+
parent: blessed.Widgets.Node;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Imperative handle returned by {@link progressBar}.
|
|
38
|
+
*
|
|
39
|
+
* The handle owns one Blessed `BoxElement`. It does not own the parent screen
|
|
40
|
+
* and never calls `screen.render()`, allowing callers to batch several updates
|
|
41
|
+
* into one terminal render.
|
|
42
|
+
*/
|
|
43
|
+
interface ProgressBarHandle {
|
|
44
|
+
/**
|
|
45
|
+
* Underlying Blessed box.
|
|
46
|
+
*
|
|
47
|
+
* Use this for standard Blessed operations such as positioning, showing,
|
|
48
|
+
* hiding, or applying styles.
|
|
49
|
+
*/
|
|
50
|
+
readonly element: blessed.Widgets.BoxElement;
|
|
51
|
+
/**
|
|
52
|
+
* Destroys and detaches the owned box from its parent.
|
|
53
|
+
*
|
|
54
|
+
* This does not destroy the parent or screen. Do not use the handle after
|
|
55
|
+
* calling this method.
|
|
56
|
+
*/
|
|
57
|
+
destroy(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Re-renders component content using new data.
|
|
60
|
+
*
|
|
61
|
+
* The underlying element is preserved. This method does not call
|
|
62
|
+
* `screen.render()`; call it explicitly when updates should become visible.
|
|
63
|
+
*
|
|
64
|
+
* @param data - Complete renderer data replacing the previous data.
|
|
65
|
+
*
|
|
66
|
+
* @throws `RangeError`
|
|
67
|
+
* Propagates validation errors from {@link renderProgressBar}.
|
|
68
|
+
*/
|
|
69
|
+
setData(data: RenderProgressBarOptions): void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates a display-only ProgressBar backed by a Blessed `BoxElement`.
|
|
73
|
+
*
|
|
74
|
+
* Import this adapter from `blessed-components/progress-bar/blessed`. Use
|
|
75
|
+
* {@link renderProgressBar} from `blessed-components/progress-bar` when a
|
|
76
|
+
* Blessed element is unnecessary.
|
|
77
|
+
*
|
|
78
|
+
* The adapter:
|
|
79
|
+
*
|
|
80
|
+
* - renders initial content through {@link renderProgressBar};
|
|
81
|
+
* - disables Blessed tags to keep dynamic text literal;
|
|
82
|
+
* - updates the existing element through {@link ProgressBarHandle.setData};
|
|
83
|
+
* - leaves screen rendering under caller control;
|
|
84
|
+
* - detaches its element through {@link ProgressBarHandle.destroy}.
|
|
85
|
+
*
|
|
86
|
+
* @param options - Parent node, renderer data, and optional box settings.
|
|
87
|
+
* @returns A handle for the created element, updates, and cleanup.
|
|
88
|
+
*
|
|
89
|
+
* @throws `RangeError`
|
|
90
|
+
* Propagates validation errors from {@link renderProgressBar}.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* import blessed from 'blessed';
|
|
96
|
+
* import { progressBar } from 'blessed-components/progress-bar/blessed';
|
|
97
|
+
*
|
|
98
|
+
* const screen = blessed.screen({ smartCSR: true });
|
|
99
|
+
* const upload = progressBar({
|
|
100
|
+
* parent: screen,
|
|
101
|
+
* box: {
|
|
102
|
+
* top: 0,
|
|
103
|
+
* left: 0,
|
|
104
|
+
* width: 40,
|
|
105
|
+
* height: 1,
|
|
106
|
+
* },
|
|
107
|
+
* data: {
|
|
108
|
+
* label: 'Uploaded',
|
|
109
|
+
* value: 25,
|
|
110
|
+
* width: 20,
|
|
111
|
+
* },
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* screen.render();
|
|
115
|
+
*
|
|
116
|
+
* upload.setData({
|
|
117
|
+
* label: 'Uploaded',
|
|
118
|
+
* value: 75,
|
|
119
|
+
* width: 20,
|
|
120
|
+
* });
|
|
121
|
+
* screen.render();
|
|
122
|
+
*
|
|
123
|
+
* upload.destroy();
|
|
124
|
+
* screen.destroy();
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function progressBar({ box, data, parent }: ProgressBarOptions): ProgressBarHandle;
|
|
128
|
+
|
|
129
|
+
export { type ProgressBarBoxOptions, type ProgressBarHandle, type ProgressBarOptions, progressBar };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import blessed from 'blessed';
|
|
2
|
+
import { RenderProgressBarOptions } from './index.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Blessed box options supported by the ProgressBar adapter.
|
|
6
|
+
*
|
|
7
|
+
* `parent`, `content`, and `tags` are managed by {@link progressBar}:
|
|
8
|
+
*
|
|
9
|
+
* - `parent` comes from {@link ProgressBarOptions.parent}.
|
|
10
|
+
* - `content` comes from {@link renderProgressBar}.
|
|
11
|
+
* - `tags` is always disabled so labels and formatter output remain literal.
|
|
12
|
+
*/
|
|
13
|
+
type ProgressBarBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;
|
|
14
|
+
/**
|
|
15
|
+
* Options accepted by the Blessed {@link progressBar} adapter.
|
|
16
|
+
*/
|
|
17
|
+
interface ProgressBarOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Optional Blessed box configuration.
|
|
20
|
+
*
|
|
21
|
+
* Position, dimensions, style, visibility, and other regular box options
|
|
22
|
+
* can be supplied here.
|
|
23
|
+
*/
|
|
24
|
+
box?: ProgressBarBoxOptions;
|
|
25
|
+
/**
|
|
26
|
+
* Data passed to the pure {@link renderProgressBar} renderer.
|
|
27
|
+
*/
|
|
28
|
+
data: RenderProgressBarOptions;
|
|
29
|
+
/**
|
|
30
|
+
* Blessed node that receives the created box as a child.
|
|
31
|
+
*
|
|
32
|
+
* Usually this is a `Screen` or another `BoxElement`.
|
|
33
|
+
*/
|
|
34
|
+
parent: blessed.Widgets.Node;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Imperative handle returned by {@link progressBar}.
|
|
38
|
+
*
|
|
39
|
+
* The handle owns one Blessed `BoxElement`. It does not own the parent screen
|
|
40
|
+
* and never calls `screen.render()`, allowing callers to batch several updates
|
|
41
|
+
* into one terminal render.
|
|
42
|
+
*/
|
|
43
|
+
interface ProgressBarHandle {
|
|
44
|
+
/**
|
|
45
|
+
* Underlying Blessed box.
|
|
46
|
+
*
|
|
47
|
+
* Use this for standard Blessed operations such as positioning, showing,
|
|
48
|
+
* hiding, or applying styles.
|
|
49
|
+
*/
|
|
50
|
+
readonly element: blessed.Widgets.BoxElement;
|
|
51
|
+
/**
|
|
52
|
+
* Destroys and detaches the owned box from its parent.
|
|
53
|
+
*
|
|
54
|
+
* This does not destroy the parent or screen. Do not use the handle after
|
|
55
|
+
* calling this method.
|
|
56
|
+
*/
|
|
57
|
+
destroy(): void;
|
|
58
|
+
/**
|
|
59
|
+
* Re-renders component content using new data.
|
|
60
|
+
*
|
|
61
|
+
* The underlying element is preserved. This method does not call
|
|
62
|
+
* `screen.render()`; call it explicitly when updates should become visible.
|
|
63
|
+
*
|
|
64
|
+
* @param data - Complete renderer data replacing the previous data.
|
|
65
|
+
*
|
|
66
|
+
* @throws `RangeError`
|
|
67
|
+
* Propagates validation errors from {@link renderProgressBar}.
|
|
68
|
+
*/
|
|
69
|
+
setData(data: RenderProgressBarOptions): void;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates a display-only ProgressBar backed by a Blessed `BoxElement`.
|
|
73
|
+
*
|
|
74
|
+
* Import this adapter from `blessed-components/progress-bar/blessed`. Use
|
|
75
|
+
* {@link renderProgressBar} from `blessed-components/progress-bar` when a
|
|
76
|
+
* Blessed element is unnecessary.
|
|
77
|
+
*
|
|
78
|
+
* The adapter:
|
|
79
|
+
*
|
|
80
|
+
* - renders initial content through {@link renderProgressBar};
|
|
81
|
+
* - disables Blessed tags to keep dynamic text literal;
|
|
82
|
+
* - updates the existing element through {@link ProgressBarHandle.setData};
|
|
83
|
+
* - leaves screen rendering under caller control;
|
|
84
|
+
* - detaches its element through {@link ProgressBarHandle.destroy}.
|
|
85
|
+
*
|
|
86
|
+
* @param options - Parent node, renderer data, and optional box settings.
|
|
87
|
+
* @returns A handle for the created element, updates, and cleanup.
|
|
88
|
+
*
|
|
89
|
+
* @throws `RangeError`
|
|
90
|
+
* Propagates validation errors from {@link renderProgressBar}.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* import blessed from 'blessed';
|
|
96
|
+
* import { progressBar } from 'blessed-components/progress-bar/blessed';
|
|
97
|
+
*
|
|
98
|
+
* const screen = blessed.screen({ smartCSR: true });
|
|
99
|
+
* const upload = progressBar({
|
|
100
|
+
* parent: screen,
|
|
101
|
+
* box: {
|
|
102
|
+
* top: 0,
|
|
103
|
+
* left: 0,
|
|
104
|
+
* width: 40,
|
|
105
|
+
* height: 1,
|
|
106
|
+
* },
|
|
107
|
+
* data: {
|
|
108
|
+
* label: 'Uploaded',
|
|
109
|
+
* value: 25,
|
|
110
|
+
* width: 20,
|
|
111
|
+
* },
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* screen.render();
|
|
115
|
+
*
|
|
116
|
+
* upload.setData({
|
|
117
|
+
* label: 'Uploaded',
|
|
118
|
+
* value: 75,
|
|
119
|
+
* width: 20,
|
|
120
|
+
* });
|
|
121
|
+
* screen.render();
|
|
122
|
+
*
|
|
123
|
+
* upload.destroy();
|
|
124
|
+
* screen.destroy();
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
declare function progressBar({ box, data, parent }: ProgressBarOptions): ProgressBarHandle;
|
|
128
|
+
|
|
129
|
+
export { type ProgressBarBoxOptions, type ProgressBarHandle, type ProgressBarOptions, progressBar };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import blessed from 'blessed';
|
|
2
|
+
|
|
3
|
+
// src/adapters/blessed/progress-bar.ts
|
|
4
|
+
|
|
5
|
+
// src/components/progress-bar/index.ts
|
|
6
|
+
function renderProgressBar({
|
|
7
|
+
characters = { empty: "\u2591", filled: "\u2588" },
|
|
8
|
+
formatValue = ({ percentage }) => `${percentage}%`,
|
|
9
|
+
label,
|
|
10
|
+
max = 100,
|
|
11
|
+
min = 0,
|
|
12
|
+
value,
|
|
13
|
+
width
|
|
14
|
+
}) {
|
|
15
|
+
if (!Number.isInteger(width) || width < 1) {
|
|
16
|
+
throw new RangeError("ProgressBar width must be a positive integer.");
|
|
17
|
+
}
|
|
18
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
|
|
19
|
+
throw new RangeError("ProgressBar max must be greater than min.");
|
|
20
|
+
}
|
|
21
|
+
if (!Number.isFinite(value)) {
|
|
22
|
+
throw new RangeError("ProgressBar value must be finite.");
|
|
23
|
+
}
|
|
24
|
+
const clampedValue = Math.min(max, Math.max(min, value));
|
|
25
|
+
const percentage = Math.round((clampedValue - min) / (max - min) * 100);
|
|
26
|
+
const filledWidth = Math.round(percentage / 100 * width);
|
|
27
|
+
const track = characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);
|
|
28
|
+
const prefix = label === void 0 ? "" : `${label} `;
|
|
29
|
+
const valueText = formatValue({ percentage, value: clampedValue });
|
|
30
|
+
return `${prefix}${track} ${valueText}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// src/adapters/blessed/progress-bar.ts
|
|
34
|
+
function progressBar({ box, data, parent }) {
|
|
35
|
+
const element = blessed.box({
|
|
36
|
+
...box,
|
|
37
|
+
content: renderProgressBar(data),
|
|
38
|
+
parent,
|
|
39
|
+
tags: false
|
|
40
|
+
});
|
|
41
|
+
return {
|
|
42
|
+
element,
|
|
43
|
+
destroy() {
|
|
44
|
+
element.destroy();
|
|
45
|
+
},
|
|
46
|
+
setData(nextData) {
|
|
47
|
+
element.setContent(renderProgressBar(nextData));
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { progressBar };
|
|
53
|
+
//# sourceMappingURL=blessed.js.map
|
|
54
|
+
//# sourceMappingURL=blessed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/progress-bar/index.ts","../../src/adapters/blessed/progress-bar.ts"],"names":[],"mappings":";;;;;AA6LO,SAAS,iBAAA,CAAkB;AAAA,EAChC,UAAA,GAAa,EAAE,KAAA,EAAO,QAAA,EAAK,QAAQ,QAAA,EAAI;AAAA,EACvC,cAAc,CAAC,EAAE,UAAA,EAAW,KAAM,GAAG,UAAU,CAAA,CAAA,CAAA;AAAA,EAC/C,KAAA;AAAA,EACA,GAAA,GAAM,GAAA;AAAA,EACN,GAAA,GAAM,CAAA;AAAA,EACN,KAAA;AAAA,EACA;AACF,CAAA,EAAqC;AACnC,EAAA,IAAI,CAAC,MAAA,CAAO,SAAA,CAAU,KAAK,CAAA,IAAK,QAAQ,CAAA,EAAG;AACzC,IAAA,MAAM,IAAI,WAAW,+CAA+C,CAAA;AAAA,EACtE;AAEA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IAAK,CAAC,MAAA,CAAO,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA,IAAO,GAAA,EAAK;AAChE,IAAA,MAAM,IAAI,WAAW,2CAA2C,CAAA;AAAA,EAClE;AAEA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA,EAAG;AAC3B,IAAA,MAAM,IAAI,WAAW,mCAAmC,CAAA;AAAA,EAC1D;AAEA,EAAA,MAAM,YAAA,GAAe,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA,EAAK,KAAK,CAAC,CAAA;AACvD,EAAA,MAAM,aAAa,IAAA,CAAK,KAAA,CAAA,CAAQ,eAAe,GAAA,KAAQ,GAAA,GAAM,OAAQ,GAAG,CAAA;AACxE,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAO,UAAA,GAAa,MAAO,KAAK,CAAA;AACzD,EAAA,MAAM,KAAA,GACJ,UAAA,CAAW,MAAA,CAAO,MAAA,CAAO,WAAW,IAAI,UAAA,CAAW,KAAA,CAAM,MAAA,CAAO,KAAA,GAAQ,WAAW,CAAA;AACrF,EAAA,MAAM,MAAA,GAAS,KAAA,KAAU,MAAA,GAAY,EAAA,GAAK,GAAG,KAAK,CAAA,CAAA,CAAA;AAClD,EAAA,MAAM,YAAY,WAAA,CAAY,EAAE,UAAA,EAAY,KAAA,EAAO,cAAc,CAAA;AAEjE,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,KAAK,IAAI,SAAS,CAAA,CAAA;AACvC;;;AClFO,SAAS,WAAA,CAAY,EAAE,GAAA,EAAK,IAAA,EAAM,QAAO,EAA0C;AACxF,EAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,CAAI;AAAA,IAC1B,GAAG,GAAA;AAAA,IACH,OAAA,EAAS,kBAAkB,IAAI,CAAA;AAAA,IAC/B,MAAA;AAAA,IACA,IAAA,EAAM;AAAA,GACP,CAAA;AAED,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,OAAA,GAAU;AACR,MAAA,OAAA,CAAQ,OAAA,EAAQ;AAAA,IAClB,CAAA;AAAA,IACA,QAAQ,QAAA,EAAU;AAChB,MAAA,OAAA,CAAQ,UAAA,CAAW,iBAAA,CAAkB,QAAQ,CAAC,CAAA;AAAA,IAChD;AAAA,GACF;AACF","file":"blessed.js","sourcesContent":["/**\n * Options accepted by {@link renderProgressBar}.\n *\n * The renderer maps `value` from the inclusive numeric range defined by\n * `min` and `max` into a fixed-width terminal track. Values outside the range\n * are clamped before rendering.\n *\n * @example Basic percentage bar\n *\n * ```ts\n * renderProgressBar({\n * value: 50,\n * width: 10,\n * });\n * // \"█████░░░░░ 50%\"\n * ```\n *\n * @example Custom range and label\n *\n * ```ts\n * renderProgressBar({\n * label: 'Workers',\n * min: 0,\n * max: 8,\n * value: 6,\n * width: 8,\n * });\n * // \"Workers ██████░░ 75%\"\n * ```\n */\nexport interface RenderProgressBarOptions {\n /**\n * Characters used to render filled and empty cells.\n *\n * Each character should occupy one terminal cell. Multi-cell or combining\n * characters can make the visible track wider than `width`.\n *\n * @defaultValue `{ filled: '█', empty: '░' }`\n */\n characters?: ProgressBarCharacters;\n\n /**\n * Formats the value text appended after the track.\n *\n * The callback receives the clamped numeric value and its rounded\n * percentage. Returning an empty string leaves the trailing separator in\n * place; callers that need a track-only representation should account for\n * that when composing output.\n *\n * @defaultValue `({ percentage }) => `${percentage}%``\n */\n formatValue?: (context: ProgressBarValueContext) => string;\n\n /**\n * Optional text rendered before the track.\n *\n * Dynamic values must be escaped by the caller if the returned string will\n * later be inserted into a Blessed element with tags enabled. The bundled\n * Blessed adapter disables tags.\n */\n label?: string;\n\n /**\n * Upper bound of the numeric range.\n *\n * Must be finite and greater than `min`.\n *\n * @defaultValue `100`\n */\n max?: number;\n\n /**\n * Lower bound of the numeric range.\n *\n * Must be finite and lower than `max`.\n *\n * @defaultValue `0`\n */\n min?: number;\n\n /**\n * Current numeric value.\n *\n * The value must be finite. Values below `min` or above `max` are clamped\n * before the percentage and formatted value are calculated.\n */\n value: number;\n\n /**\n * Number of characters reserved for the progress track.\n *\n * This excludes the optional label, spaces, and formatted value. It must be\n * a positive integer.\n */\n width: number;\n}\n\n/**\n * Character pair used to draw a progress track.\n *\n * Use ASCII characters when the target terminal cannot display Unicode block\n * glyphs reliably.\n *\n * @example\n *\n * ```ts\n * const asciiCharacters: ProgressBarCharacters = {\n * filled: '#',\n * empty: '-',\n * };\n * ```\n */\nexport interface ProgressBarCharacters {\n /** Character repeated for unfilled track cells. */\n empty: string;\n\n /** Character repeated for filled track cells. */\n filled: string;\n}\n\n/**\n * Normalized value information passed to a progress value formatter.\n */\nexport interface ProgressBarValueContext {\n /**\n * Rounded progress in the inclusive range from `0` to `100`.\n */\n percentage: number;\n\n /**\n * Numeric value after it has been clamped to the configured range.\n */\n value: number;\n}\n\n/**\n * Renders a deterministic, single-line progress bar.\n *\n * This function is framework-independent and does not import Blessed. Import\n * it from `blessed-components/progress-bar` when only string rendering is\n * needed; that subpath keeps the Blessed adapter out of the module graph.\n *\n * The result has this structure:\n *\n * ```text\n * [label + space][fixed-width track][space][formatted value]\n * ```\n *\n * @param options - Numeric range, track width, characters, and text formatting.\n * @returns A plain terminal string. No ANSI sequences or Blessed tags are added.\n *\n * @throws `RangeError`\n * Thrown when `width` is not a positive integer.\n *\n * @throws `RangeError`\n * Thrown when `min` or `max` is not finite, or when `max` is not greater than\n * `min`.\n *\n * @throws `RangeError`\n * Thrown when `value` is not finite.\n *\n * @example Unicode output\n *\n * ```ts\n * import { renderProgressBar } from 'blessed-components/progress-bar';\n *\n * const output = renderProgressBar({\n * label: 'Quality',\n * value: 78,\n * width: 16,\n * });\n *\n * // \"Quality ████████████░░░░ 78%\"\n * ```\n *\n * @example ASCII output with a custom value\n *\n * ```ts\n * const output = renderProgressBar({\n * characters: { filled: '#', empty: '-' },\n * formatValue: ({ value }) => `${value} files`,\n * label: 'Uploaded',\n * value: 25,\n * width: 8,\n * });\n *\n * // \"Uploaded ##------ 25 files\"\n * ```\n */\nexport function renderProgressBar({\n characters = { empty: '░', filled: '█' },\n formatValue = ({ percentage }) => `${percentage}%`,\n label,\n max = 100,\n min = 0,\n value,\n width,\n}: RenderProgressBarOptions): string {\n if (!Number.isInteger(width) || width < 1) {\n throw new RangeError('ProgressBar width must be a positive integer.');\n }\n\n if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {\n throw new RangeError('ProgressBar max must be greater than min.');\n }\n\n if (!Number.isFinite(value)) {\n throw new RangeError('ProgressBar value must be finite.');\n }\n\n const clampedValue = Math.min(max, Math.max(min, value));\n const percentage = Math.round(((clampedValue - min) / (max - min)) * 100);\n const filledWidth = Math.round((percentage / 100) * width);\n const track =\n characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);\n const prefix = label === undefined ? '' : `${label} `;\n const valueText = formatValue({ percentage, value: clampedValue });\n\n return `${prefix}${track} ${valueText}`;\n}\n","import blessed from 'blessed';\n\nimport {\n type RenderProgressBarOptions,\n renderProgressBar,\n} from '../../components/progress-bar/index.js';\n\n/**\n * Blessed box options supported by the ProgressBar adapter.\n *\n * `parent`, `content`, and `tags` are managed by {@link progressBar}:\n *\n * - `parent` comes from {@link ProgressBarOptions.parent}.\n * - `content` comes from {@link renderProgressBar}.\n * - `tags` is always disabled so labels and formatter output remain literal.\n */\nexport type ProgressBarBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;\n\n/**\n * Options accepted by the Blessed {@link progressBar} adapter.\n */\nexport interface ProgressBarOptions {\n /**\n * Optional Blessed box configuration.\n *\n * Position, dimensions, style, visibility, and other regular box options\n * can be supplied here.\n */\n box?: ProgressBarBoxOptions;\n\n /**\n * Data passed to the pure {@link renderProgressBar} renderer.\n */\n data: RenderProgressBarOptions;\n\n /**\n * Blessed node that receives the created box as a child.\n *\n * Usually this is a `Screen` or another `BoxElement`.\n */\n parent: blessed.Widgets.Node;\n}\n\n/**\n * Imperative handle returned by {@link progressBar}.\n *\n * The handle owns one Blessed `BoxElement`. It does not own the parent screen\n * and never calls `screen.render()`, allowing callers to batch several updates\n * into one terminal render.\n */\nexport interface ProgressBarHandle {\n /**\n * Underlying Blessed box.\n *\n * Use this for standard Blessed operations such as positioning, showing,\n * hiding, or applying styles.\n */\n readonly element: blessed.Widgets.BoxElement;\n\n /**\n * Destroys and detaches the owned box from its parent.\n *\n * This does not destroy the parent or screen. Do not use the handle after\n * calling this method.\n */\n destroy(): void;\n\n /**\n * Re-renders component content using new data.\n *\n * The underlying element is preserved. This method does not call\n * `screen.render()`; call it explicitly when updates should become visible.\n *\n * @param data - Complete renderer data replacing the previous data.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderProgressBar}.\n */\n setData(data: RenderProgressBarOptions): void;\n}\n\n/**\n * Creates a display-only ProgressBar backed by a Blessed `BoxElement`.\n *\n * Import this adapter from `blessed-components/progress-bar/blessed`. Use\n * {@link renderProgressBar} from `blessed-components/progress-bar` when a\n * Blessed element is unnecessary.\n *\n * The adapter:\n *\n * - renders initial content through {@link renderProgressBar};\n * - disables Blessed tags to keep dynamic text literal;\n * - updates the existing element through {@link ProgressBarHandle.setData};\n * - leaves screen rendering under caller control;\n * - detaches its element through {@link ProgressBarHandle.destroy}.\n *\n * @param options - Parent node, renderer data, and optional box settings.\n * @returns A handle for the created element, updates, and cleanup.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderProgressBar}.\n *\n * @example\n *\n * ```ts\n * import blessed from 'blessed';\n * import { progressBar } from 'blessed-components/progress-bar/blessed';\n *\n * const screen = blessed.screen({ smartCSR: true });\n * const upload = progressBar({\n * parent: screen,\n * box: {\n * top: 0,\n * left: 0,\n * width: 40,\n * height: 1,\n * },\n * data: {\n * label: 'Uploaded',\n * value: 25,\n * width: 20,\n * },\n * });\n *\n * screen.render();\n *\n * upload.setData({\n * label: 'Uploaded',\n * value: 75,\n * width: 20,\n * });\n * screen.render();\n *\n * upload.destroy();\n * screen.destroy();\n * ```\n */\nexport function progressBar({ box, data, parent }: ProgressBarOptions): ProgressBarHandle {\n const element = blessed.box({\n ...box,\n content: renderProgressBar(data),\n parent,\n tags: false,\n });\n\n return {\n element,\n destroy() {\n element.destroy();\n },\n setData(nextData) {\n element.setContent(renderProgressBar(nextData));\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/components/progress-bar/index.ts
|
|
4
|
+
function renderProgressBar({
|
|
5
|
+
characters = { empty: "\u2591", filled: "\u2588" },
|
|
6
|
+
formatValue = ({ percentage }) => `${percentage}%`,
|
|
7
|
+
label,
|
|
8
|
+
max = 100,
|
|
9
|
+
min = 0,
|
|
10
|
+
value,
|
|
11
|
+
width
|
|
12
|
+
}) {
|
|
13
|
+
if (!Number.isInteger(width) || width < 1) {
|
|
14
|
+
throw new RangeError("ProgressBar width must be a positive integer.");
|
|
15
|
+
}
|
|
16
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) {
|
|
17
|
+
throw new RangeError("ProgressBar max must be greater than min.");
|
|
18
|
+
}
|
|
19
|
+
if (!Number.isFinite(value)) {
|
|
20
|
+
throw new RangeError("ProgressBar value must be finite.");
|
|
21
|
+
}
|
|
22
|
+
const clampedValue = Math.min(max, Math.max(min, value));
|
|
23
|
+
const percentage = Math.round((clampedValue - min) / (max - min) * 100);
|
|
24
|
+
const filledWidth = Math.round(percentage / 100 * width);
|
|
25
|
+
const track = characters.filled.repeat(filledWidth) + characters.empty.repeat(width - filledWidth);
|
|
26
|
+
const prefix = label === void 0 ? "" : `${label} `;
|
|
27
|
+
const valueText = formatValue({ percentage, value: clampedValue });
|
|
28
|
+
return `${prefix}${track} ${valueText}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
exports.renderProgressBar = renderProgressBar;
|
|
32
|
+
//# sourceMappingURL=index.cjs.map
|
|
33
|
+
//# sourceMappingURL=index.cjs.map
|