Optimize AlignmentButtons component with improved documentation, code structure, and performance
This commit is contained in:
@@ -1,3 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* @file AlignmentButtons.tsx
|
||||||
|
* @description Component that provides functionality to align selected shapes
|
||||||
|
* in PowerPoint presentations. Supports horizontal alignment (left, center, right)
|
||||||
|
* and vertical alignment (top, middle, bottom).
|
||||||
|
*/
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -14,6 +21,35 @@ import {
|
|||||||
import { useStatusContext } from "./App";
|
import { useStatusContext } from "./App";
|
||||||
import { useCommonStyles } from "./commonStyles";
|
import { useCommonStyles } from "./commonStyles";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration constants for alignment positions
|
||||||
|
*/
|
||||||
|
const ALIGNMENT_CONFIG = {
|
||||||
|
// Horizontal alignment positions
|
||||||
|
HORIZONTAL: {
|
||||||
|
LEFT: 81.1,
|
||||||
|
CENTER: 480, // Center point of slide
|
||||||
|
RIGHT: 879.75
|
||||||
|
},
|
||||||
|
// Vertical alignment positions
|
||||||
|
VERTICAL: {
|
||||||
|
TOP: 136.75,
|
||||||
|
MIDDLE: 321, // Middle point of slide
|
||||||
|
BOTTOM: 505.25
|
||||||
|
},
|
||||||
|
// Warning message when no shapes are selected
|
||||||
|
NO_SELECTION_WARNING: "No shapes are selected. Please select shapes first."
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alignment types for horizontal and vertical alignment
|
||||||
|
*/
|
||||||
|
type HorizontalAlignmentType = 'left' | 'center' | 'right';
|
||||||
|
type VerticalAlignmentType = 'top' | 'middle' | 'bottom';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component-specific styles
|
||||||
|
*/
|
||||||
const useStyles = makeStyles({
|
const useStyles = makeStyles({
|
||||||
alignmentGrid: {
|
alignmentGrid: {
|
||||||
display: "grid",
|
display: "grid",
|
||||||
@@ -31,16 +67,41 @@ const useStyles = makeStyles({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AlignmentButtons component provides UI and functionality to align
|
||||||
|
* selected shapes in PowerPoint presentations.
|
||||||
|
*
|
||||||
|
* @returns React component
|
||||||
|
*/
|
||||||
export const AlignmentButtons: React.FC = () => {
|
export const AlignmentButtons: React.FC = () => {
|
||||||
const styles = useStyles();
|
const styles = useStyles();
|
||||||
const commonStyles = useCommonStyles();
|
const commonStyles = useCommonStyles();
|
||||||
const {
|
const {
|
||||||
statusMessage, setStatusMessage,
|
setStatusMessage,
|
||||||
statusType, setStatusType,
|
setStatusType,
|
||||||
isProcessing, setIsProcessing
|
isProcessing,
|
||||||
|
setIsProcessing
|
||||||
} = useStatusContext();
|
} = useStatusContext();
|
||||||
|
|
||||||
const alignLeft = async () => {
|
/**
|
||||||
|
* Handles errors and updates the status message
|
||||||
|
*
|
||||||
|
* @param error - The error object
|
||||||
|
* @param operation - The operation being performed (for logging)
|
||||||
|
*/
|
||||||
|
const handleError = (error: any, operation: string): void => {
|
||||||
|
setStatusMessage(`Error: ${error.message || "Unknown error occurred"}`);
|
||||||
|
setStatusType("error");
|
||||||
|
console.error(`${operation} error:`, error);
|
||||||
|
setIsProcessing(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic function to handle horizontal alignment of shapes
|
||||||
|
*
|
||||||
|
* @param alignmentType - The type of horizontal alignment to apply
|
||||||
|
*/
|
||||||
|
const handleHorizontalAlignment = async (alignmentType: HorizontalAlignmentType): Promise<void> => {
|
||||||
setIsProcessing(true);
|
setIsProcessing(true);
|
||||||
try {
|
try {
|
||||||
await PowerPoint.run(async (context) => {
|
await PowerPoint.run(async (context) => {
|
||||||
@@ -51,31 +112,45 @@ export const AlignmentButtons: React.FC = () => {
|
|||||||
|
|
||||||
// Check if shapes are selected
|
// Check if shapes are selected
|
||||||
if (shapes.items.length === 0) {
|
if (shapes.items.length === 0) {
|
||||||
setStatusMessage("No shapes are selected. Please select shapes first.");
|
setStatusMessage(ALIGNMENT_CONFIG.NO_SELECTION_WARNING);
|
||||||
setStatusType("warning");
|
setStatusType("warning");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set alignment for all shapes at once
|
// Set alignment for all shapes at once based on alignment type
|
||||||
shapes.items.forEach(shape => {
|
shapes.items.forEach(shape => {
|
||||||
shape.left = 81.1;
|
switch (alignmentType) {
|
||||||
|
case 'left':
|
||||||
|
shape.left = ALIGNMENT_CONFIG.HORIZONTAL.LEFT;
|
||||||
|
break;
|
||||||
|
case 'center':
|
||||||
|
shape.left = ALIGNMENT_CONFIG.HORIZONTAL.CENTER - (shape.width / 2);
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
shape.left = ALIGNMENT_CONFIG.HORIZONTAL.RIGHT - shape.width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Single sync after all updates
|
// Single sync after all updates
|
||||||
await context.sync();
|
await context.sync();
|
||||||
|
|
||||||
setStatusMessage("Objects aligned to left.");
|
setStatusMessage(`Objects aligned to ${alignmentType}.`);
|
||||||
setStatusType("success");
|
setStatusType("success");
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatusMessage(`Error: ${error.message}`);
|
handleError(error, `Align ${alignmentType}`);
|
||||||
setStatusType("error");
|
|
||||||
console.error("Align left error:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsProcessing(false);
|
setIsProcessing(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const alignCenter = async () => {
|
/**
|
||||||
|
* Generic function to handle vertical alignment of shapes
|
||||||
|
*
|
||||||
|
* @param alignmentType - The type of vertical alignment to apply
|
||||||
|
*/
|
||||||
|
const handleVerticalAlignment = async (alignmentType: VerticalAlignmentType): Promise<void> => {
|
||||||
setIsProcessing(true);
|
setIsProcessing(true);
|
||||||
try {
|
try {
|
||||||
await PowerPoint.run(async (context) => {
|
await PowerPoint.run(async (context) => {
|
||||||
@@ -86,168 +161,79 @@ export const AlignmentButtons: React.FC = () => {
|
|||||||
|
|
||||||
// Check if shapes are selected
|
// Check if shapes are selected
|
||||||
if (shapes.items.length === 0) {
|
if (shapes.items.length === 0) {
|
||||||
setStatusMessage("No shapes are selected. Please select shapes first.");
|
setStatusMessage(ALIGNMENT_CONFIG.NO_SELECTION_WARNING);
|
||||||
setStatusType("warning");
|
setStatusType("warning");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set alignment for all shapes at once
|
// Set alignment for all shapes at once based on alignment type
|
||||||
shapes.items.forEach(shape => {
|
shapes.items.forEach(shape => {
|
||||||
shape.left = 480 - (shape.width / 2);
|
switch (alignmentType) {
|
||||||
|
case 'top':
|
||||||
|
shape.top = ALIGNMENT_CONFIG.VERTICAL.TOP;
|
||||||
|
break;
|
||||||
|
case 'middle':
|
||||||
|
shape.top = ALIGNMENT_CONFIG.VERTICAL.MIDDLE - (shape.height / 2);
|
||||||
|
break;
|
||||||
|
case 'bottom':
|
||||||
|
shape.top = ALIGNMENT_CONFIG.VERTICAL.BOTTOM - shape.height;
|
||||||
|
break;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Single sync after all updates
|
// Single sync after all updates
|
||||||
await context.sync();
|
await context.sync();
|
||||||
|
|
||||||
setStatusMessage("Objects aligned to center.");
|
setStatusMessage(`Objects aligned to ${alignmentType}.`);
|
||||||
setStatusType("success");
|
setStatusType("success");
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatusMessage(`Error: ${error.message}`);
|
handleError(error, `Align ${alignmentType}`);
|
||||||
setStatusType("error");
|
|
||||||
console.error("Align center error:", error);
|
|
||||||
} finally {
|
} finally {
|
||||||
setIsProcessing(false);
|
setIsProcessing(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const alignRight = async () => {
|
/**
|
||||||
setIsProcessing(true);
|
* Aligns selected shapes to the left edge of the slide
|
||||||
try {
|
*/
|
||||||
await PowerPoint.run(async (context) => {
|
const alignLeft = async (): Promise<void> => {
|
||||||
// Get the selected shapes
|
await handleHorizontalAlignment('left');
|
||||||
const shapes = context.presentation.getSelectedShapes();
|
|
||||||
shapes.load("items");
|
|
||||||
await context.sync();
|
|
||||||
|
|
||||||
// Check if shapes are selected
|
|
||||||
if (shapes.items.length === 0) {
|
|
||||||
setStatusMessage("No shapes are selected. Please select shapes first.");
|
|
||||||
setStatusType("warning");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set alignment for all shapes at once
|
|
||||||
shapes.items.forEach(shape => {
|
|
||||||
shape.left = 879.75 - shape.width;
|
|
||||||
});
|
|
||||||
// Single sync after all updates
|
|
||||||
await context.sync();
|
|
||||||
|
|
||||||
setStatusMessage("Objects aligned to right.");
|
|
||||||
setStatusType("success");
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setStatusMessage(`Error: ${error.message}`);
|
|
||||||
setStatusType("error");
|
|
||||||
console.error("Align right error:", error);
|
|
||||||
} finally {
|
|
||||||
setIsProcessing(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const alignTop = async () => {
|
/**
|
||||||
setIsProcessing(true);
|
* Aligns selected shapes to the horizontal center of the slide
|
||||||
try {
|
*/
|
||||||
await PowerPoint.run(async (context) => {
|
const alignCenter = async (): Promise<void> => {
|
||||||
// Get the selected shapes
|
await handleHorizontalAlignment('center');
|
||||||
const shapes = context.presentation.getSelectedShapes();
|
|
||||||
shapes.load("items");
|
|
||||||
await context.sync();
|
|
||||||
|
|
||||||
// Check if shapes are selected
|
|
||||||
if (shapes.items.length === 0) {
|
|
||||||
setStatusMessage("No shapes are selected. Please select shapes first.");
|
|
||||||
setStatusType("warning");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set alignment for all shapes at once
|
|
||||||
shapes.items.forEach(shape => {
|
|
||||||
shape.top = 136.75;
|
|
||||||
});
|
|
||||||
// Single sync after all updates
|
|
||||||
await context.sync();
|
|
||||||
|
|
||||||
setStatusMessage("Objects aligned to top.");
|
|
||||||
setStatusType("success");
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setStatusMessage(`Error: ${error.message}`);
|
|
||||||
setStatusType("error");
|
|
||||||
console.error("Align top error:", error);
|
|
||||||
} finally {
|
|
||||||
setIsProcessing(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const alignMiddle = async () => {
|
/**
|
||||||
setIsProcessing(true);
|
* Aligns selected shapes to the right edge of the slide
|
||||||
try {
|
*/
|
||||||
await PowerPoint.run(async (context) => {
|
const alignRight = async (): Promise<void> => {
|
||||||
// Get the selected shapes
|
await handleHorizontalAlignment('right');
|
||||||
const shapes = context.presentation.getSelectedShapes();
|
|
||||||
shapes.load("items");
|
|
||||||
await context.sync();
|
|
||||||
|
|
||||||
// Check if shapes are selected
|
|
||||||
if (shapes.items.length === 0) {
|
|
||||||
setStatusMessage("No shapes are selected. Please select shapes first.");
|
|
||||||
setStatusType("warning");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set alignment for all shapes at once
|
|
||||||
shapes.items.forEach(shape => {
|
|
||||||
shape.top = 321 - (shape.height / 2);
|
|
||||||
});
|
|
||||||
// Single sync after all updates
|
|
||||||
await context.sync();
|
|
||||||
|
|
||||||
setStatusMessage("Objects aligned to middle.");
|
|
||||||
setStatusType("success");
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setStatusMessage(`Error: ${error.message}`);
|
|
||||||
setStatusType("error");
|
|
||||||
console.error("Align middle error:", error);
|
|
||||||
} finally {
|
|
||||||
setIsProcessing(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const alignBottom = async () => {
|
/**
|
||||||
setIsProcessing(true);
|
* Aligns selected shapes to the top edge of the slide
|
||||||
try {
|
*/
|
||||||
await PowerPoint.run(async (context) => {
|
const alignTop = async (): Promise<void> => {
|
||||||
// Get the selected shapes
|
await handleVerticalAlignment('top');
|
||||||
const shapes = context.presentation.getSelectedShapes();
|
};
|
||||||
shapes.load("items");
|
|
||||||
await context.sync();
|
|
||||||
|
|
||||||
// Check if shapes are selected
|
/**
|
||||||
if (shapes.items.length === 0) {
|
* Aligns selected shapes to the vertical middle of the slide
|
||||||
setStatusMessage("No shapes are selected. Please select shapes first.");
|
*/
|
||||||
setStatusType("warning");
|
const alignMiddle = async (): Promise<void> => {
|
||||||
return;
|
await handleVerticalAlignment('middle');
|
||||||
}
|
};
|
||||||
|
|
||||||
// Set alignment for all shapes at once
|
/**
|
||||||
shapes.items.forEach(shape => {
|
* Aligns selected shapes to the bottom edge of the slide
|
||||||
shape.top = 505.25 - shape.height;
|
*/
|
||||||
});
|
const alignBottom = async (): Promise<void> => {
|
||||||
// Single sync after all updates
|
await handleVerticalAlignment('bottom');
|
||||||
await context.sync();
|
|
||||||
|
|
||||||
setStatusMessage("Objects aligned to bottom.");
|
|
||||||
setStatusType("success");
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
setStatusMessage(`Error: ${error.message}`);
|
|
||||||
setStatusType("error");
|
|
||||||
console.error("Align bottom error:", error);
|
|
||||||
} finally {
|
|
||||||
setIsProcessing(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -318,4 +304,4 @@ export const AlignmentButtons: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlignmentButtons;
|
export default AlignmentButtons;
|
||||||
|
|||||||
Reference in New Issue
Block a user