Vue3 Design Mode Composables
Vue3 Composition API equivalents of the React design mode hooks.
Overview
This directory contains Vue3 composables that provide the same functionality as the React hooks in /src/client/. These composables enable design mode functionality in Vue3 applications.
Composables
1. useDesignMode.ts (912 lines)
Purpose: Global design mode state management and bridge communication.
Ported from: src/client/DesignModeContext.tsx (1,079 lines)
Key Features:
- Global state management using
reactive()andprovide/inject - Bridge communication with parent window via postMessage
- Message handling for style/content updates
- Batch update support with debouncing
- Health check and connection monitoring
Usage:
import { createDesignMode, useDesignMode } from './composables';
// In root component
const designMode = createDesignMode({
enabled: true,
iframeMode: {
enabled: true,
enableSelection: true,
enableDirectEdit: true,
},
batchUpdate: {
enabled: true,
debounceMs: 300,
},
});
// In child components
const {
isDesignMode,
selectedElement,
toggleDesignMode,
selectElement,
modifyElementClass,
updateElementContent
} = useDesignMode();
Key Methods:
toggleDesignMode()- Toggle design mode on/offselectElement(element)- Select an element for editingmodifyElementClass(element, newClass)- Update element classesupdateElementContent(element, newContent)- Update element text contentbatchUpdateElements(updates)- Batch multiple updatesresetModifications()- Reload page to reset changes
2. useSelectionManager.ts (539 lines)
Purpose: Element selection and interaction handling.
Ported from: src/client/SelectionManager.tsx (597 lines)
Key Features:
- Click and hover event handling
- Element validation (must have source mapping + static-content/static-class)
- Visual highlighting with outline and shadow
- Keyboard shortcuts (Esc to clear, Ctrl/Cmd+A to select)
- Element info extraction with hierarchy
- Component root detection for library components
Usage:
import { useSelectionManager } from './composables';
const {
selectedElement,
hoverElement,
selectElement,
clearSelection,
extractElementInfo,
addSelectionListener,
} = useSelectionManager(document.body, {
enableSelection: true,
enableHover: true,
selectionDelay: 0,
excludeSelectors: ['script', 'style', 'meta'],
includeOnlyElements: false,
});
// Listen to selection changes
const unsubscribe = addSelectionListener((element) => {
if (element) {
const info = extractElementInfo(element);
console.log('Selected:', info);
}
});
Key Methods:
selectElement(element)- Select and highlight elementclearSelection()- Clear current selectionextractElementInfo(element)- Get detailed element informationaddSelectionListener(callback)- Subscribe to selection changes
3. useEditManager.ts (367 lines)
Purpose: Content editing with contentEditable mode.
Ported from: src/client/managers/EditManager.ts (365 lines)
Key Features:
- ContentEditable mode for inline text editing
- Real-time sync to related elements (list items with same element-id)
- Throttled notifications (300ms) during typing
- Enter saves, Escape cancels
- Click outside to save
- Automatic peer element synchronization
Usage:
import { useEditManager } from './composables';
const processUpdate = async (update: UpdateState) => {
// Handle update logic
return { success: true };
};
const {
handleDirectEdit,
editTextContent,
updateContent,
updateStyle,
updateAttribute,
} = useEditManager(processUpdate, config);
// Double-click to edit
element.addEventListener('dblclick', () => {
handleDirectEdit(element, 'content');
});
Key Methods:
handleDirectEdit(element, type)- Trigger edit modeeditTextContent(element)- Enable contentEditable editingupdateContent(element, newValue)- Programmatic content updateupdateStyle(element, newClass)- Programmatic style updateupdateAttribute(element, name, value)- Update element attribute
4. useObserverManager.ts (98 lines)
Purpose: DOM mutation observation.
Ported from: src/client/managers/ObserverManager.ts (81 lines)
Key Features:
- MutationObserver setup for DOM changes
- Watches: childList, characterData, attributes (class, style)
- Skips elements with
data-ignore-mutationattribute - Callbacks for content/style edits and node additions
Usage:
import { useObserverManager } from './composables';
const { enable, disable, isEnabled } = useObserverManager(
(target, type) => {
console.log(`Edit detected: ${type} on`, target);
},
(node) => {
console.log('Node added:', node);
}
);
// Start observing
enable();
// Stop observing
disable();
Key Methods:
enable()- Start observing DOM mutationsdisable()- Stop observing and disconnect
Key Differences from React Version
State Management
- React:
useState,useCallback,useEffect - Vue3:
ref,reactive,computed,watch,onMounted,onBeforeUnmount
Context/Injection
- React:
createContext,useContext,Provider - Vue3:
provide,inject,InjectionKey
Lifecycle
- React:
useEffectwith cleanup - Vue3:
onMounted,onBeforeUnmount
Reactivity
- React: Explicit state setters
- Vue3: Direct mutation of
ref.valueorreactiveproperties
Integration with Shared Code
All composables import shared utilities from /src/client-shared/:
bridge.ts- PostMessage communicationattributeNames.ts- Data attribute name resolutionsourceInfo.ts- Source mapping extractionsourceInfoResolver.ts- Usage-site resolutionelementUtils.ts- Element validation helpers
Type Safety
All composables are fully typed with TypeScript, importing types from:
/src/types/messages.ts- Message type definitions/src/types/UpdateTypes.ts- Update operation types
Testing
To test these composables:
- Import in a Vue3 component
- Call
createDesignMode()in the root component - Use
useDesignMode()in child components - Verify bridge communication with parent window
- Test element selection and editing
Future Enhancements
- Add Vue3-specific optimizations (e.g.,
shallowReffor large objects) - Create Vue3 component wrappers for easier integration
- Add Pinia store integration option
- Implement Vue DevTools integration
- Add unit tests with Vitest