import { html, css, type TemplateResult } from '@design.estate/dees-element'; import '@design.estate/dees-wcctools/demotools'; import type { DeesInputWysiwyg } from './dees-input-wysiwyg.js'; import type { IBlock } from './wysiwyg/wysiwyg.types.js'; interface IDemoEditor { basic: DeesInputWysiwyg; article: DeesInputWysiwyg; dragDrop: DeesInputWysiwyg; tutorial: DeesInputWysiwyg; meeting: DeesInputWysiwyg; recipe: DeesInputWysiwyg; technical: DeesInputWysiwyg; formIntegration: DeesInputWysiwyg; programmatic: DeesInputWysiwyg; exportDemo: DeesInputWysiwyg; } // Sample content generators const generateReportBlocks = (): IBlock[] => { const timestamp = Date.now(); return [ { id: `title-${timestamp}`, type: 'heading-1', content: 'System Performance Report' }, { id: `date-${timestamp + 1}`, type: 'paragraph', content: `Generated on: ${new Date().toLocaleString()}` }, { id: `summary-heading-${timestamp + 2}`, type: 'heading-2', content: 'Executive Summary' }, { id: `summary-${timestamp + 3}`, type: 'paragraph', content: 'This report provides an analysis of system performance metrics over the last 30 days.' }, { id: `metrics-heading-${timestamp + 4}`, type: 'heading-2', content: 'Key Metrics' }, { id: `metrics-list-${timestamp + 5}`, type: 'list', content: 'Average response time: 124ms\nUptime: 99.97%\nCPU utilization: 45%\nMemory usage: 2.3GB / 8GB', metadata: { listType: 'bullet' } }, { id: `analysis-heading-${timestamp + 6}`, type: 'heading-2', content: 'Performance Analysis' }, { id: `analysis-quote-${timestamp + 7}`, type: 'quote', content: 'System performance remains within acceptable parameters with room for optimization in memory management.' }, { id: `code-heading-${timestamp + 8}`, type: 'heading-3', content: 'Sample Query Performance' }, { id: `code-block-${timestamp + 9}`, type: 'code', content: 'SELECT AVG(response_time) as avg_time,\n COUNT(*) as total_requests,\n DATE(created_at) as date\nFROM performance_logs\nWHERE created_at >= NOW() - INTERVAL 30 DAY\nGROUP BY DATE(created_at)\nORDER BY date DESC;', metadata: { language: 'sql' } }, { id: `divider-${timestamp + 10}`, type: 'divider', content: '' }, { id: `footer-${timestamp + 11}`, type: 'paragraph', content: 'Report generated automatically by System Monitor v2.5.0' } ]; }; const generateRecipeBlocks = (): IBlock[] => { const timestamp = Date.now(); return [ { id: `recipe-title-${timestamp}`, type: 'heading-1', content: 'Classic Margherita Pizza' }, { id: `recipe-intro-${timestamp + 1}`, type: 'paragraph', content: 'A traditional Italian pizza with fresh basil, mozzarella, and tomato sauce.' }, { id: `ingredients-heading-${timestamp + 2}`, type: 'heading-2', content: '🍕 Ingredients' }, { id: `dough-heading-${timestamp + 3}`, type: 'heading-3', content: 'For the Dough:' }, { id: `dough-list-${timestamp + 4}`, type: 'list', content: '500g tipo "00" flour\n325ml warm water\n10g salt\n7g active dry yeast\n2 tbsp olive oil', metadata: { listType: 'bullet' } }, { id: `toppings-heading-${timestamp + 5}`, type: 'heading-3', content: 'For the Toppings:' }, { id: `toppings-list-${timestamp + 6}`, type: 'list', content: '400g canned San Marzano tomatoes\n250g fresh mozzarella\nFresh basil leaves\nExtra virgin olive oil\nSalt and pepper to taste', metadata: { listType: 'bullet' } }, { id: `instructions-heading-${timestamp + 7}`, type: 'heading-2', content: '👨‍🍳 Instructions' }, { id: `steps-list-${timestamp + 8}`, type: 'list', content: 'Dissolve yeast in warm water and let stand for 5 minutes\nMix flour and salt, create a well in center\nAdd yeast mixture and olive oil\nKnead for 10 minutes until smooth\nLet rise for 1-2 hours until doubled\nPunch down and divide into portions\nRoll out each portion to 12-inch circles\nTop with crushed tomatoes, mozzarella, and basil\nBake at 475°F (245°C) for 10-12 minutes', metadata: { listType: 'ordered' } }, { id: `tip-${timestamp + 9}`, type: 'quote', content: 'Pro tip: For an authentic taste, use a pizza stone and preheat it in the oven for at least 30 minutes before baking.' }, { id: `divider-${timestamp + 10}`, type: 'divider', content: '' }, { id: `servings-${timestamp + 11}`, type: 'paragraph', content: 'Servings: 4 pizzas | Prep time: 2 hours | Cook time: 12 minutes' } ]; }; const initializeEditors = (container: HTMLElement): IDemoEditor => { const editors: Partial = {}; // Get all editor references editors.basic = container.querySelector('#editor-basic') as DeesInputWysiwyg; editors.article = container.querySelector('#editor-article') as DeesInputWysiwyg; editors.dragDrop = container.querySelector('#editor-dragdrop') as DeesInputWysiwyg; editors.tutorial = container.querySelector('#editor-tutorial') as DeesInputWysiwyg; editors.meeting = container.querySelector('#editor-meeting') as DeesInputWysiwyg; editors.recipe = container.querySelector('#editor-recipe') as DeesInputWysiwyg; editors.technical = container.querySelector('#editor-technical') as DeesInputWysiwyg; editors.formIntegration = container.querySelector('#editor-form-integration') as DeesInputWysiwyg; editors.programmatic = container.querySelector('#editor-programmatic') as DeesInputWysiwyg; editors.exportDemo = container.querySelector('#editor-export') as DeesInputWysiwyg; return editors as IDemoEditor; }; const setupProgrammaticDemo = (container: HTMLElement, editor: DeesInputWysiwyg) => { const reportBtn = container.querySelector('#btn-generate-report') as HTMLButtonElement; const recipeBtn = container.querySelector('#btn-generate-recipe') as HTMLButtonElement; const clearBtn = container.querySelector('#btn-clear-editor') as HTMLButtonElement; if (reportBtn) { reportBtn.addEventListener('click', () => { editor.importBlocks(generateReportBlocks()); }); } if (recipeBtn) { recipeBtn.addEventListener('click', () => { editor.importBlocks(generateRecipeBlocks()); }); } if (clearBtn) { clearBtn.addEventListener('click', () => { editor.importBlocks([]); }); } }; const setupExportDemo = (container: HTMLElement, editor: DeesInputWysiwyg) => { const exportBlocksBtn = container.querySelector('#btn-export-blocks') as HTMLButtonElement; const exportHtmlBtn = container.querySelector('#btn-export-html') as HTMLButtonElement; const exportMarkdownBtn = container.querySelector('#btn-export-markdown') as HTMLButtonElement; const saveStateBtn = container.querySelector('#btn-save-state') as HTMLButtonElement; const restoreStateBtn = container.querySelector('#btn-restore-state') as HTMLButtonElement; let savedState: any = null; if (exportBlocksBtn) { exportBlocksBtn.addEventListener('click', () => { const blocks = editor.exportBlocks(); console.log('Exported blocks:', blocks); alert(`Exported ${blocks.length} blocks to console. Check developer tools.`); }); } if (exportHtmlBtn) { exportHtmlBtn.addEventListener('click', () => { const html = editor.exportAsHtml(); console.log('HTML Export:', html); alert('HTML exported to console. Check developer tools.'); }); } if (exportMarkdownBtn) { exportMarkdownBtn.addEventListener('click', () => { const markdown = editor.exportAsMarkdown(); console.log('Markdown Export:', markdown); alert('Markdown exported to console. Check developer tools.'); }); } if (saveStateBtn) { saveStateBtn.addEventListener('click', () => { savedState = editor.exportState(); console.log('Saved state:', savedState); alert('Editor state saved!'); }); } if (restoreStateBtn) { restoreStateBtn.addEventListener('click', () => { if (savedState) { editor.importState(savedState); alert('Editor state restored!'); } else { alert('No saved state found. Save state first!'); } }); } }; const populateInitialContent = (editors: IDemoEditor) => { // Article editor content if (editors.article) { setTimeout(() => { const articleBlocks: IBlock[] = [ { id: 'intro-heading-' + Date.now(), type: 'heading-2', content: 'Introduction to Modern Web Development' }, { id: 'intro-para-' + Date.now(), type: 'paragraph', content: 'Modern web development has evolved significantly over the past decade. In this article, we\'ll explore the key technologies and best practices that define web development in 2024.' }, { id: 'tech-heading-' + Date.now(), type: 'heading-3', content: 'Key Technologies' }, { id: 'tech-list-' + Date.now(), type: 'list', content: 'TypeScript - Type-safe JavaScript development\nWeb Components - Native component model\nES Modules - Modern module system\nWebAssembly - High-performance computing', metadata: { listType: 'ordered' } }, { id: 'quote-' + Date.now(), type: 'quote', content: 'The best way to predict the future is to invent it. - Alan Kay' }, { id: 'example-heading-' + Date.now(), type: 'heading-3', content: 'Code Example' }, { id: 'code-example-' + Date.now(), type: 'code', content: 'class ModernWebApp extends HTMLElement {\n constructor() {\n super();\n this.attachShadow({ mode: \'open\' });\n }\n \n connectedCallback() {\n this.render();\n }\n}', metadata: { language: 'javascript' } } ]; editors.article.importBlocks(articleBlocks); }, 500); } // Drag & Drop demo content if (editors.dragDrop) { setTimeout(() => { const dragBlocks: IBlock[] = [ { id: 'drag-title-' + Date.now(), type: 'heading-1', content: 'Drag & Drop Demo' }, { id: 'drag-intro-' + Date.now(), type: 'paragraph', content: 'This editor demonstrates drag and drop functionality. Try dragging these blocks around!' }, { id: 'drag-heading-' + Date.now(), type: 'heading-2', content: 'How It Works' }, { id: 'drag-list-' + Date.now(), type: 'list', content: 'Hover over any block to see the drag handle\nClick and hold the handle to start dragging\nDrag to reorder blocks\nRelease to drop in the new position', metadata: { listType: 'ordered' } }, { id: 'drag-quote-' + Date.now(), type: 'quote', content: 'The drag and drop feature makes it easy to reorganize your content without cutting and pasting.' }, { id: 'drag-divider-' + Date.now(), type: 'divider', content: '' }, { id: 'drag-footer-' + Date.now(), type: 'paragraph', content: 'Note: Divider blocks cannot be dragged, but other blocks can be moved around them.' } ]; editors.dragDrop.importBlocks(dragBlocks); }, 600); } }; export const demoFunc = (): TemplateResult => html` { // Wait for elements to be ready await new Promise(resolve => setTimeout(resolve, 500)); const editors = initializeEditors(elementArg); // Setup programmatic demo if (editors.programmatic) { setupProgrammaticDemo(elementArg, editors.programmatic); } // Setup export demo if (editors.exportDemo) { setupExportDemo(elementArg, editors.exportDemo); } // Populate initial content populateInitialContent(editors); // Log initialization console.log('WYSIWYG Demo initialized with editors:', Object.keys(editors)); }}>

A powerful block-based editor with slash commands, keyboard shortcuts, and multiple output formats. Perfect for content creation, blog posts, documentation, and more.

Slash commands (/)
Keyboard shortcuts
Block-based editing
Drag & drop reordering
HTML & Markdown output
Dark mode support
Mobile responsive

⌨️ Keyboard Shortcuts

/ Slash commands
# Heading 1
## Heading 2
### Heading 3
> Quote
\`\`\` Code block
* or - Bullet list
1. Numbered list
--- Divider

Perfect for creating rich content with multiple block types. The editor preserves formatting and provides a clean editing experience.

Easily rearrange your content blocks by dragging them. Hover over any block to reveal the drag handle on the left side.

💡 Tips:
  • Hover over any block to see the drag handle (⋮⋮) on the left
  • Click and hold the drag handle to start dragging
  • Blue indicators show where the block will be dropped
  • Divider blocks cannot be dragged
  • The editor maintains focus on the moved block after dropping

Create comprehensive tutorials and documentation with code examples, lists, and structured content.

Choose between HTML and Markdown output formats depending on your needs. Perfect for static site generators, documentation systems, or any content management workflow.

Create complex documents with mixed content types. The editor handles all formatting seamlessly.

Seamlessly integrates with dees-form for complete form solutions. All standard form features like validation, required fields, and data binding work out of the box.

Create content programmatically using the block API for dynamic document generation.

The WYSIWYG editor provides multiple export formats and lossless save/restore capabilities for maximum flexibility.

Lossless Blocks

Export and import raw block structure for perfect round-trip editing

HTML Export

Get clean, semantic HTML regardless of output format setting

Markdown Export

Export as Markdown for docs, READMEs, and static sites

State Management

Save and restore complete editor state including settings

`;