Universal Editor - Modern TypeScript implementation with clean, modular, and maintainable code.
A modern TypeScript implementation of the Universal Editor that allows content authors to edit content directly in context. This version is written in TypeScript and generates a minified JavaScript bundle with all dependencies included.
- TypeScript: Full TypeScript implementation with type safety
- Multiple Editor Support: Works with both TinyMCE and ProseMirror
- Cross-frame Communication: Uses Penpal for secure parent-child frame communication
- Type-safe Validation: Utilizes Zod for runtime type checking
- State Management: Built with Zustand for lightweight, reactive state
- Event-driven Architecture: Comprehensive event system for content operations
- Minified Build: Production-ready minified bundle with all dependencies included
- Clean Code: Fully documented TypeScript source
npm installBuild the TypeScript source into a minified JavaScript bundle:
npm run buildThis will:
- Compile TypeScript to JavaScript
- Bundle all dependencies
- Minify the output
- Generate source maps
- Output to
dist/universal-editor.min.js(~224KB minified with all dependencies)
All public libraries are now properly managed via npm:
- penpal (^6.2.2): Cross-frame communication
- zod (^3.22.4): TypeScript-first schema validation
- prosemirror-* : Rich text editor framework
- zustand (^4.4.7): State management
- typescript (^5.3.3): TypeScript compiler
- esbuild (^0.19.9): Fast JavaScript bundler and minifier
- tsx (^4.7.0): TypeScript execution engine
Use the minified bundle that includes all dependencies:
<script src="dist/universal-editor.min.js"></script> <script type="module" src="src/universal-editor.ts"></script>
<script type="module" src="src/editor/editor-bridge.ts"></script>See src/pages/example.html for a complete working example.
First, start the development server:
npm run devThis will start a Vite server at http://localhost:3000.
You can view the example pages directly to see the content:
- Example 1 (Universal Editor):
http://localhost:3000/pages/example.html - Example 2 (Technology and AI):
http://localhost:3000/pages/example2.html - Example 3 (Travel and Nature):
http://localhost:3000/pages/example3.html
These pages show different content themes with various layouts and styles.
To edit the content, you need to use the editor host:
http://localhost:3000/pages/editor-host.html
The editor host provides:
- ๐จ Toolbar with edit/preview mode buttons
- ๐ Rich Text Editor modal for editing text content
- ๐ผ๏ธ Image Editor modal for changing images
- ๐ URL Switcher to load different pages (default:
http://localhost:3000/pages/example.html) - ๐พ Save Button to persist changes
How to use:
- Open
editor-host.htmlin your browser - Change the URL in the header if you want to edit a different page (example2.html, example3.html, etc.)
- Click "๐ Load" to load the page
- Click "โ๏ธ Edit" to enter edit mode
- Click on any highlighted element to edit it
- Make your changes in the modal editor
- Click "๐พ Save" to save (when implemented)
Example URLs to try:
http://localhost:3000/pages/example.html- Original Universal Editor introhttp://localhost:3000/pages/example2.html- Technology and AI themehttp://localhost:3000/pages/example3.html- Travel and Nature theme- Or any other URL you want to make editable!
The editor supports various content types:
- โ๏ธ Text: Plain text content
- ๐ Rich Text: HTML formatted content
- ๐ผ๏ธ Media: Images and other media
- ๐ References: Links to other content
- ๐ฆ Containers: Groups of components
- ๐งฉ Components: Reusable content blocks
Use data attributes to define editable regions:
<!-- Text Content -->
<h1
data-aue-resource="urn:aem:/content/page/title"
data-aue-type="text"
data-aue-prop="title">
My Title
</h1>
<!-- Rich Text Content -->
<div
data-aue-resource="urn:aem:/content/page/body"
data-aue-type="richtext"
data-aue-prop="content">
<p>Rich text content here...</p>
</div>
<!-- Image Content -->
<img
data-aue-resource="urn:aem:/content/page/hero"
data-aue-type="media"
data-aue-prop="image"
src="/path/to/image.jpg"
alt="Hero" />
<!-- Container -->
<div
data-aue-resource="urn:aem:/content/page/container"
data-aue-type="container">
<!-- Components go here -->
</div>The editor dispatches various custom events you can listen to:
// Editor initialized and ready
document.addEventListener('aue:initialized', () => {
console.log('Editor ready!');
});
// Entering/exiting edit mode
document.addEventListener('aue:ui-edit', () => {
console.log('Edit mode activated');
});
document.addEventListener('aue:ui-preview', () => {
console.log('Preview mode activated');
});
// Content operations
document.addEventListener('aue:content-update', (event) => {
console.log('Content updated:', event.detail);
});
document.addEventListener('aue:content-add', (event) => {
console.log('Content added:', event.detail);
});
document.addEventListener('aue:content-remove', (event) => {
console.log('Content removed:', event.detail);
});| Event | Description |
|---|---|
aue:initialized |
Editor is ready |
aue:content-add |
Content was added |
aue:content-remove |
Content was removed |
aue:content-move |
Content was moved |
aue:content-patch |
Content was patched |
aue:content-update |
Content was updated |
aue:content-copy |
Content was copied |
aue:ui-edit |
Entered edit mode |
aue:ui-preview |
Entered preview mode |
aue:ui-select |
Element was selected |
npm testThis validates the TypeScript source structure and verifies:
- All required imports and functions are present
- TypeScript types are properly defined
- Built bundle exists and is correctly generated
npm run buildCompiles TypeScript and bundles into a minified JavaScript file with all dependencies.
npm run cleanRemoves the dist/ directory with all built files.
npm run validateRuns both tests and build to ensure everything works correctly.
universal-editor/
โโโ src/ # TypeScript source files
โ โโโ universal-editor.ts # Main editor implementation
โ โโโ build.ts # Build script
โ โโโ test.ts # Test script
โ โโโ editor/ # Editor components
โ โ โโโ editor-bridge.ts # Bridge between iframe and host
โ โ โโโ prosemirror-toolbar.ts # ProseMirror toolbar implementation
โ โโโ pages/ # Example HTML pages
โ โโโ editor-host.html # Editor host with toolbar (EDITING)
โ โโโ example.html # Example page 1 - Universal Editor intro
โ โโโ example2.html # Example page 2 - Technology and AI
โ โโโ example3.html # Example page 3 - Travel and Nature
โโโ dist/ # Built files (generated)
โ โโโ universal-editor.min.js # Minified bundle with all dependencies
โ โโโ universal-editor.min.js.map # Source map
โ โโโ universal-editor.js # Compiled TypeScript (not minified)
โ โโโ universal-editor.d.ts # TypeScript declarations
โ โโโ ... # Other compiled files
โโโ tsconfig.json # TypeScript configuration
โโโ vite.config.ts # Vite configuration
โโโ package.json # Project configuration
โโโ README.md # This file
The TypeScript code is organized as follows:
src/universal-editor.ts # Main entry point
โโโ Types & Interfaces # TypeScript type definitions
โโโ Constants # EditorMode, ContentType, Events, etc.
โโโ State Management # Zustand store for editor state
โโโ ProseMirror Setup # Rich text editor configuration
โโโ Event Handlers # DOM event listeners and handlers
โโโ Parent Communication # Penpal methods for cross-frame calls
โโโ Initialization # App startup logic
File Size Comparison:
- Original minified bundle: ~596 KB
- TypeScript source: ~17 KB
- New minified bundle (with all deps): ~224 KB (62% reduction)
- With tree-shaking and gzip, production size is even smaller
src/universal-editor.ts- Main editor implementation (TypeScript)src/build.ts- Build script (TypeScript)src/test.ts- Test script (TypeScript)tsconfig.json- TypeScript configuration
dist/universal-editor.min.js- Minified bundle with all dependenciesdist/universal-editor.min.js.map- Source mapdist/universal-editor.js- Compiled JavaScript (not minified)dist/universal-editor.d.ts- TypeScript declarations
When contributing, please:
- Keep code clean and well-documented
- Use TypeScript for new code
- Follow existing code style
- Test your changes thoroughly
- Run
npm run validatebefore submitting