UNPKG

@tnkrai/tnkr-editor

Version:

A customizable wrapper around Tiptap Editor with TypeScript support and modular architecture

736 lines (594 loc) • 19.4 kB
# @tnkrai/tnkr-editor A modern, feature-rich editor package built on TipTap with advanced 3D model viewing capabilities, assembly instructions, and comprehensive documentation tools. [![npm version](https://badge.fury.io/js/@tnkrai%2Ftnkr-editor.svg)](https://www.npmjs.com/package/@tnkrai/tnkr-editor) [![CI/CD](https://github.com/tnkrai/tnkr-editor/workflows/CI%2FCD/badge.svg)](https://github.com/tnkrai/tnkr-editor/actions) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) ## Features - šŸŽÆ **TipTap-based Editor**: Modern rich text editor built on TipTap v2 with extensive customization - šŸŽØ **Pre-styled Components**: Beautiful UI components with Tailwind CSS - šŸ”§ **TypeScript Support**: Full type safety and excellent developer experience - šŸ“¦ **Modular Architecture**: Import only what you need - šŸŽ­ **3D Model Viewer**: Advanced assembly and part visualization with annotation support - ⚔ **Performance Optimized**: Tree-shakeable and optimized for production - šŸŽŖ **Assembly Mode**: Step-by-step assembly instructions with 3D visualization - šŸ“ **Preview System**: Comprehensive documentation preview with sidebar navigation - šŸŽÆ **Extensible**: Support for custom extensions and plugins ## Installation ```bash npm install @tnkrai/tnkr-editor # or yarn add @tnkrai/tnkr-editor # or pnpm add @tnkrai/tnkr-editor ``` ### Tailwind CSS Requirement This package requires Tailwind CSS to be installed and configured in your application. The components use Tailwind utility classes for styling. ```bash # Install Tailwind CSS (if not already installed) npm install -D tailwindcss ``` Add the package to your `tailwind.config.js`: ```js module.exports = { content: [ // ... your content paths "./node_modules/@tnkrai/tnkr-editor/dist/**/*.{js,ts,jsx,tsx}", ], // ... rest of config } ``` See [TAILWIND_SETUP.md](TAILWIND_SETUP.md) for detailed configuration instructions. ## Core Components ### 1. TnkrEditor The main rich text editor component based on TipTap v2 with extensive features. ```tsx import { TnkrEditor } from '@tnkrai/tnkr-editor'; import '@tnkrai/tnkr-editor/styles'; function App() { const [content, setContent] = useState(null); const handleUploadImage = async (file, onProgress, abortSignal) => { // Your upload implementation // Must return a URL string or { src: string; signedUrl?: string } const formData = new FormData(); formData.append('file', file); const response = await fetch('/api/upload', { method: 'POST', body: formData, signal: abortSignal }); const data = await response.json(); return data.url; // or return { src: data.url, signedUrl: data.signedUrl } }; return ( <TnkrEditor content={content} onChange={setContent} placeholder="Start writing..." readOnly={false} className="min-h-[400px]" minHeight={200} pageTitle="My Document" pageId="doc-1" onUploadImage={handleUploadImage} // Extension configuration extensions={[]} // Custom extensions extensionOptions={{}} // Extension-specific options disabledExtensions={[]} // Extensions to disable customExtensionSet={null} // Use custom extension set // Feature flags enableAI={false} enableCollaboration={false} // AI configuration (if enabled) aiToken={null} aiAppId="tnkr-editor-ai" // Collaboration (if enabled) collaborationProvider={null} collaborationYdoc={null} collaborationUser={{ id: "1", name: "User", color: "#40E0D0" }} // UI configuration showUndoRedo={true} showDragHandle={true} // WhatsNext configuration whatsNextPages={[ { id: 'page-1', name: 'Next Page' }, { id: 'page-2', name: 'Another Page' } ]} whatsNextGoToPage={(pageId) => console.log('Go to:', pageId)} showWhatsNext={true} /> ); } ``` #### Key Features: - **Rich Text Editing**: Full formatting capabilities with markdown support - **Image Upload**: Built-in image upload with progress tracking - **Extensions**: Modular extension system for custom functionality - **AI Integration**: Optional AI features for content generation - **Collaboration**: Real-time collaboration support - **WhatsNext Navigation**: Built-in page navigation component ### 2. AssemblyViewMode Interactive 3D assembly instructions viewer with step-by-step guidance. ```tsx import { AssemblyViewMode } from '@tnkrai/tnkr-editor'; const phases = [ { id: 'phase-1', title: 'Foundation Setup', description: 'Prepare the base structure', steps: [ { id: 'step-1', title: 'Install Base Plate', description: 'Position and secure the foundation', parts: [ { id: 'part-1', name: 'Base Plate A', position: { x: 0, y: 0, z: 0 } } ], tools: [ { id: 'tool-1', title: 'Screwdriver' } ], annotations: [ { id: 'ann-1', type: 'arrow', text: { value: 'Insert here' }, position: { x: 10, y: 20 } } ] } ], subassemblies: [] } ]; function AssemblyApp() { const handlePhasesUpdate = (updatedPhases) => { console.log('Phases updated:', updatedPhases); }; const handleUploadImage = async (file) => { // Your upload implementation const url = await uploadToServer(file); return url; }; return ( <AssemblyViewMode phases={phases} htmlContent="<div>3D Model HTML Content</div>" productTitle="Product Assembly" parts={[ { id: 'part-1', name: 'Base Plate A' }, { id: 'part-2', name: 'Side Panel B' } ]} className="h-screen" // Assembly-specific props organizationId="org-123" productId="product-456" editMode={true} // Enable editing of descriptions onUploadImage={handleUploadImage} onPhasesUpdate={handlePhasesUpdate} /> ); } ``` #### Key Features: - **3D Model Integration**: Display and interact with 3D models - **Step-by-Step Instructions**: Organized phases and steps - **Parts & Tools Management**: Track required components - **Annotations**: 2D annotations overlaying the 3D model - **Edit Mode**: In-place editing of titles and descriptions - **Progress Tracking**: Visual progress indicators ### 3. TnkrPreview Documentation preview system with sidebar navigation and content organization. ```tsx import { TnkrPreview } from '@tnkrai/tnkr-editor'; const categories = [ { id: 'cat-1', name: 'Getting Started', parentId: null, children: [ { id: 'cat-2', name: 'Installation', parentId: 'cat-1', children: [], order: 1, isExpanded: false, hasPage: true, pageContent: { /* TipTap content */ }, type: 'documentation' } ], order: 0, isExpanded: true, hasPage: false, type: 'category', // For assembly type pages organizationId: 'org-123', productId: 'product-456' } ]; function PreviewApp() { return ( <TnkrPreview categories={categories} className="h-screen" title="Product Documentation" organizationName="TNKR AI" organizationLogo="/logo.png" onCategorySelect={(category) => console.log('Selected:', category)} onContactClick={() => console.log('Contact clicked')} onDiscussionsClick={() => console.log('Discussions clicked')} /> ); } ``` #### Key Features: - **Hierarchical Navigation**: Multi-level category tree - **Content Types**: Support for documentation, tutorials, assembly instructions - **Breadcrumb Navigation**: Clear path indication - **Search Integration**: Built-in search capabilities - **Responsive Design**: Mobile-friendly sidebar ### 4. CustomPage A flexible page component that combines editor and viewer capabilities. ```tsx import { CustomPage } from '@tnkrai/tnkr-editor'; function MyPage() { const handleEditorChange = (content) => { console.log('Content changed:', content); }; const handleSave = (content) => { console.log('Saving content:', content); }; const handleUploadImage = async (file) => { // Your upload implementation return uploadedUrl; }; return ( <CustomPage pageParent="Documentation" pageTitle="Getting Started" pageId="page-1" pageType="documentation" // or 'tutorial', 'assembly', etc. initialData={existingContent} onEditorChange={handleEditorChange} onSave={handleSave} onUploadImage={handleUploadImage} className="min-h-screen" showBreadcrumbs={true} breadcrumbs={['Home', 'Documentation', 'Getting Started']} editMode={true} // WhatsNext navigation pages={[ { id: 'page-2', name: 'Next Topic' } ]} goToPage={(pageId) => navigateToPage(pageId)} // For assembly pages organizationId="org-123" productId="product-456" // Utility card handler onUtilityCardClick={() => console.log('Utility card clicked')} editorProps={{ placeholder: "Start writing your documentation...", minHeight: 400 }} /> ); } ``` #### Key Features: - **Multiple Page Types**: Documentation, tutorials, assembly instructions - **Flexible Content**: Support for various content types - **Breadcrumb Navigation**: Context-aware navigation - **Edit/View Modes**: Toggle between editing and viewing - **Auto-save Support**: Built-in save functionality ## API Dependencies **Important**: This package requires certain API endpoints to be implemented in your consuming application for full functionality. ### Required API Endpoints #### 1. Image Upload Endpoint ```typescript // POST /api/upload // Request: FormData with 'file' field // Response: { url: string } or { url: string, signedUrl: string } app.post('/api/upload', async (req, res) => { const file = req.files.file; // Upload to your storage (S3, Cloudinary, etc.) const url = await uploadToStorage(file); res.json({ url }); }); ``` #### 2. S3 Content Fetching (for Assembly Mode) ```typescript // POST /api/fetch-s3-content // Request: { url: string } // Response: { content: string } app.post('/api/fetch-s3-content', async (req, res) => { const { url } = req.body; // Fetch content from S3 const content = await fetchFromS3(url); res.json({ content }); }); ``` #### 3. Phases Management (for Assembly Mode) ```typescript // GET /api/phases?productId={productId}&organizationId={organizationId} // Response: { phases: Phase[] } app.get('/api/phases', async (req, res) => { const { productId, organizationId } = req.query; const phases = await getPhases(productId, organizationId); res.json({ phases }); }); // POST /api/phases?productId={productId}&organizationId={organizationId} // Request: { phases: Phase[], productId: string, organizationId: string } // Response: { success: boolean } app.post('/api/phases', async (req, res) => { const { phases, productId, organizationId } = req.body; await savePhases(phases, productId, organizationId); res.json({ success: true }); }); ``` #### 4. Product Information ```typescript // GET /api/get_product_by_org_id_and_product_id?orgId={orgId}&productId={productId} // Response: { product: Product } app.get('/api/get_product_by_org_id_and_product_id', async (req, res) => { const { orgId, productId } = req.query; const product = await getProduct(orgId, productId); res.json({ product }); }); // GET /api/organizations/{organizationId}/products/{productId} // Response: { product: Product } app.get('/api/organizations/:organizationId/products/:productId', async (req, res) => { const { organizationId, productId } = req.params; const product = await getProduct(organizationId, productId); res.json({ product }); }); ``` #### 5. Collaboration (Optional) ```typescript // POST /api/collaboration // Request: { action: string, document: any } // Response: { success: boolean } app.post('/api/collaboration', async (req, res) => { const { action, document } = req.body; // Handle collaboration actions res.json({ success: true }); }); ``` #### 6. AI Integration (Optional) ```typescript // POST /api/ai // Request: { prompt: string, context: any } // Response: { response: string } app.post('/api/ai', async (req, res) => { const { prompt, context } = req.body; // Call AI service const response = await callAIService(prompt, context); res.json({ response }); }); ``` ### API Implementation Notes 1. **Authentication**: Implement proper authentication and authorization for all endpoints 2. **Error Handling**: Return appropriate HTTP status codes and error messages 3. **File Size Limits**: Implement file size restrictions for uploads 4. **CORS**: Configure CORS appropriately for your environment 5. **Rate Limiting**: Implement rate limiting for API endpoints 6. **Validation**: Validate all input data before processing ## Extension System The editor uses a modular extension system. You can customize extensions: ```tsx import { TnkrEditor, getBasicExtensions, getFullExtensions, getHeaderOnlyExtensions } from '@tnkrai/tnkr-editor'; // Use predefined extension sets const basicExtensions = getBasicExtensions(); const fullExtensions = getFullExtensions(); const headerExtensions = getHeaderOnlyExtensions(); // Or create custom extensions const customExtensions = [ // Your custom TipTap extensions ]; <TnkrEditor customExtensionSet={basicExtensions} extensions={customExtensions} disabledExtensions={['emoji', 'mention']} /> ``` ## TypeScript Support All components come with full TypeScript definitions: ```tsx import type { // Core types TnkrEditorProps, AssemblyViewModeProps, CustomPageProps, TnkrPreviewProps, PreviewCategory, // Assembly types Phase, Step, Part, Tool, IAnnotation2D, // Editor types UploadFunction, WhatsNextPage, PageType, TnkrExtensionConfig, TnkrExtensionSet, ExtensionManagerOptions } from '@tnkrai/tnkr-editor'; ``` ## Styling ### Import Styles ```tsx // Import all styles import '@tnkrai/tnkr-editor/styles'; // Or import specific style modules import '@tnkrai/tnkr-editor/core/styles'; import '@tnkrai/tnkr-editor/preview/styles'; ``` ### Custom Styling The package uses CSS variables for theming: ```css :root { --tnkr-primary: #AA423A; --tnkr-background: #161617; --tnkr-surface: #0D0D0D; --tnkr-border: #313133; --tnkr-text: #ffffff; --tnkr-text-secondary: rgba(255, 255, 255, 0.7); } ``` ## Advanced Usage ### Custom Upload Handler ```tsx const handleUploadImage: UploadFunction = async (file, onProgress, abortSignal) => { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.upload.addEventListener('progress', (e) => { if (e.lengthComputable && onProgress) { onProgress({ progress: (e.loaded / e.total) * 100 }); } }); xhr.addEventListener('load', () => { if (xhr.status === 200) { const response = JSON.parse(xhr.responseText); resolve(response.url); } else { reject(new Error('Upload failed')); } }); if (abortSignal) { abortSignal.addEventListener('abort', () => { xhr.abort(); reject(new Error('Upload aborted')); }); } const formData = new FormData(); formData.append('file', file); xhr.open('POST', '/api/upload'); xhr.send(formData); }); }; ``` ### Assembly Annotations ```tsx const annotation: IAnnotation2D = { id: 'annotation-1', type: 'arrow', // or 'label' text: { value: 'Important note', style: { fontSize: '14px', color: '#ffffff' } }, position: { x: 100, y: 200 }, anchor: { x: 150, y: 250 }, // For arrow type isVisible: true, cameraSettings: { position: [0, 0, 5], rotation: [0, 0, 0], zoom: 1 } }; ``` ### Content Analysis ```tsx import { extractText, countWords, estimateReadingTime, generateTableOfContents, extractMetadata } from '@tnkrai/tnkr-editor'; const metadata = extractMetadata(content); console.log('Word count:', metadata.wordCount); console.log('Reading time:', metadata.readingTime, 'minutes'); const toc = generateTableOfContents(content); // Returns array of { id, text, level } ``` ## Development ### Prerequisites - Node.js >= 18.0.0 - npm >= 8.0.0 ### Setup ```bash git clone https://github.com/tnkrai/tnkr-editor.git cd tnkr-editor npm install ``` ### Scripts ```bash # Build the package npm run build # Watch for changes (development) npm run dev # Type checking npm run type-check # Clean build artifacts npm run clean ``` ### Testing ```bash # Run type checking npm run type-check # Build to verify everything works npm run build ``` ## Architecture ``` @tnkrai/tnkr-editor/ ā”œā”€ā”€ core/ # Core editor functionality │ ā”œā”€ā”€ TnkrEditor.tsx # Main editor component │ ā”œā”€ā”€ components/ # TipTap components │ ā”œā”€ā”€ extensions/ # TipTap extensions │ ā”œā”€ā”€ lib/ # Utilities and helpers │ └── styles/ # Core styles ā”œā”€ā”€ src/ # React components and UI │ ā”œā”€ā”€ components/ │ │ ā”œā”€ā”€ assembly/ # Assembly mode components │ │ ā”œā”€ā”€ ui/ # UI components │ │ └── CustomPage.tsx │ ā”œā”€ā”€ utils/ # Utility functions │ └── styles/ # Component styles └── preview/ # Preview system ā”œā”€ā”€ TnkrPreview.tsx ā”œā”€ā”€ PreviewSidebar.tsx └── PageNavigation.tsx ``` ## Migration Guide ### From Earlier Versions If you're upgrading from an earlier version: 1. **Import changes**: Update imports to use the new structure 2. **API endpoints**: Ensure all required API endpoints are implemented 3. **Upload function**: Update to use the new `UploadFunction` signature 4. **Extension system**: Migrate to the new extension configuration ## Troubleshooting ### Common Issues 1. **Styles not loading**: Ensure you've imported `@tnkrai/tnkr-editor/styles` 2. **Upload not working**: Check that your upload endpoint returns the correct format 3. **Assembly mode errors**: Verify all required API endpoints are implemented 4. **TypeScript errors**: Update to the latest version and check type imports ## Contributing 1. Fork the repository 2. Create your feature branch (`git checkout -b feature/amazing-feature`) 3. Commit your changes (`git commit -m 'Add some amazing feature'`) 4. Push to the branch (`git push origin feature/amazing-feature`) 5. Open a Pull Request ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Support - šŸ“§ Email: support@tnkr.ai - šŸ› Issues: [GitHub Issues](https://github.com/tnkrai/tnkr-editor/issues) - šŸ“– Documentation: [GitHub Wiki](https://github.com/tnkrai/tnkr-editor/wiki) ## Changelog See [CHANGELOG.md](CHANGELOG.md) for a list of changes in each version. --- Made with ā¤ļø by TNKR AI