|
1 | 1 | import { TextAttributes, type BorderCharacters } from '@opentui/core' |
| 2 | +import stringWidth from 'string-width' |
2 | 3 | import React, { type ReactNode } from 'react' |
3 | 4 |
|
4 | 5 | const containerBorderChars: BorderCharacters = { |
@@ -48,6 +49,7 @@ export const BranchItem = ({ |
48 | 49 | statusColor, |
49 | 50 | statusIndicator = '●', |
50 | 51 | theme, |
| 52 | + availableWidth, |
51 | 53 | onToggle, |
52 | 54 | }: BranchItemProps) => { |
53 | 55 | const resolveFg = ( |
@@ -90,9 +92,34 @@ export const BranchItem = ({ |
90 | 92 | ? `${statusLabel} ${statusIndicator}` |
91 | 93 | : `${statusIndicator} ${statusLabel}` |
92 | 94 | : null |
| 95 | + const normalizePreview = (value: string): string => |
| 96 | + value.replace(/\s+/g, ' ').trim() |
| 97 | + const ellipsisChar = '…' |
| 98 | + const ellipsisWidth = stringWidth(ellipsisChar) |
| 99 | + const maxPreviewWidth = Math.max(1, availableWidth - 4) |
| 100 | + const clampPreview = (value: string): string => { |
| 101 | + const normalized = normalizePreview(value) |
| 102 | + if (!normalized) return '' |
| 103 | + if (stringWidth(normalized) <= maxPreviewWidth) { |
| 104 | + return normalized |
| 105 | + } |
| 106 | + if (maxPreviewWidth <= ellipsisWidth) { |
| 107 | + return ellipsisChar |
| 108 | + } |
| 109 | + let truncated = '' |
| 110 | + for (const char of normalized) { |
| 111 | + if (stringWidth(truncated + char) > maxPreviewWidth - ellipsisWidth) { |
| 112 | + break |
| 113 | + } |
| 114 | + truncated += char |
| 115 | + } |
| 116 | + return `${truncated.trimEnd()}${ellipsisChar}` |
| 117 | + } |
| 118 | + const collapsedPreviewText = clampPreview( |
| 119 | + isStreaming ? streamingPreview : finishedPreview, |
| 120 | + ) |
93 | 121 | const showCollapsedPreview = |
94 | | - (isStreaming && !!streamingPreview) || |
95 | | - (!isStreaming && !!finishedPreview) |
| 122 | + isCollapsed && collapsedPreviewText.length > 0 |
96 | 123 |
|
97 | 124 | const isTextRenderable = (value: ReactNode): boolean => { |
98 | 125 | if (value === null || value === undefined || typeof value === 'boolean') { |
@@ -282,7 +309,7 @@ export const BranchItem = ({ |
282 | 309 | )} |
283 | 310 | attributes={getAttributes(TextAttributes.ITALIC)} |
284 | 311 | > |
285 | | - {isStreaming ? streamingPreview : finishedPreview} |
| 312 | + {collapsedPreviewText} |
286 | 313 | </text> |
287 | 314 | </box> |
288 | 315 | ) : null |
|
0 commit comments