inup 1.4.1 → 1.4.3

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.
@@ -10,11 +10,32 @@ exports.renderInterface = renderInterface;
10
10
  exports.renderPackagesTable = renderPackagesTable;
11
11
  const chalk_1 = __importDefault(require("chalk"));
12
12
  const utils_1 = require("../utils");
13
+ const themes_colors_1 = require("../themes-colors");
14
+ /**
15
+ * Get type badge for dependency type (theme-aware)
16
+ */
17
+ function getTypeBadge(type) {
18
+ switch (type) {
19
+ case 'devDependencies':
20
+ return (0, themes_colors_1.getThemeColor)('textSecondary')('[D]');
21
+ case 'peerDependencies':
22
+ return (0, themes_colors_1.getThemeColor)('textSecondary')('[P]');
23
+ case 'optionalDependencies':
24
+ return (0, themes_colors_1.getThemeColor)('textSecondary')('[O]');
25
+ case 'dependencies':
26
+ default:
27
+ return ''; // No badge for regular dependencies
28
+ }
29
+ }
13
30
  /**
14
31
  * Render a single package line
32
+ * @param state Package selection state
33
+ * @param index Index in the list
34
+ * @param isCurrentRow Whether this is the current/highlighted row
35
+ * @param terminalWidth Terminal width for dynamic truncation (default 80)
15
36
  */
16
- function renderPackageLine(state, index, isCurrentRow) {
17
- const prefix = isCurrentRow ? chalk_1.default.green('❯ ') : ' ';
37
+ function renderPackageLine(state, index, isCurrentRow, terminalWidth = 80) {
38
+ const prefix = isCurrentRow ? (0, themes_colors_1.getThemeColor)('success')('❯ ') : ' ';
18
39
  // Package name with special formatting for scoped packages (@author/package)
19
40
  let packageName;
20
41
  if (state.name.startsWith('@')) {
@@ -23,94 +44,111 @@ function renderPackageLine(state, index, isCurrentRow) {
23
44
  const author = parts[0]; // @author
24
45
  const packagePart = parts.slice(1).join('/'); // package name
25
46
  if (isCurrentRow) {
26
- packageName = chalk_1.default.white.bold(author) + chalk_1.default.cyan('/' + packagePart);
47
+ packageName = chalk_1.default.bold((0, themes_colors_1.getThemeColor)('packageAuthor')(author)) + (0, themes_colors_1.getThemeColor)('packageName')('/' + packagePart);
27
48
  }
28
49
  else {
29
- packageName = chalk_1.default.white.bold(author) + chalk_1.default.white('/' + packagePart);
50
+ packageName = chalk_1.default.bold.white(author) + chalk_1.default.white('/' + packagePart);
30
51
  }
31
52
  }
32
53
  else {
33
- packageName = isCurrentRow ? chalk_1.default.cyan(state.name) : chalk_1.default.white(state.name);
54
+ packageName = isCurrentRow ? (0, themes_colors_1.getThemeColor)('packageName')(state.name) : chalk_1.default.white(state.name);
34
55
  }
35
56
  }
36
57
  else {
37
- packageName = isCurrentRow ? chalk_1.default.cyan(state.name) : chalk_1.default.white(state.name);
58
+ packageName = isCurrentRow ? (0, themes_colors_1.getThemeColor)('packageName')(state.name) : chalk_1.default.white(state.name);
38
59
  }
39
60
  // Determine which dot should be filled (only one per package)
40
61
  const isCurrentSelected = state.selectedOption === 'none';
41
62
  const isRangeSelected = state.selectedOption === 'range';
42
63
  const isLatestSelected = state.selectedOption === 'latest';
43
64
  // Current version dot and version (show original specifier with prefix)
44
- const currentDot = isCurrentSelected ? chalk_1.default.green('●') : chalk_1.default.gray('○');
65
+ const currentDot = isCurrentSelected ? (0, themes_colors_1.getThemeColor)('dot')('●') : (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
45
66
  const currentVersion = chalk_1.default.white(state.currentVersionSpecifier);
46
67
  // Range version dot and version
47
68
  let rangeDot = '';
48
69
  let rangeVersionText = '';
49
- let rangeDashes = '';
50
70
  if (state.hasRangeUpdate) {
51
- rangeDot = isRangeSelected ? chalk_1.default.green('●') : chalk_1.default.gray('○');
71
+ rangeDot = isRangeSelected ? (0, themes_colors_1.getThemeColor)('dot')('●') : (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
52
72
  const rangeVersionWithPrefix = utils_1.VersionUtils.applyVersionPrefix(state.currentVersionSpecifier, state.rangeVersion);
53
- rangeVersionText = chalk_1.default.yellow(rangeVersionWithPrefix);
54
- rangeDashes = '';
73
+ rangeVersionText = (0, themes_colors_1.getThemeColor)('versionRange')(rangeVersionWithPrefix);
55
74
  }
56
75
  else {
57
- rangeDot = chalk_1.default.gray('○');
76
+ rangeDot = (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
58
77
  rangeVersionText = '';
59
- rangeDashes = chalk_1.default.gray('─');
60
78
  }
61
79
  // Latest version dot and version
62
80
  let latestDot = '';
63
81
  let latestVersionText = '';
64
- let latestDashes = '';
65
82
  if (state.hasMajorUpdate) {
66
- latestDot = isLatestSelected ? chalk_1.default.green('●') : chalk_1.default.gray('○');
83
+ latestDot = isLatestSelected ? (0, themes_colors_1.getThemeColor)('dot')('●') : (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
67
84
  const latestVersionWithPrefix = utils_1.VersionUtils.applyVersionPrefix(state.currentVersionSpecifier, state.latestVersion);
68
- latestVersionText = chalk_1.default.red(latestVersionWithPrefix);
69
- latestDashes = '';
85
+ latestVersionText = (0, themes_colors_1.getThemeColor)('versionLatest')(latestVersionWithPrefix);
70
86
  }
71
87
  else {
72
- latestDot = chalk_1.default.gray('○');
88
+ latestDot = (0, themes_colors_1.getThemeColor)('dotEmpty')('○');
73
89
  latestVersionText = '';
74
- latestDashes = chalk_1.default.gray('─');
75
90
  }
76
- // Fixed column widths for perfect alignment
77
- const packageNameWidth = 38; // Total package column width minus prefix (2 chars)
91
+ // Column widths with capped package name width
92
+ // Layout: prefix(2) + name + dashes + spacing(3) + current(16) + spacing(3) + range(16) + spacing(3) + latest(16)
78
93
  const currentColumnWidth = 16; // Increased to accommodate ^ and ~ prefixes
79
94
  const rangeColumnWidth = 16; // Increased to accommodate ^ and ~ prefixes
80
95
  const latestColumnWidth = 16; // Increased to accommodate ^ and ~ prefixes
81
- // Package name with fixed width and dashes
82
- const nameLength = state.name.length;
83
- const namePadding = Math.max(0, packageNameWidth - nameLength - 1); // -1 for space after package name
84
- const nameDashes = '-'.repeat(namePadding);
96
+ const spacingWidth = 3;
97
+ // Package name width: max 50 chars (after which ellipsis kicks in), but scales down on small terminals
98
+ const maxPackageNameWidth = 50;
99
+ const minPackageNameWidth = 24;
100
+ const otherColumnsWidth = currentColumnWidth + rangeColumnWidth + latestColumnWidth + spacingWidth * 3;
101
+ const prefixWidth = 2;
102
+ const availableForPackageName = terminalWidth - prefixWidth - otherColumnsWidth - 1;
103
+ const packageNameWidth = Math.min(maxPackageNameWidth, Math.max(minPackageNameWidth, availableForPackageName));
104
+ // Apply ellipsis truncation if package name exceeds available width
105
+ const badgeWidth = state.type === 'dependencies' ? 0 : 3; // [X] without leading space
106
+ const truncatedName = utils_1.VersionUtils.truncateMiddle(state.name, packageNameWidth - 1 - badgeWidth); // -1 for space after name, -badgeWidth for badge
107
+ // Helper function to determine if dashes should be shown based on available padding
108
+ // Only show dashes if there's significant padding (> 2 chars) to fill
109
+ const shouldShowDashes = (paddingAmount) => paddingAmount > 2;
85
110
  const dashColor = isCurrentRow ? chalk_1.default.white : chalk_1.default.gray;
86
- const packageNameSection = `${packageName} ${dashColor(nameDashes)}`;
87
- // Current version section with fixed width
111
+ // Use truncated name if it differs from original, otherwise use colored packageName
112
+ const displayName = truncatedName !== state.name ? truncatedName : packageName;
113
+ // Package name with dashes and badge at the end
114
+ const typeBadge = getTypeBadge(state.type);
115
+ const nameLength = utils_1.VersionUtils.getVisualLength(truncatedName);
116
+ const namePadding = Math.max(0, packageNameWidth - nameLength - 1 - badgeWidth); // -1 for space after package name, -badgeWidth for badge at end
117
+ const nameDashes = shouldShowDashes(namePadding) ? dashColor('-').repeat(namePadding) : ' '.repeat(namePadding);
118
+ // Place badge at the end of dashes: name ------[D]
119
+ const packageNameSection = typeBadge
120
+ ? `${displayName} ${nameDashes}${typeBadge}`
121
+ : `${displayName} ${nameDashes}`;
122
+ // Current version section with dashes only if needed
88
123
  const currentSection = `${currentDot} ${currentVersion}`;
89
- const currentSectionLength = utils_1.VersionUtils.getVisualLength(currentSection) + 1; // +1 for space before dashes
124
+ const currentSectionLength = utils_1.VersionUtils.getVisualLength(currentSection) + 1; // +1 for space before padding
90
125
  const currentPadding = Math.max(0, currentColumnWidth - currentSectionLength);
91
- const currentWithPadding = currentSection + ' ' + dashColor('-').repeat(currentPadding);
92
- // Range version section with fixed width
126
+ const currentPaddingText = shouldShowDashes(currentPadding) ? dashColor('-').repeat(currentPadding) : ' '.repeat(currentPadding);
127
+ const currentWithPadding = currentSection + ' ' + currentPaddingText;
128
+ // Range version section with dashes only if needed
93
129
  let rangeSection = '';
94
130
  if (state.hasRangeUpdate) {
95
131
  rangeSection = `${rangeDot} ${rangeVersionText}`;
96
- const rangeSectionLength = utils_1.VersionUtils.getVisualLength(rangeSection) + 1; // +1 for space before dashes
132
+ const rangeSectionLength = utils_1.VersionUtils.getVisualLength(rangeSection) + 1; // +1 for space before padding
97
133
  const rangePadding = Math.max(0, rangeColumnWidth - rangeSectionLength);
98
- rangeSection += ' ' + dashColor('-').repeat(rangePadding);
134
+ const rangePaddingText = shouldShowDashes(rangePadding) ? dashColor('-').repeat(rangePadding) : ' '.repeat(rangePadding);
135
+ rangeSection += ' ' + rangePaddingText;
99
136
  }
100
137
  else {
101
- // Empty slot - just spaces to maintain column width
138
+ // Empty slot - maintain column width
102
139
  rangeSection = ' '.repeat(rangeColumnWidth);
103
140
  }
104
- // Latest version section with fixed width
141
+ // Latest version section with dashes only if needed
105
142
  let latestSection = '';
106
143
  if (state.hasMajorUpdate) {
107
144
  latestSection = `${latestDot} ${latestVersionText}`;
108
- const latestSectionLength = utils_1.VersionUtils.getVisualLength(latestSection) + 1; // +1 for space before dashes
145
+ const latestSectionLength = utils_1.VersionUtils.getVisualLength(latestSection) + 1; // +1 for space before padding
109
146
  const latestPadding = Math.max(0, latestColumnWidth - latestSectionLength);
110
- latestSection += ' ' + dashColor('-').repeat(latestPadding);
147
+ const latestPaddingText = shouldShowDashes(latestPadding) ? dashColor('-').repeat(latestPadding) : ' '.repeat(latestPadding);
148
+ latestSection += ' ' + latestPaddingText;
111
149
  }
112
150
  else {
113
- // Empty slot - just spaces to maintain column width
151
+ // Empty slot - maintain column width
114
152
  latestSection = ' '.repeat(latestColumnWidth);
115
153
  }
116
154
  // Build line with fixed column widths
@@ -133,7 +171,7 @@ function renderSpacer() {
133
171
  /**
134
172
  * Render the main interface
135
173
  */
136
- function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, dependencyTypeLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter) {
174
+ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forceFullRender, renderableItems, activeFilterLabel, packageManager, filterMode, filterQuery, totalPackagesBeforeFilter, terminalWidth = 80) {
137
175
  const output = [];
138
176
  // Header section (same for initial and incremental render)
139
177
  if (packageManager) {
@@ -148,42 +186,59 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
148
186
  // Each character in "inup" gets a different color
149
187
  const inupColors = [chalk_1.default.red, chalk_1.default.yellow, chalk_1.default.blue, chalk_1.default.magenta];
150
188
  const coloredInup = inupColors.map((color, i) => color.bold('inup'[i])).join('');
151
- const headerLine = ' ' + chalk_1.default.bold(pmColor('🚀')) + ' ' + coloredInup + chalk_1.default.gray(` (${packageManager.displayName})`);
152
- output.push(dependencyTypeLabel ? headerLine + chalk_1.default.gray(' - ') + chalk_1.default.bold.cyan(dependencyTypeLabel) : headerLine);
189
+ const headerLine = ' ' + chalk_1.default.bold(pmColor('🚀')) + ' ' + coloredInup + (0, themes_colors_1.getThemeColor)('textSecondary')(` (${packageManager.displayName})`);
190
+ // Show filter state (always show, including "All")
191
+ const fullHeaderLine = activeFilterLabel
192
+ ? headerLine + (0, themes_colors_1.getThemeColor)('textSecondary')(' - ') + (0, themes_colors_1.getThemeColor)('primary')(activeFilterLabel)
193
+ : headerLine;
194
+ // Pad to terminal width to clear any leftover characters
195
+ const headerPadding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(fullHeaderLine));
196
+ output.push(fullHeaderLine + ' '.repeat(headerPadding));
153
197
  }
154
198
  else {
155
199
  const headerLine = ' ' + chalk_1.default.bold.blue('🚀 ') + chalk_1.default.bold.red('i') + chalk_1.default.bold.yellow('n') + chalk_1.default.bold.blue('u') + chalk_1.default.bold.magenta('p');
156
- output.push(dependencyTypeLabel ? headerLine + chalk_1.default.gray(' - ') + chalk_1.default.bold.cyan(dependencyTypeLabel) : headerLine);
200
+ // Show filter state (always show, including "All")
201
+ const fullHeaderLine = activeFilterLabel
202
+ ? headerLine + (0, themes_colors_1.getThemeColor)('textSecondary')(' - ') + (0, themes_colors_1.getThemeColor)('primary')(activeFilterLabel)
203
+ : headerLine;
204
+ // Pad to terminal width to clear any leftover characters
205
+ const headerPadding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(fullHeaderLine));
206
+ output.push(fullHeaderLine + ' '.repeat(headerPadding));
157
207
  }
158
208
  output.push('');
159
209
  if (filterMode) {
160
210
  // Show filter input with cursor when actively filtering
161
- const filterDisplay = ' ' + chalk_1.default.bold.white('Search: ') + chalk_1.default.cyan(filterQuery || '') + chalk_1.default.gray('█');
162
- output.push(filterDisplay);
211
+ const filterDisplay = ' ' + chalk_1.default.bold.white('Search: ') + (0, themes_colors_1.getThemeColor)('primary')(filterQuery || '') + (0, themes_colors_1.getThemeColor)('border')('█');
212
+ // Pad to terminal width to clear any leftover characters from backspace
213
+ const padding = Math.max(0, terminalWidth - utils_1.VersionUtils.getVisualLength(filterDisplay));
214
+ output.push(filterDisplay + ' '.repeat(padding));
163
215
  }
164
216
  else {
165
217
  // Show instructions when not filtering
166
218
  output.push(' ' +
167
219
  chalk_1.default.bold.white('/ ') +
168
- chalk_1.default.gray('Search') +
220
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Search') +
169
221
  ' ' +
170
222
  chalk_1.default.bold.white('↑/↓ ') +
171
- chalk_1.default.gray('Move') +
223
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Move') +
172
224
  ' ' +
173
225
  chalk_1.default.bold.white('←/→ ') +
174
- chalk_1.default.gray('Select') +
226
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Select') +
227
+ ' ' +
228
+ chalk_1.default.bold.white('D/P/O ') +
229
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Filter') +
175
230
  ' ' +
176
231
  chalk_1.default.bold.white('I ') +
177
- chalk_1.default.gray('Info') +
232
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Info') +
178
233
  ' ' +
179
234
  chalk_1.default.bold.white('M ') +
180
- chalk_1.default.gray('Minor') +
235
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Minor') +
181
236
  ' ' +
182
237
  chalk_1.default.bold.white('L ') +
183
- chalk_1.default.gray('All') +
238
+ (0, themes_colors_1.getThemeColor)('textSecondary')('All') +
184
239
  ' ' +
185
240
  chalk_1.default.bold.white('U ') +
186
- chalk_1.default.gray('None'));
241
+ (0, themes_colors_1.getThemeColor)('textSecondary')('None'));
187
242
  }
188
243
  // Show status line with item range
189
244
  const totalPackages = states.length;
@@ -196,42 +251,42 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
196
251
  if (filterMode) {
197
252
  // In filter mode, show ESC to exit filter
198
253
  if (totalPackages === 0) {
199
- statusLine = chalk_1.default.yellow(`No matches found`) +
254
+ statusLine = (0, themes_colors_1.getThemeColor)('warning')(`No matches found`) +
200
255
  ' ' +
201
- chalk_1.default.gray('Esc ') +
202
- chalk_1.default.gray('Clear filter');
256
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Esc ') +
257
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Clear filter');
203
258
  }
204
259
  else if (totalVisualItems > maxVisibleItems) {
205
- statusLine = chalk_1.default.gray(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
260
+ statusLine = (0, themes_colors_1.getThemeColor)('textSecondary')(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
206
261
  ' ' +
207
- chalk_1.default.gray('Esc ') +
208
- chalk_1.default.gray('Clear filter');
262
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Esc ') +
263
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Clear filter');
209
264
  }
210
265
  else {
211
- statusLine = chalk_1.default.gray(`Showing all ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
266
+ statusLine = (0, themes_colors_1.getThemeColor)('textSecondary')(`Showing all ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
212
267
  ' ' +
213
- chalk_1.default.gray('Esc ') +
214
- chalk_1.default.gray('Clear filter');
268
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Esc ') +
269
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Clear filter');
215
270
  }
216
271
  }
217
272
  else if (totalPackages < totalBeforeFilter) {
218
273
  // Filter is applied but not in filter mode
219
274
  if (totalVisualItems > maxVisibleItems) {
220
- statusLine = chalk_1.default.gray(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
275
+ statusLine = (0, themes_colors_1.getThemeColor)('textSecondary')(`Showing ${chalk_1.default.white(startItem)}-${chalk_1.default.white(endItem)} of ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
221
276
  ' ' +
222
- chalk_1.default.gray('/ ') +
223
- chalk_1.default.gray('Edit filter') +
277
+ (0, themes_colors_1.getThemeColor)('textSecondary')('/ ') +
278
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Edit filter') +
224
279
  ' ' +
225
- chalk_1.default.gray('Enter ') +
226
- chalk_1.default.gray('Confirm') +
280
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Enter ') +
281
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Confirm') +
227
282
  ' ' +
228
- chalk_1.default.gray('Esc ') +
229
- chalk_1.default.gray('Cancel');
283
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Esc ') +
284
+ (0, themes_colors_1.getThemeColor)('textSecondary')('Cancel');
230
285
  }
231
286
  else {
232
- statusLine = chalk_1.default.gray(`Showing all ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
287
+ statusLine = (0, themes_colors_1.getThemeColor)('textSecondary')(`Showing all ${chalk_1.default.white(totalPackages)} matches (${chalk_1.default.white(totalBeforeFilter)} total)`) +
233
288
  ' ' +
234
- chalk_1.default.gray('/ ') +
289
+ (0, themes_colors_1.getThemeColor)('textSecondary')('/ ') +
235
290
  chalk_1.default.gray('Edit filter') +
236
291
  ' ' +
237
292
  chalk_1.default.gray('Enter ') +
@@ -276,7 +331,7 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
276
331
  output.push(renderSpacer());
277
332
  }
278
333
  else if (item.type === 'package') {
279
- const line = renderPackageLine(item.state, item.originalIndex, item.originalIndex === currentRow);
334
+ const line = renderPackageLine(item.state, item.originalIndex, item.originalIndex === currentRow, terminalWidth);
280
335
  output.push(line);
281
336
  }
282
337
  }
@@ -284,7 +339,7 @@ function renderInterface(states, currentRow, scrollOffset, maxVisibleItems, forc
284
339
  else {
285
340
  // Fallback to flat rendering (legacy mode)
286
341
  for (let i = scrollOffset; i < Math.min(scrollOffset + maxVisibleItems, states.length); i++) {
287
- const line = renderPackageLine(states[i], i, i === currentRow);
342
+ const line = renderPackageLine(states[i], i, i === currentRow, terminalWidth);
288
343
  output.push(line);
289
344
  }
290
345
  }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.renderThemeSelectorModal = renderThemeSelectorModal;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const themes_1 = require("../themes");
9
+ /**
10
+ * Get the visual length of a string (ignoring ANSI color codes)
11
+ * Accounts for wide characters like emojis
12
+ */
13
+ function getVisualLength(str) {
14
+ const cleaned = str.replace(/\u001b\[[0-9;]*m/g, '');
15
+ let length = 0;
16
+ for (const char of cleaned) {
17
+ const code = char.charCodeAt(0);
18
+ // Emoji ranges: 0x1F000–0x1F9FF (and other ranges)
19
+ if (code >= 0x1F000 || code >= 0x2600) {
20
+ length += 2;
21
+ }
22
+ else {
23
+ length += 1;
24
+ }
25
+ }
26
+ return length;
27
+ }
28
+ /**
29
+ * Render the theme selector modal
30
+ */
31
+ function renderThemeSelectorModal(currentTheme, previewTheme, terminalWidth = 80, terminalHeight = 24) {
32
+ const maxModalWidth = 76; // Fixed width that fits comfortably in 80-char terminal
33
+ const padding = Math.max(0, Math.floor((terminalWidth - maxModalWidth) / 2));
34
+ const lines = [];
35
+ const contentWidth = maxModalWidth - 4; // Account for '│ ' on left and ' │' on right
36
+ // Helper to pad content to exact width
37
+ const createLine = (content) => {
38
+ const visualLen = getVisualLength(content);
39
+ const spacesNeeded = Math.max(0, contentWidth - visualLen);
40
+ const line = ' '.repeat(padding) + chalk_1.default.gray('│') + ' ' + content + ' '.repeat(spacesNeeded) + ' ' + chalk_1.default.gray('│');
41
+ return line;
42
+ };
43
+ // Top padding to center vertically
44
+ const topPadding = Math.max(1, Math.floor((terminalHeight - themes_1.themeNames.length - 8) / 2));
45
+ for (let i = 0; i < topPadding; i++) {
46
+ lines.push('');
47
+ }
48
+ // Top border
49
+ lines.push(' '.repeat(padding) + chalk_1.default.gray('╭' + '─'.repeat(maxModalWidth - 2) + '╮'));
50
+ // Title
51
+ const title = chalk_1.default.cyan('🎨 Select Theme');
52
+ lines.push(createLine(title));
53
+ // Separator
54
+ lines.push(' '.repeat(padding) + chalk_1.default.gray('├' + '─'.repeat(maxModalWidth - 2) + '┤'));
55
+ // Theme options
56
+ for (const themeName of themes_1.themeNames) {
57
+ const isSelected = themeName === previewTheme;
58
+ const isCurrent = themeName === currentTheme;
59
+ const themeObj = themes_1.themes[themeName];
60
+ // Build the theme line
61
+ let themeLine = '';
62
+ if (isSelected) {
63
+ themeLine = chalk_1.default.green('● ');
64
+ }
65
+ else {
66
+ themeLine = chalk_1.default.gray('○ ');
67
+ }
68
+ themeLine += themeObj.name;
69
+ if (isCurrent) {
70
+ themeLine += chalk_1.default.gray(' (current)');
71
+ }
72
+ lines.push(createLine(themeLine));
73
+ }
74
+ // Separator before instructions
75
+ lines.push(' '.repeat(padding) + chalk_1.default.gray('├' + '─'.repeat(maxModalWidth - 2) + '┤'));
76
+ // Instructions
77
+ const instruction = chalk_1.default.gray('↑/↓ to navigate • Enter to confirm • Esc to cancel');
78
+ lines.push(createLine(instruction));
79
+ // Bottom border
80
+ lines.push(' '.repeat(padding) + chalk_1.default.gray('╰' + '─'.repeat(maxModalWidth - 2) + '╯'));
81
+ return lines;
82
+ }
83
+ //# sourceMappingURL=theme-selector.js.map
@@ -6,6 +6,10 @@ class FilterManager {
6
6
  this.state = {
7
7
  filterMode: false,
8
8
  filterQuery: '',
9
+ showDependencies: true,
10
+ showDevDependencies: true,
11
+ showPeerDependencies: true,
12
+ showOptionalDependencies: true,
9
13
  };
10
14
  }
11
15
  getState() {
@@ -36,12 +40,59 @@ class FilterManager {
36
40
  this.state.filterQuery = this.state.filterQuery.slice(0, -1);
37
41
  }
38
42
  }
43
+ toggleDependencyType(type) {
44
+ switch (type) {
45
+ case 'dependencies':
46
+ this.state.showDependencies = !this.state.showDependencies;
47
+ break;
48
+ case 'devDependencies':
49
+ this.state.showDevDependencies = !this.state.showDevDependencies;
50
+ break;
51
+ case 'peerDependencies':
52
+ this.state.showPeerDependencies = !this.state.showPeerDependencies;
53
+ break;
54
+ case 'optionalDependencies':
55
+ this.state.showOptionalDependencies = !this.state.showOptionalDependencies;
56
+ break;
57
+ }
58
+ }
59
+ getActiveFilterLabel() {
60
+ const activeTypes = [];
61
+ if (this.state.showDependencies)
62
+ activeTypes.push('Deps');
63
+ if (this.state.showDevDependencies)
64
+ activeTypes.push('Dev');
65
+ if (this.state.showPeerDependencies)
66
+ activeTypes.push('Peer');
67
+ if (this.state.showOptionalDependencies)
68
+ activeTypes.push('Optional');
69
+ if (activeTypes.length === 0)
70
+ return 'None';
71
+ return activeTypes.join(', ');
72
+ }
39
73
  getFilteredStates(allStates) {
40
- if (!this.state.filterQuery) {
41
- return allStates;
74
+ let filtered = allStates;
75
+ // Apply text filter
76
+ if (this.state.filterQuery) {
77
+ const query = this.state.filterQuery.toLowerCase();
78
+ filtered = filtered.filter((state) => state.name.toLowerCase().includes(query));
42
79
  }
43
- const query = this.state.filterQuery.toLowerCase();
44
- return allStates.filter((state) => state.name.toLowerCase().includes(query));
80
+ // Apply dependency type filter
81
+ filtered = filtered.filter((state) => {
82
+ switch (state.type) {
83
+ case 'dependencies':
84
+ return this.state.showDependencies;
85
+ case 'devDependencies':
86
+ return this.state.showDevDependencies;
87
+ case 'peerDependencies':
88
+ return this.state.showPeerDependencies;
89
+ case 'optionalDependencies':
90
+ return this.state.showOptionalDependencies;
91
+ default:
92
+ return true;
93
+ }
94
+ });
95
+ return filtered;
45
96
  }
46
97
  }
47
98
  exports.FilterManager = FilterManager;
@@ -4,6 +4,7 @@ exports.StateManager = void 0;
4
4
  const navigation_manager_1 = require("./navigation-manager");
5
5
  const modal_manager_1 = require("./modal-manager");
6
6
  const filter_manager_1 = require("./filter-manager");
7
+ const theme_manager_1 = require("./theme-manager");
7
8
  class StateManager {
8
9
  constructor(initialRow = 0, terminalHeight = 24) {
9
10
  this.headerLines = 5; // title (with label) + empty + 1 instruction line + status + empty
@@ -11,6 +12,7 @@ class StateManager {
11
12
  this.navigationManager = new navigation_manager_1.NavigationManager(initialRow, maxVisibleItems);
12
13
  this.modalManager = new modal_manager_1.ModalManager();
13
14
  this.filterManager = new filter_manager_1.FilterManager();
15
+ this.themeManager = new theme_manager_1.ThemeManager();
14
16
  this.displayState = {
15
17
  maxVisibleItems,
16
18
  terminalHeight,
@@ -26,6 +28,7 @@ class StateManager {
26
28
  const navState = this.navigationManager.getState();
27
29
  const modalState = this.modalManager.getState();
28
30
  const filterState = this.filterManager.getState();
31
+ const themeState = this.themeManager.getState();
29
32
  return {
30
33
  currentRow: navState.currentRow,
31
34
  previousRow: navState.previousRow,
@@ -41,6 +44,8 @@ class StateManager {
41
44
  isLoadingModalInfo: modalState.isLoadingModalInfo,
42
45
  filterMode: filterState.filterMode,
43
46
  filterQuery: filterState.filterQuery,
47
+ showThemeModal: themeState.showThemeModal,
48
+ currentTheme: themeState.currentTheme,
44
49
  };
45
50
  }
46
51
  setRenderableItems(items) {
@@ -158,13 +163,13 @@ class StateManager {
158
163
  // Filter delegation
159
164
  enterFilterMode() {
160
165
  this.filterManager.enterFilterMode();
161
- this.renderState.forceFullRender = true;
166
+ // Use incremental render for search mode toggle (no blink)
162
167
  }
163
168
  exitFilterMode() {
164
169
  this.filterManager.exitFilterMode();
165
170
  this.navigationManager.setCurrentRow(0);
166
171
  this.navigationManager.setScrollOffset(0);
167
- this.renderState.forceFullRender = true;
172
+ // Use incremental render for search mode toggle (no blink)
168
173
  }
169
174
  updateFilterQuery(query) {
170
175
  this.filterManager.updateFilterQuery(query);
@@ -175,17 +180,25 @@ class StateManager {
175
180
  this.filterManager.appendToFilterQuery(char);
176
181
  this.navigationManager.setCurrentRow(0);
177
182
  this.navigationManager.setScrollOffset(0);
178
- this.renderState.forceFullRender = true;
179
183
  }
180
184
  deleteFromFilterQuery() {
181
185
  this.filterManager.deleteFromFilterQuery();
182
186
  this.navigationManager.setCurrentRow(0);
183
187
  this.navigationManager.setScrollOffset(0);
184
- this.renderState.forceFullRender = true;
185
188
  }
186
189
  getFilteredStates(allStates) {
187
190
  return this.filterManager.getFilteredStates(allStates);
188
191
  }
192
+ toggleDependencyTypeFilter(type) {
193
+ this.filterManager.toggleDependencyType(type);
194
+ // Reset navigation when filter changes
195
+ this.navigationManager.setCurrentRow(0);
196
+ this.navigationManager.setScrollOffset(0);
197
+ // Use incremental render (no blink)
198
+ }
199
+ getActiveFilterLabel() {
200
+ return this.filterManager.getActiveFilterLabel();
201
+ }
189
202
  // Display and render state management
190
203
  updateTerminalHeight(newHeight) {
191
204
  const newMaxVisibleItems = Math.max(5, newHeight - this.headerLines - 2);
@@ -210,6 +223,26 @@ class StateManager {
210
223
  this.navigationManager.resetForResize(totalItems);
211
224
  this.renderState.forceFullRender = true;
212
225
  }
226
+ // Theme delegation
227
+ toggleThemeModal() {
228
+ this.themeManager.toggleThemeModal();
229
+ this.renderState.forceFullRender = true;
230
+ }
231
+ closeThemeModal() {
232
+ this.themeManager.closeThemeModal();
233
+ this.renderState.forceFullRender = true;
234
+ }
235
+ previewTheme(themeName) {
236
+ this.themeManager.previewTheme(themeName);
237
+ this.renderState.forceFullRender = true;
238
+ }
239
+ confirmTheme() {
240
+ this.themeManager.confirmTheme();
241
+ this.renderState.forceFullRender = true;
242
+ }
243
+ getThemeManager() {
244
+ return this.themeManager;
245
+ }
213
246
  }
214
247
  exports.StateManager = StateManager;
215
248
  //# sourceMappingURL=state-manager.js.map