muspe-cli
Version:
MusPE Advanced Framework v2.1.3 - Mobile User-friendly Simple Progressive Engine with Enhanced CLI Tools, Specialized E-Commerce Templates, Material Design 3, Progressive Enhancement, Mobile Optimizations, Performance Analysis, and Enterprise-Grade Develo
546 lines (454 loc) • 13.9 kB
JavaScript
// MusPE Composable Hooks System - React-like hooks with Vue-like composables
class MusPEHooks {
constructor() {
this.currentInstance = null;
this.hookIndex = 0;
this.hooks = [];
}
// Set current component instance
setCurrentInstance(instance) {
this.currentInstance = instance;
this.hookIndex = 0;
}
// Get current hook index and increment
getHookIndex() {
return this.hookIndex++;
}
// Reset for next render
reset() {
this.hookIndex = 0;
}
}
const hookSystem = new MusPEHooks();
// useState hook - React-like state management
function useState(initialValue) {
const instance = hookSystem.currentInstance;
const index = hookSystem.getHookIndex();
if (!instance) {
throw new Error('useState can only be used inside components');
}
// Initialize hook if first time
if (!instance.hooks) instance.hooks = [];
if (!instance.hooks[index]) {
instance.hooks[index] = {
type: 'state',
value: ref(typeof initialValue === 'function' ? initialValue() : initialValue)
};
}
const hook = instance.hooks[index];
const setState = (newValue) => {
if (typeof newValue === 'function') {
hook.value.value = newValue(hook.value.value);
} else {
hook.value.value = newValue;
}
// Trigger re-render
if (instance.update) {
instance.update();
}
};
return [hook.value.value, setState];
}
// useEffect hook - React-like side effects
function useEffect(callback, dependencies) {
const instance = hookSystem.currentInstance;
const index = hookSystem.getHookIndex();
if (!instance) {
throw new Error('useEffect can only be used inside components');
}
if (!instance.hooks) instance.hooks = [];
const hook = instance.hooks[index];
const depsChanged = !hook || !dependencies ||
!hook.dependencies ||
dependencies.some((dep, i) => dep !== hook.dependencies[i]);
if (!hook) {
instance.hooks[index] = {
type: 'effect',
callback,
dependencies: dependencies ? [...dependencies] : null,
cleanup: null
};
} else if (depsChanged) {
// Cleanup previous effect
if (hook.cleanup && typeof hook.cleanup === 'function') {
hook.cleanup();
}
hook.callback = callback;
hook.dependencies = dependencies ? [...dependencies] : null;
hook.cleanup = null;
}
// Run effect if dependencies changed
if (depsChanged) {
const currentHook = instance.hooks[index];
// Schedule effect to run after render
setTimeout(() => {
if (currentHook.callback) {
const cleanup = currentHook.callback();
if (typeof cleanup === 'function') {
currentHook.cleanup = cleanup;
}
}
}, 0);
}
}
// useRef hook - React-like refs
function useRef(initialValue) {
const instance = hookSystem.currentInstance;
const index = hookSystem.getHookIndex();
if (!instance) {
throw new Error('useRef can only be used inside components');
}
if (!instance.hooks) instance.hooks = [];
if (!instance.hooks[index]) {
instance.hooks[index] = {
type: 'ref',
current: initialValue
};
}
return instance.hooks[index];
}
// useComputed hook - Vue-like computed values
function useComputed(computeFn) {
const instance = hookSystem.currentInstance;
const index = hookSystem.getHookIndex();
if (!instance) {
throw new Error('useComputed can only be used inside components');
}
if (!instance.hooks) instance.hooks = [];
if (!instance.hooks[index]) {
instance.hooks[index] = {
type: 'computed',
value: computed(computeFn)
};
}
return instance.hooks[index].value;
}
// useWatch hook - Vue-like watchers
function useWatch(source, callback, options) {
const instance = hookSystem.currentInstance;
const index = hookSystem.getHookIndex();
if (!instance) {
throw new Error('useWatch can only be used inside components');
}
if (!instance.hooks) instance.hooks = [];
if (!instance.hooks[index]) {
instance.hooks[index] = {
type: 'watch',
watcher: watch(source, callback, options)
};
}
return instance.hooks[index].watcher;
}
// useMemo hook - React-like memoization
function useMemo(factory, dependencies) {
const instance = hookSystem.currentInstance;
const index = hookSystem.getHookIndex();
if (!instance) {
throw new Error('useMemo can only be used inside components');
}
if (!instance.hooks) instance.hooks = [];
const hook = instance.hooks[index];
const depsChanged = !hook || !dependencies ||
!hook.dependencies ||
dependencies.some((dep, i) => dep !== hook.dependencies[i]);
if (!hook || depsChanged) {
const value = factory();
instance.hooks[index] = {
type: 'memo',
value,
dependencies: dependencies ? [...dependencies] : null
};
return value;
}
return hook.value;
}
// useCallback hook - React-like callback memoization
function useCallback(callback, dependencies) {
return useMemo(() => callback, dependencies);
}
// useReducer hook - React-like state reducer
function useReducer(reducer, initialState, init) {
const instance = hookSystem.currentInstance;
const index = hookSystem.getHookIndex();
if (!instance) {
throw new Error('useReducer can only be used inside components');
}
if (!instance.hooks) instance.hooks = [];
if (!instance.hooks[index]) {
const initialValue = init ? init(initialState) : initialState;
instance.hooks[index] = {
type: 'reducer',
state: ref(initialValue),
reducer
};
}
const hook = instance.hooks[index];
const dispatch = (action) => {
const newState = hook.reducer(hook.state.value, action);
hook.state.value = newState;
// Trigger re-render
if (instance.update) {
instance.update();
}
};
return [hook.state.value, dispatch];
}
// Custom hooks for mobile-specific functionality
// useTouch hook - Touch gesture handling
function useTouch() {
const touchState = reactive({
isTouch: false,
touches: [],
startTime: 0,
startPosition: { x: 0, y: 0 },
currentPosition: { x: 0, y: 0 },
velocity: { x: 0, y: 0 }
});
const handlers = {
onTouchStart: (e) => {
touchState.isTouch = true;
touchState.touches = Array.from(e.touches);
touchState.startTime = Date.now();
touchState.startPosition = {
x: e.touches[0].clientX,
y: e.touches[0].clientY
};
touchState.currentPosition = { ...touchState.startPosition };
},
onTouchMove: (e) => {
if (!touchState.isTouch) return;
touchState.touches = Array.from(e.touches);
const newPosition = {
x: e.touches[0].clientX,
y: e.touches[0].clientY
};
const deltaTime = Date.now() - touchState.startTime;
const deltaX = newPosition.x - touchState.currentPosition.x;
const deltaY = newPosition.y - touchState.currentPosition.y;
touchState.velocity = {
x: deltaX / deltaTime,
y: deltaY / deltaTime
};
touchState.currentPosition = newPosition;
},
onTouchEnd: (e) => {
touchState.isTouch = false;
touchState.touches = [];
}
};
return {
touchState,
handlers
};
}
// useSwipe hook - Swipe gesture detection
function useSwipe(onSwipe, options = {}) {
const { threshold = 50, timeout = 500 } = options;
const { touchState, handlers } = useTouch();
useEffect(() => {
if (!touchState.isTouch && touchState.startTime > 0) {
const deltaTime = Date.now() - touchState.startTime;
const deltaX = touchState.currentPosition.x - touchState.startPosition.x;
const deltaY = touchState.currentPosition.y - touchState.startPosition.y;
if (deltaTime < timeout) {
if (Math.abs(deltaX) > threshold && Math.abs(deltaX) > Math.abs(deltaY)) {
const direction = deltaX > 0 ? 'right' : 'left';
onSwipe(direction, { deltaX, deltaY, deltaTime, velocity: touchState.velocity });
} else if (Math.abs(deltaY) > threshold && Math.abs(deltaY) > Math.abs(deltaX)) {
const direction = deltaY > 0 ? 'down' : 'up';
onSwipe(direction, { deltaX, deltaY, deltaTime, velocity: touchState.velocity });
}
}
}
}, [touchState.isTouch]);
return handlers;
}
// useGeolocation hook - Device geolocation
function useGeolocation(options = {}) {
const [position, setPosition] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const getCurrentPosition = useCallback(() => {
if (!navigator.geolocation) {
setError(new Error('Geolocation is not supported'));
return;
}
setLoading(true);
navigator.geolocation.getCurrentPosition(
(pos) => {
setPosition({
latitude: pos.coords.latitude,
longitude: pos.coords.longitude,
accuracy: pos.coords.accuracy,
timestamp: pos.timestamp
});
setLoading(false);
setError(null);
},
(err) => {
setError(err);
setLoading(false);
},
options
);
}, [options]);
useEffect(() => {
getCurrentPosition();
}, [getCurrentPosition]);
return {
position,
error,
loading,
getCurrentPosition
};
}
// useDeviceOrientation hook - Device orientation
function useDeviceOrientation() {
const [orientation, setOrientation] = useState({
alpha: 0,
beta: 0,
gamma: 0
});
useEffect(() => {
const handleOrientation = (event) => {
setOrientation({
alpha: event.alpha,
beta: event.beta,
gamma: event.gamma
});
};
if ('DeviceOrientationEvent' in window) {
window.addEventListener('deviceorientation', handleOrientation);
return () => {
window.removeEventListener('deviceorientation', handleOrientation);
};
}
}, []);
return orientation;
}
// useNetworkStatus hook - Network connectivity
function useNetworkStatus() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
const [connection, setConnection] = useState(null);
useEffect(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
// Get connection info if available
if ('connection' in navigator) {
setConnection(navigator.connection);
const handleConnectionChange = () => {
setConnection({ ...navigator.connection });
};
navigator.connection.addEventListener('change', handleConnectionChange);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
navigator.connection.removeEventListener('change', handleConnectionChange);
};
}
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return {
isOnline,
connection
};
}
// useLocalStorage hook - LocalStorage with reactivity
function useLocalStorage(key, defaultValue) {
const [value, setValue] = useState(() => {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (error) {
console.error('Error reading from localStorage:', error);
return defaultValue;
}
});
const setStoredValue = useCallback((newValue) => {
try {
setValue(newValue);
localStorage.setItem(key, JSON.stringify(newValue));
} catch (error) {
console.error('Error writing to localStorage:', error);
}
}, [key]);
return [value, setStoredValue];
}
// useAnimation hook - Animation utilities
function useAnimation() {
const animationsRef = useRef(new Set());
const animate = useCallback((element, keyframes, options = {}) => {
const animation = element.animate(keyframes, {
duration: 300,
easing: 'ease-out',
fill: 'forwards',
...options
});
animationsRef.current.add(animation);
animation.addEventListener('finish', () => {
animationsRef.current.delete(animation);
});
return animation;
}, []);
const cancelAll = useCallback(() => {
animationsRef.current.forEach(animation => {
if (animation.cancel) animation.cancel();
});
animationsRef.current.clear();
}, []);
// Cleanup on unmount
useEffect(() => {
return () => {
cancelAll();
};
}, [cancelAll]);
return {
animate,
cancelAll,
activeAnimations: animationsRef.current
};
}
// Export for module usage
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
hookSystem,
useState,
useEffect,
useRef,
useComputed,
useWatch,
useMemo,
useCallback,
useReducer,
useTouch,
useSwipe,
useGeolocation,
useDeviceOrientation,
useNetworkStatus,
useLocalStorage,
useAnimation
};
}
// Make available globally
if (typeof window !== 'undefined') {
window.useState = useState;
window.useEffect = useEffect;
window.useRef = useRef;
window.useComputed = useComputed;
window.useWatch = useWatch;
window.useMemo = useMemo;
window.useCallback = useCallback;
window.useReducer = useReducer;
window.useTouch = useTouch;
window.useSwipe = useSwipe;
window.useGeolocation = useGeolocation;
window.useDeviceOrientation = useDeviceOrientation;
window.useNetworkStatus = useNetworkStatus;
window.useLocalStorage = useLocalStorage;
window.useAnimation = useAnimation;
}