@@ -134,7 +134,8 @@ export async function ConvertSomeButtonGraphicsElementForDrawing(
134134 globalReferences ,
135135 processedElementIds ,
136136 currentLocationStr ,
137- getRenderAtLocation
137+ getRenderAtLocation ,
138+ new Set ( )
138139 )
139140
140141 const newElements = await convertElements ( context , elements , '' )
@@ -224,8 +225,11 @@ async function convertElements(
224225 if ( cacheEntry . referencedLocation )
225226 context . globalReferences . referencedLocations . drawn . add ( cacheEntry . referencedLocation )
226227
227- // If this is a group, populate the children
228- if ( element . type === 'group' || element . type === 'composite' ) {
228+ if ( cacheEntry . compositeElement ?. isPlaceholder ) {
229+ // Placeholder already carries its children
230+ return cacheEntry . drawElement
231+ } else if ( element . type === 'group' || element . type === 'composite' ) {
232+ // If this is a group, populate the children
229233 const childIdPrefix = cacheEntry . compositeElement ? cacheEntry . compositeElement . childIdPrefix : idPrefix
230234
231235 const children =
@@ -234,8 +238,11 @@ async function convertElements(
234238 : ( context . resolveCompositeElement ( element . connectionId , element . elementId ) ?. elements ?? [ ] )
235239
236240 if ( cacheEntry . drawElement ?. type === 'group' ) {
237- const childContext = cacheEntry . compositeElement ?. childPropOverrides
238- ? context . withPropOverrides ( cacheEntry . compositeElement . childPropOverrides )
241+ const childContext = cacheEntry . compositeElement
242+ ? context . withCompositeChild (
243+ cacheEntry . compositeElement . elementId ,
244+ cacheEntry . compositeElement . childPropOverrides
245+ )
239246 : context
240247
241248 // Recurse to process children
@@ -577,64 +584,54 @@ async function convertCompositeElementForDrawing(
577584 // The full ID of this composite element (with any parent prefixes)
578585 const compositeFullId = idPrefix + element . id
579586
587+ // Perform enabled check first, to avoid executing expressions when not needed
588+ const enabled = helper . getBoolean ( 'enabled' , true )
589+
580590 const childElement = context . resolveCompositeElement ( element . connectionId , element . elementId )
581- if ( ! childElement ) {
582- return {
583- drawElement : null ,
584- references,
585- compositeElement : {
586- elementId : compositeElementId ,
587- childIdPrefix : compositeFullId + '/' ,
588- childPropOverrides : { } ,
589- } ,
590- }
591+ const placeholderText = ! childElement
592+ ? 'Missing\nElement'
593+ : context . compositeAncestors . has ( compositeElementId )
594+ ? '\u221e'
595+ : null
596+
597+ let propOverrides : VariableValues = { }
598+ let childIdPrefix = compositeFullId + '/'
599+ if ( childElement && placeholderText === null ) {
600+ propOverrides = parseCompositeElementChildOptions ( helper , childElement , element )
601+ const propOverridesHash = createHash ( 'sha256' ) . update ( JSON . stringify ( propOverrides ) ) . digest ( 'hex' )
602+ childIdPrefix = compositeFullId + '-' + propOverridesHash + '/'
591603 }
592604
593- const propOverrides = parseCompositeElementChildOptions ( helper , childElement , element )
594- const propOverridesHash = createHash ( 'sha256' ) . update ( JSON . stringify ( propOverrides ) ) . digest ( 'hex' )
595-
596- const childIdPrefix = compositeFullId + '-' + propOverridesHash + '/'
597-
598- // Perform enabled check first, to avoid executing expressions when not needed
599- const enabled = helper . getBoolean ( 'enabled' , true )
600- if ( ! enabled && context . onlyEnabled )
601- return {
602- drawElement : null ,
603- references,
604- compositeElement : {
605- elementId : compositeElementId ,
606- childIdPrefix,
607- childPropOverrides : propOverrides ,
608- } ,
609- }
605+ const compositeElement : ElementConversionCacheEntry [ 'compositeElement' ] = {
606+ elementId : compositeElementId ,
607+ childIdPrefix,
608+ childPropOverrides : propOverrides ,
609+ isPlaceholder : placeholderText !== null ,
610+ }
610611
611- const opacity = helper . getNumber ( 'opacity' , 1 , 0.01 )
612- const bounds = convertDrawBounds ( helper )
612+ if ( ! enabled && context . onlyEnabled ) return { drawElement : null , references, compositeElement }
613613
614614 // Note: Composite elements render as groups - hash is shallow (children have their own hashes)
615615 const drawElement : ButtonGraphicsGroupDrawElement = {
616616 id : compositeFullId ,
617617 type : 'group' ,
618618 usage : element . usage ,
619619 enabled,
620- opacity,
621- ...bounds ,
620+ opacity : helper . getNumber ( 'opacity' , 1 , 0.01 ) ,
621+ ...convertDrawBounds ( helper ) ,
622622 rotation : helper . getNumber ( 'rotation' , 0 ) ,
623623 squareCoords : false ,
624- children : [ ] , // Will be filled in by caller
624+ children : [ ] , // Will be filled in by caller, unless a placeholder
625625 contentHash : '' , // Will be computed below
626626 }
627627
628628 drawElement . contentHash = computeElementContentHash ( drawElement )
629- return {
630- drawElement,
631- references,
632- compositeElement : {
633- elementId : compositeElementId ,
634- childIdPrefix,
635- childPropOverrides : propOverrides ,
636- } ,
629+
630+ if ( placeholderText !== null ) {
631+ drawElement . children = makeReferencePlaceholder ( compositeFullId , placeholderText )
637632 }
633+
634+ return { drawElement, references, compositeElement }
638635}
639636
640637async function convertImageElementForDrawing (
@@ -930,7 +927,7 @@ function collectChildElementIds(
930927 // If this child is a composite, we need to check if we have a cached entry
931928 // to determine the correct childIdPrefix for its children
932929 if ( child . type === 'composite' ) {
933- if ( cachedEntry ?. compositeElement ) {
930+ if ( cachedEntry ?. compositeElement && ! cachedEntry . compositeElement . isPlaceholder ) {
934931 const compositeChildren = context . resolveCompositeElement ( child . connectionId , child . elementId ) ?. elements
935932 if ( compositeChildren ) {
936933 collectChildElementIds ( context , compositeChildren , cachedEntry . compositeElement . childIdPrefix )
0 commit comments