Files
powerpoint-toolbox/docs/DEVELOPERS.md
T

10 KiB

Edison PowerPoint Add-in Developer Documentation

This document provides detailed technical information for developers working on the Edison PowerPoint Add-in.

Architecture Overview

Edison is a PowerPoint add-in built with:

  • TypeScript for type-safe code
  • React for UI components
  • Office.js API for PowerPoint integration
  • Fluent UI for Microsoft-style interface components

The application follows a component-based architecture where each tool is encapsulated in its own React component.

UML Diagrams

To better understand the architecture and structure of the Edison PowerPoint Add-in, refer to the following UML diagrams:

These diagrams provide visual representations of the application's architecture, component relationships, and data flow patterns, which can help new developers understand the codebase more quickly.

Project Structure

/
├── assets/                  # Images and icons
├── dist/                    # Build output (generated)
├── src/
│   ├── commands/            # Command handlers
│   │   ├── commands.html    # HTML for command UI
│   │   └── commands.ts      # Command implementations
│   └── taskpane/            # Main add-in UI
│       ├── components/      # React components
│       │   ├── ActionButton.tsx  # Reusable button with error handling
│       │   ├── AlignmentButtons.tsx
│       │   ├── App.tsx           # Main application component
│       │   ├── ConfidentialButtons.tsx
│       │   ├── DraftButtons.tsx
│       │   ├── GridGuidelineManager.tsx
│       │   ├── Header.tsx
│       │   ├── InsertTitles.tsx
│       │   ├── MatchProperties.tsx
│       │   ├── MatchSizes.tsx
│       │   ├── ProgressBarButtons.tsx
│       │   ├── RoundImage.tsx
│       │   ├── Section.tsx       # Reusable section component
│       │   ├── SmartTextFormatter.tsx
│       │   ├── SwapPositions.tsx
│       │   └── commonStyles.tsx
│       ├── types/            # TypeScript type definitions
│       │   └── office-types.ts # Office API type utilities
│       ├── index.tsx        # Entry point
│       └── taskpane.html    # Main HTML container
├── babel.config.json        # Babel configuration
├── manifest.xml             # Add-in manifest
├── package.json             # Dependencies and scripts
├── tsconfig.json            # TypeScript configuration
└── webpack.config.js        # Webpack configuration

Development Environment Setup

Prerequisites

  • Node.js (LTS version recommended)
  • npm
  • Microsoft PowerPoint (desktop version)

Setup Steps

  1. Clone the repository:

    git clone https://github.com/your-org/edison-powerpoint-addin.git
    cd edison-powerpoint-addin
    
  2. Install dependencies:

    npm install
    
  3. Build the project:

    npm run build:dev
    
  4. Start the development server:

    npm run dev-server
    
  5. Start the add-in in PowerPoint:

    npm run start
    

Local Development Certificates

Office Add-ins require HTTPS even for local development. The office-addin-dev-certs package is used to create and install self-signed certificates for development.

If you encounter certificate issues, run:

npx office-addin-dev-certs install

Component Development Guidelines

Reusable Components

ActionButton

A reusable button component that handles error states, loading states, and consistent styling:

import ActionButton from "./ActionButton";

// In your component:
<ActionButton
  title="Match Sizes"
  icon={<ArrowFitInRegular />}
  onClick={myAsyncFunction}
/>

Section

A consistent container for organizing the UI:

import Section from "./Section";

// In your component:
<Section title="My Feature Group">
  <MyFeatureComponent />
</Section>

Creating a New Tool

  1. Create a new component file in src/taskpane/components/
  2. Import the necessary Office.js APIs and React hooks
  3. Use the StatusContext for user feedback
  4. Follow the pattern of existing components:
    • Use the PowerPoint.run() method for PowerPoint operations
    • Provide clear success/error messaging
    • Handle selection states appropriately

Example component structure:

import * as React from "react";
import { useState } from "react";
import { Button } from "@fluentui/react-components";
import { useStatusContext } from "./App";

const MyNewTool: React.FC = () => {
  const { setStatusMessage, setStatusType, isProcessing, setIsProcessing } = useStatusContext();

  const performAction = async () => {
    setIsProcessing(true);
    try {
      await PowerPoint.run(async (context) => {
        // Implement your PowerPoint operations here
        await context.sync();
      });
      setStatusMessage("Operation completed successfully!");
      setStatusType("success");
    } catch (error) {
      setStatusMessage(`Error: ${error.message}`);
      setStatusType("error");
      console.error("Operation error:", error);
    } finally {
      setIsProcessing(false);
    }
  };

  return (
    <Button onClick={performAction} disabled={isProcessing}>
      My New Tool
    </Button>
  );
};

export default MyNewTool;

Common PowerPoint.js Operations

Type-Safe Utilities

The application provides type-safe utility functions in src/taskpane/types/office-types.ts:

// Get error message safely from any error type
const errorMsg = getErrorMessage(error);

// Check if a shape is an image
if (isPictureShape(shape)) {
  // It's a picture shape
}

// Get the first selected slide
const slide = getFirstSelectedSlide(context);

// Select shapes by ID
selectShapesById(slide, [shape1.id, shape2.id]);

Selecting Shapes

const shapes = context.presentation.getSelectedShapes();
shapes.load("items");
await context.sync();

Working with Slide Masters

const slideMasters = context.presentation.slideMasters;
slideMasters.load("items");
await context.sync();

Creating Shapes

const shape = slide.shapes.addGeometricShape("Rectangle");
shape.left = 100;
shape.top = 100;
shape.height = 50;
shape.width = 50;
await context.sync();

Status System

The application includes a status system that provides feedback to users:

  • Success: Operation completed successfully
  • Warning: Operation completed with concerns
  • Error: Operation failed
  • Processing: Shows a spinner while operations are in progress

Use the status context in your components:

const { 
  statusMessage, 
  setStatusMessage, 
  statusType, 
  setStatusType, 
  isProcessing, 
  setIsProcessing 
} = useStatusContext();

Build and Deployment

Development Build

npm run build:dev

Production Build

npm run build

Manifest Validation

npm run validate

This validates the manifest.xml file against the Office Add-in schema.

Testing

Currently, the project doesn't have automated tests. This is an area for future improvement.

Recommended testing approach:

  1. Manual testing in PowerPoint
  2. Implementation of unit tests for individual utilities
  3. Integration tests for PowerPoint API interactions

Performance Considerations

Optimizing context.sync() calls

A key performance optimization is to batch context.sync() calls:

// BAD: Calling context.sync() in a loop
for (let i = 0; i < shapes.items.length; i++) {
  shapes.items[i].load("name");
  await context.sync(); // Slow! One network roundtrip per shape
  if (shapes.items[i].name === "Target") {
    // Do something
  }
}

// GOOD: Batching context.sync() calls
// Load all properties at once
for (let i = 0; i < shapes.items.length; i++) {
  shapes.items[i].load("name");
}
await context.sync(); // Single network roundtrip for all shapes

// Process the data locally
for (let i = 0; i < shapes.items.length; i++) {
  if (shapes.items[i].name === "Target") {
    // Do something
  }
}

Additional performance tips:

  • Use memoization for expensive calculations
  • Ensure proper cleanup of event listeners
  • Use the ActionButton component for consistent loading states
  • Consider using Web Workers for heavy computations

Common Issues and Solutions

Add-in not loading in PowerPoint

  • Verify the development server is running
  • Check for certificate errors in the browser console
  • Validate the manifest.xml file

PowerPoint API errors

  • Ensure correct API version is being used
  • Check the sequence of operations (some operations require specific order)
  • Verify selections exist before operating on them

Best Practices

  1. Error Handling: Always use try/catch blocks with PowerPoint API calls and use proper types (see office-types.ts)
  2. User Feedback: Provide clear status messages for all operations using the StatusContext
  3. Accessibility: Ensure all UI elements have proper ARIA attributes and support keyboard navigation
  4. Theme Support: Use Fluent UI theme tokens for consistent theming
  5. Code Organization: Keep component files focused on a single responsibility
  6. Performance: Batch context.sync() calls and avoid calling them inside loops
  7. Reusability: Use custom hooks for common operations and shared components like ActionButton and Section
  8. Type Safety: Avoid using "any" type and leverage TypeScript's static typing

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Submit a pull request with a clear description of the changes

Resources