@boba-cli/list 0.1.0-alpha.2
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 +19 -0
- package/dist/index.cjs +562 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +218 -0
- package/dist/index.d.ts +218 -0
- package/dist/index.js +551 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
import { Style } from '@boba-cli/chapstick';
|
|
2
|
+
import { newBinding, matches } from '@boba-cli/key';
|
|
3
|
+
import { HelpModel } from '@boba-cli/help';
|
|
4
|
+
import { PaginatorModel } from '@boba-cli/paginator';
|
|
5
|
+
import { SpinnerModel, TickMsg } from '@boba-cli/spinner';
|
|
6
|
+
import { batch, KeyMsg } from '@boba-cli/tea';
|
|
7
|
+
import fuzzysort from 'fuzzysort';
|
|
8
|
+
|
|
9
|
+
// src/styles.ts
|
|
10
|
+
function defaultStyles() {
|
|
11
|
+
return {
|
|
12
|
+
title: new Style().bold(true),
|
|
13
|
+
titleBar: new Style().underline(true),
|
|
14
|
+
spinner: new Style(),
|
|
15
|
+
filterPrompt: new Style(),
|
|
16
|
+
filterCursor: new Style().background("#303030").foreground("#ffffff"),
|
|
17
|
+
noItems: new Style().italic(true),
|
|
18
|
+
statusBar: new Style().italic(true),
|
|
19
|
+
statusEmpty: new Style().italic(true),
|
|
20
|
+
pagination: new Style(),
|
|
21
|
+
help: new Style().italic(true),
|
|
22
|
+
normalTitle: new Style(),
|
|
23
|
+
normalDesc: new Style().italic(true),
|
|
24
|
+
selectedTitle: new Style().bold(true),
|
|
25
|
+
selectedDesc: new Style(),
|
|
26
|
+
dimmedTitle: new Style().italic(true),
|
|
27
|
+
dimmedDesc: new Style().italic(true)
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function mergeStyles(overrides) {
|
|
31
|
+
if (!overrides) {
|
|
32
|
+
return defaultStyles();
|
|
33
|
+
}
|
|
34
|
+
return { ...defaultStyles(), ...overrides };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/delegate.ts
|
|
38
|
+
var DefaultDelegate = class _DefaultDelegate {
|
|
39
|
+
#styles;
|
|
40
|
+
constructor(styles = defaultStyles()) {
|
|
41
|
+
this.#styles = styles;
|
|
42
|
+
}
|
|
43
|
+
height() {
|
|
44
|
+
return 2;
|
|
45
|
+
}
|
|
46
|
+
spacing() {
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
render(item, _index, selected) {
|
|
50
|
+
const titleStyle = selected ? this.#styles.selectedTitle : this.#styles.normalTitle;
|
|
51
|
+
const descStyle = selected ? this.#styles.selectedDesc : this.#styles.normalDesc;
|
|
52
|
+
const title = titleStyle.render(item.title());
|
|
53
|
+
const desc = item.description() ? "\n" + descStyle.render(item.description()) : "";
|
|
54
|
+
return `${title}${desc}`;
|
|
55
|
+
}
|
|
56
|
+
/** Return a copy using different styles. */
|
|
57
|
+
withStyles(styles) {
|
|
58
|
+
return new _DefaultDelegate(styles);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/item.ts
|
|
63
|
+
var DefaultItem = class {
|
|
64
|
+
constructor(titleText, descText = "") {
|
|
65
|
+
this.titleText = titleText;
|
|
66
|
+
this.descText = descText;
|
|
67
|
+
}
|
|
68
|
+
filterValue() {
|
|
69
|
+
return this.titleText;
|
|
70
|
+
}
|
|
71
|
+
title() {
|
|
72
|
+
return this.titleText;
|
|
73
|
+
}
|
|
74
|
+
description() {
|
|
75
|
+
return this.descText;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var defaultKeyMap = {
|
|
79
|
+
cursorUp: newBinding({ keys: ["up", "k"] }),
|
|
80
|
+
cursorDown: newBinding({ keys: ["down", "j"] }),
|
|
81
|
+
prevPage: newBinding({ keys: ["left", "h", "pgup", "b", "u"] }),
|
|
82
|
+
nextPage: newBinding({ keys: ["right", "l", "pgdown", "f", "d"] }),
|
|
83
|
+
gotoTop: newBinding({ keys: ["home", "g"] }),
|
|
84
|
+
gotoBottom: newBinding({ keys: ["end", "G"] }),
|
|
85
|
+
filter: newBinding({ keys: ["/"] }),
|
|
86
|
+
clearFilter: newBinding({ keys: ["esc"] }),
|
|
87
|
+
acceptFilter: newBinding({
|
|
88
|
+
keys: ["enter", "tab", "shift+tab", "ctrl+k", "up", "ctrl+j", "down"]
|
|
89
|
+
}),
|
|
90
|
+
cancelFilter: newBinding({ keys: ["esc"] }),
|
|
91
|
+
showFullHelp: newBinding({ keys: ["?"] }),
|
|
92
|
+
closeFullHelp: newBinding({ keys: ["?"] }),
|
|
93
|
+
quit: newBinding({ keys: ["q", "esc"] }),
|
|
94
|
+
forceQuit: newBinding({ keys: ["ctrl+c"] }),
|
|
95
|
+
shortHelp() {
|
|
96
|
+
return [
|
|
97
|
+
this.cursorUp,
|
|
98
|
+
this.cursorDown,
|
|
99
|
+
this.prevPage,
|
|
100
|
+
this.nextPage,
|
|
101
|
+
this.filter,
|
|
102
|
+
this.quit
|
|
103
|
+
];
|
|
104
|
+
},
|
|
105
|
+
fullHelp() {
|
|
106
|
+
return [
|
|
107
|
+
[this.cursorUp, this.cursorDown, this.gotoTop, this.gotoBottom],
|
|
108
|
+
[this.prevPage, this.nextPage, this.filter, this.clearFilter],
|
|
109
|
+
[this.showFullHelp, this.acceptFilter, this.cancelFilter, this.quit]
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
function clamp(value, min, max) {
|
|
114
|
+
return Math.max(min, Math.min(max, value));
|
|
115
|
+
}
|
|
116
|
+
function perPageFromHeight(height, delegate, fallback) {
|
|
117
|
+
if (height <= 0) {
|
|
118
|
+
return fallback;
|
|
119
|
+
}
|
|
120
|
+
const perItem = Math.max(1, delegate.height() + delegate.spacing());
|
|
121
|
+
return Math.max(1, Math.floor(height / perItem));
|
|
122
|
+
}
|
|
123
|
+
function setPaginatorPage(paginator, page, totalItems) {
|
|
124
|
+
const clampedPage = clamp(page, 0, Math.max(0, paginator.totalPages - 1));
|
|
125
|
+
return PaginatorModel.new({
|
|
126
|
+
type: paginator.type,
|
|
127
|
+
page: clampedPage,
|
|
128
|
+
perPage: paginator.perPage,
|
|
129
|
+
totalPages: Math.max(1, Math.ceil(totalItems / paginator.perPage)),
|
|
130
|
+
activeDot: paginator.activeDot,
|
|
131
|
+
inactiveDot: paginator.inactiveDot,
|
|
132
|
+
arabicFormat: paginator.arabicFormat,
|
|
133
|
+
keyMap: paginator.keyMap
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function filterItems(items, query) {
|
|
137
|
+
if (!query) return items;
|
|
138
|
+
const targets = items.map((item) => ({
|
|
139
|
+
item,
|
|
140
|
+
text: item.filterValue()
|
|
141
|
+
}));
|
|
142
|
+
const results = fuzzysort.go(query, targets, {
|
|
143
|
+
key: "text",
|
|
144
|
+
threshold: -1e4
|
|
145
|
+
});
|
|
146
|
+
return results.map((r) => r.obj.item);
|
|
147
|
+
}
|
|
148
|
+
var ListModel = class _ListModel {
|
|
149
|
+
items;
|
|
150
|
+
filteredItems;
|
|
151
|
+
cursor;
|
|
152
|
+
filterValue;
|
|
153
|
+
filterState;
|
|
154
|
+
paginator;
|
|
155
|
+
help;
|
|
156
|
+
spinner;
|
|
157
|
+
delegate;
|
|
158
|
+
styles;
|
|
159
|
+
keyMap;
|
|
160
|
+
width;
|
|
161
|
+
height;
|
|
162
|
+
title;
|
|
163
|
+
showTitle;
|
|
164
|
+
showFilter;
|
|
165
|
+
showStatusBar;
|
|
166
|
+
showPagination;
|
|
167
|
+
showHelp;
|
|
168
|
+
filteringEnabled;
|
|
169
|
+
loading;
|
|
170
|
+
constructor(state) {
|
|
171
|
+
this.items = state.items;
|
|
172
|
+
this.filteredItems = state.filteredItems;
|
|
173
|
+
this.cursor = state.cursor;
|
|
174
|
+
this.filterValue = state.filterValue;
|
|
175
|
+
this.filterState = state.filterState;
|
|
176
|
+
this.paginator = state.paginator;
|
|
177
|
+
this.help = state.help;
|
|
178
|
+
this.spinner = state.spinner;
|
|
179
|
+
this.delegate = state.delegate;
|
|
180
|
+
this.styles = state.styles;
|
|
181
|
+
this.keyMap = state.keyMap;
|
|
182
|
+
this.width = state.width;
|
|
183
|
+
this.height = state.height;
|
|
184
|
+
this.title = state.title;
|
|
185
|
+
this.showTitle = state.showTitle;
|
|
186
|
+
this.showFilter = state.showFilter;
|
|
187
|
+
this.showStatusBar = state.showStatusBar;
|
|
188
|
+
this.showPagination = state.showPagination;
|
|
189
|
+
this.showHelp = state.showHelp;
|
|
190
|
+
this.filteringEnabled = state.filteringEnabled;
|
|
191
|
+
this.loading = state.loading;
|
|
192
|
+
}
|
|
193
|
+
/** Create a new list model. */
|
|
194
|
+
static new(options) {
|
|
195
|
+
const styles = mergeStyles(options.styles);
|
|
196
|
+
const delegate = options.delegate instanceof DefaultDelegate ? options.delegate.withStyles(styles) : options.delegate ?? new DefaultDelegate(styles);
|
|
197
|
+
const items = options.items ?? [];
|
|
198
|
+
const filteredItems = items;
|
|
199
|
+
const perPage = perPageFromHeight(options.height ?? 0, delegate, 10);
|
|
200
|
+
let paginator = PaginatorModel.new({ perPage }).setTotalPages(items.length);
|
|
201
|
+
paginator = setPaginatorPage(paginator, 0, filteredItems.length);
|
|
202
|
+
const width = options.width ?? 0;
|
|
203
|
+
const height = options.height ?? 0;
|
|
204
|
+
return new _ListModel({
|
|
205
|
+
items,
|
|
206
|
+
filteredItems,
|
|
207
|
+
cursor: 0,
|
|
208
|
+
filterValue: "",
|
|
209
|
+
filterState: "unfiltered",
|
|
210
|
+
paginator,
|
|
211
|
+
help: HelpModel.new({ width }),
|
|
212
|
+
spinner: new SpinnerModel(),
|
|
213
|
+
delegate,
|
|
214
|
+
styles,
|
|
215
|
+
keyMap: options.keyMap ?? defaultKeyMap,
|
|
216
|
+
width,
|
|
217
|
+
height,
|
|
218
|
+
title: options.title ?? "",
|
|
219
|
+
showTitle: options.showTitle ?? true,
|
|
220
|
+
showFilter: options.showFilter ?? true,
|
|
221
|
+
showStatusBar: options.showStatusBar ?? true,
|
|
222
|
+
showPagination: options.showPagination ?? true,
|
|
223
|
+
showHelp: options.showHelp ?? true,
|
|
224
|
+
filteringEnabled: options.filteringEnabled ?? true,
|
|
225
|
+
loading: false
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
/** Currently selected item (after filtering). */
|
|
229
|
+
selectedItem() {
|
|
230
|
+
return this.filteredItems[this.cursor];
|
|
231
|
+
}
|
|
232
|
+
/** Index of the selected item within the filtered collection. */
|
|
233
|
+
selectedIndex() {
|
|
234
|
+
return this.cursor;
|
|
235
|
+
}
|
|
236
|
+
/** Items visible on the current page. */
|
|
237
|
+
visibleItems() {
|
|
238
|
+
if (!this.showPagination) {
|
|
239
|
+
return this.filteredItems;
|
|
240
|
+
}
|
|
241
|
+
const [start, end] = this.paginator.getSliceBounds(
|
|
242
|
+
this.filteredItems.length
|
|
243
|
+
);
|
|
244
|
+
return this.filteredItems.slice(start, end);
|
|
245
|
+
}
|
|
246
|
+
/** Move cursor up by one item. */
|
|
247
|
+
cursorUp() {
|
|
248
|
+
if (this.filteredItems.length === 0) return this;
|
|
249
|
+
const nextCursor = clamp(this.cursor - 1, 0, this.filteredItems.length - 1);
|
|
250
|
+
const nextPaginator = this.showPagination ? setPaginatorPage(
|
|
251
|
+
this.paginator,
|
|
252
|
+
Math.floor(nextCursor / this.paginator.perPage),
|
|
253
|
+
this.filteredItems.length
|
|
254
|
+
) : this.paginator;
|
|
255
|
+
return this.with({ cursor: nextCursor, paginator: nextPaginator });
|
|
256
|
+
}
|
|
257
|
+
/** Move cursor down by one item. */
|
|
258
|
+
cursorDown() {
|
|
259
|
+
if (this.filteredItems.length === 0) return this;
|
|
260
|
+
const nextCursor = clamp(this.cursor + 1, 0, this.filteredItems.length - 1);
|
|
261
|
+
const nextPaginator = this.showPagination ? setPaginatorPage(
|
|
262
|
+
this.paginator,
|
|
263
|
+
Math.floor(nextCursor / this.paginator.perPage),
|
|
264
|
+
this.filteredItems.length
|
|
265
|
+
) : this.paginator;
|
|
266
|
+
return this.with({ cursor: nextCursor, paginator: nextPaginator });
|
|
267
|
+
}
|
|
268
|
+
/** Jump to first item. */
|
|
269
|
+
gotoTop() {
|
|
270
|
+
if (this.filteredItems.length === 0) return this;
|
|
271
|
+
const nextPaginator = this.showPagination ? setPaginatorPage(this.paginator, 0, this.filteredItems.length) : this.paginator;
|
|
272
|
+
return this.with({ cursor: 0, paginator: nextPaginator });
|
|
273
|
+
}
|
|
274
|
+
/** Jump to last item. */
|
|
275
|
+
gotoBottom() {
|
|
276
|
+
if (this.filteredItems.length === 0) return this;
|
|
277
|
+
const last = this.filteredItems.length - 1;
|
|
278
|
+
const nextPaginator = this.showPagination ? setPaginatorPage(
|
|
279
|
+
this.paginator,
|
|
280
|
+
Math.floor(last / this.paginator.perPage),
|
|
281
|
+
this.filteredItems.length
|
|
282
|
+
) : this.paginator;
|
|
283
|
+
return this.with({ cursor: last, paginator: nextPaginator });
|
|
284
|
+
}
|
|
285
|
+
/** Move to next page. */
|
|
286
|
+
nextPage() {
|
|
287
|
+
if (!this.showPagination) return this;
|
|
288
|
+
const nextPaginator = this.paginator.nextPage();
|
|
289
|
+
const [start] = nextPaginator.getSliceBounds(this.filteredItems.length);
|
|
290
|
+
const nextCursor = clamp(
|
|
291
|
+
Math.max(start, this.cursor),
|
|
292
|
+
0,
|
|
293
|
+
this.filteredItems.length - 1
|
|
294
|
+
);
|
|
295
|
+
return this.with({ paginator: nextPaginator, cursor: nextCursor });
|
|
296
|
+
}
|
|
297
|
+
/** Move to previous page. */
|
|
298
|
+
prevPage() {
|
|
299
|
+
if (!this.showPagination) return this;
|
|
300
|
+
const nextPaginator = this.paginator.prevPage();
|
|
301
|
+
const [start] = nextPaginator.getSliceBounds(this.filteredItems.length);
|
|
302
|
+
const nextCursor = clamp(
|
|
303
|
+
Math.max(start, this.cursor),
|
|
304
|
+
0,
|
|
305
|
+
this.filteredItems.length - 1
|
|
306
|
+
);
|
|
307
|
+
return this.with({ paginator: nextPaginator, cursor: nextCursor });
|
|
308
|
+
}
|
|
309
|
+
/** Begin filtering. */
|
|
310
|
+
startFiltering() {
|
|
311
|
+
if (!this.filteringEnabled) return this;
|
|
312
|
+
return this.with({ filterState: "filtering" });
|
|
313
|
+
}
|
|
314
|
+
/** Set the filter query. */
|
|
315
|
+
setFilter(value) {
|
|
316
|
+
if (!this.filteringEnabled) return this;
|
|
317
|
+
const filtered = filterItems(this.items, value);
|
|
318
|
+
const nextPaginator = this.showPagination ? this.paginator.setTotalPages(filtered.length) : this.paginator;
|
|
319
|
+
const boundedCursor = filtered.length === 0 ? 0 : clamp(this.cursor, 0, Math.max(0, filtered.length - 1));
|
|
320
|
+
return this.with({
|
|
321
|
+
filterValue: value,
|
|
322
|
+
filterState: value ? "filtering" : "unfiltered",
|
|
323
|
+
filteredItems: filtered,
|
|
324
|
+
cursor: boundedCursor,
|
|
325
|
+
paginator: this.showPagination ? setPaginatorPage(
|
|
326
|
+
nextPaginator,
|
|
327
|
+
Math.floor(boundedCursor / nextPaginator.perPage),
|
|
328
|
+
filtered.length
|
|
329
|
+
) : nextPaginator
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
/** Accept the current filter value. */
|
|
333
|
+
acceptFilter() {
|
|
334
|
+
if (!this.filteringEnabled) return this;
|
|
335
|
+
const state = this.filterValue ? "applied" : "unfiltered";
|
|
336
|
+
return this.with({ filterState: state });
|
|
337
|
+
}
|
|
338
|
+
/** Cancel filtering and restore the unfiltered list. */
|
|
339
|
+
cancelFilter() {
|
|
340
|
+
if (!this.filteringEnabled) return this;
|
|
341
|
+
return this.with({
|
|
342
|
+
filterValue: "",
|
|
343
|
+
filterState: "unfiltered",
|
|
344
|
+
filteredItems: this.items,
|
|
345
|
+
cursor: clamp(this.cursor, 0, Math.max(0, this.items.length - 1)),
|
|
346
|
+
paginator: this.showPagination ? this.paginator.setTotalPages(this.items.length) : this.paginator
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
/** Clear the filter text and results. */
|
|
350
|
+
clearFilter() {
|
|
351
|
+
return this.cancelFilter();
|
|
352
|
+
}
|
|
353
|
+
/** Replace items with a new list. */
|
|
354
|
+
setItems(items) {
|
|
355
|
+
const filtered = filterItems(items, this.filterValue);
|
|
356
|
+
const nextPaginator = this.showPagination ? this.paginator.setTotalPages(filtered.length) : this.paginator;
|
|
357
|
+
const nextCursor = filtered.length === 0 ? 0 : clamp(this.cursor, 0, filtered.length - 1);
|
|
358
|
+
return this.with({
|
|
359
|
+
items,
|
|
360
|
+
filteredItems: filtered,
|
|
361
|
+
cursor: nextCursor,
|
|
362
|
+
paginator: this.showPagination ? setPaginatorPage(
|
|
363
|
+
nextPaginator,
|
|
364
|
+
Math.floor(nextCursor / nextPaginator.perPage),
|
|
365
|
+
filtered.length
|
|
366
|
+
) : nextPaginator
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
/** Insert a single item. */
|
|
370
|
+
insertItem(index, item) {
|
|
371
|
+
const nextItems = [...this.items];
|
|
372
|
+
nextItems.splice(clamp(index, 0, nextItems.length), 0, item);
|
|
373
|
+
return this.setItems(nextItems);
|
|
374
|
+
}
|
|
375
|
+
/** Remove an item by index. */
|
|
376
|
+
removeItem(index) {
|
|
377
|
+
const nextItems = [...this.items];
|
|
378
|
+
if (index < 0 || index >= nextItems.length) return this;
|
|
379
|
+
nextItems.splice(index, 1);
|
|
380
|
+
return this.setItems(nextItems);
|
|
381
|
+
}
|
|
382
|
+
/** Enter loading mode and start the spinner. */
|
|
383
|
+
startLoading() {
|
|
384
|
+
const model = this.with({ loading: true });
|
|
385
|
+
return [model, model.spinner.tick()];
|
|
386
|
+
}
|
|
387
|
+
/** Stop loading. */
|
|
388
|
+
stopLoading() {
|
|
389
|
+
return this.with({ loading: false });
|
|
390
|
+
}
|
|
391
|
+
/** Update width. */
|
|
392
|
+
setWidth(width) {
|
|
393
|
+
return this.with({ width, help: this.help.withWidth(width) });
|
|
394
|
+
}
|
|
395
|
+
/** Update height and adjust pagination. */
|
|
396
|
+
setHeight(height) {
|
|
397
|
+
const perPage = perPageFromHeight(
|
|
398
|
+
height,
|
|
399
|
+
this.delegate,
|
|
400
|
+
this.paginator.perPage
|
|
401
|
+
);
|
|
402
|
+
const nextPaginator = this.showPagination ? PaginatorModel.new({
|
|
403
|
+
type: this.paginator.type,
|
|
404
|
+
perPage,
|
|
405
|
+
page: this.paginator.page,
|
|
406
|
+
totalPages: Math.max(
|
|
407
|
+
1,
|
|
408
|
+
Math.ceil(this.filteredItems.length / perPage)
|
|
409
|
+
),
|
|
410
|
+
activeDot: this.paginator.activeDot,
|
|
411
|
+
inactiveDot: this.paginator.inactiveDot,
|
|
412
|
+
arabicFormat: this.paginator.arabicFormat,
|
|
413
|
+
keyMap: this.paginator.keyMap
|
|
414
|
+
}) : this.paginator;
|
|
415
|
+
return this.with({ height, paginator: nextPaginator });
|
|
416
|
+
}
|
|
417
|
+
/** Show detailed help. */
|
|
418
|
+
showHelpView() {
|
|
419
|
+
return this.with({ showHelp: true, help: this.help.withShowAll(true) });
|
|
420
|
+
}
|
|
421
|
+
/** Hide detailed help. */
|
|
422
|
+
hideHelpView() {
|
|
423
|
+
return this.with({ help: this.help.withShowAll(false) });
|
|
424
|
+
}
|
|
425
|
+
/** Tea init - start spinner if already loading. */
|
|
426
|
+
init() {
|
|
427
|
+
return this.loading ? this.spinner.tick() : null;
|
|
428
|
+
}
|
|
429
|
+
/** Handle Tea messages. */
|
|
430
|
+
update(msg) {
|
|
431
|
+
const cmds = [];
|
|
432
|
+
if (msg instanceof TickMsg) {
|
|
433
|
+
if (!this.loading) {
|
|
434
|
+
return [this, null];
|
|
435
|
+
}
|
|
436
|
+
const [nextSpinner, spinnerCmd] = this.spinner.update(msg);
|
|
437
|
+
cmds.push(spinnerCmd);
|
|
438
|
+
return [this.with({ spinner: nextSpinner }), batch(...cmds)];
|
|
439
|
+
}
|
|
440
|
+
if (msg instanceof KeyMsg) {
|
|
441
|
+
if (matches(msg, this.keyMap.cursorUp)) {
|
|
442
|
+
return [this.cursorUp(), null];
|
|
443
|
+
}
|
|
444
|
+
if (matches(msg, this.keyMap.cursorDown)) {
|
|
445
|
+
return [this.cursorDown(), null];
|
|
446
|
+
}
|
|
447
|
+
if (matches(msg, this.keyMap.gotoTop)) {
|
|
448
|
+
return [this.gotoTop(), null];
|
|
449
|
+
}
|
|
450
|
+
if (matches(msg, this.keyMap.gotoBottom)) {
|
|
451
|
+
return [this.gotoBottom(), null];
|
|
452
|
+
}
|
|
453
|
+
if (matches(msg, this.keyMap.nextPage)) {
|
|
454
|
+
return [this.nextPage(), null];
|
|
455
|
+
}
|
|
456
|
+
if (matches(msg, this.keyMap.prevPage)) {
|
|
457
|
+
return [this.prevPage(), null];
|
|
458
|
+
}
|
|
459
|
+
if (matches(msg, this.keyMap.filter)) {
|
|
460
|
+
return [this.startFiltering(), null];
|
|
461
|
+
}
|
|
462
|
+
if (matches(msg, this.keyMap.clearFilter)) {
|
|
463
|
+
return [this.clearFilter(), null];
|
|
464
|
+
}
|
|
465
|
+
if (matches(msg, this.keyMap.acceptFilter)) {
|
|
466
|
+
return [this.acceptFilter(), null];
|
|
467
|
+
}
|
|
468
|
+
if (matches(msg, this.keyMap.cancelFilter)) {
|
|
469
|
+
return [this.cancelFilter(), null];
|
|
470
|
+
}
|
|
471
|
+
if (matches(msg, this.keyMap.showFullHelp)) {
|
|
472
|
+
return [this.showHelpView(), null];
|
|
473
|
+
}
|
|
474
|
+
if (matches(msg, this.keyMap.closeFullHelp)) {
|
|
475
|
+
return [this.hideHelpView(), null];
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const [nextPaginator, paginatorCmd] = this.paginator.update(msg);
|
|
479
|
+
if (paginatorCmd) cmds.push(paginatorCmd);
|
|
480
|
+
const nextModel = nextPaginator === this.paginator ? this : this.with({ paginator: nextPaginator });
|
|
481
|
+
return [nextModel, batch(...cmds)];
|
|
482
|
+
}
|
|
483
|
+
/** Render the list to a string. */
|
|
484
|
+
view() {
|
|
485
|
+
const lines = [];
|
|
486
|
+
if (this.showTitle && this.title) {
|
|
487
|
+
lines.push(this.styles.titleBar.render(this.title));
|
|
488
|
+
}
|
|
489
|
+
if (this.showFilter) {
|
|
490
|
+
const prompt = this.styles.filterPrompt.render("Filter: ");
|
|
491
|
+
const cursor = this.styles.filterCursor.render(this.filterValue || "_");
|
|
492
|
+
lines.push(prompt + cursor);
|
|
493
|
+
}
|
|
494
|
+
if (this.filteredItems.length === 0) {
|
|
495
|
+
lines.push(this.styles.noItems.render("No items"));
|
|
496
|
+
} else {
|
|
497
|
+
const visible = this.visibleItems();
|
|
498
|
+
for (const [idx, item] of visible.entries()) {
|
|
499
|
+
const absoluteIndex = this.showPagination ? this.paginator.getSliceBounds(this.filteredItems.length)[0] + idx : idx;
|
|
500
|
+
const selected = absoluteIndex === this.cursor;
|
|
501
|
+
const rendered = this.delegate.render(item, absoluteIndex, selected);
|
|
502
|
+
lines.push((selected ? "\u25CF " : " ") + rendered);
|
|
503
|
+
if (idx < visible.length - 1 && this.delegate.spacing() > 0) {
|
|
504
|
+
lines.push("".padEnd(this.delegate.spacing(), " "));
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (this.showStatusBar) {
|
|
509
|
+
const statusText = `${this.filteredItems.length} items`;
|
|
510
|
+
const pagination = this.showPagination ? this.styles.pagination.render(this.paginator.view()) : "";
|
|
511
|
+
const spinner = this.loading ? this.styles.spinner.render(this.spinner.view()) + " " : "";
|
|
512
|
+
const bar = `${spinner}${statusText}${pagination ? " \u2022 " + pagination : ""}`;
|
|
513
|
+
const style = this.filteredItems.length === 0 ? this.styles.statusEmpty : this.styles.statusBar;
|
|
514
|
+
lines.push(style.render(bar.trim()));
|
|
515
|
+
}
|
|
516
|
+
if (this.showHelp) {
|
|
517
|
+
lines.push(this.styles.help.render(this.help.view(this.keyMap)));
|
|
518
|
+
}
|
|
519
|
+
return lines.join("\n");
|
|
520
|
+
}
|
|
521
|
+
with(patch) {
|
|
522
|
+
return new _ListModel({
|
|
523
|
+
items: this.items,
|
|
524
|
+
filteredItems: this.filteredItems,
|
|
525
|
+
cursor: this.cursor,
|
|
526
|
+
filterValue: this.filterValue,
|
|
527
|
+
filterState: this.filterState,
|
|
528
|
+
paginator: this.paginator,
|
|
529
|
+
help: this.help,
|
|
530
|
+
spinner: this.spinner,
|
|
531
|
+
delegate: this.delegate,
|
|
532
|
+
styles: this.styles,
|
|
533
|
+
keyMap: this.keyMap,
|
|
534
|
+
width: this.width,
|
|
535
|
+
height: this.height,
|
|
536
|
+
title: this.title,
|
|
537
|
+
showTitle: this.showTitle,
|
|
538
|
+
showFilter: this.showFilter,
|
|
539
|
+
showStatusBar: this.showStatusBar,
|
|
540
|
+
showPagination: this.showPagination,
|
|
541
|
+
showHelp: this.showHelp,
|
|
542
|
+
filteringEnabled: this.filteringEnabled,
|
|
543
|
+
loading: this.loading,
|
|
544
|
+
...patch
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
export { DefaultDelegate, DefaultItem, ListModel, defaultKeyMap, defaultStyles, mergeStyles };
|
|
550
|
+
//# sourceMappingURL=index.js.map
|
|
551
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/styles.ts","../src/delegate.ts","../src/item.ts","../src/keymap.ts","../src/model.ts"],"names":["SpinnerTickMsg"],"mappings":"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","file":"index.js","sourcesContent":["import { Style } from '@boba-cli/chapstick'\n\n/**\n * Style configuration for the list component.\n * @public\n */\nexport interface ListStyles {\n title: Style\n titleBar: Style\n spinner: Style\n filterPrompt: Style\n filterCursor: Style\n noItems: Style\n statusBar: Style\n statusEmpty: Style\n pagination: Style\n help: Style\n normalTitle: Style\n normalDesc: Style\n selectedTitle: Style\n selectedDesc: Style\n dimmedTitle: Style\n dimmedDesc: Style\n}\n\n/** Default styles used by the list component. @public */\nexport function defaultStyles(): ListStyles {\n return {\n title: new Style().bold(true),\n titleBar: new Style().underline(true),\n spinner: new Style(),\n filterPrompt: new Style(),\n filterCursor: new Style().background('#303030').foreground('#ffffff'),\n noItems: new Style().italic(true),\n statusBar: new Style().italic(true),\n statusEmpty: new Style().italic(true),\n pagination: new Style(),\n help: new Style().italic(true),\n normalTitle: new Style(),\n normalDesc: new Style().italic(true),\n selectedTitle: new Style().bold(true),\n selectedDesc: new Style(),\n dimmedTitle: new Style().italic(true),\n dimmedDesc: new Style().italic(true),\n }\n}\n\n/**\n * Merge user provided overrides with defaults.\n * @public\n */\nexport function mergeStyles(overrides?: Partial<ListStyles>): ListStyles {\n if (!overrides) {\n return defaultStyles()\n }\n return { ...defaultStyles(), ...overrides }\n}\n","import type { Item } from './item.js'\nimport { defaultStyles, type ListStyles } from './styles.js'\n\n/**\n * Delegate interface for rendering list items.\n * @public\n */\nexport interface ItemDelegate<T extends Item> {\n /** Height of each item in lines. */\n height(): number\n /** Spacing between items in lines. */\n spacing(): number\n /** Render an item to a string. */\n render(item: T, index: number, selected: boolean): string\n}\n\n/**\n * Default delegate renders a title plus optional description.\n * @public\n */\nexport class DefaultDelegate implements ItemDelegate<Item> {\n #styles: ListStyles\n\n constructor(styles: ListStyles = defaultStyles()) {\n this.#styles = styles\n }\n\n height(): number {\n return 2\n }\n\n spacing(): number {\n return 1\n }\n\n render(item: Item, _index: number, selected: boolean): string {\n const titleStyle = selected\n ? this.#styles.selectedTitle\n : this.#styles.normalTitle\n const descStyle = selected\n ? this.#styles.selectedDesc\n : this.#styles.normalDesc\n\n const title = titleStyle.render(item.title())\n const desc = item.description()\n ? '\\n' + descStyle.render(item.description())\n : ''\n return `${title}${desc}`\n }\n\n /** Return a copy using different styles. */\n withStyles(styles: ListStyles): DefaultDelegate {\n return new DefaultDelegate(styles)\n }\n}\n","/**\n * Items displayed in a list must implement this interface.\n * @public\n */\nexport interface Item {\n /** Text used for filtering. */\n filterValue(): string\n /** Title shown in the list. */\n title(): string\n /** Optional description. */\n description(): string\n}\n\n/**\n * Simple default item implementation.\n * @public\n */\nexport class DefaultItem implements Item {\n constructor(\n private readonly titleText: string,\n private readonly descText: string = '',\n ) {}\n\n filterValue(): string {\n return this.titleText\n }\n\n title(): string {\n return this.titleText\n }\n\n description(): string {\n return this.descText\n }\n}\n","import type { KeyMap as HelpKeyMap } from '@boba-cli/help'\nimport { Binding, newBinding } from '@boba-cli/key'\n\n/**\n * Keyboard bindings for the list component.\n * @public\n */\nexport interface ListKeyMap extends HelpKeyMap {\n cursorUp: Binding\n cursorDown: Binding\n gotoTop: Binding\n gotoBottom: Binding\n nextPage: Binding\n prevPage: Binding\n filter: Binding\n clearFilter: Binding\n acceptFilter: Binding\n cancelFilter: Binding\n showFullHelp: Binding\n closeFullHelp: Binding\n quit: Binding\n forceQuit: Binding\n}\n\n/** Default bindings modeled after the Go bubbles list. @public */\nexport const defaultKeyMap: ListKeyMap = {\n cursorUp: newBinding({ keys: ['up', 'k'] }),\n cursorDown: newBinding({ keys: ['down', 'j'] }),\n prevPage: newBinding({ keys: ['left', 'h', 'pgup', 'b', 'u'] }),\n nextPage: newBinding({ keys: ['right', 'l', 'pgdown', 'f', 'd'] }),\n gotoTop: newBinding({ keys: ['home', 'g'] }),\n gotoBottom: newBinding({ keys: ['end', 'G'] }),\n filter: newBinding({ keys: ['/'] }),\n clearFilter: newBinding({ keys: ['esc'] }),\n acceptFilter: newBinding({\n keys: ['enter', 'tab', 'shift+tab', 'ctrl+k', 'up', 'ctrl+j', 'down'],\n }),\n cancelFilter: newBinding({ keys: ['esc'] }),\n showFullHelp: newBinding({ keys: ['?'] }),\n closeFullHelp: newBinding({ keys: ['?'] }),\n quit: newBinding({ keys: ['q', 'esc'] }),\n forceQuit: newBinding({ keys: ['ctrl+c'] }),\n shortHelp() {\n return [\n this.cursorUp,\n this.cursorDown,\n this.prevPage,\n this.nextPage,\n this.filter,\n this.quit,\n ]\n },\n fullHelp() {\n return [\n [this.cursorUp, this.cursorDown, this.gotoTop, this.gotoBottom],\n [this.prevPage, this.nextPage, this.filter, this.clearFilter],\n [this.showFullHelp, this.acceptFilter, this.cancelFilter, this.quit],\n ]\n },\n}\n","import { HelpModel } from '@boba-cli/help'\nimport { matches } from '@boba-cli/key'\nimport { PaginatorModel } from '@boba-cli/paginator'\nimport { SpinnerModel, TickMsg as SpinnerTickMsg } from '@boba-cli/spinner'\nimport { batch, type Cmd, type Msg, KeyMsg } from '@boba-cli/tea'\nimport fuzzysort from 'fuzzysort'\nimport { DefaultDelegate, type ItemDelegate } from './delegate.js'\nimport type { Item } from './item.js'\nimport { defaultKeyMap, type ListKeyMap } from './keymap.js'\nimport { mergeStyles, type ListStyles } from './styles.js'\nimport type { FilterState, ListOptions } from './types.js'\n\ntype ListState<T extends Item> = {\n items: T[]\n filteredItems: T[]\n cursor: number\n filterValue: string\n filterState: FilterState\n paginator: PaginatorModel\n help: HelpModel\n spinner: SpinnerModel\n delegate: ItemDelegate<T>\n styles: ListStyles\n keyMap: ListKeyMap\n width: number\n height: number\n title: string\n showTitle: boolean\n showFilter: boolean\n showStatusBar: boolean\n showPagination: boolean\n showHelp: boolean\n filteringEnabled: boolean\n loading: boolean\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value))\n}\n\nfunction perPageFromHeight(\n height: number,\n delegate: ItemDelegate<Item>,\n fallback: number,\n): number {\n if (height <= 0) {\n return fallback\n }\n const perItem = Math.max(1, delegate.height() + delegate.spacing())\n return Math.max(1, Math.floor(height / perItem))\n}\n\nfunction setPaginatorPage(\n paginator: PaginatorModel,\n page: number,\n totalItems: number,\n): PaginatorModel {\n const clampedPage = clamp(page, 0, Math.max(0, paginator.totalPages - 1))\n return PaginatorModel.new({\n type: paginator.type,\n page: clampedPage,\n perPage: paginator.perPage,\n totalPages: Math.max(1, Math.ceil(totalItems / paginator.perPage)),\n activeDot: paginator.activeDot,\n inactiveDot: paginator.inactiveDot,\n arabicFormat: paginator.arabicFormat,\n keyMap: paginator.keyMap,\n })\n}\n\ntype FilterTarget<T> = { item: T; text: string }\n\nfunction filterItems<T extends Item>(items: T[], query: string): T[] {\n if (!query) return items\n const targets: Array<FilterTarget<T>> = items.map((item) => ({\n item,\n text: item.filterValue(),\n }))\n const results = fuzzysort.go(query, targets, {\n key: 'text',\n threshold: -10000,\n })\n return results.map((r) => r.obj.item)\n}\n\n/**\n * Composite list component with filtering, pagination, spinner, and help.\n * @public\n */\nexport class ListModel<T extends Item> {\n readonly items: T[]\n readonly filteredItems: T[]\n readonly cursor: number\n readonly filterValue: string\n readonly filterState: FilterState\n readonly paginator: PaginatorModel\n readonly help: HelpModel\n readonly spinner: SpinnerModel\n readonly delegate: ItemDelegate<T>\n readonly styles: ListStyles\n readonly keyMap: ListKeyMap\n readonly width: number\n readonly height: number\n readonly title: string\n readonly showTitle: boolean\n readonly showFilter: boolean\n readonly showStatusBar: boolean\n readonly showPagination: boolean\n readonly showHelp: boolean\n readonly filteringEnabled: boolean\n readonly loading: boolean\n\n private constructor(state: ListState<T>) {\n this.items = state.items\n this.filteredItems = state.filteredItems\n this.cursor = state.cursor\n this.filterValue = state.filterValue\n this.filterState = state.filterState\n this.paginator = state.paginator\n this.help = state.help\n this.spinner = state.spinner\n this.delegate = state.delegate\n this.styles = state.styles\n this.keyMap = state.keyMap\n this.width = state.width\n this.height = state.height\n this.title = state.title\n this.showTitle = state.showTitle\n this.showFilter = state.showFilter\n this.showStatusBar = state.showStatusBar\n this.showPagination = state.showPagination\n this.showHelp = state.showHelp\n this.filteringEnabled = state.filteringEnabled\n this.loading = state.loading\n }\n\n /** Create a new list model. */\n static new<T extends Item>(options: ListOptions<T>): ListModel<T> {\n const styles = mergeStyles(options.styles)\n const delegate =\n options.delegate instanceof DefaultDelegate\n ? options.delegate.withStyles(styles)\n : (options.delegate ?? new DefaultDelegate(styles))\n const items = options.items ?? []\n const filteredItems = items\n const perPage = perPageFromHeight(options.height ?? 0, delegate, 10)\n let paginator = PaginatorModel.new({ perPage }).setTotalPages(items.length)\n paginator = setPaginatorPage(paginator, 0, filteredItems.length)\n\n const width = options.width ?? 0\n const height = options.height ?? 0\n\n return new ListModel<T>({\n items,\n filteredItems,\n cursor: 0,\n filterValue: '',\n filterState: 'unfiltered',\n paginator,\n help: HelpModel.new({ width }),\n spinner: new SpinnerModel(),\n delegate,\n styles,\n keyMap: options.keyMap ?? defaultKeyMap,\n width,\n height,\n title: options.title ?? '',\n showTitle: options.showTitle ?? true,\n showFilter: options.showFilter ?? true,\n showStatusBar: options.showStatusBar ?? true,\n showPagination: options.showPagination ?? true,\n showHelp: options.showHelp ?? true,\n filteringEnabled: options.filteringEnabled ?? true,\n loading: false,\n })\n }\n\n /** Currently selected item (after filtering). */\n selectedItem(): T | undefined {\n return this.filteredItems[this.cursor]\n }\n\n /** Index of the selected item within the filtered collection. */\n selectedIndex(): number {\n return this.cursor\n }\n\n /** Items visible on the current page. */\n visibleItems(): T[] {\n if (!this.showPagination) {\n return this.filteredItems\n }\n const [start, end] = this.paginator.getSliceBounds(\n this.filteredItems.length,\n )\n return this.filteredItems.slice(start, end)\n }\n\n /** Move cursor up by one item. */\n cursorUp(): ListModel<T> {\n if (this.filteredItems.length === 0) return this\n const nextCursor = clamp(this.cursor - 1, 0, this.filteredItems.length - 1)\n const nextPaginator = this.showPagination\n ? setPaginatorPage(\n this.paginator,\n Math.floor(nextCursor / this.paginator.perPage),\n this.filteredItems.length,\n )\n : this.paginator\n return this.with({ cursor: nextCursor, paginator: nextPaginator })\n }\n\n /** Move cursor down by one item. */\n cursorDown(): ListModel<T> {\n if (this.filteredItems.length === 0) return this\n const nextCursor = clamp(this.cursor + 1, 0, this.filteredItems.length - 1)\n const nextPaginator = this.showPagination\n ? setPaginatorPage(\n this.paginator,\n Math.floor(nextCursor / this.paginator.perPage),\n this.filteredItems.length,\n )\n : this.paginator\n return this.with({ cursor: nextCursor, paginator: nextPaginator })\n }\n\n /** Jump to first item. */\n gotoTop(): ListModel<T> {\n if (this.filteredItems.length === 0) return this\n const nextPaginator = this.showPagination\n ? setPaginatorPage(this.paginator, 0, this.filteredItems.length)\n : this.paginator\n return this.with({ cursor: 0, paginator: nextPaginator })\n }\n\n /** Jump to last item. */\n gotoBottom(): ListModel<T> {\n if (this.filteredItems.length === 0) return this\n const last = this.filteredItems.length - 1\n const nextPaginator = this.showPagination\n ? setPaginatorPage(\n this.paginator,\n Math.floor(last / this.paginator.perPage),\n this.filteredItems.length,\n )\n : this.paginator\n return this.with({ cursor: last, paginator: nextPaginator })\n }\n\n /** Move to next page. */\n nextPage(): ListModel<T> {\n if (!this.showPagination) return this\n const nextPaginator = this.paginator.nextPage()\n const [start] = nextPaginator.getSliceBounds(this.filteredItems.length)\n const nextCursor = clamp(\n Math.max(start, this.cursor),\n 0,\n this.filteredItems.length - 1,\n )\n return this.with({ paginator: nextPaginator, cursor: nextCursor })\n }\n\n /** Move to previous page. */\n prevPage(): ListModel<T> {\n if (!this.showPagination) return this\n const nextPaginator = this.paginator.prevPage()\n const [start] = nextPaginator.getSliceBounds(this.filteredItems.length)\n const nextCursor = clamp(\n Math.max(start, this.cursor),\n 0,\n this.filteredItems.length - 1,\n )\n return this.with({ paginator: nextPaginator, cursor: nextCursor })\n }\n\n /** Begin filtering. */\n startFiltering(): ListModel<T> {\n if (!this.filteringEnabled) return this\n return this.with({ filterState: 'filtering' })\n }\n\n /** Set the filter query. */\n setFilter(value: string): ListModel<T> {\n if (!this.filteringEnabled) return this\n const filtered = filterItems(this.items, value)\n const nextPaginator = this.showPagination\n ? this.paginator.setTotalPages(filtered.length)\n : this.paginator\n const boundedCursor =\n filtered.length === 0\n ? 0\n : clamp(this.cursor, 0, Math.max(0, filtered.length - 1))\n return this.with({\n filterValue: value,\n filterState: value ? 'filtering' : 'unfiltered',\n filteredItems: filtered,\n cursor: boundedCursor,\n paginator: this.showPagination\n ? setPaginatorPage(\n nextPaginator,\n Math.floor(boundedCursor / nextPaginator.perPage),\n filtered.length,\n )\n : nextPaginator,\n })\n }\n\n /** Accept the current filter value. */\n acceptFilter(): ListModel<T> {\n if (!this.filteringEnabled) return this\n const state: FilterState = this.filterValue ? 'applied' : 'unfiltered'\n return this.with({ filterState: state })\n }\n\n /** Cancel filtering and restore the unfiltered list. */\n cancelFilter(): ListModel<T> {\n if (!this.filteringEnabled) return this\n return this.with({\n filterValue: '',\n filterState: 'unfiltered',\n filteredItems: this.items,\n cursor: clamp(this.cursor, 0, Math.max(0, this.items.length - 1)),\n paginator: this.showPagination\n ? this.paginator.setTotalPages(this.items.length)\n : this.paginator,\n })\n }\n\n /** Clear the filter text and results. */\n clearFilter(): ListModel<T> {\n return this.cancelFilter()\n }\n\n /** Replace items with a new list. */\n setItems(items: T[]): ListModel<T> {\n const filtered = filterItems(items, this.filterValue)\n const nextPaginator = this.showPagination\n ? this.paginator.setTotalPages(filtered.length)\n : this.paginator\n const nextCursor =\n filtered.length === 0 ? 0 : clamp(this.cursor, 0, filtered.length - 1)\n return this.with({\n items,\n filteredItems: filtered,\n cursor: nextCursor,\n paginator: this.showPagination\n ? setPaginatorPage(\n nextPaginator,\n Math.floor(nextCursor / nextPaginator.perPage),\n filtered.length,\n )\n : nextPaginator,\n })\n }\n\n /** Insert a single item. */\n insertItem(index: number, item: T): ListModel<T> {\n const nextItems = [...this.items]\n nextItems.splice(clamp(index, 0, nextItems.length), 0, item)\n return this.setItems(nextItems)\n }\n\n /** Remove an item by index. */\n removeItem(index: number): ListModel<T> {\n const nextItems = [...this.items]\n if (index < 0 || index >= nextItems.length) return this\n nextItems.splice(index, 1)\n return this.setItems(nextItems)\n }\n\n /** Enter loading mode and start the spinner. */\n startLoading(): [ListModel<T>, Cmd<Msg>] {\n const model = this.with({ loading: true })\n return [model, model.spinner.tick()]\n }\n\n /** Stop loading. */\n stopLoading(): ListModel<T> {\n return this.with({ loading: false })\n }\n\n /** Update width. */\n setWidth(width: number): ListModel<T> {\n return this.with({ width, help: this.help.withWidth(width) })\n }\n\n /** Update height and adjust pagination. */\n setHeight(height: number): ListModel<T> {\n const perPage = perPageFromHeight(\n height,\n this.delegate,\n this.paginator.perPage,\n )\n const nextPaginator = this.showPagination\n ? PaginatorModel.new({\n type: this.paginator.type,\n perPage,\n page: this.paginator.page,\n totalPages: Math.max(\n 1,\n Math.ceil(this.filteredItems.length / perPage),\n ),\n activeDot: this.paginator.activeDot,\n inactiveDot: this.paginator.inactiveDot,\n arabicFormat: this.paginator.arabicFormat,\n keyMap: this.paginator.keyMap,\n })\n : this.paginator\n return this.with({ height, paginator: nextPaginator })\n }\n\n /** Show detailed help. */\n showHelpView(): ListModel<T> {\n return this.with({ showHelp: true, help: this.help.withShowAll(true) })\n }\n\n /** Hide detailed help. */\n hideHelpView(): ListModel<T> {\n return this.with({ help: this.help.withShowAll(false) })\n }\n\n /** Tea init - start spinner if already loading. */\n init(): Cmd<Msg> {\n return this.loading ? this.spinner.tick() : null\n }\n\n /** Handle Tea messages. */\n update(msg: Msg): [ListModel<T>, Cmd<Msg>] {\n const cmds: Array<Cmd<Msg>> = []\n\n if (msg instanceof SpinnerTickMsg) {\n if (!this.loading) {\n return [this, null]\n }\n const [nextSpinner, spinnerCmd] = this.spinner.update(msg)\n cmds.push(spinnerCmd)\n return [this.with({ spinner: nextSpinner }), batch(...cmds)]\n }\n\n if (msg instanceof KeyMsg) {\n // Navigation\n if (matches(msg, this.keyMap.cursorUp)) {\n return [this.cursorUp(), null]\n }\n if (matches(msg, this.keyMap.cursorDown)) {\n return [this.cursorDown(), null]\n }\n if (matches(msg, this.keyMap.gotoTop)) {\n return [this.gotoTop(), null]\n }\n if (matches(msg, this.keyMap.gotoBottom)) {\n return [this.gotoBottom(), null]\n }\n if (matches(msg, this.keyMap.nextPage)) {\n return [this.nextPage(), null]\n }\n if (matches(msg, this.keyMap.prevPage)) {\n return [this.prevPage(), null]\n }\n\n // Filtering\n if (matches(msg, this.keyMap.filter)) {\n return [this.startFiltering(), null]\n }\n if (matches(msg, this.keyMap.clearFilter)) {\n return [this.clearFilter(), null]\n }\n if (matches(msg, this.keyMap.acceptFilter)) {\n return [this.acceptFilter(), null]\n }\n if (matches(msg, this.keyMap.cancelFilter)) {\n return [this.cancelFilter(), null]\n }\n\n // Help toggles\n if (matches(msg, this.keyMap.showFullHelp)) {\n return [this.showHelpView(), null]\n }\n if (matches(msg, this.keyMap.closeFullHelp)) {\n return [this.hideHelpView(), null]\n }\n }\n\n const [nextPaginator, paginatorCmd] = this.paginator.update(msg)\n if (paginatorCmd) cmds.push(paginatorCmd)\n const nextModel =\n nextPaginator === this.paginator\n ? this\n : this.with({ paginator: nextPaginator })\n return [nextModel, batch(...cmds)]\n }\n\n /** Render the list to a string. */\n view(): string {\n const lines: string[] = []\n\n if (this.showTitle && this.title) {\n lines.push(this.styles.titleBar.render(this.title))\n }\n\n if (this.showFilter) {\n const prompt = this.styles.filterPrompt.render('Filter: ')\n const cursor = this.styles.filterCursor.render(this.filterValue || '_')\n lines.push(prompt + cursor)\n }\n\n if (this.filteredItems.length === 0) {\n lines.push(this.styles.noItems.render('No items'))\n } else {\n const visible = this.visibleItems()\n for (const [idx, item] of visible.entries()) {\n const absoluteIndex = this.showPagination\n ? this.paginator.getSliceBounds(this.filteredItems.length)[0] + idx\n : idx\n const selected = absoluteIndex === this.cursor\n const rendered = this.delegate.render(item, absoluteIndex, selected)\n lines.push((selected ? '● ' : ' ') + rendered)\n if (idx < visible.length - 1 && this.delegate.spacing() > 0) {\n lines.push(''.padEnd(this.delegate.spacing(), ' '))\n }\n }\n }\n\n if (this.showStatusBar) {\n const statusText = `${this.filteredItems.length} items`\n const pagination = this.showPagination\n ? this.styles.pagination.render(this.paginator.view())\n : ''\n const spinner = this.loading\n ? this.styles.spinner.render(this.spinner.view()) + ' '\n : ''\n const bar = `${spinner}${statusText}${pagination ? ' • ' + pagination : ''}`\n const style =\n this.filteredItems.length === 0\n ? this.styles.statusEmpty\n : this.styles.statusBar\n lines.push(style.render(bar.trim()))\n }\n\n if (this.showHelp) {\n lines.push(this.styles.help.render(this.help.view(this.keyMap)))\n }\n\n return lines.join('\\n')\n }\n\n private with(patch: Partial<ListState<T>>): ListModel<T> {\n return new ListModel<T>({\n items: this.items,\n filteredItems: this.filteredItems,\n cursor: this.cursor,\n filterValue: this.filterValue,\n filterState: this.filterState,\n paginator: this.paginator,\n help: this.help,\n spinner: this.spinner,\n delegate: this.delegate,\n styles: this.styles,\n keyMap: this.keyMap,\n width: this.width,\n height: this.height,\n title: this.title,\n showTitle: this.showTitle,\n showFilter: this.showFilter,\n showStatusBar: this.showStatusBar,\n showPagination: this.showPagination,\n showHelp: this.showHelp,\n filteringEnabled: this.filteringEnabled,\n loading: this.loading,\n ...patch,\n })\n }\n}\n"]}
|