6.5 KiB
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