@@ -99,11 +99,12 @@ function isPsbt(bytes: Uint8Array): boolean {
9999/**
100100 * Format a primitive value for display.
101101 */
102- function formatPrimitive ( primitive : Primitive ) : string {
102+ function formatPrimitive ( primitive : Primitive , expanded : boolean = false ) : string {
103103 if ( primitive . type === "None" ) return "" ;
104104 if ( primitive . type === "Buffer" ) {
105105 const hex = String ( primitive . value ?? "" ) ;
106- if ( hex . length > 64 ) {
106+ // Only truncate when hiding more than 8 characters (64 shown + 8 hidden = 72)
107+ if ( ! expanded && hex . length > 72 ) {
107108 return hex . slice ( 0 , 32 ) + "..." + hex . slice ( - 32 ) ;
108109 }
109110 return hex ;
@@ -114,6 +115,16 @@ function formatPrimitive(primitive: Primitive): string {
114115 return String ( primitive . value ?? "" ) ;
115116}
116117
118+ /**
119+ * Check if a buffer value is truncatable.
120+ */
121+ function isTruncatable ( primitive : Primitive ) : boolean {
122+ if ( primitive . type !== "Buffer" ) return false ;
123+ const hex = String ( primitive . value ?? "" ) ;
124+ // Only expandable when truncation would hide more than 8 characters
125+ return hex . length > 72 ;
126+ }
127+
117128/**
118129 * Get full value for copying.
119130 */
@@ -148,16 +159,25 @@ function renderTreeNode(
148159 node : Node ,
149160 expandedPaths : Set < string > ,
150161 onToggle : ( path : string ) => void ,
162+ expandedValues : Set < string > ,
163+ onToggleValue : ( path : string ) => void ,
151164 path : string = "root" ,
152165) : HTMLElement {
153166 const hasChildren = node . children . length > 0 ;
154167 const isExpanded = expandedPaths . has ( path ) ;
155168 const hasValue = node . value . type !== "None" ;
169+ const isValueExpanded = expandedValues . has ( path ) ;
170+ const canExpandValue = isTruncatable ( node . value ) ;
156171
157172 const toggleExpand = ( ) => {
158173 onToggle ( path ) ;
159174 } ;
160175
176+ const toggleValueExpand = ( e : Event ) => {
177+ e . stopPropagation ( ) ;
178+ onToggleValue ( path ) ;
179+ } ;
180+
161181 // Leaf node - just show label: value
162182 if ( ! hasChildren ) {
163183 return h (
@@ -170,10 +190,12 @@ function renderTreeNode(
170190 h (
171191 "span" ,
172192 {
173- class : `tree-value tree-value-${ node . value . type . toLowerCase ( ) } ` ,
174- title : getFullValue ( node . value ) ,
193+ class : `tree-value tree-value-${ node . value . type . toLowerCase ( ) } ${ canExpandValue ? " expandable" : "" } ${ isValueExpanded ? " expanded" : "" } ` ,
194+ title :
195+ canExpandValue && ! isValueExpanded ? "Click to expand" : getFullValue ( node . value ) ,
196+ onclick : canExpandValue ? toggleValueExpand : undefined ,
175197 } ,
176- formatPrimitive ( node . value ) ,
198+ formatPrimitive ( node . value , isValueExpanded ) ,
177199 ) ,
178200 h (
179201 "button" ,
@@ -194,7 +216,7 @@ function renderTreeNode(
194216 // Branch node - collapsible
195217 const childCount = node . children . length ;
196218 const labelText = hasValue
197- ? `${ node . label } : ${ formatPrimitive ( node . value ) } `
219+ ? `${ node . label } : ${ formatPrimitive ( node . value , isValueExpanded ) } `
198220 : `${ node . label } [${ childCount } ]` ;
199221
200222 return h (
@@ -214,7 +236,14 @@ function renderTreeNode(
214236 "div" ,
215237 { class : "tree-children" } ,
216238 ...node . children . map ( ( child , i ) =>
217- renderTreeNode ( child , expandedPaths , onToggle , `${ path } .${ i } ` ) ,
239+ renderTreeNode (
240+ child ,
241+ expandedPaths ,
242+ onToggle ,
243+ expandedValues ,
244+ onToggleValue ,
245+ `${ path } .${ i } ` ,
246+ ) ,
218247 ) ,
219248 )
220249 : null ,
@@ -227,6 +256,7 @@ function renderTreeNode(
227256class PsbtTxParser extends BaseComponent {
228257 private debounceTimer : number | null = null ;
229258 private expandedPaths : Set < string > = new Set ( [ "root" ] ) ;
259+ private expandedValues : Set < string > = new Set ( ) ;
230260 private currentMode : ParseMode = "psbt" ;
231261 private currentNode : Node | null = null ;
232262 private currentNetwork : CoinName = "btc" ;
@@ -453,6 +483,23 @@ class PsbtTxParser extends BaseComponent {
453483 font-family: inherit;
454484 }
455485
486+ .tree-value-buffer.expandable {
487+ cursor: pointer;
488+ text-decoration: underline dotted;
489+ text-underline-offset: 2px;
490+ }
491+
492+ .tree-value-buffer.expandable:hover {
493+ background: rgba(122, 204, 143, 0.1);
494+ border-radius: 2px;
495+ }
496+
497+ .tree-value-buffer.expanded {
498+ text-decoration: none;
499+ word-break: break-all;
500+ max-width: none;
501+ }
502+
456503 .tree-value-string {
457504 color: var(--yellow, #EBC55E);
458505 }
@@ -862,11 +909,7 @@ class PsbtTxParser extends BaseComponent {
862909 onclick : ( ) => this . selectSample ( index ) ,
863910 } ,
864911 sample . name ,
865- h (
866- "span" ,
867- { class : "sample-type" } ,
868- sample . type === "tx" ? "TX" : "PSBT" ,
869- ) ,
912+ h ( "span" , { class : "sample-type" } , sample . type === "tx" ? "TX" : "PSBT" ) ,
870913 ) ,
871914 ) ,
872915 ) ,
@@ -1031,6 +1074,7 @@ class PsbtTxParser extends BaseComponent {
10311074 // Clear previous state
10321075 errorEl . innerHTML = "" ;
10331076 this . expandedPaths = new Set ( [ "root" ] ) ;
1077+ this . expandedValues = new Set ( ) ;
10341078
10351079 let bytes : Uint8Array ;
10361080 try {
@@ -1118,14 +1162,27 @@ class PsbtTxParser extends BaseComponent {
11181162 const resultsEl = this . $ ( "#results" ) ;
11191163 if ( ! resultsEl || ! this . currentNode ) return ;
11201164
1121- const treeEl = renderTreeNode ( this . currentNode , this . expandedPaths , ( path ) => {
1122- if ( this . expandedPaths . has ( path ) ) {
1123- this . expandedPaths . delete ( path ) ;
1124- } else {
1125- this . expandedPaths . add ( path ) ;
1126- }
1127- this . renderTree ( ) ;
1128- } ) ;
1165+ const treeEl = renderTreeNode (
1166+ this . currentNode ,
1167+ this . expandedPaths ,
1168+ ( path ) => {
1169+ if ( this . expandedPaths . has ( path ) ) {
1170+ this . expandedPaths . delete ( path ) ;
1171+ } else {
1172+ this . expandedPaths . add ( path ) ;
1173+ }
1174+ this . renderTree ( ) ;
1175+ } ,
1176+ this . expandedValues ,
1177+ ( path ) => {
1178+ if ( this . expandedValues . has ( path ) ) {
1179+ this . expandedValues . delete ( path ) ;
1180+ } else {
1181+ this . expandedValues . add ( path ) ;
1182+ }
1183+ this . renderTree ( ) ;
1184+ } ,
1185+ ) ;
11291186
11301187 resultsEl . replaceChildren ( h ( "div" , { class : "tree-container" } , treeEl ) ) ;
11311188 }
@@ -1147,6 +1204,7 @@ class PsbtTxParser extends BaseComponent {
11471204
11481205 private collapseAll ( ) : void {
11491206 this . expandedPaths = new Set ( [ "root" ] ) ;
1207+ this . expandedValues = new Set ( ) ;
11501208 this . renderTree ( ) ;
11511209 }
11521210
0 commit comments