Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Implement getElement
Browse files Browse the repository at this point in the history
  • Loading branch information
DAreRodz committed Oct 10, 2023
1 parent 96631ce commit c3ac5c5
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 3 deletions.
43 changes: 41 additions & 2 deletions assets/js/interactivity/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
import { h, options, createContext, cloneElement } from 'preact';
import { useRef, useCallback, useContext } from 'preact/hooks';
import { deepSignal } from 'deepsignal';
/**
* Internal dependencies
*/
Expand Down Expand Up @@ -40,6 +41,30 @@ import { nsPathParser } from './vdom';
// Main context.
const context = createContext( {} );

const immutableMap = new WeakMap();
const deepImmutable = < T extends Object = {} >( target: T ): T => {
if ( immutableMap.has( target ) ) {
return immutableMap.get( target );
}
const proxy = new Proxy( target, {
get( target, prop ) {
const value = Reflect.get< any, string | symbol >( target, prop );
if ( !! value && typeof value === 'object' ) {
return deepImmutable( value );
}
return value;
},
set() {
throw Error( 'Cannot modify a deep immutable object.' );
},
deleteProperty() {
throw Error( 'Cannot modify a deep immutable object.' );
},
} );
immutableMap.set( target, proxy );
return proxy;
};

let scopeStack: any[] = [];
let namespaceStack: string[] = [];

Expand All @@ -48,7 +73,19 @@ export const getContext = < T extends object >( namespace?: string ): T => {
return getScope()?.context[ namespace || currentNamespace ];
};

export const getElementRef = () => getScope()?.ref.current;
export const getElement = () => {
if ( ! getScope() ) {
throw Error(
'Cannot call `getElement()` outside getters and actions used by directives.'
);
}
const { ref, state, props } = getScope();
return Object.freeze( {
ref: ref.current,
state: state.current,
props: deepImmutable( props ),
} );
};

export const getScope = () => scopeStack.slice( -1 )[ 0 ];

Expand Down Expand Up @@ -191,10 +228,12 @@ const Directives = ( {
} ) => {
// Initialize the scope of this element. These scopes are different per each
// level because each level has a different context, but they share the same
// element ref, evaluate and props.
// element ref, state and props.
const scope = useRef( {} ).current;
scope.context = useContext( context );
scope.ref = previousScope.ref || useRef( null );
scope.state = previousScope.state || useRef( deepSignal( {} ) );
scope.props = element?.props || originalProps;
scope.evaluate = useCallback(
getEvaluate( { namespace: directives.namespace, scope } )
);
Expand Down
2 changes: 1 addition & 1 deletion assets/js/interactivity/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import registerDirectives from './directives';
import { init } from './router';

export { store } from './store';
export { directive, getContext, getElementRef } from './hooks';
export { directive, getContext, getElement } from './hooks';
export { navigate, prefetch } from './router';
export { h as createElement } from 'preact';
export { useEffect, useContext, useMemo } from 'preact/hooks';
Expand Down

0 comments on commit c3ac5c5

Please sign in to comment.