@lewishowles/cli-style 0.17.1 → 0.18.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/CHANGELOG.md +10 -0
- package/adapters/python/pyproject.toml +1 -1
- package/package.json +1 -1
- package/src/formatters/ansi.js +64 -15
- package/src/gallery/render-gallery.js +5 -2
- package/src/primitives/panel.js +6 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.0 - 2026-10-20
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
- BREAKING: Panels without a `width` are now 80 columns wide instead of 40. Pass `width: 40` to keep the narrower panel.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Panels, chips, statuses, spans, feedback and labelled lines now keep their background, text colour and bold or dim text after text coloured by chalk, picocolors or `util.styleText`, which switches off one style at a time instead of resetting everything.
|
|
12
|
+
|
|
3
13
|
## 0.17.1 - 2026-10-20
|
|
4
14
|
|
|
5
15
|
### Changed
|
package/package.json
CHANGED
package/src/formatters/ansi.js
CHANGED
|
@@ -29,6 +29,18 @@ const hyperlinkPattern = new RegExp(
|
|
|
29
29
|
// The sequences that clear every colour and text style at once.
|
|
30
30
|
const clearStyleCodes = [reset, "\u001b[m"];
|
|
31
31
|
|
|
32
|
+
// The sequence that switches the text colour back to the terminal default.
|
|
33
|
+
const foregroundClose = "\u001b[39m";
|
|
34
|
+
|
|
35
|
+
// The sequence that switches the background colour back to the terminal default.
|
|
36
|
+
const backgroundClose = "\u001b[49m";
|
|
37
|
+
|
|
38
|
+
// The sequence that switches off both bold and dim text.
|
|
39
|
+
const weightClose = "\u001b[22m";
|
|
40
|
+
|
|
41
|
+
// Matches a full reset or a sequence that switches off only the text colour, background or bold and dim.
|
|
42
|
+
const closingStylePattern = new RegExp(`${escapeCharacter}\\[(?:0|22|39|49)?m`, "gu");
|
|
43
|
+
|
|
32
44
|
// Splits text into the characters people see, so a joined emoji or an accented letter counts as one.
|
|
33
45
|
const graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
34
46
|
|
|
@@ -105,10 +117,12 @@ export function style(value, style, options = {}) {
|
|
|
105
117
|
}
|
|
106
118
|
|
|
107
119
|
/**
|
|
108
|
-
* Switch the given styles back on
|
|
109
|
-
* carries on past
|
|
110
|
-
* written as `\u001b[0m` or
|
|
111
|
-
* style
|
|
120
|
+
* Switch the given styles back on wherever coloured text inside switches them off, so an
|
|
121
|
+
* outer style carries on past text coloured by this package, chalk, picocolors or
|
|
122
|
+
* `util.styleText`. After a full reset, written as `\u001b[0m` or `\u001b[m`, every given
|
|
123
|
+
* style comes back on. After a sequence that ends only the text colour, the background,
|
|
124
|
+
* or bold and dim, only the given styles of that kind come back on, so other colours the
|
|
125
|
+
* inner text left on stay on.
|
|
112
126
|
*
|
|
113
127
|
* @param {string} value
|
|
114
128
|
* Text that may hold coloured parts.
|
|
@@ -116,22 +130,57 @@ export function style(value, style, options = {}) {
|
|
|
116
130
|
* The styles to switch back on, each rendered on an empty string, such as
|
|
117
131
|
* `style("", "bold", options)`. An empty entry adds nothing.
|
|
118
132
|
* @returns {string}
|
|
119
|
-
* The text with
|
|
133
|
+
* The text with each switched-off style turned back on.
|
|
120
134
|
*/
|
|
121
135
|
export function restoreStyles(value, stylesToRestore) {
|
|
122
|
-
// The codes that turn
|
|
123
|
-
const openingCodes = stylesToRestore
|
|
124
|
-
|
|
125
|
-
|
|
136
|
+
// The codes that turn each style on, with its closing reset cut off.
|
|
137
|
+
const openingCodes = stylesToRestore.map((styleToRestore) =>
|
|
138
|
+
styleToRestore.slice(0, -reset.length),
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// Every style, switched back on together after a full reset.
|
|
142
|
+
const allOpeningCodes = openingCodes.join("");
|
|
143
|
+
|
|
144
|
+
// The text colour styles, switched back on after a text colour close.
|
|
145
|
+
let foregroundCodes = "";
|
|
146
|
+
// The background styles, switched back on after a background close.
|
|
147
|
+
let backgroundCodes = "";
|
|
148
|
+
// The bold and dim styles, switched back on after a bold and dim close.
|
|
149
|
+
let weightCodes = "";
|
|
150
|
+
|
|
151
|
+
// Sorts each style by the number at the start of its code. The text colour and
|
|
152
|
+
// background ranges include 39 and 49 because the default colour opens with them.
|
|
153
|
+
for (const openingCode of openingCodes) {
|
|
154
|
+
// The first number after the escape and bracket, such as 31 for red text.
|
|
155
|
+
const styleNumber = Number.parseInt(openingCode.slice(2), 10);
|
|
156
|
+
|
|
157
|
+
if ((styleNumber >= 30 && styleNumber <= 39) || (styleNumber >= 90 && styleNumber <= 97)) {
|
|
158
|
+
foregroundCodes += openingCode;
|
|
159
|
+
} else if (
|
|
160
|
+
(styleNumber >= 40 && styleNumber <= 49) ||
|
|
161
|
+
(styleNumber >= 100 && styleNumber <= 107)
|
|
162
|
+
) {
|
|
163
|
+
backgroundCodes += openingCode;
|
|
164
|
+
} else if (styleNumber === 1 || styleNumber === 2) {
|
|
165
|
+
weightCodes += openingCode;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
126
168
|
|
|
127
|
-
|
|
128
|
-
|
|
169
|
+
return value.replace(closingStylePattern, (closingCode) => {
|
|
170
|
+
if (closingCode === foregroundClose) {
|
|
171
|
+
return `${closingCode}${foregroundCodes}`;
|
|
172
|
+
}
|
|
129
173
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
174
|
+
if (closingCode === backgroundClose) {
|
|
175
|
+
return `${closingCode}${backgroundCodes}`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (closingCode === weightClose) {
|
|
179
|
+
return `${closingCode}${weightCodes}`;
|
|
180
|
+
}
|
|
133
181
|
|
|
134
|
-
|
|
182
|
+
return `${closingCode}${allOpeningCodes}`;
|
|
183
|
+
});
|
|
135
184
|
}
|
|
136
185
|
|
|
137
186
|
/**
|
|
@@ -1179,12 +1179,15 @@ function renderPanelExamples(options) {
|
|
|
1179
1179
|
}),
|
|
1180
1180
|
);
|
|
1181
1181
|
|
|
1182
|
-
// A panel holding a coloured status line
|
|
1183
|
-
// background carrying on after them.
|
|
1182
|
+
// A panel holding a coloured status line, coloured values and a word coloured the way
|
|
1183
|
+
// chalk colours it, to show the panel background carrying on after them. The word is
|
|
1184
|
+
// written out by hand because chalk ends a colour by switching off only the text
|
|
1185
|
+
// colour, while this package's own colours end with a full reset.
|
|
1184
1186
|
const nestedStylesExample = panel({
|
|
1185
1187
|
...options,
|
|
1186
1188
|
lines: [
|
|
1187
1189
|
status(resultTypes.SUCCESS, "Checks passed", options),
|
|
1190
|
+
options.colour === true ? "A \u001b[31mred\u001b[39m word" : "A red word",
|
|
1188
1191
|
rowGroup({
|
|
1189
1192
|
...options,
|
|
1190
1193
|
rows: [
|
package/src/primitives/panel.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { background, foreground, restoreStyles, style, visibleWidth } from "../formatters/ansi.js";
|
|
2
|
+
import { defaultWidth } from "../formatters/width.js";
|
|
2
3
|
import { wrapText } from "../formatters/wrap.js";
|
|
3
4
|
import { profiles } from "../profiles/profiles.js";
|
|
4
5
|
import { panelColours } from "../theme/colours.js";
|
|
5
6
|
|
|
6
|
-
// The width used when no width is given, such as a direct library call outside a terminal.
|
|
7
|
-
const defaultWidth = 40;
|
|
8
|
-
|
|
9
7
|
// The narrowest panel that still leaves one column for content beside the accent and padding.
|
|
10
8
|
const minimumWidth = 6;
|
|
11
9
|
|
|
@@ -22,8 +20,9 @@ const defaultTone = "info";
|
|
|
22
20
|
* @param {string[]} options.lines
|
|
23
21
|
* Content lines to render.
|
|
24
22
|
* @param {number} options.width
|
|
25
|
-
* Total panel width, including the accent and padding.
|
|
26
|
-
* which leaves room for one character of content.
|
|
23
|
+
* Total panel width, including the accent and padding. Defaults to 80 columns.
|
|
24
|
+
* Widths below 6 are raised to 6, which leaves room for one character of content.
|
|
25
|
+
* Longer lines wrap to fit.
|
|
27
26
|
* @param {string} options.profile
|
|
28
27
|
* Active output profile.
|
|
29
28
|
* @param {string} options.title
|
|
@@ -86,8 +85,8 @@ function renderLine(line, width, isTitle, options) {
|
|
|
86
85
|
|
|
87
86
|
const renderedAccent = renderPanelColour(accent, options);
|
|
88
87
|
|
|
89
|
-
// The content with the panel colours switched back on
|
|
90
|
-
// the panel background carries on to the right edge.
|
|
88
|
+
// The content with the panel colours switched back on wherever coloured text inside
|
|
89
|
+
// switches them off, so the panel background carries on to the right edge.
|
|
91
90
|
const restoredContent = restoreStyles(content, [
|
|
92
91
|
background("", panelColours.background, options),
|
|
93
92
|
foreground("", panelColours.body, options),
|