- `
- }))
- };
-};
-
-function getDeviceClass(): string {
- const width = window.innerWidth;
- if (width < 768) return 'mobile';
- if (width < 1024) return 'tablet';
- return 'desktop';
-}
-```
-
-### 5. Performance Optimization
-
-```typescript
-// optimization/lazy-components.ts
-export const lazyComponent = (
- importFn: () => Promise,
- componentName: string
-) => {
- let loaded = false;
-
- return () => {
- if (!loaded) {
- importFn().then(() => {
- loaded = true;
- });
- return html``;
- }
-
- return html`<${componentName}>${componentName}>`;
- };
-};
-
-// Usage in view
-tabs: [
- {
- key: 'heavy-component',
- content: lazyComponent(
- () => import('./components/heavy-component.js'),
- 'heavy-component'
- )
- }
-]
-```
-
-## Advanced Features
-
-### 1. View Permissions
-
-```typescript
-interface IAppViewWithPermissions extends IAppView {
- requiredPermissions?: string[];
- visibleTo?: (user: User) => boolean;
-}
-
-class PermissionManager {
- canAccessView(view: IAppViewWithPermissions, user: User): boolean {
- if (view.visibleTo) {
- return view.visibleTo(user);
- }
-
- if (view.requiredPermissions) {
- return view.requiredPermissions.every(
- perm => user.permissions.includes(perm)
- );
- }
-
- return true;
- }
-}
-```
-
-### 2. View Lifecycle Hooks
-
-```typescript
-interface IAppViewLifecycle extends IAppView {
- onActivate?: () => Promise;
- onDeactivate?: () => Promise;
- onTabChange?: (oldTab: string, newTab: string) => void;
- onDestroy?: () => void;
-}
-```
-
-### 3. Dynamic Menu Generation
-
-```typescript
-class DynamicMenuBuilder {
- buildMainMenu(views: IAppView[], user: User): ITab[] {
- return views
- .filter(view => this.canShowInMenu(view, user))
- .map(view => ({
- key: view.id,
- iconName: view.iconName || 'file',
- action: () => this.navigation.navigateToView(view.id)
- }));
- }
-
- buildSelectorMenu(view: IAppView, context: any): ISelectionOption[] {
- const baseItems = view.menuItems || [];
- const contextItems = this.getContextualItems(view, context);
-
- return [...baseItems, ...contextItems];
- }
-}
-```
-
-## Migration Strategy
-
-For existing applications:
-
-1. **Identify Views**: Map existing routes/pages to views
-2. **Extract Components**: Move page-specific components into view folders
-3. **Define View Configs**: Create IAppView configurations
-4. **Update Navigation**: Replace existing routing with view navigation
-5. **Migrate State**: Move page state to ViewManager
-6. **Test & Optimize**: Ensure smooth transitions and performance
-
-## Example Application Structure
-
-```typescript
-// main.ts
-import { ViewManager } from './services/view-manager.js';
-import { AppNavigation } from './services/navigation.js';
-import { dashboardView } from './views/dashboard/index.js';
-import { projectsView } from './views/projects/index.js';
-import { settingsView } from './views/settings/index.js';
-
-const app = new MyAppShell();
-const viewManager = new ViewManager();
-const navigation = new AppNavigation(viewManager, app);
-
-// Register views
-viewManager.registerView(dashboardView);
-viewManager.registerView(projectsView);
-viewManager.registerView(settingsView);
-
-// Setup navigation
-app.views = [dashboardView, projectsView, settingsView];
-navigation.setupMainMenu();
-navigation.handleBrowserNavigation();
-
-// Initial navigation
-navigation.navigateToView('dashboard');
-
-document.body.appendChild(app);
-```
-
-This architecture provides:
-- **Modularity**: Each view is self-contained
-- **Scalability**: Easy to add new views
-- **Performance**: Lazy loading and caching
-- **Consistency**: Unified navigation and layout
-- **Flexibility**: Customizable per view
-- **Maintainability**: Clear separation of concerns
\ No newline at end of file
diff --git a/readme.md b/readme.md
index f7eda81..cc833a6 100644
--- a/readme.md
+++ b/readme.md
@@ -1,6 +1,9 @@
# @design.estate/dees-catalog
A comprehensive web components library built with TypeScript and LitElement, providing 75+ UI components for building modern web applications with consistent design and behavior.
+## Development Guide
+For developers working on this library, please refer to the [UI Components Playbook](readme.playbook.md) for comprehensive patterns, best practices, and architectural guidelines.
+
## Install
To install the `@design.estate/dees-catalog` library, you can use npm or any other compatible JavaScript package manager:
diff --git a/readme.playbook.md b/readme.playbook.md
new file mode 100644
index 0000000..0d4cd47
--- /dev/null
+++ b/readme.playbook.md
@@ -0,0 +1,784 @@
+# UI Components Playbook
+
+This playbook provides comprehensive guidance for creating and maintaining UI components in the @design.estate/dees-catalog library. Follow these patterns and best practices to ensure consistency, maintainability, and quality.
+
+## Table of Contents
+
+1. [Component Creation Checklist](#component-creation-checklist)
+2. [Architectural Patterns](#architectural-patterns)
+3. [Component Types and Base Classes](#component-types-and-base-classes)
+4. [Theming System](#theming-system)
+5. [Event Handling](#event-handling)
+6. [State Management](#state-management)
+7. [Form Components](#form-components)
+8. [Overlay Components](#overlay-components)
+9. [Complex Components](#complex-components)
+10. [Performance Optimization](#performance-optimization)
+11. [Focus Management](#focus-management)
+12. [Demo System](#demo-system)
+13. [Common Pitfalls and Anti-patterns](#common-pitfalls-and-anti-patterns)
+14. [Code Examples](#code-examples)
+
+## Component Creation Checklist
+
+When creating a new component, follow this checklist:
+
+- [ ] Choose the appropriate base class (`DeesElement` or `DeesInputBase`)
+- [ ] Use `@customElement('dees-componentname')` decorator
+- [ ] Implement consistent theming with `cssManager.bdTheme()`
+- [ ] Create demo function in separate `.demo.ts` file
+- [ ] Export component from `ts_web/elements/index.ts`
+- [ ] Use proper TypeScript types and interfaces (prefix with `I` for interfaces, `T` for types)
+- [ ] Implement proper event handling with bubbling and composition
+- [ ] Consider mobile responsiveness
+- [ ] Add focus states for accessibility
+- [ ] Clean up resources in `destroy()` method
+- [ ] Follow lowercase naming convention for files
+- [ ] Add z-index registry support if it's an overlay component
+
+## Architectural Patterns
+
+### Base Component Structure
+
+```typescript
+import { customElement, property, state, css, TemplateResult, html } from '@design.estate/dees-element';
+import { DeesElement } from '@design.estate/dees-element';
+import * as cssManager from './00colors.js';
+import * as demoFunc from './dees-componentname.demo.js';
+
+@customElement('dees-componentname')
+export class DeesComponentName extends DeesElement {
+ // Static demo reference
+ public static demo = demoFunc.demoFunc;
+
+ // Public properties (reactive, can be set via attributes)
+ @property({ type: String })
+ public label: string = '';
+
+ @property({ type: Boolean, reflect: true })
+ public disabled: boolean = false;
+
+ // Internal state (reactive, but not exposed as attributes)
+ @state()
+ private internalState: string = '';
+
+ // Static styles with theme support
+ public static styles = [
+ cssManager.defaultStyles,
+ css`
+ :host {
+ display: block;
+ background: ${cssManager.bdTheme('#ffffff', '#09090b')};
+ }
+ `
+ ];
+
+ // Render method
+ public render(): TemplateResult {
+ return html`
+
+
+
+ `;
+ }
+
+ // Lifecycle methods
+ public connectedCallback() {
+ super.connectedCallback();
+ // Setup that needs DOM access
+ }
+
+ public async firstUpdated() {
+ // One-time initialization after first render
+ }
+
+ // Cleanup
+ public destroy() {
+ // Clean up listeners, observers, registrations
+ super.destroy();
+ }
+}
+```
+
+### Advanced Patterns
+
+#### 1. Separation of Concerns (Complex Components)
+
+For complex components like WYSIWYG editors, separate concerns into handler classes:
+
+```typescript
+export class DeesComplexComponent extends DeesElement {
+ // Orchestrator pattern - main component coordinates handlers
+ private inputHandler: InputHandler;
+ private stateHandler: StateHandler;
+ private renderHandler: RenderHandler;
+
+ constructor() {
+ super();
+ this.inputHandler = new InputHandler(this);
+ this.stateHandler = new StateHandler(this);
+ this.renderHandler = new RenderHandler(this);
+ }
+}
+```
+
+#### 2. Singleton Pattern (Global Components)
+
+For global UI elements like menus:
+
+```typescript
+export class DeesGlobalMenu extends DeesElement {
+ private static instance: DeesGlobalMenu;
+
+ public static getInstance(): DeesGlobalMenu {
+ if (!DeesGlobalMenu.instance) {
+ DeesGlobalMenu.instance = new DeesGlobalMenu();
+ document.body.appendChild(DeesGlobalMenu.instance);
+ }
+ return DeesGlobalMenu.instance;
+ }
+}
+```
+
+#### 3. Registry Pattern (Z-Index Management)
+
+Use centralized registries for global state:
+
+```typescript
+class ComponentRegistry {
+ private static instance: ComponentRegistry;
+ private registry = new WeakMap();
+
+ public register(element: HTMLElement, value: number) {
+ this.registry.set(element, value);
+ }
+
+ public unregister(element: HTMLElement) {
+ this.registry.delete(element);
+ }
+}
+```
+
+## Component Types and Base Classes
+
+### Standard Component (extends DeesElement)
+
+Use for most UI components:
+- Buttons, badges, icons
+- Layout components
+- Data display components
+- Overlay components
+
+### Form Input Component (extends DeesInputBase)
+
+Use for all form inputs:
+- Text inputs, dropdowns, checkboxes
+- Date pickers, file uploads
+- Rich text editors
+
+**Required implementations:**
+```typescript
+export class DeesInputCustom extends DeesInputBase {
+ // Required: Get current value
+ public getValue(): ValueType {
+ return this.value;
+ }
+
+ // Required: Set value programmatically
+ public setValue(value: ValueType): void {
+ this.value = value;
+ this.changeSubject.next(this); // Notify form
+ }
+
+ // Optional: Custom validation
+ public async validate(): Promise {
+ // Custom validation logic
+ return true;
+ }
+}
+```
+
+## Theming System
+
+### DO: Use Theme Functions
+
+Always use `cssManager.bdTheme()` for colors that change between themes:
+
+```typescript
+// ✅ CORRECT
+background: ${cssManager.bdTheme('#ffffff', '#09090b')};
+color: ${cssManager.bdTheme('#000000', '#ffffff')};
+border: 1px solid ${cssManager.bdTheme('#e5e5e5', '#333333')};
+
+// ❌ INCORRECT
+background: #ffffff; // Hard-coded color
+color: var(--custom-color); // Custom CSS variable
+```
+
+### DO: Use Consistent Color Values
+
+Reference shared color constants when possible:
+
+```typescript
+// From 00colors.ts
+background: ${cssManager.bdTheme(colors.bright.background, colors.dark.background)};
+```
+
+## Event Handling
+
+### DO: Dispatch Custom Events Properly
+
+```typescript
+// ✅ CORRECT - Events bubble and cross shadow DOM
+this.dispatchEvent(new CustomEvent('dees-componentname-change', {
+ detail: { value: this.value },
+ bubbles: true,
+ composed: true
+}));
+
+// ❌ INCORRECT - Event won't propagate properly
+this.dispatchEvent(new CustomEvent('change', {
+ detail: { value: this.value }
+ // Missing bubbles and composed
+}));
+```
+
+### DO: Use Event Delegation
+
+For dynamic content, use event delegation:
+
+```typescript
+// ✅ CORRECT - Single listener for all items
+this.addEventListener('click', (e: MouseEvent) => {
+ const item = (e.target as HTMLElement).closest('.item');
+ if (item) {
+ this.handleItemClick(item);
+ }
+});
+
+// ❌ INCORRECT - Multiple listeners
+this.items.forEach(item => {
+ item.addEventListener('click', () => this.handleItemClick(item));
+});
+```
+
+## State Management
+
+### DO: Use Appropriate Property Decorators
+
+```typescript
+// Public API - use @property
+@property({ type: String })
+public label: string;
+
+// Internal state - use @state
+@state()
+private isLoading: boolean = false;
+
+// Reflect to attribute when needed
+@property({ type: Boolean, reflect: true })
+public disabled: boolean = false;
+```
+
+### DON'T: Manipulate State in Render
+
+```typescript
+// ❌ INCORRECT - Side effects in render
+public render() {
+ this.counter++; // Don't modify state
+ return html`
${this.counter}
`;
+}
+
+// ✅ CORRECT - Pure render function
+public render() {
+ return html`
${this.counter}
`;
+}
+```
+
+## Form Components
+
+### DO: Extend DeesInputBase
+
+All form inputs must extend the base class:
+
+```typescript
+export class DeesInputNew extends DeesInputBase {
+ // Inherits: key, label, value, required, disabled, validationState
+}
+```
+
+### DO: Emit Changes Consistently
+
+```typescript
+private handleInput(e: Event) {
+ this.value = (e.target as HTMLInputElement).value;
+ this.changeSubject.next(this); // Notify form system
+}
+```
+
+### DO: Support Standard Form Properties
+
+```typescript
+// All form inputs should support:
+@property() public key: string;
+@property() public label: string;
+@property() public required: boolean = false;
+@property() public disabled: boolean = false;
+@property() public validationState: 'valid' | 'warn' | 'invalid';
+```
+
+## Overlay Components
+
+### DO: Use Z-Index Registry
+
+Never hardcode z-index values:
+
+```typescript
+// ✅ CORRECT
+import { zIndexRegistry } from './00zindex.js';
+
+public async show() {
+ this.modalZIndex = zIndexRegistry.getNextZIndex();
+ zIndexRegistry.register(this, this.modalZIndex);
+ this.style.zIndex = `${this.modalZIndex}`;
+}
+
+public async hide() {
+ zIndexRegistry.unregister(this);
+}
+
+// ❌ INCORRECT
+public async show() {
+ this.style.zIndex = '9999'; // Hardcoded z-index
+}
+```
+
+### DO: Use Window Layers
+
+For modal backdrops:
+
+```typescript
+import { DeesWindowLayer } from './dees-windowlayer.js';
+
+private windowLayer: DeesWindowLayer;
+
+public async show() {
+ this.windowLayer = new DeesWindowLayer();
+ this.windowLayer.zIndex = zIndexRegistry.getNextZIndex();
+ document.body.append(this.windowLayer);
+}
+```
+
+## Complex Components
+
+### DO: Use Handler Classes
+
+For complex logic, separate into specialized handlers:
+
+```typescript
+// wysiwyg/handlers/input.handler.ts
+export class InputHandler {
+ constructor(private component: DeesInputWysiwyg) {}
+
+ public handleInput(event: InputEvent) {
+ // Specialized input handling
+ }
+}
+
+// Main component orchestrates
+export class DeesInputWysiwyg extends DeesInputBase {
+ private inputHandler = new InputHandler(this);
+}
+```
+
+### DO: Use Programmatic Rendering
+
+For performance-critical updates that shouldn't trigger re-renders:
+
+```typescript
+// ✅ CORRECT - Direct DOM manipulation when needed
+private updateBlockContent(blockId: string, content: string) {
+ const blockElement = this.shadowRoot.querySelector(`#${blockId}`);
+ if (blockElement) {
+ blockElement.textContent = content; // Direct update
+ }
+}
+
+// ❌ INCORRECT - Triggering full re-render
+private updateBlockContent(blockId: string, content: string) {
+ this.blocks.find(b => b.id === blockId).content = content;
+ this.requestUpdate(); // Unnecessary re-render
+}
+```
+
+## Performance Optimization
+
+### DO: Debounce Expensive Operations
+
+```typescript
+private resizeTimeout: number;
+
+private handleResize = () => {
+ clearTimeout(this.resizeTimeout);
+ this.resizeTimeout = window.setTimeout(() => {
+ this.updateLayout();
+ }, 250);
+};
+```
+
+### DO: Use Observers Efficiently
+
+```typescript
+// Clean up observers
+public disconnectedCallback() {
+ super.disconnectedCallback();
+ this.resizeObserver?.disconnect();
+ this.mutationObserver?.disconnect();
+}
+```
+
+### DO: Implement Virtual Scrolling
+
+For large lists:
+
+```typescript
+// Only render visible items
+private getVisibleItems() {
+ const scrollTop = this.scrollContainer.scrollTop;
+ const containerHeight = this.scrollContainer.clientHeight;
+ const itemHeight = 50;
+
+ const startIndex = Math.floor(scrollTop / itemHeight);
+ const endIndex = Math.ceil((scrollTop + containerHeight) / itemHeight);
+
+ return this.items.slice(startIndex, endIndex);
+}
+```
+
+## Focus Management
+
+### DO: Handle Focus Timing
+
+```typescript
+// ✅ CORRECT - Wait for render
+async focusInput() {
+ await this.updateComplete;
+ await new Promise(resolve => requestAnimationFrame(resolve));
+ this.inputElement?.focus();
+}
+
+// ❌ INCORRECT - Focus too early
+focusInput() {
+ this.inputElement?.focus(); // Element might not exist
+}
+```
+
+### DO: Prevent Focus Loss
+
+```typescript
+// For global menus
+constructor() {
+ super();
+ // Prevent focus loss when clicking menu
+ this.addEventListener('mousedown', (e) => {
+ e.preventDefault();
+ });
+}
+```
+
+### DO: Implement Blur Debouncing
+
+```typescript
+private blurTimeout: number;
+
+private handleBlur = () => {
+ clearTimeout(this.blurTimeout);
+ this.blurTimeout = window.setTimeout(() => {
+ // Check if truly blurred
+ if (!this.contains(document.activeElement)) {
+ this.handleTrueBlur();
+ }
+ }, 100);
+};
+```
+
+## Demo System
+
+### DO: Create Comprehensive Demos
+
+Every component needs a demo:
+
+```typescript
+// dees-button.demo.ts
+import { html } from '@design.estate/dees-element';
+
+export const demoFunc = () => html`
+ Default Button
+ Primary Button
+ Disabled Danger
+`;
+
+// In component file
+import * as demoFunc from './dees-button.demo.js';
+
+export class DeesButton extends DeesElement {
+ public static demo = demoFunc.demoFunc;
+}
+```
+
+### DO: Include All Variants
+
+Show all component states and variations in demos:
+- Default state
+- Different types/variants
+- Disabled state
+- Loading state
+- Error states
+- Edge cases (long text, empty content)
+
+## Common Pitfalls and Anti-patterns
+
+### ❌ DON'T: Hardcode Z-Index Values
+
+```typescript
+// ❌ WRONG
+this.style.zIndex = '9999';
+
+// ✅ CORRECT
+this.style.zIndex = `${zIndexRegistry.getNextZIndex()}`;
+```
+
+### ❌ DON'T: Skip Base Classes
+
+```typescript
+// ❌ WRONG - Form input without base class
+export class DeesInputCustom extends DeesElement {
+ // Missing standard form functionality
+}
+
+// ✅ CORRECT
+export class DeesInputCustom extends DeesInputBase {
+ // Inherits all form functionality
+}
+```
+
+### ❌ DON'T: Forget Theme Support
+
+```typescript
+// ❌ WRONG
+background-color: #ffffff;
+color: #000000;
+
+// ✅ CORRECT
+background-color: ${cssManager.bdTheme('#ffffff', '#09090b')};
+color: ${cssManager.bdTheme('#000000', '#ffffff')};
+```
+
+### ❌ DON'T: Create Components Without Demos
+
+```typescript
+// ❌ WRONG
+export class DeesComponent extends DeesElement {
+ // No demo property
+}
+
+// ✅ CORRECT
+export class DeesComponent extends DeesElement {
+ public static demo = demoFunc.demoFunc;
+}
+```
+
+### ❌ DON'T: Emit Non-Bubbling Events
+
+```typescript
+// ❌ WRONG
+this.dispatchEvent(new CustomEvent('change', {
+ detail: this.value
+}));
+
+// ✅ CORRECT
+this.dispatchEvent(new CustomEvent('change', {
+ detail: this.value,
+ bubbles: true,
+ composed: true
+}));
+```
+
+### ❌ DON'T: Skip Cleanup
+
+```typescript
+// ❌ WRONG
+public connectedCallback() {
+ window.addEventListener('resize', this.handleResize);
+}
+
+// ✅ CORRECT
+public connectedCallback() {
+ super.connectedCallback();
+ window.addEventListener('resize', this.handleResize);
+}
+
+public disconnectedCallback() {
+ super.disconnectedCallback();
+ window.removeEventListener('resize', this.handleResize);
+}
+```
+
+### ❌ DON'T: Use Inline Styles for Theming
+
+```typescript
+// ❌ WRONG
+
+
+// ✅ CORRECT
+
+// In styles:
+.themed-container {
+ background-color: ${cssManager.bdTheme('#ffffff', '#000000')};
+}
+```
+
+### ❌ DON'T: Forget Mobile Responsiveness
+
+```typescript
+// ❌ WRONG
+:host {
+ width: 800px; // Fixed width
+}
+
+// ✅ CORRECT
+:host {
+ width: 100%;
+ max-width: 800px;
+}
+
+@media (max-width: 768px) {
+ :host {
+ /* Mobile adjustments */
+ }
+}
+```
+
+## Code Examples
+
+### Example: Creating a New Button Variant
+
+```typescript
+// dees-special-button.ts
+import { customElement, property, css, html } from '@design.estate/dees-element';
+import { DeesElement } from '@design.estate/dees-element';
+import * as cssManager from './00colors.js';
+import * as demoFunc from './dees-special-button.demo.js';
+
+@customElement('dees-special-button')
+export class DeesSpecialButton extends DeesElement {
+ public static demo = demoFunc.demoFunc;
+
+ @property({ type: String })
+ public text: string = 'Click me';
+
+ @property({ type: Boolean, reflect: true })
+ public loading: boolean = false;
+
+ public static styles = [
+ cssManager.defaultStyles,
+ css`
+ :host {
+ display: inline-block;
+ }
+
+ .button {
+ padding: 8px 16px;
+ background: ${cssManager.bdTheme('#0066ff', '#0044cc')};
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: all 0.2s;
+ }
+
+ .button:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 8px ${cssManager.bdTheme('rgba(0,0,0,0.1)', 'rgba(0,0,0,0.3)')};
+ }
+
+ :host([loading]) .button {
+ opacity: 0.7;
+ cursor: not-allowed;
+ }
+ `
+ ];
+
+ public render() {
+ return html`
+
+ `;
+ }
+
+ private handleClick() {
+ this.dispatchEvent(new CustomEvent('special-click', {
+ bubbles: true,
+ composed: true
+ }));
+ }
+}
+```
+
+### Example: Creating a Form Input
+
+```typescript
+// dees-input-special.ts
+export class DeesInputSpecial extends DeesInputBase {
+ public static demo = demoFunc.demoFunc;
+
+ public render() {
+ return html`
+
+
+
+ `;
+ }
+
+ private handleInput(e: Event) {
+ this.value = (e.target as HTMLInputElement).value;
+ this.changeSubject.next(this);
+ }
+
+ private handleBlur() {
+ this.dispatchEvent(new CustomEvent('blur', {
+ bubbles: true,
+ composed: true
+ }));
+ }
+
+ public getValue(): string {
+ return this.value;
+ }
+
+ public setValue(value: string): void {
+ this.value = value;
+ this.changeSubject.next(this);
+ }
+}
+```
+
+## Summary
+
+This playbook represents the collective wisdom and patterns found in the @design.estate/dees-catalog component library. Following these guidelines will help you create components that are:
+
+- **Consistent**: Following established patterns
+- **Maintainable**: Easy to understand and modify
+- **Performant**: Optimized for real-world use
+- **Accessible**: Usable by everyone
+- **Theme-aware**: Supporting light and dark modes
+- **Well-integrated**: Working seamlessly with the component ecosystem
+
+Remember: When in doubt, look at existing components for examples. The codebase itself is the best documentation of these patterns in action.
\ No newline at end of file
diff --git a/readme.refactoring-summary.md b/readme.refactoring-summary.md
deleted file mode 100644
index d8443b5..0000000
--- a/readme.refactoring-summary.md
+++ /dev/null
@@ -1,138 +0,0 @@
-# WYSIWYG Editor Refactoring Progress Summary
-
-## Latest Updates
-
-### Selection Highlighting Fix ✅
-- **Issue**: "Paragraphs are not highlighted consistently, headings are always highlighted"
-- **Root Cause**: The `shouldUpdate` method in `dees-wysiwyg-block.ts` was using a generic `.block` selector that would match the first element with that class, not necessarily the correct block element
-- **Solution**: Changed the selector to be more specific: `.block.${blockType}` which ensures the correct element is found for each block type
-- **Result**: All block types now highlight consistently when selected
-
-### Enter Key Block Creation Fix ✅
-- **Issue**: "When pressing enter and jumping to new block then typing something: The cursor is not at the beginning of the new block and there is content"
-- **Root Cause**: Block handlers were rendering content with template syntax `${block.content || ''}` in their render methods, which violates the static HTML principle
-- **Solution**:
- - Removed all `${block.content}` from render methods in paragraph, heading, quote, and code block handlers
- - Content is now set programmatically in the setup() method only when needed
- - Fixed `setCursorToStart` and `setCursorToEnd` to always find elements fresh instead of relying on cached `blockElement`
-- **Result**: New empty blocks remain truly empty, cursor positioning works correctly
-
-### Backspace Key Deletion Fix ✅
-- **Issue**: "After typing in a new block, pressing backspace deletes the whole block instead of just the last character"
-- **Root Cause**:
- 1. `getCursorPositionInElement` was using `element.contains()` which doesn't work across Shadow DOM boundaries
- 2. The backspace handler was checking `block.content === ''` which only contains the stored content, not the actual DOM content
-- **Solution**:
- 1. Fixed `getCursorPositionInElement` to use `containsAcrossShadowDOM` for proper Shadow DOM support
- 2. Updated backspace handler to get actual content from DOM using `blockComponent.getContent()` instead of relying on stored `block.content`
- 3. Added debug logging to track cursor position and content state
-- **Result**: Backspace now correctly deletes individual characters instead of the whole block
-
-### Arrow Left Navigation Fix ✅
-- **Issue**: "When jumping to the previous block from the beginning of a block with arrow left, the cursor should be at the end of the previous block, not at the start"
-- **Root Cause**: Browser's default focus behavior places cursor at the beginning of contenteditable elements, overriding our cursor positioning
-- **Solution**: For 'end' position, set up the selection range BEFORE focusing the element:
- 1. Create a range pointing to the end of content
- 2. Apply the selection
- 3. Then focus the element (which preserves the existing selection)
- 4. Only use setCursorToEnd for empty blocks
-- **Result**: Arrow left navigation now correctly places cursor at the end of the previous block
-
-## Completed Phases
-
-### Phase 1: Infrastructure ✅
-- Created modular block handler architecture
-- Implemented `IBlockHandler` interface and `BaseBlockHandler` class
-- Created `BlockRegistry` for dynamic block type registration
-- Set up proper file structure under `blocks/` directory
-
-### Phase 2: Proof of Concept ✅
-- Successfully migrated divider block as the simplest example
-- Validated the architecture works correctly
-- Established patterns for block migration
-
-### Phase 3: Text Blocks ✅
-- **Paragraph Block**: Full editing support with text splitting, selection handling, and cursor tracking
-- **Heading Blocks**: All three heading levels (h1, h2, h3) with unified handler
-- **Quote Block**: Italic styling with border, full editing capabilities
-- **Code Block**: Monospace font, tab handling, plain text paste support
-- **List Block**: Bullet/numbered lists with proper list item management
-
-## Key Achievements
-
-### 1. Preserved Critical Knowledge
-- **Static Rendering**: Blocks use `innerHTML` in `firstUpdated` to prevent focus loss during typing
-- **Shadow DOM Selection**: Implemented `containsAcrossShadowDOM` utility for proper selection detection
-- **Cursor Position Tracking**: All editable blocks track cursor position across multiple events
-- **Content Splitting**: HTML-aware splitting using Range API preserves formatting
-- **Focus Management**: Microtask-based focus restoration ensures reliable cursor placement
-
-### 2. Enhanced Architecture
-- Each block type is now self-contained in its own file
-- Block handlers are dynamically registered and loaded
-- Common functionality is shared through base classes
-- Styles are co-located with their block handlers
-
-### 3. Maintained Functionality
-- All keyboard navigation works (arrows, backspace, delete, enter)
-- Text selection across Shadow DOM boundaries functions correctly
-- Block merging and splitting behave as before
-- IME (Input Method Editor) support is preserved
-- Formatting shortcuts (Cmd/Ctrl+B/I/U/K) continue to work
-
-## Code Organization
-
-```
-ts_web/elements/wysiwyg/
-├── dees-wysiwyg-block.ts (simplified main component)
-├── wysiwyg.selection.ts (Shadow DOM selection utilities)
-├── wysiwyg.blockregistration.ts (handler registration)
-└── blocks/
- ├── index.ts (exports and registry)
- ├── block.base.ts (base handler interface)
- ├── decorative/
- │ └── divider.block.ts
- └── text/
- ├── paragraph.block.ts
- ├── heading.block.ts
- ├── quote.block.ts
- ├── code.block.ts
- └── list.block.ts
-```
-
-## Next Steps
-
-### Phase 4: Media Blocks (In Progress)
-- Image block with upload/drag-drop support
-- YouTube block with video embedding
-- Attachment block for file uploads
-
-### Phase 5: Content Blocks
-- Markdown block with preview toggle
-- HTML block with raw HTML editing
-
-### Phase 6: Cleanup
-- Remove old code from main component
-- Optimize bundle size
-- Update documentation
-
-## Technical Improvements
-
-1. **Modularity**: Each block type is now completely self-contained
-2. **Extensibility**: New blocks can be added by creating a handler and registering it
-3. **Maintainability**: Files are smaller and focused on single responsibilities
-4. **Type Safety**: Strong TypeScript interfaces ensure consistent implementation
-5. **Performance**: No degradation in performance; potential for lazy loading in future
-
-## Migration Pattern
-
-For future block migrations, follow this pattern:
-
-1. Create block handler extending `BaseBlockHandler`
-2. Implement required methods: `render()`, `setup()`, `getStyles()`
-3. Add helper methods for cursor/content management
-4. Handle Shadow DOM selection properly using utilities
-5. Register handler in `wysiwyg.blockregistration.ts`
-6. Test all interactions (typing, selection, navigation)
-
-The refactoring has been successful in making the codebase more maintainable while preserving all the hard-won functionality and edge case handling from the original implementation.
\ No newline at end of file
diff --git a/readme.refactoring.md b/readme.refactoring.md
deleted file mode 100644
index 737c33b..0000000
--- a/readme.refactoring.md
+++ /dev/null
@@ -1,82 +0,0 @@
-# WYSIWYG Editor Refactoring
-
-## Summary of Changes
-
-This refactoring cleaned up the wysiwyg editor implementation to fix focus, cursor position, and selection issues.
-
-### Phase 1: Code Organization
-
-#### 1. Removed Duplicate Code
-- Removed duplicate `handleBlockInput` method from main component (was already in inputHandler)
-- Removed duplicate `handleBlockKeyDown` method from main component (was already in keyboardHandler)
-- Consolidated all input handling in the respective handler classes
-
-#### 2. Simplified Focus Management
-- Removed complex `updated` lifecycle method that was trying to maintain focus
-- Simplified `handleBlockBlur` to not immediately close menus
-- Added `requestAnimationFrame` to focus operations for better timing
-- Removed `slashMenuOpenTime` tracking which was no longer needed
-
-#### 3. Fixed Slash Menu Behavior
-- Changed from `@mousedown` to `@click` events for better UX
-- Added proper event prevention to avoid focus loss
-- Menu now closes when clicking outside
-- Simplified the insertBlock method to close menu first
-
-### Phase 2: Cursor & Selection Fixes
-
-#### 4. Enhanced Cursor Position Management
-- Added `focusWithCursor()` method to block component for precise cursor positioning
-- Improved `handleSlashCommand` to preserve cursor position when menu opens
-- Added `getCaretCoordinates()` for accurate menu positioning based on cursor location
-- Updated `focusBlock()` to support numeric cursor positions
-
-#### 5. Fixed Selection Across Shadow DOM
-- Added custom `block-text-selected` event to communicate selections across shadow boundaries
-- Implemented `handleMouseUp()` in block component to detect selections
-- Updated main component to listen for selection events from blocks
-- Selection now works properly even with nested shadow DOMs
-
-#### 6. Improved Slash Menu Close Behavior
-- Added optional `clearSlash` parameter to `closeSlashMenu()`
-- Escape key now properly clears the slash command
-- Clicking outside clears the slash if menu is open
-- Selecting an item preserves content and just transforms the block
-
-### Technical Improvements
-
-#### Block Component (`dees-wysiwyg-block`)
-- Better focus management with immediate focus (removed unnecessary requestAnimationFrame)
-- Added cursor position control methods
-- Custom event dispatching for cross-shadow-DOM communication
-- Improved content handling for different block types
-
-#### Input Handler
-- Preserves cursor position when showing slash menu
-- Better caret coordinate calculation for menu positioning
-- Ensures focus stays in the block when menu appears
-
-#### Block Operations
-- Enhanced `focusBlock()` to support start/end/numeric positions
-- Better timing with requestAnimationFrame for focus operations
-
-### Key Benefits
-- Slash menu no longer causes focus or cursor position loss
-- Text selection works properly across shadow DOM boundaries
-- Cursor position is preserved when interacting with menus
-- Cleaner, more maintainable code structure
-- Better separation of concerns
-
-## Testing
-
-Use the test files in `.nogit/debug/`:
-- `test-slash-menu.html` - Tests slash menu focus behavior
-- `test-wysiwyg-formatting.html` - Tests text formatting
-
-## Known Issues Fixed
-- Slash menu disappearing immediately on first "/"
-- Focus lost when slash menu opens
-- Cursor position lost when typing "/"
-- Text selection not working properly
-- Selection events not propagating across shadow DOM
-- Duplicate event handling causing conflicts
\ No newline at end of file
diff --git a/test-output.log b/test-output.log
deleted file mode 100644
index 25476f4..0000000
--- a/test-output.log
+++ /dev/null
@@ -1,72 +0,0 @@
-
-> @design.estate/dees-catalog@1.10.8 test /mnt/data/lossless/design.estate/dees-catalog
-> tstest test/ --web --verbose --timeout 30 --logfile test/test.tabs-indicator.browser.ts
-
-[38;5;231m
-🔍 Test Discovery[0m
-[38;5;231m Mode: file[0m
-[38;5;231m Pattern: test/test.tabs-indicator.browser.ts[0m
-[38;5;113m Found: 1 test file(s)[0m
-[38;5;33m
-▶️ test/test.tabs-indicator.browser.ts (1/1)[0m
-[38;5;231m Runtime: chromium[0m
-running spawned compilation process
-=======> ESBUILD
-{
- cwd: '/mnt/data/lossless/design.estate/dees-catalog',
- from: 'test/test.tabs-indicator.browser.ts',
- to: '/mnt/data/lossless/design.estate/dees-catalog/.nogit/tstest_cache/test__test.tabs-indicator.browser.ts.js',
- mode: 'test',
- argv: { bundler: 'esbuild' }
-}
-switched to /mnt/data/lossless/design.estate/dees-catalog
-building for test:
-Got no SSL certificates. Please ensure encryption using e.g. a reverse proxy
-"/test" maps to 1 handlers
- -> GET
-"*" maps to 1 handlers
- -> GET
-now listening on 3007!
-Launching puppeteer browser with arguments:
-[]
-Using executable: /usr/bin/google-chrome
-added connection. now 1 sockets connected.
-added connection. now 2 sockets connected.
-connection ended
-removed connection. 1 sockets remaining.
-connection ended
-removed connection. 0 sockets remaining.
-added connection. now 1 sockets connected.
-/favicon.ico
-could not resolve /mnt/data/lossless/design.estate/dees-catalog/.nogit/tstest_cache/favicon.ico
-/test__test.tabs-indicator.browser.ts.js
-[38;5;231m [38;5;116mTest starting: tabs indicator positioning debug[0m[0m
-[38;5;231m !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!![0m
-[38;5;231m Using globalThis.tapPromise[0m
-[38;5;231m !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!![0m
-connection ended
-removed connection. 0 sockets remaining.
-[38;5;33m=> [0m Stopped [38;5;215mtest/test.tabs-indicator.browser.ts[0m chromium instance and server.
-[38;5;196m
-⚠️ Error[0m
-[38;5;196m Only 0 out of 1 completed![0m
-[38;5;196m
-⚠️ Error[0m
-[38;5;196m The amount of received tests and expectedTests is unequal! Therefore the testfile failed[0m
-[38;5;196m Summary: -1 passed, 1 failed of 0 tests in 2.7s[0m
-[38;5;231m
-📊 Test Summary[0m
-[38;5;231m┌────────────────────────────────┐[0m
-[38;5;231m│ Total Files: 1 │[0m
-[38;5;231m│ Total Tests: 0 │[0m
-[38;5;113m│ Passed: 0 │[0m
-[38;5;113m│ Failed: 0 │[0m
-[38;5;231m│ Duration: 4.2s │[0m
-[38;5;231m└────────────────────────────────┘[0m
-[38;5;116m
-⏱️ Performance Metrics:[0m
-[38;5;231m Average per test: 0ms[0m
-[38;5;113m
-ALL TESTS PASSED! 🎉[0m
-Exited NOT OK!
- ELIFECYCLE Test failed. See above for more details.