@lewishowles/cli-style 0.8.1 → 0.9.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/README.md +22 -0
- package/adapters/bash/cli-style.sh +128 -6
- package/adapters/python/cli_style.py +52 -3
- package/adapters/swift/CliStyle.swift +60 -6
- package/package.json +1 -1
- package/src/cli/render-command.js +6 -0
- package/src/gallery/render-gallery.js +25 -0
- package/src/index.js +1 -0
- package/src/primitives/row-group.js +84 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.9.0 - 2026-07-16
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added a `rowGroup` primitive (`rowGroup()` in JS, the `row-group` renderer for `cli-style render`, and the same generic `render()`/`cli_style_render`/`CliStyle.render` entry points in Python, Bash, and Swift) that aligns a group of related rows automatically, without the caller computing `labelWidth` by hand.
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- Fixed the Python, Bash, and Swift adapters silently dropping `row()`, `span()`, and `divider()` options beyond their two or three main fields. `row()` now forwards `labelWidth`, `labelColour`, `valueColour`, and `separator`; `span()` forwards `weight`; `divider()` forwards `dividerWidth`, `dividerColour`, and `labelColour`.
|
|
14
|
+
|
|
5
15
|
## 0.8.1 - 2026-07-15
|
|
6
16
|
|
|
7
17
|
### Fixed
|
package/README.md
CHANGED
|
@@ -227,6 +227,7 @@ Renderer names are stable for `cli-style render`, `cli_style_render`, and Python
|
|
|
227
227
|
| --------------------- | ------------------------------------- | ------------------------------------ | ---------------------------------- | -------------------------------------- | --------------------------------------------------------------- |
|
|
228
228
|
| `status` | `status(resultType, detail, options)` | `cli_style_status type label detail` | `status(type, label, detail)` | `CliStyle.status(type, label, detail)` | Result line with symbol, label, and detail. |
|
|
229
229
|
| `row` | `row(label, value, options)` | `cli_style_row label value [result]` | `row(label, value, result)` | `CliStyle.row(label, value, result)` | Aligned label/value row, optionally marked with a result state. |
|
|
230
|
+
| `row-group` | `rowGroup(options)` | Use `cli_style_render` | Use `render("row-group", ...)` | Use `CliStyle.render` | Auto-aligned group of labelled value rows. |
|
|
230
231
|
| `span` | `span(value, tone, options)` | `cli_style_span value [tone]` | `span(value, tone)` | `CliStyle.span(value, tone)` | Inline colour or weight for a word, command, file, or value. |
|
|
231
232
|
| `hint` | `hint(message, options)` | `cli_style_hint message` | `hint(message)` | `CliStyle.hint(message)` | Informational hint line. |
|
|
232
233
|
| `divider` | `divider(options)` | `cli_style_divider label` | `divider(label)` | `CliStyle.divider(label)` | Section divider with an optional label. |
|
|
@@ -282,6 +283,27 @@ Use these shapes with `cli-style render`, `cli_style_render`, or Python `render(
|
|
|
282
283
|
- `labelWidth`: optional minimum label width
|
|
283
284
|
- `labelColour`, `valueColour`, `separator`: optional presentation overrides
|
|
284
285
|
|
|
286
|
+
### `row-group`
|
|
287
|
+
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"rows": [
|
|
291
|
+
{
|
|
292
|
+
"label": "Package",
|
|
293
|
+
"value": "@lewishowles/components"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"label": "Version",
|
|
297
|
+
"value": "minor: 2.7.4 -> 2.8.0"
|
|
298
|
+
}
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
- `rows`: labelled values to align and render
|
|
304
|
+
- `labelWidth`: optional minimum width for every label
|
|
305
|
+
- Per-row fields match `row`, including `label`, `value`, `result`, `labelColour`, `valueColour`, and `separator`
|
|
306
|
+
|
|
285
307
|
### `span`
|
|
286
308
|
|
|
287
309
|
```json
|
|
@@ -159,6 +159,11 @@ cli_style_row() {
|
|
|
159
159
|
local label="${1:-}"
|
|
160
160
|
local value="${2:-}"
|
|
161
161
|
local result=""
|
|
162
|
+
local label_width=""
|
|
163
|
+
local label_colour_json="null"
|
|
164
|
+
local value_colour_json="null"
|
|
165
|
+
local separator_json="null"
|
|
166
|
+
local -a render_args=()
|
|
162
167
|
local json
|
|
163
168
|
|
|
164
169
|
if (($# >= 3)) && [[ "${3:-}" != --* ]]; then
|
|
@@ -170,9 +175,60 @@ cli_style_row() {
|
|
|
170
175
|
set --
|
|
171
176
|
fi
|
|
172
177
|
|
|
173
|
-
|
|
178
|
+
while (($# > 0)); do
|
|
179
|
+
case "$1" in
|
|
180
|
+
--label-width)
|
|
181
|
+
label_width="${2:-}"
|
|
182
|
+
shift 2
|
|
183
|
+
;;
|
|
184
|
+
--label-width=*)
|
|
185
|
+
label_width="${1#*=}"
|
|
186
|
+
shift
|
|
187
|
+
;;
|
|
188
|
+
--label-colour)
|
|
189
|
+
label_colour_json="$(cli_style_json_string "${2:-}")"
|
|
190
|
+
shift 2
|
|
191
|
+
;;
|
|
192
|
+
--label-colour=*)
|
|
193
|
+
label_colour_json="$(cli_style_json_string "${1#*=}")"
|
|
194
|
+
shift
|
|
195
|
+
;;
|
|
196
|
+
--value-colour)
|
|
197
|
+
value_colour_json="$(cli_style_json_string "${2:-}")"
|
|
198
|
+
shift 2
|
|
199
|
+
;;
|
|
200
|
+
--value-colour=*)
|
|
201
|
+
value_colour_json="$(cli_style_json_string "${1#*=}")"
|
|
202
|
+
shift
|
|
203
|
+
;;
|
|
204
|
+
--separator)
|
|
205
|
+
separator_json="$(cli_style_json_string "${2:-}")"
|
|
206
|
+
shift 2
|
|
207
|
+
;;
|
|
208
|
+
--separator=*)
|
|
209
|
+
separator_json="$(cli_style_json_string "${1#*=}")"
|
|
210
|
+
shift
|
|
211
|
+
;;
|
|
212
|
+
*)
|
|
213
|
+
render_args+=("$1")
|
|
214
|
+
shift
|
|
215
|
+
;;
|
|
216
|
+
esac
|
|
217
|
+
done
|
|
218
|
+
|
|
219
|
+
json="{\"label\":$(cli_style_json_string "$label"),\"value\":$(cli_style_json_string "$value"),\"result\":$(cli_style_json_string "$result"),\"labelWidth\":$(cli_style_json_integer_or_null "$label_width"),\"separator\":$separator_json"
|
|
220
|
+
|
|
221
|
+
if [[ "$label_colour_json" != "null" ]]; then
|
|
222
|
+
json="${json},\"labelColour\":$label_colour_json"
|
|
223
|
+
fi
|
|
174
224
|
|
|
175
|
-
|
|
225
|
+
if [[ "$value_colour_json" != "null" ]]; then
|
|
226
|
+
json="${json},\"valueColour\":$value_colour_json"
|
|
227
|
+
fi
|
|
228
|
+
|
|
229
|
+
json="${json}}"
|
|
230
|
+
|
|
231
|
+
cli_style_render_json row "$json" "${render_args[@]}"
|
|
176
232
|
}
|
|
177
233
|
|
|
178
234
|
# Render an inline span from Bash string values.
|
|
@@ -186,6 +242,8 @@ cli_style_row() {
|
|
|
186
242
|
cli_style_span() {
|
|
187
243
|
local value="${1:-}"
|
|
188
244
|
local tone="info"
|
|
245
|
+
local weight_json="null"
|
|
246
|
+
local -a render_args=()
|
|
189
247
|
local json
|
|
190
248
|
|
|
191
249
|
if (($# >= 2)) && [[ "${2:-}" != --* ]]; then
|
|
@@ -197,9 +255,26 @@ cli_style_span() {
|
|
|
197
255
|
set --
|
|
198
256
|
fi
|
|
199
257
|
|
|
200
|
-
|
|
258
|
+
while (($# > 0)); do
|
|
259
|
+
case "$1" in
|
|
260
|
+
--weight)
|
|
261
|
+
weight_json="$(cli_style_json_string "${2:-}")"
|
|
262
|
+
shift 2
|
|
263
|
+
;;
|
|
264
|
+
--weight=*)
|
|
265
|
+
weight_json="$(cli_style_json_string "${1#*=}")"
|
|
266
|
+
shift
|
|
267
|
+
;;
|
|
268
|
+
*)
|
|
269
|
+
render_args+=("$1")
|
|
270
|
+
shift
|
|
271
|
+
;;
|
|
272
|
+
esac
|
|
273
|
+
done
|
|
274
|
+
|
|
275
|
+
json="{\"value\":$(cli_style_json_string "$value"),\"tone\":$(cli_style_json_string "$tone"),\"weight\":$weight_json}"
|
|
201
276
|
|
|
202
|
-
cli_style_render_json span "$json" "
|
|
277
|
+
cli_style_render_json span "$json" "${render_args[@]}"
|
|
203
278
|
}
|
|
204
279
|
|
|
205
280
|
# Render a divider from a Bash string value.
|
|
@@ -210,6 +285,10 @@ cli_style_span() {
|
|
|
210
285
|
# Render flags passed through to `cli-style render`.
|
|
211
286
|
cli_style_divider() {
|
|
212
287
|
local label="${1:-}"
|
|
288
|
+
local divider_width=""
|
|
289
|
+
local divider_colour_json="null"
|
|
290
|
+
local label_colour_json="null"
|
|
291
|
+
local -a render_args=()
|
|
213
292
|
local json
|
|
214
293
|
|
|
215
294
|
if (($# >= 1)); then
|
|
@@ -218,9 +297,52 @@ cli_style_divider() {
|
|
|
218
297
|
set --
|
|
219
298
|
fi
|
|
220
299
|
|
|
221
|
-
|
|
300
|
+
while (($# > 0)); do
|
|
301
|
+
case "$1" in
|
|
302
|
+
--divider-width)
|
|
303
|
+
divider_width="${2:-}"
|
|
304
|
+
shift 2
|
|
305
|
+
;;
|
|
306
|
+
--divider-width=*)
|
|
307
|
+
divider_width="${1#*=}"
|
|
308
|
+
shift
|
|
309
|
+
;;
|
|
310
|
+
--divider-colour)
|
|
311
|
+
divider_colour_json="$(cli_style_json_string "${2:-}")"
|
|
312
|
+
shift 2
|
|
313
|
+
;;
|
|
314
|
+
--divider-colour=*)
|
|
315
|
+
divider_colour_json="$(cli_style_json_string "${1#*=}")"
|
|
316
|
+
shift
|
|
317
|
+
;;
|
|
318
|
+
--label-colour)
|
|
319
|
+
label_colour_json="$(cli_style_json_string "${2:-}")"
|
|
320
|
+
shift 2
|
|
321
|
+
;;
|
|
322
|
+
--label-colour=*)
|
|
323
|
+
label_colour_json="$(cli_style_json_string "${1#*=}")"
|
|
324
|
+
shift
|
|
325
|
+
;;
|
|
326
|
+
*)
|
|
327
|
+
render_args+=("$1")
|
|
328
|
+
shift
|
|
329
|
+
;;
|
|
330
|
+
esac
|
|
331
|
+
done
|
|
332
|
+
|
|
333
|
+
json="{\"label\":$(cli_style_json_string "$label"),\"dividerWidth\":$(cli_style_json_integer_or_null "$divider_width")"
|
|
334
|
+
|
|
335
|
+
if [[ "$divider_colour_json" != "null" ]]; then
|
|
336
|
+
json="${json},\"dividerColour\":$divider_colour_json"
|
|
337
|
+
fi
|
|
338
|
+
|
|
339
|
+
if [[ "$label_colour_json" != "null" ]]; then
|
|
340
|
+
json="${json},\"labelColour\":$label_colour_json"
|
|
341
|
+
fi
|
|
342
|
+
|
|
343
|
+
json="${json}}"
|
|
222
344
|
|
|
223
|
-
cli_style_render_json divider "$json" "
|
|
345
|
+
cli_style_render_json divider "$json" "${render_args[@]}"
|
|
224
346
|
}
|
|
225
347
|
|
|
226
348
|
# Render a hint from a Bash string value.
|
|
@@ -124,13 +124,39 @@ def status(
|
|
|
124
124
|
# Row value.
|
|
125
125
|
# @param {str} result
|
|
126
126
|
# Optional result type for a symbol and tone.
|
|
127
|
+
# @param {int|None} label_width
|
|
128
|
+
# Optional minimum label width.
|
|
129
|
+
# @param {str|None} label_colour
|
|
130
|
+
# Optional label colour token.
|
|
131
|
+
# @param {str|None} value_colour
|
|
132
|
+
# Optional value colour token.
|
|
133
|
+
# @param {str|None} separator
|
|
134
|
+
# Optional text between the label and value.
|
|
127
135
|
def row(
|
|
128
136
|
label: str,
|
|
129
137
|
value: str,
|
|
130
138
|
result: str = "",
|
|
139
|
+
label_width: int | None = None,
|
|
140
|
+
label_colour: str | None = None,
|
|
141
|
+
value_colour: str | None = None,
|
|
142
|
+
separator: str | None = None,
|
|
131
143
|
**kwargs: Any,
|
|
132
144
|
) -> str:
|
|
133
|
-
|
|
145
|
+
data = {
|
|
146
|
+
"label": label,
|
|
147
|
+
"value": value,
|
|
148
|
+
"result": result,
|
|
149
|
+
"labelWidth": label_width,
|
|
150
|
+
"separator": separator,
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if label_colour is not None:
|
|
154
|
+
data["labelColour"] = label_colour
|
|
155
|
+
|
|
156
|
+
if value_colour is not None:
|
|
157
|
+
data["valueColour"] = value_colour
|
|
158
|
+
|
|
159
|
+
return render("row", data, **kwargs)
|
|
134
160
|
|
|
135
161
|
|
|
136
162
|
# Render an inline span from Python values.
|
|
@@ -139,23 +165,46 @@ def row(
|
|
|
139
165
|
# Span text.
|
|
140
166
|
# @param {str} tone
|
|
141
167
|
# Optional colour tone, defaulting to info.
|
|
168
|
+
# @param {str|None} weight
|
|
169
|
+
# Optional ANSI text weight.
|
|
142
170
|
def span(
|
|
143
171
|
value: str,
|
|
144
172
|
tone: str = "info",
|
|
173
|
+
weight: str | None = None,
|
|
145
174
|
**kwargs: Any,
|
|
146
175
|
) -> str:
|
|
147
|
-
return render("span", {"value": value, "tone": tone}, **kwargs)
|
|
176
|
+
return render("span", {"value": value, "tone": tone, "weight": weight}, **kwargs)
|
|
148
177
|
|
|
149
178
|
|
|
150
179
|
# Render a divider from a Python value.
|
|
151
180
|
#
|
|
152
181
|
# @param {str} label
|
|
153
182
|
# Optional divider label.
|
|
183
|
+
# @param {int|None} divider_width
|
|
184
|
+
# Optional divider width.
|
|
185
|
+
# @param {str|None} divider_colour
|
|
186
|
+
# Optional divider colour token.
|
|
187
|
+
# @param {str|None} label_colour
|
|
188
|
+
# Optional label colour token.
|
|
154
189
|
def divider(
|
|
155
190
|
label: str = "",
|
|
191
|
+
divider_width: int | None = None,
|
|
192
|
+
divider_colour: str | None = None,
|
|
193
|
+
label_colour: str | None = None,
|
|
156
194
|
**kwargs: Any,
|
|
157
195
|
) -> str:
|
|
158
|
-
|
|
196
|
+
data = {
|
|
197
|
+
"label": label,
|
|
198
|
+
"dividerWidth": divider_width,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if divider_colour is not None:
|
|
202
|
+
data["dividerColour"] = divider_colour
|
|
203
|
+
|
|
204
|
+
if label_colour is not None:
|
|
205
|
+
data["labelColour"] = label_colour
|
|
206
|
+
|
|
207
|
+
return render("divider", data, **kwargs)
|
|
159
208
|
|
|
160
209
|
|
|
161
210
|
# Render a hint from a Python value.
|
|
@@ -175,6 +175,10 @@ enum CliStyle {
|
|
|
175
175
|
- parameter label: Row label.
|
|
176
176
|
- parameter value: Row value.
|
|
177
177
|
- parameter result: Optional result type for a symbol and tone.
|
|
178
|
+
- parameter labelWidth: Optional minimum label width.
|
|
179
|
+
- parameter labelColour: Optional label colour token.
|
|
180
|
+
- parameter valueColour: Optional value colour token.
|
|
181
|
+
- parameter separator: Optional text between the label and value.
|
|
178
182
|
- parameter options: Render options.
|
|
179
183
|
- returns: Rendered row line.
|
|
180
184
|
- throws: `CliStyleError` on failure.
|
|
@@ -183,13 +187,35 @@ enum CliStyle {
|
|
|
183
187
|
label: String,
|
|
184
188
|
value: String,
|
|
185
189
|
result: String = "",
|
|
190
|
+
labelWidth: Int? = nil,
|
|
191
|
+
labelColour: String? = nil,
|
|
192
|
+
valueColour: String? = nil,
|
|
193
|
+
separator: String? = nil,
|
|
186
194
|
options: CliStyleOptions = .init()
|
|
187
195
|
) throws -> String {
|
|
188
|
-
|
|
196
|
+
var data: [String: Any] = [
|
|
189
197
|
"label": label,
|
|
190
198
|
"value": value,
|
|
191
199
|
"result": result,
|
|
192
|
-
]
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
if let labelWidth = labelWidth {
|
|
203
|
+
data["labelWidth"] = labelWidth
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if let labelColour = labelColour {
|
|
207
|
+
data["labelColour"] = labelColour
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if let valueColour = valueColour {
|
|
211
|
+
data["valueColour"] = valueColour
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if let separator = separator {
|
|
215
|
+
data["separator"] = separator
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return try render("row", data: data, options: options)
|
|
193
219
|
}
|
|
194
220
|
|
|
195
221
|
/**
|
|
@@ -197,6 +223,7 @@ enum CliStyle {
|
|
|
197
223
|
|
|
198
224
|
- parameter value: Span text.
|
|
199
225
|
- parameter tone: Optional colour tone, defaulting to info.
|
|
226
|
+
- parameter weight: Optional ANSI text weight.
|
|
200
227
|
- parameter options: Render options.
|
|
201
228
|
- returns: Rendered span string.
|
|
202
229
|
- throws: `CliStyleError` on failure.
|
|
@@ -204,29 +231,56 @@ enum CliStyle {
|
|
|
204
231
|
static func span(
|
|
205
232
|
value: String,
|
|
206
233
|
tone: String = "info",
|
|
234
|
+
weight: String? = nil,
|
|
207
235
|
options: CliStyleOptions = .init()
|
|
208
236
|
) throws -> String {
|
|
209
|
-
|
|
237
|
+
var data: [String: Any] = [
|
|
210
238
|
"value": value,
|
|
211
239
|
"tone": tone,
|
|
212
|
-
]
|
|
240
|
+
]
|
|
241
|
+
|
|
242
|
+
if let weight = weight {
|
|
243
|
+
data["weight"] = weight
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return try render("span", data: data, options: options)
|
|
213
247
|
}
|
|
214
248
|
|
|
215
249
|
/**
|
|
216
250
|
Render a divider.
|
|
217
251
|
|
|
218
252
|
- parameter label: Optional divider label.
|
|
253
|
+
- parameter dividerWidth: Optional divider width.
|
|
254
|
+
- parameter dividerColour: Optional divider colour token.
|
|
255
|
+
- parameter labelColour: Optional label colour token.
|
|
219
256
|
- parameter options: Render options.
|
|
220
257
|
- returns: Rendered divider line.
|
|
221
258
|
- throws: `CliStyleError` on failure.
|
|
222
259
|
*/
|
|
223
260
|
static func divider(
|
|
224
261
|
label: String = "",
|
|
262
|
+
dividerWidth: Int? = nil,
|
|
263
|
+
dividerColour: String? = nil,
|
|
264
|
+
labelColour: String? = nil,
|
|
225
265
|
options: CliStyleOptions = .init()
|
|
226
266
|
) throws -> String {
|
|
227
|
-
|
|
267
|
+
var data: [String: Any] = [
|
|
228
268
|
"label": label,
|
|
229
|
-
]
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
if let dividerWidth = dividerWidth {
|
|
272
|
+
data["dividerWidth"] = dividerWidth
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if let dividerColour = dividerColour {
|
|
276
|
+
data["dividerColour"] = dividerColour
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if let labelColour = labelColour {
|
|
280
|
+
data["labelColour"] = labelColour
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return try render("divider", data: data, options: options)
|
|
230
284
|
}
|
|
231
285
|
|
|
232
286
|
/**
|
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@ import { emptyState, errorBlock, hint } from "../primitives/feedback.js";
|
|
|
13
13
|
import { panel } from "../primitives/panel.js";
|
|
14
14
|
import { progressBar } from "../primitives/progress-bar.js";
|
|
15
15
|
import { row } from "../primitives/row.js";
|
|
16
|
+
import { rowGroup } from "../primitives/row-group.js";
|
|
16
17
|
import { span } from "../primitives/span.js";
|
|
17
18
|
import { status } from "../primitives/status.js";
|
|
18
19
|
import { step, stepProgress } from "../primitives/step-progress.js";
|
|
@@ -73,6 +74,11 @@ const renderers = {
|
|
|
73
74
|
...input,
|
|
74
75
|
...options,
|
|
75
76
|
}),
|
|
77
|
+
"row-group": (input, options) =>
|
|
78
|
+
rowGroup({
|
|
79
|
+
...input,
|
|
80
|
+
...options,
|
|
81
|
+
}),
|
|
76
82
|
span: (input, options) =>
|
|
77
83
|
span(input.value, input.tone, {
|
|
78
84
|
...input,
|
|
@@ -14,6 +14,7 @@ import { emptyState, errorBlock, hint } from "../primitives/feedback.js";
|
|
|
14
14
|
import { panel } from "../primitives/panel.js";
|
|
15
15
|
import { progressBar } from "../primitives/progress-bar.js";
|
|
16
16
|
import { row } from "../primitives/row.js";
|
|
17
|
+
import { rowGroup } from "../primitives/row-group.js";
|
|
17
18
|
import { span } from "../primitives/span.js";
|
|
18
19
|
import { status } from "../primitives/status.js";
|
|
19
20
|
import { step, stepProgress, stepStates } from "../primitives/step-progress.js";
|
|
@@ -715,6 +716,30 @@ function renderPrimitives(options) {
|
|
|
715
716
|
labelWidth: 8,
|
|
716
717
|
result: resultTypes.FAILED,
|
|
717
718
|
}),
|
|
719
|
+
"",
|
|
720
|
+
"Row groups",
|
|
721
|
+
rowGroup({
|
|
722
|
+
...options,
|
|
723
|
+
rows: [
|
|
724
|
+
{
|
|
725
|
+
label: "Package",
|
|
726
|
+
value: "@lewishowles/components",
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
label: "Version",
|
|
730
|
+
value: "minor: 2.7.4 -> 2.8.0",
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
label: "Checks",
|
|
734
|
+
value: "type-check, unit, build",
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
label: "Bundle",
|
|
738
|
+
result: resultTypes.FAILED,
|
|
739
|
+
value: "is 22.3 KB, above the 12.0 KB budget",
|
|
740
|
+
},
|
|
741
|
+
],
|
|
742
|
+
}),
|
|
718
743
|
].join("\n");
|
|
719
744
|
}
|
|
720
745
|
|
package/src/index.js
CHANGED
|
@@ -35,6 +35,7 @@ export { emptyState, errorBlock, hint } from "./primitives/feedback.js";
|
|
|
35
35
|
export { panel } from "./primitives/panel.js";
|
|
36
36
|
export { progressBar } from "./primitives/progress-bar.js";
|
|
37
37
|
export { row } from "./primitives/row.js";
|
|
38
|
+
export { rowGroup } from "./primitives/row-group.js";
|
|
38
39
|
export { span } from "./primitives/span.js";
|
|
39
40
|
export { status } from "./primitives/status.js";
|
|
40
41
|
export { step, stepProgress, stepStates } from "./primitives/step-progress.js";
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { getResultSymbol } from "../theme/results.js";
|
|
2
|
+
import { row } from "./row.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Render related labelled values against a shared label width.
|
|
6
|
+
*
|
|
7
|
+
* @param {object} options
|
|
8
|
+
* Rendering options.
|
|
9
|
+
* @param {number} options.labelWidth
|
|
10
|
+
* Optional minimum label width.
|
|
11
|
+
* @param {object[]} options.rows
|
|
12
|
+
* Labelled values to render.
|
|
13
|
+
* @returns {string}
|
|
14
|
+
* Rendered row group.
|
|
15
|
+
*/
|
|
16
|
+
export function rowGroup(options = {}) {
|
|
17
|
+
const rows = normaliseRows(options.rows);
|
|
18
|
+
|
|
19
|
+
if (rows.length === 0) {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const labelWidth = Math.max(
|
|
24
|
+
...rows.map((entry) => displayedLabelLength(entry, options)),
|
|
25
|
+
options.labelWidth ?? 0,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return rows
|
|
29
|
+
.map((entry) =>
|
|
30
|
+
row(entry.label, entry.value ?? "", {
|
|
31
|
+
...options,
|
|
32
|
+
...entry,
|
|
33
|
+
labelWidth,
|
|
34
|
+
}),
|
|
35
|
+
)
|
|
36
|
+
.join("\n");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Return rows with usable labels.
|
|
41
|
+
*
|
|
42
|
+
* @param {object[]} rows
|
|
43
|
+
* Requested row entries.
|
|
44
|
+
* @returns {object[]}
|
|
45
|
+
* Valid row entries.
|
|
46
|
+
*/
|
|
47
|
+
function normaliseRows(rows) {
|
|
48
|
+
if (!Array.isArray(rows)) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return rows.filter(
|
|
53
|
+
(entry) =>
|
|
54
|
+
entry !== null &&
|
|
55
|
+
typeof entry === "object" &&
|
|
56
|
+
typeof entry.label === "string" &&
|
|
57
|
+
entry.label !== "",
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Return the visible width of a row label.
|
|
63
|
+
*
|
|
64
|
+
* @param {object} entry
|
|
65
|
+
* Row entry.
|
|
66
|
+
* @param {object} options
|
|
67
|
+
* Group rendering options.
|
|
68
|
+
* @returns {number}
|
|
69
|
+
* Displayed label length.
|
|
70
|
+
*/
|
|
71
|
+
function displayedLabelLength(entry, options) {
|
|
72
|
+
if (typeof entry.result !== "string" || entry.result === "") {
|
|
73
|
+
return entry.label.length;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const entryOptions = {
|
|
77
|
+
...options,
|
|
78
|
+
...entry,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const symbol = getResultSymbol(entry.result, entryOptions);
|
|
82
|
+
|
|
83
|
+
return [symbol, entry.label].join(" ").length;
|
|
84
|
+
}
|