@mnmal-ai/surface-kit 0.16.0 → 0.17.1
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/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -1
- package/dist/list-view.d.ts +13 -0
- package/dist/list-view.d.ts.map +1 -0
- package/dist/list.d.ts +44 -0
- package/dist/list.d.ts.map +1 -0
- package/dist/list.js +121 -0
- package/package.json +6 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export { BAR_GLYPH, barFrame } from './bar.js';
|
|
2
2
|
export { cellWidth, cutToWidth, padCells, truncateCells } from './cells.js';
|
|
3
|
+
export { filterRows, LIST_GUTTER, LIST_INDENT, LIST_ORDINAL_GAP, LIST_VALUE_GAP, type ListLine, type ListRow, type ListSpan, type ListSpec, listLines, wrapCells } from './list.js';
|
|
4
|
+
export { ListRows, type ListRowsProps } from './list-view.js';
|
|
3
5
|
export { type MarkdownSpan, type MarkdownStyle, markdownSpans } from './markdown.js';
|
|
4
6
|
export { Panel, type PanelProps } from './panel.js';
|
|
5
7
|
export { sparkline } from './sparkline.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC5E,OAAO,EACL,UAAU,EACV,WAAW,EACX,WAAW,EACX,gBAAgB,EAChB,cAAc,EACd,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,SAAS,EACT,SAAS,EACV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACrF,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,40 @@
|
|
|
1
1
|
import { a as sparkline, c as barFrame, i as spinnerFrame, n as BRAILLE_RING, o as markdownSpans, r as SPINNER, s as BAR_GLYPH, t as BOX_CHASE } from "./spinner-DIFSSHah.js";
|
|
2
2
|
import { cellWidth, cutToWidth, padCells, truncateCells } from "./cells.js";
|
|
3
|
+
import { LIST_GUTTER, LIST_INDENT, LIST_ORDINAL_GAP, LIST_VALUE_GAP, filterRows, listLines, wrapCells } from "./list.js";
|
|
3
4
|
import { Box, Text } from "ink";
|
|
4
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
6
|
|
|
7
|
+
//#region src/list-view.tsx
|
|
8
|
+
/** Laid-out list lines, one terminal line each: dim ordinal, name, dim details, value. */
|
|
9
|
+
function ListRows({ lines, theme, cursor }) {
|
|
10
|
+
const detailColumn = lines.some((l) => l.detail !== "");
|
|
11
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
12
|
+
flexDirection: "column",
|
|
13
|
+
children: lines.map((l, i) => /* @__PURE__ */ jsxs(Text, {
|
|
14
|
+
wrap: "truncate",
|
|
15
|
+
...i === cursor ? { backgroundColor: theme.color.selection } : {},
|
|
16
|
+
children: [
|
|
17
|
+
" ".repeat(2),
|
|
18
|
+
l.ordinal !== "" ? /* @__PURE__ */ jsx(Text, {
|
|
19
|
+
color: theme.color.dim,
|
|
20
|
+
children: l.ordinal + " ".repeat(2)
|
|
21
|
+
}) : null,
|
|
22
|
+
l.name.map((s, j) => s.em === true ? /* @__PURE__ */ jsx(Text, {
|
|
23
|
+
bold: true,
|
|
24
|
+
italic: true,
|
|
25
|
+
children: s.text
|
|
26
|
+
}, j) : /* @__PURE__ */ jsx(Text, { children: s.text }, j)),
|
|
27
|
+
detailColumn ? /* @__PURE__ */ jsx(Text, {
|
|
28
|
+
color: theme.color.dim,
|
|
29
|
+
children: " ".repeat(3) + l.detail
|
|
30
|
+
}) : null,
|
|
31
|
+
l.value !== "" ? /* @__PURE__ */ jsx(Text, { children: " ".repeat(2) + l.value }) : null
|
|
32
|
+
]
|
|
33
|
+
}, i))
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
6
38
|
//#region src/panel.tsx
|
|
7
39
|
/** The panel anatomy: a single-line border in the panel's tone and an upper-case title line led by `theme.glyph.title`. */
|
|
8
40
|
function Panel({ title, theme, tone = "accent", width, ground, children }) {
|
|
@@ -24,4 +56,4 @@ function Panel({ title, theme, tone = "accent", width, ground, children }) {
|
|
|
24
56
|
}
|
|
25
57
|
|
|
26
58
|
//#endregion
|
|
27
|
-
export { BAR_GLYPH, BOX_CHASE, BRAILLE_RING, Panel, SPINNER, barFrame, cellWidth, cutToWidth, markdownSpans, padCells, sparkline, spinnerFrame, truncateCells };
|
|
59
|
+
export { BAR_GLYPH, BOX_CHASE, BRAILLE_RING, LIST_GUTTER, LIST_INDENT, LIST_ORDINAL_GAP, LIST_VALUE_GAP, ListRows, Panel, SPINNER, barFrame, cellWidth, cutToWidth, filterRows, listLines, markdownSpans, padCells, sparkline, spinnerFrame, truncateCells, wrapCells };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Theme } from '@mnmal-ai/surface-theme';
|
|
2
|
+
import type { ReactElement } from 'react';
|
|
3
|
+
import { type ListLine } from './list.js';
|
|
4
|
+
export interface ListRowsProps {
|
|
5
|
+
/** From `listLines`, at the width this view draws in. */
|
|
6
|
+
readonly lines: readonly ListLine[];
|
|
7
|
+
readonly theme: Theme;
|
|
8
|
+
/** The highlighted row, on the `selection` tone as the palette's is. */
|
|
9
|
+
readonly cursor?: number;
|
|
10
|
+
}
|
|
11
|
+
/** Laid-out list lines, one terminal line each: dim ordinal, name, dim details, value. */
|
|
12
|
+
export declare function ListRows({ lines, theme, cursor }: ListRowsProps): ReactElement;
|
|
13
|
+
//# sourceMappingURL=list-view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-view.d.ts","sourceRoot":"","sources":["../src/list-view.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAErD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAKL,KAAK,QAAQ,EACd,MAAM,WAAW,CAAC;AAEnB,MAAM,WAAW,aAAa;IAC5B,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,0FAA0F;AAC1F,wBAAgB,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,aAAa,GAAG,YAAY,CAkC9E"}
|
package/dist/list.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface ListSpan {
|
|
2
|
+
readonly text: string;
|
|
3
|
+
readonly em?: boolean;
|
|
4
|
+
}
|
|
5
|
+
export interface ListRow {
|
|
6
|
+
/** Stable identity, for the app's hooks; never shown. */
|
|
7
|
+
readonly key: string;
|
|
8
|
+
/** What the row is: plain text, or spans with emphasised parts (`"*Kid A*" by *Radiohead*`). */
|
|
9
|
+
readonly name: string | readonly ListSpan[];
|
|
10
|
+
/** Quieter facts beside the name, joined with ` · `. */
|
|
11
|
+
readonly details?: readonly string[];
|
|
12
|
+
/** One figure per row (money, a count, a score), right-aligned in its own column. */
|
|
13
|
+
readonly value?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ListSpec {
|
|
16
|
+
readonly heading: string;
|
|
17
|
+
readonly rows: readonly ListRow[];
|
|
18
|
+
/** All matches, when the rows are only some of them. */
|
|
19
|
+
readonly total?: number;
|
|
20
|
+
/** Asides drawn after the rows. */
|
|
21
|
+
readonly notes?: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
export interface ListLine {
|
|
24
|
+
/** Right-aligned to the widest ordinal. */
|
|
25
|
+
readonly ordinal: string;
|
|
26
|
+
/** Fitted, and padded to the shared name width when a detail or value column follows. */
|
|
27
|
+
readonly name: readonly ListSpan[];
|
|
28
|
+
/** ` · `-joined details, fitted; padded to the detail column when a value column follows. */
|
|
29
|
+
readonly detail: string;
|
|
30
|
+
/** Right-aligned to the value column; '' when no row has a value. */
|
|
31
|
+
readonly value: string;
|
|
32
|
+
}
|
|
33
|
+
/** The gaps the view draws: before the ordinal, after it, before the details, before the value. */
|
|
34
|
+
export declare const LIST_INDENT = 2;
|
|
35
|
+
export declare const LIST_ORDINAL_GAP = 2;
|
|
36
|
+
export declare const LIST_GUTTER = 3;
|
|
37
|
+
export declare const LIST_VALUE_GAP = 2;
|
|
38
|
+
/** One line per row in `width` cells, numbered from `firstOrdinal`. */
|
|
39
|
+
export declare function listLines(rows: readonly ListRow[], width: number, firstOrdinal?: number): ListLine[];
|
|
40
|
+
/** Rows whose name or details contain `filter`, ignoring case. An empty filter keeps them all. */
|
|
41
|
+
export declare function filterRows(rows: readonly ListRow[], filter: string): ListRow[];
|
|
42
|
+
/** `text` wrapped to `width` cells on spaces; a word longer than the width is cut. */
|
|
43
|
+
export declare function wrapCells(text: string, width: number): string[];
|
|
44
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../src/list.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,OAAO;IACtB,yDAAyD;IACzD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,CAAC;IAC5C,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC;IAClC,wDAAwD;IACxD,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,QAAQ;IACvB,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAC;IACnC,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,mGAAmG;AACnG,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,cAAc,IAAI,CAAC;AAuDhC,uEAAuE;AACvE,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,SAAI,GAAG,QAAQ,EAAE,CA8C/F;AAED,kGAAkG;AAClG,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,EAAE,CAM9E;AAED,sFAAsF;AACtF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA6B/D"}
|
package/dist/list.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { cellWidth, cutToWidth, padCells, truncateCells } from "./cells.js";
|
|
2
|
+
|
|
3
|
+
//#region src/list.ts
|
|
4
|
+
/** The gaps the view draws: before the ordinal, after it, before the details, before the value. */
|
|
5
|
+
const LIST_INDENT = 2;
|
|
6
|
+
const LIST_ORDINAL_GAP = 2;
|
|
7
|
+
const LIST_GUTTER = 3;
|
|
8
|
+
const LIST_VALUE_GAP = 2;
|
|
9
|
+
/** The narrowest a shortened detail cell is cut to: below this an ellipsis says nothing. */
|
|
10
|
+
const MIN_CELL = 8;
|
|
11
|
+
/** A detail column is not squeezed below this while the name can give way. */
|
|
12
|
+
const MIN_DETAIL = 16;
|
|
13
|
+
/** A name is not cut below this while a value column can give way. */
|
|
14
|
+
const MIN_NAME = 8;
|
|
15
|
+
const DETAIL_SEP = " · ";
|
|
16
|
+
const EMPTY = "—";
|
|
17
|
+
const spansOf = (name) => typeof name === "string" ? [{ text: name }] : name;
|
|
18
|
+
const spanText = (spans) => spans.map((s) => s.text).join("");
|
|
19
|
+
const detailsOf = (r) => (r.details ?? []).filter((d) => d !== "");
|
|
20
|
+
/** Spans cut to `max` cells, ending in `…` when anything was cut. */
|
|
21
|
+
function fitSpans(spans, max) {
|
|
22
|
+
if (cellWidth(spanText(spans)) <= max) return [...spans];
|
|
23
|
+
if (max <= 1) return [{ text: cutToWidth(spanText(spans), Math.max(0, max)) }];
|
|
24
|
+
const out = [];
|
|
25
|
+
let left = max - 1;
|
|
26
|
+
for (const s of spans) {
|
|
27
|
+
if (left <= 0) break;
|
|
28
|
+
const t = cutToWidth(s.text, left);
|
|
29
|
+
out.push(s.em === true ? {
|
|
30
|
+
text: t,
|
|
31
|
+
em: true
|
|
32
|
+
} : { text: t });
|
|
33
|
+
left -= cellWidth(t);
|
|
34
|
+
if (t !== s.text) break;
|
|
35
|
+
}
|
|
36
|
+
out.push({ text: "…" });
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/** Details fitted into `room` by shortening the longest cell first, so short facts survive. */
|
|
40
|
+
function fitCells(cells, room) {
|
|
41
|
+
const out = [...cells];
|
|
42
|
+
const length = () => cellWidth(out.join(DETAIL_SEP));
|
|
43
|
+
while (length() > room) {
|
|
44
|
+
let longest = -1;
|
|
45
|
+
for (const [i, c] of out.entries()) if (cellWidth(c) > MIN_CELL && (longest < 0 || cellWidth(c) > cellWidth(out[longest] ?? ""))) longest = i;
|
|
46
|
+
if (longest < 0) return truncateCells(out.join(DETAIL_SEP), room);
|
|
47
|
+
const c = out[longest] ?? "";
|
|
48
|
+
out[longest] = truncateCells(c, Math.max(MIN_CELL, cellWidth(c) - (length() - room)));
|
|
49
|
+
}
|
|
50
|
+
return out.join(DETAIL_SEP);
|
|
51
|
+
}
|
|
52
|
+
/** One line per row in `width` cells, numbered from `firstOrdinal`. */
|
|
53
|
+
function listLines(rows, width, firstOrdinal = 1) {
|
|
54
|
+
const ordinals = rows.map((_, i) => String(firstOrdinal + i));
|
|
55
|
+
const ordW = Math.max(0, ...ordinals.map((o) => o.length));
|
|
56
|
+
const names = rows.map((r) => spansOf(r.name));
|
|
57
|
+
const details = rows.map(detailsOf);
|
|
58
|
+
const hasValue = rows.some((r) => r.value !== void 0 && r.value !== "");
|
|
59
|
+
const values = rows.map((r) => r.value === void 0 || r.value === "" ? EMPTY : r.value);
|
|
60
|
+
const avail0 = width - 2 - (ordW > 0 ? ordW + 2 : 0);
|
|
61
|
+
const valW = hasValue ? Math.max(1, Math.min(Math.max(...values.map(cellWidth)), Math.floor(width / 3), avail0 - 2 - MIN_NAME)) : 0;
|
|
62
|
+
const avail = avail0 - (hasValue ? valW + 2 : 0);
|
|
63
|
+
const detailWidth = Math.max(0, ...details.map((d) => cellWidth(d.join(DETAIL_SEP))));
|
|
64
|
+
const nameNatural = Math.max(0, ...names.map((n) => cellWidth(spanText(n))));
|
|
65
|
+
const detailFloor = detailWidth > 0 ? 3 + Math.min(detailWidth, MIN_DETAIL) : 0;
|
|
66
|
+
const nameWidth = Math.max(1, Math.min(MIN_NAME, avail), Math.min(nameNatural, avail - detailFloor));
|
|
67
|
+
const detailRoom = Math.max(0, avail - nameWidth - (detailWidth > 0 ? 3 : 0));
|
|
68
|
+
const padName = detailWidth > 0 || hasValue;
|
|
69
|
+
return rows.map((_, i) => {
|
|
70
|
+
const fitted = fitSpans(names[i] ?? [], nameWidth);
|
|
71
|
+
const pad = padName ? nameWidth - cellWidth(spanText(fitted)) : 0;
|
|
72
|
+
const name = pad > 0 ? [...fitted, { text: " ".repeat(pad) }] : fitted;
|
|
73
|
+
const cells = details[i] ?? [];
|
|
74
|
+
const fit = cells.length === 0 || detailRoom === 0 ? "" : fitCells(cells, detailRoom);
|
|
75
|
+
const detail = hasValue && detailRoom > 0 && detailWidth > 0 ? padCells(fit, detailRoom) : fit;
|
|
76
|
+
return {
|
|
77
|
+
ordinal: ordinals[i]?.padStart(ordW) ?? "",
|
|
78
|
+
name,
|
|
79
|
+
detail,
|
|
80
|
+
value: hasValue ? padCells(truncateCells(values[i] ?? EMPTY, valW), valW, true) : ""
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** Rows whose name or details contain `filter`, ignoring case. An empty filter keeps them all. */
|
|
85
|
+
function filterRows(rows, filter) {
|
|
86
|
+
const f = filter.toLowerCase();
|
|
87
|
+
if (f === "") return [...rows];
|
|
88
|
+
return rows.filter((r) => `${spanText(spansOf(r.name))} ${detailsOf(r).join(" ")}`.toLowerCase().includes(f));
|
|
89
|
+
}
|
|
90
|
+
/** `text` wrapped to `width` cells on spaces; a word longer than the width is cut. */
|
|
91
|
+
function wrapCells(text, width) {
|
|
92
|
+
const w = Math.max(1, width);
|
|
93
|
+
const out = [];
|
|
94
|
+
for (const para of text.split("\n")) {
|
|
95
|
+
const start = out.length;
|
|
96
|
+
let line = "";
|
|
97
|
+
for (let word of para.split(" ").filter((x) => x !== "")) {
|
|
98
|
+
while (cellWidth(word) > w) {
|
|
99
|
+
if (line !== "") {
|
|
100
|
+
out.push(line);
|
|
101
|
+
line = "";
|
|
102
|
+
}
|
|
103
|
+
const head = cutToWidth(word, w) || ([...word][0] ?? "");
|
|
104
|
+
out.push(head);
|
|
105
|
+
word = word.slice(head.length);
|
|
106
|
+
}
|
|
107
|
+
if (word === "") continue;
|
|
108
|
+
const next = line === "" ? word : `${line} ${word}`;
|
|
109
|
+
if (cellWidth(next) <= w) line = next;
|
|
110
|
+
else {
|
|
111
|
+
out.push(line);
|
|
112
|
+
line = word;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (line !== "" || out.length === start) out.push(line);
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
export { LIST_GUTTER, LIST_INDENT, LIST_ORDINAL_GAP, LIST_VALUE_GAP, filterRows, listLines, wrapCells };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mnmal-ai/surface-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "Stateless Ink view primitives for surface terminal UIs: panels, cells, markdown spans, spinners, sparklines.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -21,13 +21,17 @@
|
|
|
21
21
|
"./text": {
|
|
22
22
|
"types": "./dist/text.d.ts",
|
|
23
23
|
"import": "./dist/text.js"
|
|
24
|
+
},
|
|
25
|
+
"./list": {
|
|
26
|
+
"types": "./dist/list.d.ts",
|
|
27
|
+
"import": "./dist/list.js"
|
|
24
28
|
}
|
|
25
29
|
},
|
|
26
30
|
"files": [
|
|
27
31
|
"dist"
|
|
28
32
|
],
|
|
29
33
|
"dependencies": {
|
|
30
|
-
"@mnmal-ai/surface-theme": "0.
|
|
34
|
+
"@mnmal-ai/surface-theme": "0.17.1",
|
|
31
35
|
"string-width": "^8.1.0"
|
|
32
36
|
},
|
|
33
37
|
"peerDependencies": {
|