feat: delete documentation change
This commit is contained in:
parent
d5fdc5b4af
commit
0d12b105fb
|
|
@ -1,274 +0,0 @@
|
|||
# 🚀 CKEditor5 Migration to Official Packages
|
||||
|
||||
## Current Situation
|
||||
You're currently using a custom CKEditor5 build from `vendor/ckeditor5` which is:
|
||||
- **2.4MB in size** (very large)
|
||||
- **Outdated version** (41.3.1)
|
||||
- **Hard to maintain** (custom build)
|
||||
- **No automatic updates**
|
||||
|
||||
## 🎯 Migration Benefits
|
||||
|
||||
### Performance Improvements
|
||||
- **Bundle Size:** 2.4MB → 800KB (67% reduction)
|
||||
- **Load Time:** 2-3 seconds faster
|
||||
- **Memory Usage:** 50% reduction
|
||||
- **Tree Shaking:** Better optimization
|
||||
|
||||
### Maintainability
|
||||
- **Automatic Updates:** Latest CKEditor5 versions
|
||||
- **Security Patches:** Regular updates
|
||||
- **Bug Fixes:** Official support
|
||||
- **Documentation:** Better resources
|
||||
|
||||
## 📦 Available Official Builds
|
||||
|
||||
### 1. Classic Build (RECOMMENDED) ⭐
|
||||
```bash
|
||||
npm install @ckeditor/ckeditor5-build-classic
|
||||
```
|
||||
- **Size:** ~800KB
|
||||
- **Features:** Full-featured editor
|
||||
- **Best for:** Most use cases
|
||||
|
||||
### 2. Decoupled Document Build
|
||||
```bash
|
||||
npm install @ckeditor/ckeditor5-build-decoupled-document
|
||||
```
|
||||
- **Size:** ~1MB
|
||||
- **Features:** Document-style editing
|
||||
- **Best for:** Document editors
|
||||
|
||||
### 3. Inline Build
|
||||
```bash
|
||||
npm install @ckeditor/ckeditor5-build-inline
|
||||
```
|
||||
- **Size:** ~600KB
|
||||
- **Features:** Inline editing
|
||||
- **Best for:** Inline text editing
|
||||
|
||||
### 4. Super Build
|
||||
```bash
|
||||
npm install @ckeditor/ckeditor5-build-super-build
|
||||
```
|
||||
- **Size:** ~1.5MB
|
||||
- **Features:** All features included
|
||||
- **Best for:** Maximum functionality
|
||||
|
||||
## 🔧 Migration Steps
|
||||
|
||||
### Step 1: Install Official Package
|
||||
```bash
|
||||
# Remove custom build dependency
|
||||
npm uninstall ckeditor5-custom-build
|
||||
|
||||
# Install official classic build (recommended)
|
||||
npm install @ckeditor/ckeditor5-build-classic
|
||||
```
|
||||
|
||||
### Step 2: Update Import Statements
|
||||
**Before:**
|
||||
```javascript
|
||||
import Editor from "ckeditor5-custom-build";
|
||||
```
|
||||
|
||||
**After:**
|
||||
```javascript
|
||||
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
|
||||
```
|
||||
|
||||
### Step 3: Update Components
|
||||
Your components are already updated:
|
||||
- ✅ `components/editor/custom-editor.js`
|
||||
- ✅ `components/editor/view-editor.js`
|
||||
|
||||
### Step 4: Remove Vendor Directory
|
||||
```bash
|
||||
rm -rf vendor/ckeditor5/
|
||||
```
|
||||
|
||||
## 📝 Updated Component Examples
|
||||
|
||||
### Custom Editor (Updated)
|
||||
```javascript
|
||||
import React from "react";
|
||||
import { CKEditor } from "@ckeditor/ckeditor5-react";
|
||||
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
|
||||
|
||||
function CustomEditor(props) {
|
||||
return (
|
||||
<CKEditor
|
||||
editor={ClassicEditor}
|
||||
data={props.initialData}
|
||||
onChange={(event, editor) => {
|
||||
const data = editor.getData();
|
||||
props.onChange(data);
|
||||
}}
|
||||
config={{
|
||||
toolbar: [
|
||||
'heading', 'fontSize', 'bold', 'italic', 'link',
|
||||
'numberedList', 'bulletedList', 'undo', 'redo',
|
||||
'alignment', 'outdent', 'indent', 'blockQuote',
|
||||
'insertTable', 'codeBlock', 'sourceEditing'
|
||||
],
|
||||
// Performance optimizations
|
||||
removePlugins: ['CKFinderUploadAdapter', 'CKFinder', 'EasyImage'],
|
||||
// Better mobile support
|
||||
mobile: {
|
||||
toolbar: ['bold', 'italic', 'link', 'bulletedList', 'numberedList']
|
||||
},
|
||||
// Auto-save feature
|
||||
autosave: {
|
||||
waitingTime: 30000,
|
||||
save(editor) {
|
||||
const data = editor.getData();
|
||||
localStorage.setItem('editor-autosave', data);
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### View Editor (Updated)
|
||||
```javascript
|
||||
import React from "react";
|
||||
import { CKEditor } from "@ckeditor/ckeditor5-react";
|
||||
import ClassicEditor from "@ckeditor/ckeditor5-build-classic";
|
||||
|
||||
function ViewEditor(props) {
|
||||
return (
|
||||
<CKEditor
|
||||
editor={ClassicEditor}
|
||||
data={props.initialData}
|
||||
disabled={true}
|
||||
config={{
|
||||
toolbar: [],
|
||||
readOnly: true,
|
||||
removePlugins: [
|
||||
'CKFinderUploadAdapter', 'CKFinder', 'EasyImage',
|
||||
'Image', 'ImageCaption', 'ImageStyle', 'ImageToolbar', 'ImageUpload',
|
||||
'MediaEmbed', 'Table', 'TableToolbar'
|
||||
]
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 🎛️ Configuration Options
|
||||
|
||||
### Performance Optimizations
|
||||
```javascript
|
||||
config={{
|
||||
// Remove unused plugins
|
||||
removePlugins: ['CKFinderUploadAdapter', 'CKFinder', 'EasyImage'],
|
||||
|
||||
// Mobile optimization
|
||||
mobile: {
|
||||
toolbar: ['bold', 'italic', 'link', 'bulletedList', 'numberedList']
|
||||
},
|
||||
|
||||
// Auto-save
|
||||
autosave: {
|
||||
waitingTime: 30000,
|
||||
save(editor) {
|
||||
const data = editor.getData();
|
||||
localStorage.setItem('editor-autosave', data);
|
||||
}
|
||||
}
|
||||
}}
|
||||
```
|
||||
|
||||
### Custom Toolbar
|
||||
```javascript
|
||||
toolbar: [
|
||||
'heading', 'fontSize', '|',
|
||||
'bold', 'italic', 'underline', '|',
|
||||
'link', '|',
|
||||
'bulletedList', 'numberedList', '|',
|
||||
'alignment', 'outdent', 'indent', '|',
|
||||
'blockQuote', 'insertTable', '|',
|
||||
'undo', 'redo'
|
||||
]
|
||||
```
|
||||
|
||||
### Image Upload
|
||||
```javascript
|
||||
simpleUpload: {
|
||||
uploadUrl: '/api/upload',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': 'your-csrf-token'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🚀 Quick Migration Script
|
||||
|
||||
Run this command to automate the migration:
|
||||
```bash
|
||||
npm run migrate-editor
|
||||
```
|
||||
|
||||
Or manually:
|
||||
```bash
|
||||
# 1. Install official package
|
||||
npm uninstall ckeditor5-custom-build
|
||||
npm install @ckeditor/ckeditor5-build-classic
|
||||
|
||||
# 2. Remove vendor directory
|
||||
rm -rf vendor/ckeditor5/
|
||||
|
||||
# 3. Test your application
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 📊 Performance Comparison
|
||||
|
||||
| Metric | Custom Build | Official Build | Improvement |
|
||||
|--------|-------------|----------------|-------------|
|
||||
| Bundle Size | 2.4MB | 800KB | 67% reduction |
|
||||
| Load Time | ~5s | ~2s | 60% faster |
|
||||
| Memory Usage | High | Medium | 50% reduction |
|
||||
| Updates | Manual | Automatic | ✅ |
|
||||
| Maintenance | High | Low | ✅ |
|
||||
|
||||
## 🔍 Files to Update
|
||||
|
||||
1. ✅ `components/editor/custom-editor.js` - Updated
|
||||
2. ✅ `components/editor/view-editor.js` - Updated
|
||||
3. `package.json` - Remove `ckeditor5-custom-build`
|
||||
4. Remove `vendor/ckeditor5/` directory
|
||||
|
||||
## 🎉 Expected Results
|
||||
|
||||
After migration, you should see:
|
||||
- **Faster page loads**
|
||||
- **Smaller bundle size**
|
||||
- **Better mobile performance**
|
||||
- **Easier maintenance**
|
||||
- **Automatic updates**
|
||||
|
||||
## 🚨 Important Notes
|
||||
|
||||
1. **Backup your current setup** before migration
|
||||
2. **Test thoroughly** after migration
|
||||
3. **Check for breaking changes** in editor API
|
||||
4. **Update any custom configurations**
|
||||
5. **Monitor performance improvements**
|
||||
|
||||
## 🎯 Next Steps
|
||||
|
||||
1. Run the migration script
|
||||
2. Test your editor components
|
||||
3. Remove the vendor directory
|
||||
4. Monitor performance improvements
|
||||
5. Update documentation
|
||||
|
||||
## 📞 Support
|
||||
|
||||
If you encounter any issues:
|
||||
1. Check the [CKEditor5 documentation](https://ckeditor.com/docs/ckeditor5/)
|
||||
2. Review the [migration guide](https://ckeditor.com/docs/ckeditor5/latest/installation/getting-started/quick-start.html)
|
||||
3. Test with the official examples
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
# 🚀 CKEditor5 Optimization Plan
|
||||
|
||||
## Current Issues
|
||||
- **Bundle Size:** 2.4MB custom build (very large)
|
||||
- **Version:** CKEditor 41.3.1 (outdated - current is 44.x)
|
||||
- **Performance:** All plugins loaded at once
|
||||
- **No Tree Shaking:** Unused code included
|
||||
|
||||
## 🎯 Optimization Options
|
||||
|
||||
### Option 1: Replace with TinyMCE (RECOMMENDED) ⭐
|
||||
**Bundle Size:** ~200KB (90% reduction)
|
||||
**Benefits:**
|
||||
- Much smaller bundle size
|
||||
- Better performance
|
||||
- Modern features
|
||||
- Better mobile support
|
||||
- Built-in auto-save
|
||||
|
||||
**Installation:**
|
||||
```bash
|
||||
npm install @tinymce/tinymce-react
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
import OptimizedEditor from '@/components/editor/optimized-editor';
|
||||
|
||||
<OptimizedEditor
|
||||
initialData={content}
|
||||
onChange={handleChange}
|
||||
height={400}
|
||||
placeholder="Start typing..."
|
||||
/>
|
||||
```
|
||||
|
||||
### Option 2: Use Official CKEditor5 Build with Tree Shaking
|
||||
**Bundle Size:** ~800KB (67% reduction)
|
||||
**Benefits:**
|
||||
- Keep CKEditor features
|
||||
- Better tree shaking
|
||||
- Updated version
|
||||
- Lazy loading
|
||||
|
||||
**Installation:**
|
||||
```bash
|
||||
npm uninstall ckeditor5-custom-build
|
||||
npm install @ckeditor/ckeditor5-build-classic @ckeditor/ckeditor5-react
|
||||
```
|
||||
|
||||
### Option 3: Minimal Editor with React Quill
|
||||
**Bundle Size:** ~100KB (96% reduction)
|
||||
**Benefits:**
|
||||
- Extremely lightweight
|
||||
- Fast loading
|
||||
- Simple features
|
||||
- Perfect for basic text editing
|
||||
|
||||
**Installation:**
|
||||
```bash
|
||||
npm install react-quill
|
||||
```
|
||||
|
||||
## 📊 Performance Comparison
|
||||
|
||||
| Editor | Bundle Size | Load Time | Features | Mobile Support |
|
||||
|--------|-------------|-----------|----------|----------------|
|
||||
| Current CKEditor5 | 2.4MB | Slow | Full | Limited |
|
||||
| TinyMCE | 200KB | Fast | Rich | Excellent |
|
||||
| CKEditor5 Classic | 800KB | Medium | Full | Good |
|
||||
| React Quill | 100KB | Very Fast | Basic | Good |
|
||||
|
||||
## 🔧 Implementation Steps
|
||||
|
||||
### Step 1: Choose Your Option
|
||||
Based on your needs:
|
||||
- **Full-featured editing:** TinyMCE
|
||||
- **Keep CKEditor:** Option 2
|
||||
- **Basic editing:** React Quill
|
||||
|
||||
### Step 2: Update Dependencies
|
||||
```bash
|
||||
# Remove current CKEditor
|
||||
npm uninstall ckeditor5-custom-build @ckeditor/ckeditor5-react
|
||||
|
||||
# Install chosen option
|
||||
npm install @tinymce/tinymce-react # Option 1
|
||||
# OR
|
||||
npm install @ckeditor/ckeditor5-build-classic @ckeditor/ckeditor5-react # Option 2
|
||||
# OR
|
||||
npm install react-quill # Option 3
|
||||
```
|
||||
|
||||
### Step 3: Replace Components
|
||||
Update your existing editor components:
|
||||
- `components/editor/custom-editor.js`
|
||||
- `components/editor/view-editor.js`
|
||||
|
||||
### Step 4: Remove Custom Build
|
||||
```bash
|
||||
rm -rf vendor/ckeditor5/
|
||||
```
|
||||
|
||||
## 🎯 Recommended Implementation
|
||||
|
||||
**For your MediaHub project, I recommend TinyMCE because:**
|
||||
1. **90% bundle size reduction** (2.4MB → 200KB)
|
||||
2. **Better performance** for your users
|
||||
3. **Modern features** like auto-save
|
||||
4. **Excellent mobile support**
|
||||
5. **Active development** and community
|
||||
|
||||
## 📝 Migration Checklist
|
||||
|
||||
- [ ] Choose optimization option
|
||||
- [ ] Install new dependencies
|
||||
- [ ] Update editor components
|
||||
- [ ] Test functionality
|
||||
- [ ] Remove old CKEditor files
|
||||
- [ ] Update imports across project
|
||||
- [ ] Test performance improvement
|
||||
- [ ] Update documentation
|
||||
|
||||
## 🔍 Files to Update
|
||||
|
||||
1. `components/editor/custom-editor.js`
|
||||
2. `components/editor/view-editor.js`
|
||||
3. `package.json` (dependencies)
|
||||
4. Any forms using the editor
|
||||
5. Remove `vendor/ckeditor5/` directory
|
||||
|
||||
## 📈 Expected Performance Gains
|
||||
|
||||
- **Initial Load:** 2-3 seconds faster
|
||||
- **Bundle Size:** 90% reduction
|
||||
- **Memory Usage:** 50% reduction
|
||||
- **Mobile Performance:** Significantly better
|
||||
- **Lighthouse Score:** +10-15 points
|
||||
|
||||
## 🚨 Important Notes
|
||||
|
||||
1. **Backup your current setup** before making changes
|
||||
2. **Test thoroughly** after migration
|
||||
3. **Update any custom configurations**
|
||||
4. **Check for breaking changes** in editor API
|
||||
5. **Update any image upload handlers**
|
||||
|
||||
## 🎉 Next Steps
|
||||
|
||||
1. Choose your preferred option
|
||||
2. Run the installation commands
|
||||
3. Replace the editor components
|
||||
4. Test the new implementation
|
||||
5. Remove the old custom build
|
||||
6. Monitor performance improvements
|
||||
Binary file not shown.
|
|
@ -1,186 +0,0 @@
|
|||
# Editor Fixes Summary
|
||||
|
||||
## Masalah yang Diperbaiki
|
||||
|
||||
### 1. **Data dari setValue Tidak Tampil**
|
||||
- **Masalah**: Ketika menggunakan `setValue` dari react-hook-form, data tidak muncul di editor
|
||||
- **Penyebab**: Timing issue antara editor initialization dan data setting
|
||||
- **Solusi**: Implementasi state management yang lebih baik dan multiple useEffect untuk handle berbagai timing scenarios
|
||||
|
||||
### 2. **Cursor Jumping**
|
||||
- **Masalah**: Cursor melompat saat mengetik
|
||||
- **Penyebab**: Event handling yang tidak tepat dan content manipulation yang berlebihan
|
||||
- **Solusi**: Simplifikasi event handling dan removal of problematic event prevention
|
||||
|
||||
## Perbaikan yang Dilakukan
|
||||
|
||||
### CustomEditor (`components/editor/custom-editor.js`)
|
||||
|
||||
#### State Management
|
||||
```javascript
|
||||
const [isEditorReady, setIsEditorReady] = useState(false);
|
||||
const [currentContent, setCurrentContent] = useState(props.initialData || "");
|
||||
```
|
||||
|
||||
#### Improved useEffect Structure
|
||||
1. **Editor Initialization**: Handle editor ready state
|
||||
2. **Content Updates**: Watch for initialData changes
|
||||
3. **Initial Data Loading**: Handle data when editor becomes ready
|
||||
|
||||
#### Key Changes
|
||||
- Simplified event handling (removed excessive event prevention)
|
||||
- Better state synchronization between props and internal state
|
||||
- Multiple timing checks to ensure data is set correctly
|
||||
|
||||
### FormEditor (`components/editor/form-editor.js`)
|
||||
|
||||
#### Enhanced Data Handling
|
||||
```javascript
|
||||
// Watch for initialData changes (from setValue)
|
||||
useEffect(() => {
|
||||
if (initialData !== editorContent) {
|
||||
setEditorContent(initialData || "");
|
||||
|
||||
// Update editor content if ready
|
||||
if (editorRef.current && isEditorReady) {
|
||||
editorRef.current.setContent(initialData || "");
|
||||
}
|
||||
}
|
||||
}, [initialData, editorContent, isEditorReady]);
|
||||
```
|
||||
|
||||
#### Features
|
||||
- Robust initial data handling
|
||||
- Proper state synchronization
|
||||
- Better timing management
|
||||
|
||||
### Image Update Form (`components/form/content/image-update-form.tsx`)
|
||||
|
||||
#### Improved setValue Timing
|
||||
```javascript
|
||||
// Set form values immediately and then again after a delay to ensure editor is ready
|
||||
setValue("title", details.title);
|
||||
setValue("description", details.htmlDescription);
|
||||
setValue("creatorName", details.creatorName);
|
||||
|
||||
// Set again after delay to ensure editor has loaded
|
||||
setTimeout(() => {
|
||||
setValue("title", details.title);
|
||||
setValue("description", details.htmlDescription);
|
||||
setValue("creatorName", details.creatorName);
|
||||
}, 500);
|
||||
```
|
||||
|
||||
#### Key Changes
|
||||
- Immediate setValue call for instant feedback
|
||||
- Delayed setValue call to ensure editor is ready
|
||||
- Better dependency management in useEffect
|
||||
|
||||
## Testing
|
||||
|
||||
### Editor Test Component (`components/editor/editor-test.tsx`)
|
||||
- Test both CustomEditor and FormEditor
|
||||
- Test setValue functionality with different content types
|
||||
- Real-time form value monitoring
|
||||
- Multiple test scenarios (empty, HTML, timestamp)
|
||||
|
||||
### Test Scenarios
|
||||
1. **Set Value**: Test basic setValue functionality
|
||||
2. **Set Empty**: Test empty content handling
|
||||
3. **Set HTML**: Test rich HTML content
|
||||
4. **Real-time Typing**: Test onChange functionality
|
||||
5. **Form Submission**: Test complete form workflow
|
||||
|
||||
## Cara Penggunaan
|
||||
|
||||
### Untuk CustomEditor
|
||||
```javascript
|
||||
<Controller
|
||||
control={control}
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<CustomEditor onChange={field.onChange} initialData={field.value} />
|
||||
)}
|
||||
/>
|
||||
```
|
||||
|
||||
### Untuk FormEditor
|
||||
```javascript
|
||||
<Controller
|
||||
control={control}
|
||||
name="description"
|
||||
render={({ field }) => (
|
||||
<FormEditor onChange={field.onChange} initialData={field.value} />
|
||||
)}
|
||||
/>
|
||||
```
|
||||
|
||||
### SetValue Usage
|
||||
```javascript
|
||||
// Immediate setValue
|
||||
setValue("description", "New content");
|
||||
|
||||
// With delay for editor readiness
|
||||
setTimeout(() => {
|
||||
setValue("description", "New content");
|
||||
}, 500);
|
||||
```
|
||||
|
||||
## Rekomendasi
|
||||
|
||||
### 1. **Gunakan FormEditor untuk Form yang Kompleks**
|
||||
- FormEditor lebih robust untuk handling setValue
|
||||
- Better state management
|
||||
- More reliable initial data loading
|
||||
|
||||
### 2. **Timing Considerations**
|
||||
- Always set form values immediately
|
||||
- Use setTimeout for additional setValue calls if needed
|
||||
- Monitor editor ready state
|
||||
|
||||
### 3. **Testing**
|
||||
- Use EditorTest component untuk testing
|
||||
- Test berbagai scenarios sebelum production
|
||||
- Monitor console untuk debugging
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Data Tidak Tampil
|
||||
1. Check if editor is ready (`isEditorReady`)
|
||||
2. Verify setValue timing
|
||||
3. Check initialData prop value
|
||||
4. Use EditorTest untuk debugging
|
||||
|
||||
### Cursor Masih Melompat
|
||||
1. Ensure no excessive event prevention
|
||||
2. Check for conflicting event handlers
|
||||
3. Verify TinyMCE configuration
|
||||
4. Test with simplified content
|
||||
|
||||
### Performance Issues
|
||||
1. Avoid unnecessary re-renders
|
||||
2. Use useCallback for event handlers
|
||||
3. Optimize useEffect dependencies
|
||||
4. Monitor component lifecycle
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Dari CustomEditor Lama
|
||||
1. Update import path
|
||||
2. Verify prop names (onChange, initialData)
|
||||
3. Test setValue functionality
|
||||
4. Monitor for any breaking changes
|
||||
|
||||
### Ke FormEditor
|
||||
1. Replace CustomEditor with FormEditor
|
||||
2. Update any custom configurations
|
||||
3. Test all form scenarios
|
||||
4. Verify data persistence
|
||||
|
||||
## Future Improvements
|
||||
|
||||
1. **Auto-save functionality**
|
||||
2. **Better error handling**
|
||||
3. **Performance optimizations**
|
||||
4. **Enhanced mobile support**
|
||||
5. **Accessibility improvements**
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
# Editor Optimization Summary
|
||||
|
||||
## Masalah yang Dipecahkan
|
||||
Masalah cursor jumping di TinyMCE editor telah berhasil diatasi dengan menggunakan pendekatan minimal yang konsisten.
|
||||
|
||||
## Editor yang Dioptimalkan
|
||||
|
||||
### 1. Minimal Editor ✅ (Working Well)
|
||||
**File:** `components/editor/minimal-editor.js`
|
||||
- **Status:** Berfungsi sangat baik
|
||||
- **Pendekatan:** Minimal, tanpa state management kompleks
|
||||
- **Event Handling:** Hanya menggunakan event 'change'
|
||||
|
||||
### 2. Custom Editor ✅ (Updated)
|
||||
**File:** `components/editor/custom-editor.js`
|
||||
- **Status:** Diperbarui menggunakan pendekatan Minimal Editor
|
||||
- **Perubahan:**
|
||||
- Menghapus state management kompleks
|
||||
- Menghapus debouncing dan recursive updates
|
||||
- Menggunakan event 'change' sederhana
|
||||
- Menghapus `onEditorChange` prop
|
||||
|
||||
### 3. View Editor ✅ (Updated)
|
||||
**File:** `components/editor/view-editor.js`
|
||||
- **Status:** Diperbarui menggunakan pendekatan Minimal Editor
|
||||
- **Perubahan:**
|
||||
- Menghapus `initialValue` dan `disabled` props
|
||||
- Menggunakan `setContent()` untuk set initial data
|
||||
- Menambahkan pengaturan yang sama dengan Minimal Editor
|
||||
- Tetap mempertahankan mode read-only
|
||||
|
||||
## Pendekatan yang Berhasil
|
||||
|
||||
### Kunci Sukses:
|
||||
1. **Tidak menggunakan React state** untuk content management
|
||||
2. **Hanya menggunakan event 'change'** untuk onChange
|
||||
3. **Menggunakan `setContent()`** untuk set initial data
|
||||
4. **Pengaturan TinyMCE yang minimal** dan stabil
|
||||
5. **Tidak ada debouncing atau complex logic**
|
||||
|
||||
### Pengaturan TinyMCE yang Kritis:
|
||||
```javascript
|
||||
init={{
|
||||
// Mencegah cursor jumping
|
||||
auto_focus: false,
|
||||
forced_root_block: 'p',
|
||||
entity_encoding: 'raw',
|
||||
|
||||
// Menonaktifkan fitur bermasalah
|
||||
verify_html: false,
|
||||
cleanup: false,
|
||||
cleanup_on_startup: false,
|
||||
auto_resize: false,
|
||||
|
||||
// Content handling sederhana
|
||||
paste_as_text: false,
|
||||
paste_enable_default_filters: true
|
||||
}}
|
||||
```
|
||||
|
||||
## Struktur Kode yang Konsisten
|
||||
|
||||
### Template untuk Editor Baru:
|
||||
```javascript
|
||||
import React, { useRef } from "react";
|
||||
import { Editor } from "@tinymce/tinymce-react";
|
||||
|
||||
function MyEditor(props) {
|
||||
const editorRef = useRef(null);
|
||||
|
||||
const handleInit = (evt, editor) => {
|
||||
editorRef.current = editor;
|
||||
|
||||
// Set initial content if provided
|
||||
if (props.initialData) {
|
||||
editor.setContent(props.initialData);
|
||||
}
|
||||
|
||||
// Simple onChange handler
|
||||
editor.on('change', () => {
|
||||
if (props.onChange) {
|
||||
props.onChange(editor.getContent());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Editor
|
||||
onInit={handleInit}
|
||||
apiKey={process.env.NEXT_PUBLIC_TINYMCE_API_KEY}
|
||||
init={{
|
||||
// ... pengaturan TinyMCE
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Cara Menggunakan
|
||||
|
||||
### 1. Untuk Editor yang Dapat Diedit:
|
||||
```javascript
|
||||
import CustomEditor from './components/editor/custom-editor';
|
||||
|
||||
<CustomEditor
|
||||
initialData={content}
|
||||
onChange={setContent}
|
||||
/>
|
||||
```
|
||||
|
||||
### 2. Untuk Editor Read-Only:
|
||||
```javascript
|
||||
import ViewEditor from './components/editor/view-editor';
|
||||
|
||||
<ViewEditor
|
||||
initialData={content}
|
||||
/>
|
||||
```
|
||||
|
||||
## Test Component
|
||||
|
||||
Gunakan `components/editor/editor-test.tsx` untuk menguji semua versi editor:
|
||||
- Static Editor
|
||||
- Minimal Editor (Working Well)
|
||||
- Simple Editor
|
||||
- Custom Editor (Updated)
|
||||
- Advanced Editor
|
||||
|
||||
## Kesimpulan
|
||||
|
||||
Semua editor sekarang menggunakan pendekatan yang konsisten dan minimal, yang telah terbukti mengatasi masalah cursor jumping. Pendekatan ini:
|
||||
|
||||
- ✅ Mengatasi cursor jumping
|
||||
- ✅ Konsisten di semua editor
|
||||
- ✅ Mudah dimaintain
|
||||
- ✅ Performa yang baik
|
||||
- ✅ Tidak ada re-render yang tidak perlu
|
||||
|
||||
**Rekomendasi:** Gunakan Custom Editor untuk editing dan View Editor untuk read-only mode.
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
# Form Editor Initial Data Fix
|
||||
|
||||
## Masalah yang Ditemukan
|
||||
|
||||
CustomEditor tidak menampilkan initial data yang diset melalui `setValue` dari react-hook-form karena:
|
||||
|
||||
1. **Timing Issue**: `setValue` dipanggil sebelum editor selesai di-mount
|
||||
2. **Tidak ada state management** untuk initial data di CustomEditor
|
||||
3. **Tidak ada useEffect** untuk watch perubahan props
|
||||
|
||||
## Solusi yang Diterapkan
|
||||
|
||||
### 1. **CustomEditor Diperbaiki** ✅
|
||||
- **Menambahkan:** `useEffect` untuk watch perubahan `initialData` prop
|
||||
- **Menambahkan:** `editorRef.current.setContent()` ketika props berubah
|
||||
- **Mempertahankan:** Pendekatan minimal yang sudah bekerja
|
||||
|
||||
### 2. **FormEditor Dibuat** ✅ (New)
|
||||
- **File baru:** `components/editor/form-editor.js`
|
||||
- **Fitur:** State management untuk initial data
|
||||
- **Fitur:** Watch perubahan props dengan lebih baik
|
||||
- **Fitur:** Editor ready state management
|
||||
|
||||
### 3. **Form Diperbarui** ✅
|
||||
- **Menggunakan:** FormEditor sebagai pengganti CustomEditor
|
||||
- **Import:** Dynamic import untuk FormEditor
|
||||
- **Mempertahankan:** Interface yang sama
|
||||
|
||||
## Kode yang Diperbaiki
|
||||
|
||||
### CustomEditor (Diperbaiki):
|
||||
```javascript
|
||||
// Watch for changes in initialData prop and update editor content
|
||||
useEffect(() => {
|
||||
if (editorRef.current && props.initialData) {
|
||||
editorRef.current.setContent(props.initialData);
|
||||
}
|
||||
}, [props.initialData]);
|
||||
```
|
||||
|
||||
### FormEditor (Baru):
|
||||
```javascript
|
||||
const [isEditorReady, setIsEditorReady] = useState(false);
|
||||
const [initialData, setInitialData] = useState(props.initialData || '');
|
||||
|
||||
// Watch for changes in initialData prop
|
||||
useEffect(() => {
|
||||
if (props.initialData !== initialData) {
|
||||
setInitialData(props.initialData || '');
|
||||
|
||||
// Update editor content if editor is ready
|
||||
if (isEditorReady && editorRef.current) {
|
||||
editorRef.current.setContent(props.initialData || '');
|
||||
}
|
||||
}
|
||||
}, [props.initialData, initialData, isEditorReady]);
|
||||
```
|
||||
|
||||
### Form Update:
|
||||
```javascript
|
||||
const CustomEditor = dynamic(
|
||||
() => {
|
||||
return import("@/components/editor/form-editor");
|
||||
},
|
||||
{ ssr: false }
|
||||
);
|
||||
```
|
||||
|
||||
## Cara Kerja Solusi
|
||||
|
||||
### 1. **Timing Management**:
|
||||
- FormEditor menggunakan state `isEditorReady` untuk memastikan editor sudah siap
|
||||
- `useEffect` hanya update content ketika editor sudah ready
|
||||
|
||||
### 2. **Props Watching**:
|
||||
- `useEffect` watch perubahan `props.initialData`
|
||||
- Ketika props berubah, update internal state dan editor content
|
||||
|
||||
### 3. **State Management**:
|
||||
- Internal state `initialData` untuk tracking perubahan
|
||||
- Mencegah infinite loop dengan comparison
|
||||
|
||||
## Keunggulan FormEditor
|
||||
|
||||
1. **Better Initial Data Handling** - Menangani setValue dengan benar
|
||||
2. **State Management** - Internal state untuk tracking
|
||||
3. **Ready State** - Memastikan editor sudah siap sebelum update
|
||||
4. **Props Watching** - Watch perubahan props secara efektif
|
||||
5. **No Cursor Jumping** - Menggunakan pendekatan minimal yang sudah bekerja
|
||||
|
||||
## Cara Menggunakan
|
||||
|
||||
### Di Form:
|
||||
```javascript
|
||||
<Controller
|
||||
control={control}
|
||||
name="description"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<CustomEditor onChange={onChange} initialData={value} />
|
||||
)}
|
||||
/>
|
||||
```
|
||||
|
||||
### setValue akan bekerja:
|
||||
```javascript
|
||||
setValue("description", details.htmlDescription);
|
||||
```
|
||||
|
||||
## Kesimpulan
|
||||
|
||||
Masalah initial data di form sudah diperbaiki dengan:
|
||||
- CustomEditor yang diperbaiki dengan useEffect
|
||||
- FormEditor baru yang lebih robust
|
||||
- Form yang menggunakan FormEditor
|
||||
|
||||
Sekarang `setValue` akan bekerja dengan benar dan initial data akan ditampilkan di editor!
|
||||
2028
pnpm-lock.yaml
2028
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue