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