@@ -112,13 +112,137 @@ export default {
112112 },
113113
114114 findFieldByAttribute (attribute ) {
115- const parent = this .$parent ;
116- if (parent && parent .fields ) {
117- return parent .fields .find (f => f .attribute === attribute);
115+ const allFields = this .getAllFields ();
116+
117+ // First try exact match
118+ const exactMatch = allFields .find (f => f .attribute === attribute);
119+ if (exactMatch) {
120+ return exactMatch;
121+ }
122+
123+ // For Flexible fields: resolve attribute relative to current context
124+ const contextPrefix = this .getFlexibleContextPrefix ();
125+ if (contextPrefix) {
126+ // Try to find field with same prefix (within same Flexible group)
127+ const prefixedAttribute = ` ${ contextPrefix}${ attribute} ` ;
128+ const prefixedMatch = allFields .find (f => f .attribute === prefixedAttribute);
129+ if (prefixedMatch) {
130+ return prefixedMatch;
131+ }
132+
133+ // Also try alternative Flexible attribute formats
134+ const alternativeFormats = this .getFlexibleAttributeFormats (contextPrefix, attribute);
135+ for (const format of alternativeFormats) {
136+ const match = allFields .find (f => f .attribute === format);
137+ if (match) {
138+ return match;
139+ }
140+ }
141+ }
142+
143+ // Fallback: find any field that ends with the attribute name (for nested contexts)
144+ const suffixMatch = allFields .find (f => {
145+ if (! f .attribute ) return false ;
146+ const attr = f .attribute ;
147+ // Match patterns like: prefix__attribute, prefix[index][attribute]
148+ return attr .endsWith (` __${ attribute} ` ) ||
149+ attr .endsWith (` ][${ attribute} ]` ) ||
150+ attr .endsWith (` [${ attribute} ]` );
151+ });
152+
153+ return suffixMatch || null ;
154+ },
155+
156+ /**
157+ * Get all fields from the parent context.
158+ * Handles both standard Nova detail views and nested Flexible field contexts.
159+ */
160+ getAllFields () {
161+ // Walk up the component tree to find fields
162+ let parent = this .$parent ;
163+ let maxDepth = 10 ;
164+
165+ while (parent && maxDepth-- > 0 ) {
166+ // Check for fields array directly on parent
167+ if (parent .fields && Array .isArray (parent .fields )) {
168+ return parent .fields ;
169+ }
170+ // Check for fields in parent's refs
171+ if (parent .$refs ? .fields && Array .isArray (parent .$refs .fields )) {
172+ return parent .$refs .fields .map (f => f .field || f);
173+ }
174+ parent = parent .$parent ;
175+ }
176+
177+ return [];
178+ },
179+
180+ /**
181+ * Detect the Flexible field context prefix from the container's own field attribute.
182+ * Flexible fields use prefixes like: flexible_key__index__ or flexible_key[index]
183+ */
184+ getFlexibleContextPrefix () {
185+ // Check if this container has a prefixed attribute (indicating it's inside a Flexible field)
186+ const ownAttribute = this .field ? .attribute || ' ' ;
187+
188+ // Pattern 1: Double underscore format (e.g., "overlay_items__0__field_name")
189+ const underscoreMatch = ownAttribute .match (/ ^ (. + __\d + __)/ );
190+ if (underscoreMatch) {
191+ return underscoreMatch[1 ];
192+ }
193+
194+ // Pattern 2: Bracket format (e.g., "overlay_items[0][field_name]")
195+ const bracketMatch = ownAttribute .match (/ ^ (. + \[ \d + \]\[ )/ );
196+ if (bracketMatch) {
197+ return bracketMatch[1 ];
198+ }
199+
200+ // Try to detect from parent/sibling field attributes
201+ const siblingFields = this .field ? .fields || [];
202+ for (const sibling of siblingFields) {
203+ if (sibling .attribute ) {
204+ const siblingUnderscoreMatch = sibling .attribute .match (/ ^ (. + __\d + __)/ );
205+ if (siblingUnderscoreMatch) {
206+ return siblingUnderscoreMatch[1 ];
207+ }
208+ const siblingBracketMatch = sibling .attribute .match (/ ^ (. + \[ \d + \]\[ )/ );
209+ if (siblingBracketMatch) {
210+ return siblingBracketMatch[1 ];
211+ }
212+ }
118213 }
214+
119215 return null ;
120216 },
121217
218+ /**
219+ * Generate alternative attribute formats for Flexible fields.
220+ */
221+ getFlexibleAttributeFormats (prefix , attribute ) {
222+ const formats = [];
223+
224+ // Extract the base key and index from the prefix
225+ const underscoreMatch = prefix .match (/ ^ (. + )__(\d + )__$ / );
226+ const bracketMatch = prefix .match (/ ^ (. + )\[ (\d + )\]\[ $ / );
227+
228+ if (underscoreMatch) {
229+ const [, key , index ] = underscoreMatch;
230+ // Generate bracket format alternative
231+ formats .push (` ${ key} [${ index} ][${ attribute} ]` );
232+ // Single underscore variant
233+ formats .push (` ${ key} _${ index} _${ attribute} ` );
234+ }
235+
236+ if (bracketMatch) {
237+ const [, key , index ] = bracketMatch;
238+ // Generate underscore format alternative
239+ formats .push (` ${ key} __${ index} __${ attribute} ` );
240+ formats .push (` ${ key} _${ index} _${ attribute} ` );
241+ }
242+
243+ return formats;
244+ },
245+
122246 isEmpty (value ) {
123247 return value === null ||
124248 value === undefined ||
0 commit comments