diff --git a/src/taskpane/components/MatchProperties.tsx b/src/taskpane/components/MatchProperties.tsx index 991293e3..c5f2e197 100644 --- a/src/taskpane/components/MatchProperties.tsx +++ b/src/taskpane/components/MatchProperties.tsx @@ -92,68 +92,156 @@ export const MatchProperties: React.FC = () => { // Get the first shape to use as template const firstShape = shapes.items[0]; - // Load all properties we need from the first shape + // Load all necessary properties from the first shape firstShape.load([ - "lineFormat/weight", - "lineFormat/dashStyle", - "fill/transparency" + "lineFormat/weight", + "lineFormat/dashStyle", + "lineFormat/color", + "fill/transparency", + "textFrame" ]); await context.sync(); - - // Loop through remaining shapes and apply properties - for (let i = 1; i < shapes.items.length; i++) { - const targetShape = shapes.items[i]; + + // Check if the shape has text and load text properties + let hasText = false; + if (firstShape.textFrame) { + firstShape.textFrame.load("textRange"); + await context.sync(); - // Copy line properties that are available in the Office JS API - try { - // Line weight (width) - targetShape.lineFormat.weight = firstShape.lineFormat.weight; - - // Line style (dash type) - targetShape.lineFormat.dashStyle = firstShape.lineFormat.dashStyle; - - // Fill transparency - targetShape.fill.transparency = firstShape.fill.transparency; - - } catch (err) { - console.error("Error copying basic properties:", err); - } - - // Check if first shape has text frame - try { - // Get text ranges to copy font properties - const sourceTextRange = firstShape.textFrame.textRange; - const targetTextRange = targetShape.textFrame.textRange; - - // Load font properties from source - sourceTextRange.load([ + if (firstShape.textFrame.textRange) { + firstShape.textFrame.textRange.load([ "font/name", "font/size", "font/bold", "font/italic", - "font/underline" + "font/underline", + "font/color" ]); - await context.sync(); - - // Copy font properties - targetTextRange.font.name = sourceTextRange.font.name; - targetTextRange.font.size = sourceTextRange.font.size; - targetTextRange.font.bold = sourceTextRange.font.bold; - targetTextRange.font.italic = sourceTextRange.font.italic; - targetTextRange.font.underline = sourceTextRange.font.underline; - - } catch (err) { - // Silently fail if text properties can't be copied - // This could happen if shape doesn't have text frame - console.error("Error copying text properties:", err); + hasText = true; } } - await context.sync(); - setStatusMessage(`Copied properties from the first shape to ${shapes.items.length - 1} other shapes.`); - setStatusType("success"); + let successCount = 0; + let textStyleCount = 0; + + // Loop through remaining shapes and apply properties + for (let i = 1; i < shapes.items.length; i++) { + try { + const targetShape = shapes.items[i]; + let propertiesApplied = false; + + // Apply line formatting properties + try { + // Line weight + if (firstShape.lineFormat.weight !== undefined) { + targetShape.lineFormat.weight = firstShape.lineFormat.weight; + } + + // Line style + if (firstShape.lineFormat.dashStyle !== undefined) { + targetShape.lineFormat.dashStyle = firstShape.lineFormat.dashStyle; + } + + // Line color + if (firstShape.lineFormat.color !== undefined) { + targetShape.lineFormat.color = firstShape.lineFormat.color; + } + + await context.sync(); + propertiesApplied = true; + } catch (err) { + console.error(`Error applying line format to shape ${i}:`, err); + } + + // Apply fill properties + try { + // Fill transparency + if (firstShape.fill.transparency !== undefined) { + targetShape.fill.transparency = firstShape.fill.transparency; + } + + // We're only copying fill transparency as the other fill properties + // like color and type appear to be read-only or not accessible in Office JS API + + await context.sync(); + propertiesApplied = true; + } catch (err) { + console.error(`Error applying fill format to shape ${i}:`, err); + } + + // Apply text properties if the source has text + if (hasText) { + try { + // First check if target shape has text + targetShape.load("textFrame"); + await context.sync(); + + if (targetShape.textFrame) { + targetShape.textFrame.load("textRange"); + await context.sync(); + + if (targetShape.textFrame.textRange) { + const sourceFont = firstShape.textFrame.textRange.font; + const targetFont = targetShape.textFrame.textRange.font; + + // Apply font properties + if (sourceFont.name !== undefined) { + targetFont.name = sourceFont.name; + } + + if (sourceFont.size !== undefined) { + targetFont.size = sourceFont.size; + } + + if (sourceFont.bold !== undefined) { + targetFont.bold = sourceFont.bold; + } + + if (sourceFont.italic !== undefined) { + targetFont.italic = sourceFont.italic; + } + + if (sourceFont.underline !== undefined) { + targetFont.underline = sourceFont.underline; + } + + if (sourceFont.color !== undefined) { + targetFont.color = sourceFont.color; + } + + await context.sync(); + textStyleCount++; + } + } + } catch (err) { + console.error(`Error applying text format to shape ${i}:`, err); + } + } + + if (propertiesApplied) { + successCount++; + } + + } catch (err) { + console.error(`Error updating shape ${i}:`, err); + } + } + + // Final status message based on what was applied + if (successCount > 0) { + let message = `Applied properties to ${successCount} shapes`; + if (textStyleCount > 0) { + message += ` (including text styling on ${textStyleCount})`; + } + message += ". Note: Fill colors may not be fully supported in the Office JS API."; + setStatusMessage(message); + setStatusType("success"); + } else { + setStatusMessage("Couldn't apply properties. Try selecting different shapes."); + setStatusType("error"); + } // Auto-clear success message after 5 seconds setTimeout(() => { @@ -165,7 +253,7 @@ export const MatchProperties: React.FC = () => { } catch (error) { setStatusMessage(`Error: ${error.message}`); setStatusType("error"); - console.error(error); + console.error("Main error:", error); } finally { setIsProcessing(false); }