@tech-alfia/pitch-deck-editor
v1.1.2
Published
A reusable pitch deck editor component library
Maintainers
Readme
Pitch Deck Editor Library
A reusable Canva-like pitch deck editor component that can be integrated into any React project.
Features
- Drag-and-drop slide editor
- Rich text elements
- Shapes and icons
- Image support
- Tables and charts
- Drawing tools
- AI panel integration
- Template library
- Presentation mode
- Undo/redo functionality
- Auto-save with custom API endpoints
- Dark/light theme support
- Fully customizable API layer
Documentation
| Document | Audience | |----------|----------| | docs/PITCH_DECK_EDITOR_SPEC.md | Full JSON schema, element types, canvas rules, React/API integration | | docs/AI_GENERATION_PROMPT.md | Copy-paste system prompt: editor tools + JSON rules only (no fixed slide templates) |
Use these when wiring AI-generated decks in production: the system prompt explains capabilities; the user message carries topic, outline, and brand. Pass parsed JSON as initialDeck to PitchDeckEditor.
Installation
Install the package:
npm install @tech-alfia/pitch-deck-editorIf you use pnpm:
pnpm add @tech-alfia/pitch-deck-editorRequired Setup
This library depends on Tailwind CSS v3.
1. Install Tailwind CSS
pnpm install -D tailwindcss@3Or with npm:
npm install -D tailwindcss@32. Initialize Tailwind
npx tailwindcss init3. Generate Tailwind CSS Output
npx tailwindcss -i ./src/index.css -o ./src/app.css --watch4. Configure tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./index.html",
"./src/**/*.{js,jsx,ts,tsx}",
"./node_modules/@alfia/pitch-deck-editor/dist/**/*.{js,jsx,ts,tsx}"
],
darkMode: "class",
theme: {
extend: {
colors: {
"alfia-black": "#000000",
"alfia-white": "#ffffff",
"alfia-bg-root": "#000000",
"alfia-bg-surface": "#0b0b0b",
"alfia-bg-elevated": "#111111",
"alfia-bg-hover": "#1a1a1a",
"alfia-bg-active": "#222222",
"alfia-bg-root-light": "#ffffff",
"alfia-bg-surface-light": "#F9F9F9",
"alfia-bg-elevated-light": "#fafafa",
"alfia-bg-hover-light": "#EAEAEA",
"alfia-bg-active-light": "#EAEAEA",
"alfia-border-subtle": "#1f1f1f",
"alfia-border-default": "#2a2a2a",
"alfia-border-strong": "#3a3a3a",
"alfia-border-subtle-light": "#e0e0e0",
"alfia-border-default-light": "#d4d4d4",
"alfia-border-strong-light": "#b3b3b3",
"alfia-text-primary": "#ffffff",
"alfia-text-secondary": "#b3b3b3",
"alfia-text-muted": "#7a7a7a",
"alfia-text-disabled": "#4d4d4d",
"alfia-text-inverse": "#000000",
"alfia-text-primary-light": "#000000",
"alfia-text-secondary-light": "#838383",
"alfia-text-muted-light": "#7a7a7a",
"alfia-text-disabled-light": "#b3b3b3",
"alfia-text-inverse-light": "#ffffff",
"alfia-btn-primary": "#ffffff",
"alfia-btn-primary-hover": "#e6e6e6",
"alfia-btn-secondary": "#1a1a1a",
"alfia-btn-secondary-hover": "#262626",
"alfia-btn-ghost-hover": "#1f1f1f",
"alfia-btn-primary-light": "#000000",
"alfia-btn-primary-hover-light": "#1a1a1a",
"alfia-btn-secondary-light": "#f5f5f5",
"alfia-btn-secondary-hover-light": "#e6e6e6",
"alfia-btn-ghost-hover-light": "#e0e0e0",
"alfia-icon-default": "#b3b3b3",
"alfia-icon-active": "#ffffff",
"alfia-icon-muted": "#666666",
"alfia-icon-default-light": "#4d4d4d",
"alfia-icon-active-light": "#000000",
"alfia-icon-muted-light": "#7a7a7a",
"alfia-grad-start": "#ffffff",
"alfia-grad-mid": "#bfbfbf",
"alfia-grad-end": "#000000",
"alfia-accent": "#3b82f6",
"alfia-accent-hover": "#2563eb",
"alfia-status-pending": "#6b7280",
"alfia-status-rejected": "#dc2626",
"alfia-status-live": "#16a34a",
"alfia-status-upcoming": "#2563eb",
"alfia-status-completed": "#6b7280",
},
backgroundImage: {
"alfia-gradient-main":
"linear-gradient(135deg, #ffffff 0%, #bfbfbf 50%, #000000 100%)",
},
keyframes: {
"ai-glow-border": {
"0%": { backgroundPosition: "0% 50%" },
"100%": { backgroundPosition: "100% 50%" },
},
},
animation: {
"ai-glow-border": "ai-glow-border 3.5s linear infinite",
},
},
},
plugins: [],
};5. Configure postcss.config.js
export default {
plugins: {
tailwindcss: {},
},
}6. Import Your CSS File
Inside your main entry file (main.jsx, main.tsx, etc.):
import "./app.css";Usage
Basic Usage
import React from 'react';
import { PitchDeckEditor } from '@alfia/pitch-deck-editor';
function App() {
const handleDeckChange = (deck) => {
console.log('Deck changed:', deck);
};
return (
<div style={{ height: '100vh' }}>
<PitchDeckEditor
initialDeck={null}
onChange={handleDeckChange}
onNavigateBack={() => console.log('Navigate back')}
/>
</div>
);
}
export default App;With Custom API Integration
import React from 'react';
import { PitchDeckEditor } from '@alfia/pitch-deck-editor';
function App() {
const apiClient = {
updatePitchDeck: async (deckId, payload) => {
const response = await fetch(`/api/decks/${deckId}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
return response.json();
},
getPitchDeck: async (deckId) => {
const response = await fetch(`/api/decks/${deckId}`);
return response.json();
}
};
return (
<div style={{ height: '100vh' }}>
<PitchDeckEditor
initialDeck={null}
apiClient={apiClient}
deckId="my-deck-id"
onChange={(deck) => console.log(deck)}
onNavigateBack={() => console.log('Back')}
/>
</div>
);
}
export default App;With AI Integration
import React from 'react';
import { PitchDeckEditor } from '@alfia/pitch-deck-editor';
function App() {
const ai = {
generateSlide: async (prompt) => {
// Your AI generation logic
},
improveDeck: async (deck) => {
// Your AI deck improvement logic
}
};
return (
<div style={{ height: '100vh' }}>
<PitchDeckEditor
initialDeck={null}
ai={ai}
onChange={(deck) => console.log(deck)}
onNavigateBack={() => console.log('Back')}
/>
</div>
);
}
export default App;API Reference
PitchDeckEditor Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| initialDeck | Object | No | Initial deck state |
| onChange | Function | Yes | Callback when deck changes |
| onNavigateBack | Function | Yes | Callback for back navigation |
| saveStatus | String | No | Save status (idle, saving, saved, error) |
| className | String | No | Additional CSS classes |
| apiClient | Object | No | Custom API client for persistence |
| deckId | String | No | Deck ID for API operations |
| ai | Object | No | AI integration methods |
API Client Interface
interface ApiClient {
updatePitchDeck: (deckId: string, payload: any) => Promise<any>;
getPitchDeck?: (deckId: string) => Promise<any>;
createPitchDeck?: (payload: any) => Promise<any>;
deletePitchDeck?: (deckId: string) => Promise<any>;
}Re-exported Hooks and Types
import {
useEditor,
createEmptyEditorDeck,
ElementType,
ShapeType,
BackgroundType,
CANVAS_WIDTH,
CANVAS_HEIGHT,
FONT_FAMILIES,
DEFAULT_THEME
} from '@alfia/pitch-deck-editor';Development
# Install dependencies
npm install
# Build the library
npm run build
# Run development mode
npm run dev
# Run tests
npm test
# Lint code
npm run lintTroubleshooting
Tailwind styles are not working
Make sure:
- Tailwind CSS v3 is installed
- The library path is included inside
content - Your generated CSS file is imported
- The Tailwind watcher/build process is running
Correct path:
"./node_modules/@alfia/pitch-deck-editor/dist/**/*.{js,jsx,ts,tsx}"Dark mode does not work
Ensure your application adds the dark class to the root HTML element:
document.documentElement.classList.add("dark");License
MIT License — see LICENSE file for details.
