blessed-components 0.0.1 → 1.1.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.
@@ -0,0 +1,86 @@
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/sparkline.ts
10
+
11
+ // src/components/sparkline/index.ts
12
+ var DEFAULT_CHARACTERS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
13
+ function renderSparkline({
14
+ characters = DEFAULT_CHARACTERS,
15
+ emptyText = "No data",
16
+ label,
17
+ max: configuredMax,
18
+ min: configuredMin,
19
+ summary,
20
+ value: displayValue,
21
+ values,
22
+ width
23
+ }) {
24
+ if (!Number.isInteger(width) || width < 1) {
25
+ throw new RangeError("Sparkline width must be a positive integer.");
26
+ }
27
+ if (characters.length < 2 || characters.some((character) => character.length === 0)) {
28
+ throw new RangeError("Sparkline characters must contain at least two non-empty strings.");
29
+ }
30
+ if (values.some((value) => !Number.isFinite(value))) {
31
+ throw new RangeError("Sparkline values must be finite.");
32
+ }
33
+ if (values.length === 0) {
34
+ return emptyText;
35
+ }
36
+ const min = configuredMin ?? Math.min(...values);
37
+ const max = configuredMax ?? Math.max(...values);
38
+ if (!Number.isFinite(min) || !Number.isFinite(max) || max < min) {
39
+ throw new RangeError("Sparkline max must be greater than or equal to min.");
40
+ }
41
+ if ((configuredMin !== void 0 || configuredMax !== void 0) && max === min) {
42
+ throw new RangeError("Sparkline explicit max must be greater than min.");
43
+ }
44
+ const constantIndex = Math.floor((characters.length - 1) / 2);
45
+ const samples = values.length <= width ? values : Array.from({ length: width }, (_, index) => {
46
+ const start = Math.floor(index * values.length / width);
47
+ const end = Math.floor((index + 1) * values.length / width);
48
+ return Math.max(...values.slice(start, end));
49
+ });
50
+ const sparkline2 = samples.map((value) => {
51
+ if (min === max) {
52
+ return characters[constantIndex];
53
+ }
54
+ const clampedValue = Math.min(max, Math.max(min, value));
55
+ const ratio = (clampedValue - min) / (max - min);
56
+ const index = clampedValue >= max ? characters.length - 1 : Math.floor(ratio * (characters.length - 1));
57
+ return characters[index];
58
+ }).join("");
59
+ const heading = [label, displayValue].filter((part) => part !== void 0).join(" ");
60
+ const chartLine = summary === void 0 ? sparkline2 : `${sparkline2} ${summary}`;
61
+ return heading.length === 0 ? chartLine : `${heading}
62
+ ${chartLine}`;
63
+ }
64
+
65
+ // src/adapters/blessed/sparkline.ts
66
+ function sparkline({ box, data, parent }) {
67
+ const element = blessed__default.default.box({
68
+ ...box,
69
+ content: renderSparkline(data),
70
+ parent,
71
+ tags: false
72
+ });
73
+ return {
74
+ element,
75
+ destroy() {
76
+ element.destroy();
77
+ },
78
+ setData(nextData) {
79
+ element.setContent(renderSparkline(nextData));
80
+ }
81
+ };
82
+ }
83
+
84
+ exports.sparkline = sparkline;
85
+ //# sourceMappingURL=blessed.cjs.map
86
+ //# sourceMappingURL=blessed.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/sparkline/index.ts","../../src/adapters/blessed/sparkline.ts"],"names":["sparkline","blessed"],"mappings":"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","file":"blessed.cjs","sourcesContent":["const DEFAULT_CHARACTERS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'] as const;\n\n/**\n * Options accepted by {@link renderSparkline}.\n *\n * Samples are kept in input order, scaled into `characters`, and reduced to at\n * most `width` cells. Values outside an explicit domain are clamped.\n */\nexport interface RenderSparklineOptions {\n /**\n * Ordered glyph scale from lowest to highest intensity.\n *\n * At least two non-empty strings are required. Glyphs should occupy one\n * terminal cell to keep output width predictable.\n *\n * @defaultValue `['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']`\n */\n characters?: readonly string[];\n\n /**\n * Text returned when `values` is empty.\n *\n * Metadata is not rendered for an empty series.\n *\n * @defaultValue `'No data'`\n */\n emptyText?: string;\n\n /** Optional heading label rendered above the graph. */\n label?: string;\n\n /**\n * Explicit upper domain bound.\n *\n * When omitted, the largest input value is used. If either explicit bound is\n * supplied, the resolved `max` must be greater than the resolved `min`.\n */\n max?: number;\n\n /**\n * Explicit lower domain bound.\n *\n * When omitted, the smallest input value is used.\n */\n min?: number;\n\n /** Optional text appended to the graph line after one space. */\n summary?: string;\n\n /**\n * Optional primary value rendered next to `label`.\n *\n * This value is presentation metadata and does not affect graph scaling.\n */\n value?: number | string;\n\n /**\n * Ordered finite numeric samples.\n *\n * The input array is never mutated.\n */\n values: readonly number[];\n\n /**\n * Positive integer maximum number of graph cells.\n *\n * Longer series are downsampled. Shorter series are not padded.\n */\n width: number;\n}\n\n/**\n * Renders a deterministic terminal sparkline.\n *\n * This pure renderer does not import Blessed. Use the\n * `blessed-components/sparkline` subpath to keep the Blessed adapter outside\n * the module graph.\n *\n * When downsampling is required, the series is divided into ordered buckets\n * and each bucket keeps its maximum value. This preserves narrow peaks. A\n * constant series uses the middle glyph to avoid division by zero.\n *\n * Output shape:\n *\n * ```text\n * [optional label and value]\n * [graph][optional summary]\n * ```\n *\n * With no metadata, only the graph line is returned.\n *\n * @param options - Series, domain, width, glyphs, and optional metadata.\n * @returns Plain text without ANSI sequences or Blessed tags.\n *\n * @throws `RangeError`\n * Thrown when `width` is not a positive integer.\n *\n * @throws `RangeError`\n * Thrown when fewer than two non-empty characters are provided.\n *\n * @throws `RangeError`\n * Thrown when any sample or domain bound is not finite.\n *\n * @throws `RangeError`\n * Thrown when an explicit domain does not have `max > min`.\n *\n * @example Basic series\n *\n * ```ts\n * import { renderSparkline } from 'blessed-components/sparkline';\n *\n * renderSparkline({\n * values: [1, 2, 3, 4, 5, 6, 7, 8],\n * width: 8,\n * });\n * // \"▁▂▃▄▅▆▇█\"\n * ```\n *\n * @example Metadata and summary\n *\n * ```ts\n * renderSparkline({\n * label: 'Downloads',\n * value: '25.2M',\n * values: [1, 3, 2, 8],\n * width: 4,\n * summary: 'peak: 8M',\n * });\n * // \"Downloads 25.2M\\n▁▃▂█ peak: 8M\"\n * ```\n */\nexport function renderSparkline({\n characters = DEFAULT_CHARACTERS,\n emptyText = 'No data',\n label,\n max: configuredMax,\n min: configuredMin,\n summary,\n value: displayValue,\n values,\n width,\n}: RenderSparklineOptions): string {\n if (!Number.isInteger(width) || width < 1) {\n throw new RangeError('Sparkline width must be a positive integer.');\n }\n\n if (characters.length < 2 || characters.some((character) => character.length === 0)) {\n throw new RangeError('Sparkline characters must contain at least two non-empty strings.');\n }\n\n if (values.some((value) => !Number.isFinite(value))) {\n throw new RangeError('Sparkline values must be finite.');\n }\n\n if (values.length === 0) {\n return emptyText;\n }\n\n const min = configuredMin ?? Math.min(...values);\n const max = configuredMax ?? Math.max(...values);\n\n if (!Number.isFinite(min) || !Number.isFinite(max) || max < min) {\n throw new RangeError('Sparkline max must be greater than or equal to min.');\n }\n\n if ((configuredMin !== undefined || configuredMax !== undefined) && max === min) {\n throw new RangeError('Sparkline explicit max must be greater than min.');\n }\n\n const constantIndex = Math.floor((characters.length - 1) / 2);\n const samples =\n values.length <= width\n ? values\n : Array.from({ length: width }, (_, index) => {\n const start = Math.floor((index * values.length) / width);\n const end = Math.floor(((index + 1) * values.length) / width);\n\n return Math.max(...values.slice(start, end));\n });\n const sparkline = samples\n .map((value) => {\n if (min === max) {\n return characters[constantIndex];\n }\n\n const clampedValue = Math.min(max, Math.max(min, value));\n const ratio = (clampedValue - min) / (max - min);\n const index =\n clampedValue >= max ? characters.length - 1 : Math.floor(ratio * (characters.length - 1));\n\n return characters[index];\n })\n .join('');\n const heading = [label, displayValue].filter((part) => part !== undefined).join(' ');\n const chartLine = summary === undefined ? sparkline : `${sparkline} ${summary}`;\n\n return heading.length === 0 ? chartLine : `${heading}\\n${chartLine}`;\n}\n","import blessed from 'blessed';\n\nimport { type RenderSparklineOptions, renderSparkline } from '../../components/sparkline/index.js';\n\n/**\n * Blessed box options supported by the Sparkline adapter.\n *\n * `parent`, `content`, and `tags` are controlled by {@link sparkline}.\n */\nexport type SparklineBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;\n\n/** Options accepted by the Blessed {@link sparkline} adapter. */\nexport interface SparklineOptions {\n /** Optional position, dimensions, style, and other Blessed box settings. */\n box?: SparklineBoxOptions;\n\n /** Data passed to the pure {@link renderSparkline} renderer. */\n data: RenderSparklineOptions;\n\n /** Blessed screen or node that receives the created box. */\n parent: blessed.Widgets.Node;\n}\n\n/**\n * Imperative handle returned by {@link sparkline}.\n *\n * The handle owns one box, never owns the parent screen, and never calls\n * `screen.render()`.\n */\nexport interface SparklineHandle {\n /** Underlying Blessed box used for standard element operations. */\n readonly element: blessed.Widgets.BoxElement;\n\n /**\n * Destroys and detaches the owned box.\n *\n * The parent and screen remain alive.\n */\n destroy(): void;\n\n /**\n * Replaces renderer data while preserving the Blessed element.\n *\n * Call `screen.render()` after one or more updates to flush visible output.\n *\n * @param data - Complete renderer data replacing the previous data.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderSparkline}.\n */\n setData(data: RenderSparklineOptions): void;\n}\n\n/**\n * Creates a display-only Sparkline backed by a Blessed `BoxElement`.\n *\n * Import from `blessed-components/sparkline/blessed`. The adapter disables\n * Blessed tags, renders through {@link renderSparkline}, and leaves terminal\n * rendering under caller control.\n *\n * @param options - Parent node, renderer data, and optional box settings.\n * @returns Handle for the created box, updates, and cleanup.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderSparkline}.\n *\n * @example\n *\n * ```ts\n * import blessed from 'blessed';\n * import { sparkline } from 'blessed-components/sparkline/blessed';\n *\n * const screen = blessed.screen({ smartCSR: true });\n * const downloads = sparkline({\n * parent: screen,\n * box: { top: 0, left: 0, width: 40, height: 2 },\n * data: {\n * label: 'Downloads',\n * values: [1, 3, 2, 8],\n * width: 20,\n * },\n * });\n *\n * screen.render();\n * downloads.setData({\n * label: 'Downloads',\n * values: [2, 4, 6, 8],\n * width: 20,\n * });\n * screen.render();\n *\n * downloads.destroy();\n * screen.destroy();\n * ```\n */\nexport function sparkline({ box, data, parent }: SparklineOptions): SparklineHandle {\n const element = blessed.box({\n ...box,\n content: renderSparkline(data),\n parent,\n tags: false,\n });\n\n return {\n element,\n destroy() {\n element.destroy();\n },\n setData(nextData) {\n element.setContent(renderSparkline(nextData));\n },\n };\n}\n"]}
@@ -0,0 +1,90 @@
1
+ import blessed from 'blessed';
2
+ import { RenderSparklineOptions } from './index.cjs';
3
+
4
+ /**
5
+ * Blessed box options supported by the Sparkline adapter.
6
+ *
7
+ * `parent`, `content`, and `tags` are controlled by {@link sparkline}.
8
+ */
9
+ type SparklineBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;
10
+ /** Options accepted by the Blessed {@link sparkline} adapter. */
11
+ interface SparklineOptions {
12
+ /** Optional position, dimensions, style, and other Blessed box settings. */
13
+ box?: SparklineBoxOptions;
14
+ /** Data passed to the pure {@link renderSparkline} renderer. */
15
+ data: RenderSparklineOptions;
16
+ /** Blessed screen or node that receives the created box. */
17
+ parent: blessed.Widgets.Node;
18
+ }
19
+ /**
20
+ * Imperative handle returned by {@link sparkline}.
21
+ *
22
+ * The handle owns one box, never owns the parent screen, and never calls
23
+ * `screen.render()`.
24
+ */
25
+ interface SparklineHandle {
26
+ /** Underlying Blessed box used for standard element operations. */
27
+ readonly element: blessed.Widgets.BoxElement;
28
+ /**
29
+ * Destroys and detaches the owned box.
30
+ *
31
+ * The parent and screen remain alive.
32
+ */
33
+ destroy(): void;
34
+ /**
35
+ * Replaces renderer data while preserving the Blessed element.
36
+ *
37
+ * Call `screen.render()` after one or more updates to flush visible output.
38
+ *
39
+ * @param data - Complete renderer data replacing the previous data.
40
+ *
41
+ * @throws `RangeError`
42
+ * Propagates validation errors from {@link renderSparkline}.
43
+ */
44
+ setData(data: RenderSparklineOptions): void;
45
+ }
46
+ /**
47
+ * Creates a display-only Sparkline backed by a Blessed `BoxElement`.
48
+ *
49
+ * Import from `blessed-components/sparkline/blessed`. The adapter disables
50
+ * Blessed tags, renders through {@link renderSparkline}, and leaves terminal
51
+ * rendering under caller control.
52
+ *
53
+ * @param options - Parent node, renderer data, and optional box settings.
54
+ * @returns Handle for the created box, updates, and cleanup.
55
+ *
56
+ * @throws `RangeError`
57
+ * Propagates validation errors from {@link renderSparkline}.
58
+ *
59
+ * @example
60
+ *
61
+ * ```ts
62
+ * import blessed from 'blessed';
63
+ * import { sparkline } from 'blessed-components/sparkline/blessed';
64
+ *
65
+ * const screen = blessed.screen({ smartCSR: true });
66
+ * const downloads = sparkline({
67
+ * parent: screen,
68
+ * box: { top: 0, left: 0, width: 40, height: 2 },
69
+ * data: {
70
+ * label: 'Downloads',
71
+ * values: [1, 3, 2, 8],
72
+ * width: 20,
73
+ * },
74
+ * });
75
+ *
76
+ * screen.render();
77
+ * downloads.setData({
78
+ * label: 'Downloads',
79
+ * values: [2, 4, 6, 8],
80
+ * width: 20,
81
+ * });
82
+ * screen.render();
83
+ *
84
+ * downloads.destroy();
85
+ * screen.destroy();
86
+ * ```
87
+ */
88
+ declare function sparkline({ box, data, parent }: SparklineOptions): SparklineHandle;
89
+
90
+ export { type SparklineBoxOptions, type SparklineHandle, type SparklineOptions, sparkline };
@@ -0,0 +1,90 @@
1
+ import blessed from 'blessed';
2
+ import { RenderSparklineOptions } from './index.js';
3
+
4
+ /**
5
+ * Blessed box options supported by the Sparkline adapter.
6
+ *
7
+ * `parent`, `content`, and `tags` are controlled by {@link sparkline}.
8
+ */
9
+ type SparklineBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;
10
+ /** Options accepted by the Blessed {@link sparkline} adapter. */
11
+ interface SparklineOptions {
12
+ /** Optional position, dimensions, style, and other Blessed box settings. */
13
+ box?: SparklineBoxOptions;
14
+ /** Data passed to the pure {@link renderSparkline} renderer. */
15
+ data: RenderSparklineOptions;
16
+ /** Blessed screen or node that receives the created box. */
17
+ parent: blessed.Widgets.Node;
18
+ }
19
+ /**
20
+ * Imperative handle returned by {@link sparkline}.
21
+ *
22
+ * The handle owns one box, never owns the parent screen, and never calls
23
+ * `screen.render()`.
24
+ */
25
+ interface SparklineHandle {
26
+ /** Underlying Blessed box used for standard element operations. */
27
+ readonly element: blessed.Widgets.BoxElement;
28
+ /**
29
+ * Destroys and detaches the owned box.
30
+ *
31
+ * The parent and screen remain alive.
32
+ */
33
+ destroy(): void;
34
+ /**
35
+ * Replaces renderer data while preserving the Blessed element.
36
+ *
37
+ * Call `screen.render()` after one or more updates to flush visible output.
38
+ *
39
+ * @param data - Complete renderer data replacing the previous data.
40
+ *
41
+ * @throws `RangeError`
42
+ * Propagates validation errors from {@link renderSparkline}.
43
+ */
44
+ setData(data: RenderSparklineOptions): void;
45
+ }
46
+ /**
47
+ * Creates a display-only Sparkline backed by a Blessed `BoxElement`.
48
+ *
49
+ * Import from `blessed-components/sparkline/blessed`. The adapter disables
50
+ * Blessed tags, renders through {@link renderSparkline}, and leaves terminal
51
+ * rendering under caller control.
52
+ *
53
+ * @param options - Parent node, renderer data, and optional box settings.
54
+ * @returns Handle for the created box, updates, and cleanup.
55
+ *
56
+ * @throws `RangeError`
57
+ * Propagates validation errors from {@link renderSparkline}.
58
+ *
59
+ * @example
60
+ *
61
+ * ```ts
62
+ * import blessed from 'blessed';
63
+ * import { sparkline } from 'blessed-components/sparkline/blessed';
64
+ *
65
+ * const screen = blessed.screen({ smartCSR: true });
66
+ * const downloads = sparkline({
67
+ * parent: screen,
68
+ * box: { top: 0, left: 0, width: 40, height: 2 },
69
+ * data: {
70
+ * label: 'Downloads',
71
+ * values: [1, 3, 2, 8],
72
+ * width: 20,
73
+ * },
74
+ * });
75
+ *
76
+ * screen.render();
77
+ * downloads.setData({
78
+ * label: 'Downloads',
79
+ * values: [2, 4, 6, 8],
80
+ * width: 20,
81
+ * });
82
+ * screen.render();
83
+ *
84
+ * downloads.destroy();
85
+ * screen.destroy();
86
+ * ```
87
+ */
88
+ declare function sparkline({ box, data, parent }: SparklineOptions): SparklineHandle;
89
+
90
+ export { type SparklineBoxOptions, type SparklineHandle, type SparklineOptions, sparkline };
@@ -0,0 +1,80 @@
1
+ import blessed from 'blessed';
2
+
3
+ // src/adapters/blessed/sparkline.ts
4
+
5
+ // src/components/sparkline/index.ts
6
+ var DEFAULT_CHARACTERS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
7
+ function renderSparkline({
8
+ characters = DEFAULT_CHARACTERS,
9
+ emptyText = "No data",
10
+ label,
11
+ max: configuredMax,
12
+ min: configuredMin,
13
+ summary,
14
+ value: displayValue,
15
+ values,
16
+ width
17
+ }) {
18
+ if (!Number.isInteger(width) || width < 1) {
19
+ throw new RangeError("Sparkline width must be a positive integer.");
20
+ }
21
+ if (characters.length < 2 || characters.some((character) => character.length === 0)) {
22
+ throw new RangeError("Sparkline characters must contain at least two non-empty strings.");
23
+ }
24
+ if (values.some((value) => !Number.isFinite(value))) {
25
+ throw new RangeError("Sparkline values must be finite.");
26
+ }
27
+ if (values.length === 0) {
28
+ return emptyText;
29
+ }
30
+ const min = configuredMin ?? Math.min(...values);
31
+ const max = configuredMax ?? Math.max(...values);
32
+ if (!Number.isFinite(min) || !Number.isFinite(max) || max < min) {
33
+ throw new RangeError("Sparkline max must be greater than or equal to min.");
34
+ }
35
+ if ((configuredMin !== void 0 || configuredMax !== void 0) && max === min) {
36
+ throw new RangeError("Sparkline explicit max must be greater than min.");
37
+ }
38
+ const constantIndex = Math.floor((characters.length - 1) / 2);
39
+ const samples = values.length <= width ? values : Array.from({ length: width }, (_, index) => {
40
+ const start = Math.floor(index * values.length / width);
41
+ const end = Math.floor((index + 1) * values.length / width);
42
+ return Math.max(...values.slice(start, end));
43
+ });
44
+ const sparkline2 = samples.map((value) => {
45
+ if (min === max) {
46
+ return characters[constantIndex];
47
+ }
48
+ const clampedValue = Math.min(max, Math.max(min, value));
49
+ const ratio = (clampedValue - min) / (max - min);
50
+ const index = clampedValue >= max ? characters.length - 1 : Math.floor(ratio * (characters.length - 1));
51
+ return characters[index];
52
+ }).join("");
53
+ const heading = [label, displayValue].filter((part) => part !== void 0).join(" ");
54
+ const chartLine = summary === void 0 ? sparkline2 : `${sparkline2} ${summary}`;
55
+ return heading.length === 0 ? chartLine : `${heading}
56
+ ${chartLine}`;
57
+ }
58
+
59
+ // src/adapters/blessed/sparkline.ts
60
+ function sparkline({ box, data, parent }) {
61
+ const element = blessed.box({
62
+ ...box,
63
+ content: renderSparkline(data),
64
+ parent,
65
+ tags: false
66
+ });
67
+ return {
68
+ element,
69
+ destroy() {
70
+ element.destroy();
71
+ },
72
+ setData(nextData) {
73
+ element.setContent(renderSparkline(nextData));
74
+ }
75
+ };
76
+ }
77
+
78
+ export { sparkline };
79
+ //# sourceMappingURL=blessed.js.map
80
+ //# sourceMappingURL=blessed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/sparkline/index.ts","../../src/adapters/blessed/sparkline.ts"],"names":["sparkline"],"mappings":"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","file":"blessed.js","sourcesContent":["const DEFAULT_CHARACTERS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'] as const;\n\n/**\n * Options accepted by {@link renderSparkline}.\n *\n * Samples are kept in input order, scaled into `characters`, and reduced to at\n * most `width` cells. Values outside an explicit domain are clamped.\n */\nexport interface RenderSparklineOptions {\n /**\n * Ordered glyph scale from lowest to highest intensity.\n *\n * At least two non-empty strings are required. Glyphs should occupy one\n * terminal cell to keep output width predictable.\n *\n * @defaultValue `['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']`\n */\n characters?: readonly string[];\n\n /**\n * Text returned when `values` is empty.\n *\n * Metadata is not rendered for an empty series.\n *\n * @defaultValue `'No data'`\n */\n emptyText?: string;\n\n /** Optional heading label rendered above the graph. */\n label?: string;\n\n /**\n * Explicit upper domain bound.\n *\n * When omitted, the largest input value is used. If either explicit bound is\n * supplied, the resolved `max` must be greater than the resolved `min`.\n */\n max?: number;\n\n /**\n * Explicit lower domain bound.\n *\n * When omitted, the smallest input value is used.\n */\n min?: number;\n\n /** Optional text appended to the graph line after one space. */\n summary?: string;\n\n /**\n * Optional primary value rendered next to `label`.\n *\n * This value is presentation metadata and does not affect graph scaling.\n */\n value?: number | string;\n\n /**\n * Ordered finite numeric samples.\n *\n * The input array is never mutated.\n */\n values: readonly number[];\n\n /**\n * Positive integer maximum number of graph cells.\n *\n * Longer series are downsampled. Shorter series are not padded.\n */\n width: number;\n}\n\n/**\n * Renders a deterministic terminal sparkline.\n *\n * This pure renderer does not import Blessed. Use the\n * `blessed-components/sparkline` subpath to keep the Blessed adapter outside\n * the module graph.\n *\n * When downsampling is required, the series is divided into ordered buckets\n * and each bucket keeps its maximum value. This preserves narrow peaks. A\n * constant series uses the middle glyph to avoid division by zero.\n *\n * Output shape:\n *\n * ```text\n * [optional label and value]\n * [graph][optional summary]\n * ```\n *\n * With no metadata, only the graph line is returned.\n *\n * @param options - Series, domain, width, glyphs, and optional metadata.\n * @returns Plain text without ANSI sequences or Blessed tags.\n *\n * @throws `RangeError`\n * Thrown when `width` is not a positive integer.\n *\n * @throws `RangeError`\n * Thrown when fewer than two non-empty characters are provided.\n *\n * @throws `RangeError`\n * Thrown when any sample or domain bound is not finite.\n *\n * @throws `RangeError`\n * Thrown when an explicit domain does not have `max > min`.\n *\n * @example Basic series\n *\n * ```ts\n * import { renderSparkline } from 'blessed-components/sparkline';\n *\n * renderSparkline({\n * values: [1, 2, 3, 4, 5, 6, 7, 8],\n * width: 8,\n * });\n * // \"▁▂▃▄▅▆▇█\"\n * ```\n *\n * @example Metadata and summary\n *\n * ```ts\n * renderSparkline({\n * label: 'Downloads',\n * value: '25.2M',\n * values: [1, 3, 2, 8],\n * width: 4,\n * summary: 'peak: 8M',\n * });\n * // \"Downloads 25.2M\\n▁▃▂█ peak: 8M\"\n * ```\n */\nexport function renderSparkline({\n characters = DEFAULT_CHARACTERS,\n emptyText = 'No data',\n label,\n max: configuredMax,\n min: configuredMin,\n summary,\n value: displayValue,\n values,\n width,\n}: RenderSparklineOptions): string {\n if (!Number.isInteger(width) || width < 1) {\n throw new RangeError('Sparkline width must be a positive integer.');\n }\n\n if (characters.length < 2 || characters.some((character) => character.length === 0)) {\n throw new RangeError('Sparkline characters must contain at least two non-empty strings.');\n }\n\n if (values.some((value) => !Number.isFinite(value))) {\n throw new RangeError('Sparkline values must be finite.');\n }\n\n if (values.length === 0) {\n return emptyText;\n }\n\n const min = configuredMin ?? Math.min(...values);\n const max = configuredMax ?? Math.max(...values);\n\n if (!Number.isFinite(min) || !Number.isFinite(max) || max < min) {\n throw new RangeError('Sparkline max must be greater than or equal to min.');\n }\n\n if ((configuredMin !== undefined || configuredMax !== undefined) && max === min) {\n throw new RangeError('Sparkline explicit max must be greater than min.');\n }\n\n const constantIndex = Math.floor((characters.length - 1) / 2);\n const samples =\n values.length <= width\n ? values\n : Array.from({ length: width }, (_, index) => {\n const start = Math.floor((index * values.length) / width);\n const end = Math.floor(((index + 1) * values.length) / width);\n\n return Math.max(...values.slice(start, end));\n });\n const sparkline = samples\n .map((value) => {\n if (min === max) {\n return characters[constantIndex];\n }\n\n const clampedValue = Math.min(max, Math.max(min, value));\n const ratio = (clampedValue - min) / (max - min);\n const index =\n clampedValue >= max ? characters.length - 1 : Math.floor(ratio * (characters.length - 1));\n\n return characters[index];\n })\n .join('');\n const heading = [label, displayValue].filter((part) => part !== undefined).join(' ');\n const chartLine = summary === undefined ? sparkline : `${sparkline} ${summary}`;\n\n return heading.length === 0 ? chartLine : `${heading}\\n${chartLine}`;\n}\n","import blessed from 'blessed';\n\nimport { type RenderSparklineOptions, renderSparkline } from '../../components/sparkline/index.js';\n\n/**\n * Blessed box options supported by the Sparkline adapter.\n *\n * `parent`, `content`, and `tags` are controlled by {@link sparkline}.\n */\nexport type SparklineBoxOptions = Omit<blessed.Widgets.BoxOptions, 'content' | 'parent' | 'tags'>;\n\n/** Options accepted by the Blessed {@link sparkline} adapter. */\nexport interface SparklineOptions {\n /** Optional position, dimensions, style, and other Blessed box settings. */\n box?: SparklineBoxOptions;\n\n /** Data passed to the pure {@link renderSparkline} renderer. */\n data: RenderSparklineOptions;\n\n /** Blessed screen or node that receives the created box. */\n parent: blessed.Widgets.Node;\n}\n\n/**\n * Imperative handle returned by {@link sparkline}.\n *\n * The handle owns one box, never owns the parent screen, and never calls\n * `screen.render()`.\n */\nexport interface SparklineHandle {\n /** Underlying Blessed box used for standard element operations. */\n readonly element: blessed.Widgets.BoxElement;\n\n /**\n * Destroys and detaches the owned box.\n *\n * The parent and screen remain alive.\n */\n destroy(): void;\n\n /**\n * Replaces renderer data while preserving the Blessed element.\n *\n * Call `screen.render()` after one or more updates to flush visible output.\n *\n * @param data - Complete renderer data replacing the previous data.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderSparkline}.\n */\n setData(data: RenderSparklineOptions): void;\n}\n\n/**\n * Creates a display-only Sparkline backed by a Blessed `BoxElement`.\n *\n * Import from `blessed-components/sparkline/blessed`. The adapter disables\n * Blessed tags, renders through {@link renderSparkline}, and leaves terminal\n * rendering under caller control.\n *\n * @param options - Parent node, renderer data, and optional box settings.\n * @returns Handle for the created box, updates, and cleanup.\n *\n * @throws `RangeError`\n * Propagates validation errors from {@link renderSparkline}.\n *\n * @example\n *\n * ```ts\n * import blessed from 'blessed';\n * import { sparkline } from 'blessed-components/sparkline/blessed';\n *\n * const screen = blessed.screen({ smartCSR: true });\n * const downloads = sparkline({\n * parent: screen,\n * box: { top: 0, left: 0, width: 40, height: 2 },\n * data: {\n * label: 'Downloads',\n * values: [1, 3, 2, 8],\n * width: 20,\n * },\n * });\n *\n * screen.render();\n * downloads.setData({\n * label: 'Downloads',\n * values: [2, 4, 6, 8],\n * width: 20,\n * });\n * screen.render();\n *\n * downloads.destroy();\n * screen.destroy();\n * ```\n */\nexport function sparkline({ box, data, parent }: SparklineOptions): SparklineHandle {\n const element = blessed.box({\n ...box,\n content: renderSparkline(data),\n parent,\n tags: false,\n });\n\n return {\n element,\n destroy() {\n element.destroy();\n },\n setData(nextData) {\n element.setContent(renderSparkline(nextData));\n },\n };\n}\n"]}
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ // src/components/sparkline/index.ts
4
+ var DEFAULT_CHARACTERS = ["\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
5
+ function renderSparkline({
6
+ characters = DEFAULT_CHARACTERS,
7
+ emptyText = "No data",
8
+ label,
9
+ max: configuredMax,
10
+ min: configuredMin,
11
+ summary,
12
+ value: displayValue,
13
+ values,
14
+ width
15
+ }) {
16
+ if (!Number.isInteger(width) || width < 1) {
17
+ throw new RangeError("Sparkline width must be a positive integer.");
18
+ }
19
+ if (characters.length < 2 || characters.some((character) => character.length === 0)) {
20
+ throw new RangeError("Sparkline characters must contain at least two non-empty strings.");
21
+ }
22
+ if (values.some((value) => !Number.isFinite(value))) {
23
+ throw new RangeError("Sparkline values must be finite.");
24
+ }
25
+ if (values.length === 0) {
26
+ return emptyText;
27
+ }
28
+ const min = configuredMin ?? Math.min(...values);
29
+ const max = configuredMax ?? Math.max(...values);
30
+ if (!Number.isFinite(min) || !Number.isFinite(max) || max < min) {
31
+ throw new RangeError("Sparkline max must be greater than or equal to min.");
32
+ }
33
+ if ((configuredMin !== void 0 || configuredMax !== void 0) && max === min) {
34
+ throw new RangeError("Sparkline explicit max must be greater than min.");
35
+ }
36
+ const constantIndex = Math.floor((characters.length - 1) / 2);
37
+ const samples = values.length <= width ? values : Array.from({ length: width }, (_, index) => {
38
+ const start = Math.floor(index * values.length / width);
39
+ const end = Math.floor((index + 1) * values.length / width);
40
+ return Math.max(...values.slice(start, end));
41
+ });
42
+ const sparkline = samples.map((value) => {
43
+ if (min === max) {
44
+ return characters[constantIndex];
45
+ }
46
+ const clampedValue = Math.min(max, Math.max(min, value));
47
+ const ratio = (clampedValue - min) / (max - min);
48
+ const index = clampedValue >= max ? characters.length - 1 : Math.floor(ratio * (characters.length - 1));
49
+ return characters[index];
50
+ }).join("");
51
+ const heading = [label, displayValue].filter((part) => part !== void 0).join(" ");
52
+ const chartLine = summary === void 0 ? sparkline : `${sparkline} ${summary}`;
53
+ return heading.length === 0 ? chartLine : `${heading}
54
+ ${chartLine}`;
55
+ }
56
+
57
+ exports.renderSparkline = renderSparkline;
58
+ //# sourceMappingURL=index.cjs.map
59
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/sparkline/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["const DEFAULT_CHARACTERS = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'] as const;\n\n/**\n * Options accepted by {@link renderSparkline}.\n *\n * Samples are kept in input order, scaled into `characters`, and reduced to at\n * most `width` cells. Values outside an explicit domain are clamped.\n */\nexport interface RenderSparklineOptions {\n /**\n * Ordered glyph scale from lowest to highest intensity.\n *\n * At least two non-empty strings are required. Glyphs should occupy one\n * terminal cell to keep output width predictable.\n *\n * @defaultValue `['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']`\n */\n characters?: readonly string[];\n\n /**\n * Text returned when `values` is empty.\n *\n * Metadata is not rendered for an empty series.\n *\n * @defaultValue `'No data'`\n */\n emptyText?: string;\n\n /** Optional heading label rendered above the graph. */\n label?: string;\n\n /**\n * Explicit upper domain bound.\n *\n * When omitted, the largest input value is used. If either explicit bound is\n * supplied, the resolved `max` must be greater than the resolved `min`.\n */\n max?: number;\n\n /**\n * Explicit lower domain bound.\n *\n * When omitted, the smallest input value is used.\n */\n min?: number;\n\n /** Optional text appended to the graph line after one space. */\n summary?: string;\n\n /**\n * Optional primary value rendered next to `label`.\n *\n * This value is presentation metadata and does not affect graph scaling.\n */\n value?: number | string;\n\n /**\n * Ordered finite numeric samples.\n *\n * The input array is never mutated.\n */\n values: readonly number[];\n\n /**\n * Positive integer maximum number of graph cells.\n *\n * Longer series are downsampled. Shorter series are not padded.\n */\n width: number;\n}\n\n/**\n * Renders a deterministic terminal sparkline.\n *\n * This pure renderer does not import Blessed. Use the\n * `blessed-components/sparkline` subpath to keep the Blessed adapter outside\n * the module graph.\n *\n * When downsampling is required, the series is divided into ordered buckets\n * and each bucket keeps its maximum value. This preserves narrow peaks. A\n * constant series uses the middle glyph to avoid division by zero.\n *\n * Output shape:\n *\n * ```text\n * [optional label and value]\n * [graph][optional summary]\n * ```\n *\n * With no metadata, only the graph line is returned.\n *\n * @param options - Series, domain, width, glyphs, and optional metadata.\n * @returns Plain text without ANSI sequences or Blessed tags.\n *\n * @throws `RangeError`\n * Thrown when `width` is not a positive integer.\n *\n * @throws `RangeError`\n * Thrown when fewer than two non-empty characters are provided.\n *\n * @throws `RangeError`\n * Thrown when any sample or domain bound is not finite.\n *\n * @throws `RangeError`\n * Thrown when an explicit domain does not have `max > min`.\n *\n * @example Basic series\n *\n * ```ts\n * import { renderSparkline } from 'blessed-components/sparkline';\n *\n * renderSparkline({\n * values: [1, 2, 3, 4, 5, 6, 7, 8],\n * width: 8,\n * });\n * // \"▁▂▃▄▅▆▇█\"\n * ```\n *\n * @example Metadata and summary\n *\n * ```ts\n * renderSparkline({\n * label: 'Downloads',\n * value: '25.2M',\n * values: [1, 3, 2, 8],\n * width: 4,\n * summary: 'peak: 8M',\n * });\n * // \"Downloads 25.2M\\n▁▃▂█ peak: 8M\"\n * ```\n */\nexport function renderSparkline({\n characters = DEFAULT_CHARACTERS,\n emptyText = 'No data',\n label,\n max: configuredMax,\n min: configuredMin,\n summary,\n value: displayValue,\n values,\n width,\n}: RenderSparklineOptions): string {\n if (!Number.isInteger(width) || width < 1) {\n throw new RangeError('Sparkline width must be a positive integer.');\n }\n\n if (characters.length < 2 || characters.some((character) => character.length === 0)) {\n throw new RangeError('Sparkline characters must contain at least two non-empty strings.');\n }\n\n if (values.some((value) => !Number.isFinite(value))) {\n throw new RangeError('Sparkline values must be finite.');\n }\n\n if (values.length === 0) {\n return emptyText;\n }\n\n const min = configuredMin ?? Math.min(...values);\n const max = configuredMax ?? Math.max(...values);\n\n if (!Number.isFinite(min) || !Number.isFinite(max) || max < min) {\n throw new RangeError('Sparkline max must be greater than or equal to min.');\n }\n\n if ((configuredMin !== undefined || configuredMax !== undefined) && max === min) {\n throw new RangeError('Sparkline explicit max must be greater than min.');\n }\n\n const constantIndex = Math.floor((characters.length - 1) / 2);\n const samples =\n values.length <= width\n ? values\n : Array.from({ length: width }, (_, index) => {\n const start = Math.floor((index * values.length) / width);\n const end = Math.floor(((index + 1) * values.length) / width);\n\n return Math.max(...values.slice(start, end));\n });\n const sparkline = samples\n .map((value) => {\n if (min === max) {\n return characters[constantIndex];\n }\n\n const clampedValue = Math.min(max, Math.max(min, value));\n const ratio = (clampedValue - min) / (max - min);\n const index =\n clampedValue >= max ? characters.length - 1 : Math.floor(ratio * (characters.length - 1));\n\n return characters[index];\n })\n .join('');\n const heading = [label, displayValue].filter((part) => part !== undefined).join(' ');\n const chartLine = summary === undefined ? sparkline : `${sparkline} ${summary}`;\n\n return heading.length === 0 ? chartLine : `${heading}\\n${chartLine}`;\n}\n"]}
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Options accepted by {@link renderSparkline}.
3
+ *
4
+ * Samples are kept in input order, scaled into `characters`, and reduced to at
5
+ * most `width` cells. Values outside an explicit domain are clamped.
6
+ */
7
+ interface RenderSparklineOptions {
8
+ /**
9
+ * Ordered glyph scale from lowest to highest intensity.
10
+ *
11
+ * At least two non-empty strings are required. Glyphs should occupy one
12
+ * terminal cell to keep output width predictable.
13
+ *
14
+ * @defaultValue `['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']`
15
+ */
16
+ characters?: readonly string[];
17
+ /**
18
+ * Text returned when `values` is empty.
19
+ *
20
+ * Metadata is not rendered for an empty series.
21
+ *
22
+ * @defaultValue `'No data'`
23
+ */
24
+ emptyText?: string;
25
+ /** Optional heading label rendered above the graph. */
26
+ label?: string;
27
+ /**
28
+ * Explicit upper domain bound.
29
+ *
30
+ * When omitted, the largest input value is used. If either explicit bound is
31
+ * supplied, the resolved `max` must be greater than the resolved `min`.
32
+ */
33
+ max?: number;
34
+ /**
35
+ * Explicit lower domain bound.
36
+ *
37
+ * When omitted, the smallest input value is used.
38
+ */
39
+ min?: number;
40
+ /** Optional text appended to the graph line after one space. */
41
+ summary?: string;
42
+ /**
43
+ * Optional primary value rendered next to `label`.
44
+ *
45
+ * This value is presentation metadata and does not affect graph scaling.
46
+ */
47
+ value?: number | string;
48
+ /**
49
+ * Ordered finite numeric samples.
50
+ *
51
+ * The input array is never mutated.
52
+ */
53
+ values: readonly number[];
54
+ /**
55
+ * Positive integer maximum number of graph cells.
56
+ *
57
+ * Longer series are downsampled. Shorter series are not padded.
58
+ */
59
+ width: number;
60
+ }
61
+ /**
62
+ * Renders a deterministic terminal sparkline.
63
+ *
64
+ * This pure renderer does not import Blessed. Use the
65
+ * `blessed-components/sparkline` subpath to keep the Blessed adapter outside
66
+ * the module graph.
67
+ *
68
+ * When downsampling is required, the series is divided into ordered buckets
69
+ * and each bucket keeps its maximum value. This preserves narrow peaks. A
70
+ * constant series uses the middle glyph to avoid division by zero.
71
+ *
72
+ * Output shape:
73
+ *
74
+ * ```text
75
+ * [optional label and value]
76
+ * [graph][optional summary]
77
+ * ```
78
+ *
79
+ * With no metadata, only the graph line is returned.
80
+ *
81
+ * @param options - Series, domain, width, glyphs, and optional metadata.
82
+ * @returns Plain text without ANSI sequences or Blessed tags.
83
+ *
84
+ * @throws `RangeError`
85
+ * Thrown when `width` is not a positive integer.
86
+ *
87
+ * @throws `RangeError`
88
+ * Thrown when fewer than two non-empty characters are provided.
89
+ *
90
+ * @throws `RangeError`
91
+ * Thrown when any sample or domain bound is not finite.
92
+ *
93
+ * @throws `RangeError`
94
+ * Thrown when an explicit domain does not have `max > min`.
95
+ *
96
+ * @example Basic series
97
+ *
98
+ * ```ts
99
+ * import { renderSparkline } from 'blessed-components/sparkline';
100
+ *
101
+ * renderSparkline({
102
+ * values: [1, 2, 3, 4, 5, 6, 7, 8],
103
+ * width: 8,
104
+ * });
105
+ * // "▁▂▃▄▅▆▇█"
106
+ * ```
107
+ *
108
+ * @example Metadata and summary
109
+ *
110
+ * ```ts
111
+ * renderSparkline({
112
+ * label: 'Downloads',
113
+ * value: '25.2M',
114
+ * values: [1, 3, 2, 8],
115
+ * width: 4,
116
+ * summary: 'peak: 8M',
117
+ * });
118
+ * // "Downloads 25.2M\n▁▃▂█ peak: 8M"
119
+ * ```
120
+ */
121
+ declare function renderSparkline({ characters, emptyText, label, max: configuredMax, min: configuredMin, summary, value: displayValue, values, width, }: RenderSparklineOptions): string;
122
+
123
+ export { type RenderSparklineOptions, renderSparkline };