@@ -326,7 +326,12 @@ export class InteractiveCodeElement extends HTMLElement {
326326 blockCommentKeys . add ( match [ 1 ] ) ;
327327 }
328328
329- return lines . map ( line => {
329+ // Track which block comments are currently open (for multi-line block comments)
330+ const openBlockComments = new Set < string > ( ) ;
331+
332+ const renderedLines : string [ ] = [ ] ;
333+
334+ for ( const line of lines ) {
330335 const indentMatch = line . match ( / ^ ( \s * ) / ) ;
331336 const indent = indentMatch ? indentMatch [ 1 ] : '' ;
332337 let content = line . slice ( indent . length ) ;
@@ -344,16 +349,28 @@ export class InteractiveCodeElement extends HTMLElement {
344349 }
345350 }
346351
352+ // Check if this line is inside an active (commented) block comment
353+ const isInsideActiveBlock = Array . from ( openBlockComments ) . some ( key => {
354+ const binding = this . bindings . get ( key ) ;
355+ return binding ?. value === false ; // false means commented (active)
356+ } ) ;
357+
347358 // Replace bindings with markers, then highlight, then restore
348359 let markerIndex = 0 ;
349360 const markers = new Map < string , string > ( ) ;
350361
362+ // Track block comment state changes on this line
363+ const blockStartsOnLine : string [ ] = [ ] ;
364+ const blockEndsOnLine : string [ ] = [ ] ;
365+
351366 // Handle bindings - capture optional ="value" for attribute type
352367 // Pattern matches ${key} optionally followed by ="value"
353368 let processedContent = content . replace ( / \$ \{ ( \w + ) \} ( = " [ ^ " ] * " ) ? / g, ( _ , key , attrValue ) => {
354369 const binding = this . bindings . get ( key ) ;
355- if ( binding ?. type === 'comment' ) {
356- // This is a block comment start marker - make it clickable like line toggle
370+ if ( binding ?. type === 'comment' && blockCommentKeys . has ( key ) ) {
371+ // This is a block comment start marker
372+ blockStartsOnLine . push ( key ) ;
373+ openBlockComments . add ( key ) ;
357374 const marker = `__COMMENT_START_${ markerIndex ++ } __` ;
358375 const isEnabled = binding . value === true ;
359376 const toggleClass = isEnabled ? 'block-toggle-inactive' : 'block-toggle-active' ;
@@ -378,10 +395,11 @@ export class InteractiveCodeElement extends HTMLElement {
378395 processedContent = processedContent . replace ( / \$ \{ \/ ( \w + ) \} / g, ( _ , key ) => {
379396 const binding = this . bindings . get ( key ) ;
380397 if ( binding ?. type === 'comment' && commentStyle . blockEndIndicator ) {
398+ blockEndsOnLine . push ( key ) ;
399+ openBlockComments . delete ( key ) ;
381400 const marker = `__COMMENT_END_${ markerIndex ++ } __` ;
382401 const isEnabled = binding . value === true ;
383402 const toggleClass = isEnabled ? 'block-toggle-inactive' : 'block-toggle-active' ;
384- // End indicator is not clickable, just visual
385403 const endHtml = `<span class="block-end ${ toggleClass } ">${ commentStyle . blockEndIndicator } </span>` ;
386404 markers . set ( marker , ( isEnabled ? '' : ' ' ) + endHtml ) ;
387405 return marker ;
@@ -397,19 +415,27 @@ export class InteractiveCodeElement extends HTMLElement {
397415 processedContent = processedContent . replace ( marker , html ) ;
398416 }
399417
418+ // Determine if line content should be grayed
419+ // Gray if: inside active block OR block starts/ends on this line and is active
420+ const hasActiveBlockStart = blockStartsOnLine . some ( key => this . bindings . get ( key ) ?. value === false ) ;
421+ const hasActiveBlockEnd = blockEndsOnLine . some ( key => this . bindings . get ( key ) ?. value === false ) ;
422+ const shouldGrayLine = isInsideActiveBlock || hasActiveBlockStart || hasActiveBlockEnd ;
423+
400424 // Build line HTML
401425 if ( lineToggleBinding ) {
402426 const isEnabled = lineToggleBinding . value === true ;
403- // Comment indicator is clickable - grayed when not active (line visible), visible when active (line commented)
404- // isEnabled=true means line is NOT commented (comment is "off"), isEnabled=false means line IS commented (comment is "on")
405427 const toggleClass = isEnabled ? 'line-toggle-inactive' : 'line-toggle-active' ;
406428 const toggleHtml = `<span class="line-toggle inline-control ${ toggleClass } " data-binding="${ lineToggleBinding . key } " data-action="toggle">${ commentStyle . lineIndicator } </span>` ;
407429 const commentSuffix = this . language === 'html' && ! isEnabled ? `<span class="token-comment">${ commentStyle . blockEnd } </span>` : '' ;
408- return `<span class="code-line${ isEnabled ? '' : ' line-disabled' } "><span class="indent">${ indent } </span>${ toggleHtml } ${ processedContent } ${ commentSuffix } </span>` ;
430+ renderedLines . push ( `<span class="code-line${ isEnabled ? '' : ' line-disabled' } "><span class="indent">${ indent } </span>${ toggleHtml } ${ processedContent } ${ commentSuffix } </span>` ) ;
431+ } else if ( shouldGrayLine ) {
432+ renderedLines . push ( `<span class="code-line line-disabled"><span class="indent">${ indent } </span>${ processedContent } </span>` ) ;
433+ } else {
434+ renderedLines . push ( `<span class="code-line"><span class="indent">${ indent } </span>${ processedContent } </span>` ) ;
409435 }
436+ }
410437
411- return `<span class="code-line"><span class="indent">${ indent } </span>${ processedContent } </span>` ;
412- } ) . join ( '' ) ;
438+ return renderedLines . join ( '' ) ;
413439 }
414440
415441 private renderBinding ( binding : CodeBindingElement , attrValue ?: string ) : string {
@@ -625,8 +651,9 @@ export class InteractiveCodeElement extends HTMLElement {
625651 background: transparent;
626652 }
627653
628- .line-disabled {
629- opacity: 0.4;
654+ .line-disabled,
655+ .block-content-disabled {
656+ opacity: 0.3;
630657 }
631658
632659 /* Token colors */
0 commit comments