@tnkrai/tnkr-editor
Version:
A customizable wrapper around Tiptap Editor with TypeScript support and modular architecture
736 lines (594 loc) ⢠19.4 kB
Markdown
# @tnkrai/tnkr-editor
A modern, feature-rich editor package built on TipTap with advanced 3D model viewing capabilities, assembly instructions, and comprehensive documentation tools.
[](https://www.npmjs.com/package/@tnkrai/tnkr-editor)
[](https://github.com/tnkrai/tnkr-editor/actions)
[](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