-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Interactivity: Strict type checking (#59865)
Enable `strictNullChecks` and improve types. Co-authored-by: sirreal <[email protected]> Co-authored-by: cbravobernal <[email protected]>
- Loading branch information
1 parent
7a9f1de
commit 966f0f7
Showing
8 changed files
with
141 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
// eslint-disable-next-line eslint-comments/disable-enable-pair | ||
/* eslint-disable react-hooks/exhaustive-deps */ | ||
|
||
/* @jsx createElement */ | ||
|
||
/** | ||
* External dependencies | ||
*/ | ||
import { h as createElement } from 'preact'; | ||
import { h as createElement, type RefObject } from 'preact'; | ||
import { useContext, useMemo, useRef } from 'preact/hooks'; | ||
import { deepSignal, peek } from 'deepsignal'; | ||
import { deepSignal, peek, type DeepSignal } from 'deepsignal'; | ||
|
||
/** | ||
* Internal dependencies | ||
|
@@ -23,8 +26,8 @@ const contextObjectToProxy = new WeakMap(); | |
const contextProxyToObject = new WeakMap(); | ||
const contextObjectToFallback = new WeakMap(); | ||
|
||
const isPlainObject = ( item ) => | ||
item && typeof item === 'object' && item.constructor === Object; | ||
const isPlainObject = ( item: unknown ): boolean => | ||
Boolean( item && typeof item === 'object' && item.constructor === Object ); | ||
|
||
const descriptor = Reflect.getOwnPropertyDescriptor; | ||
|
||
|
@@ -37,17 +40,17 @@ const descriptor = Reflect.getOwnPropertyDescriptor; | |
* By default, all plain objects inside the context are wrapped, unless it is | ||
* listed in the `ignore` option. | ||
* | ||
* @param {Object} current Current context. | ||
* @param {Object} inherited Inherited context, used as fallback. | ||
* @param current Current context. | ||
* @param inherited Inherited context, used as fallback. | ||
* | ||
* @return {Object} The wrapped context object. | ||
* @return The wrapped context object. | ||
*/ | ||
const proxifyContext = ( current, inherited = {} ) => { | ||
const proxifyContext = ( current: object, inherited: object = {} ): object => { | ||
// Update the fallback object reference when it changes. | ||
contextObjectToFallback.set( current, inherited ); | ||
if ( ! contextObjectToProxy.has( current ) ) { | ||
const proxy = new Proxy( current, { | ||
get: ( target, k ) => { | ||
get: ( target: DeepSignal< any >, k ) => { | ||
const fallback = contextObjectToFallback.get( current ); | ||
// Always subscribe to prop changes in the current context. | ||
const currentProp = target[ k ]; | ||
|
@@ -127,10 +130,13 @@ const proxifyContext = ( current, inherited = {} ) => { | |
/** | ||
* Recursively update values within a deepSignal object. | ||
* | ||
* @param {Object} target A deepSignal instance. | ||
* @param {Object} source Object with properties to update in `target` | ||
* @param target A deepSignal instance. | ||
* @param source Object with properties to update in `target`. | ||
*/ | ||
const updateSignals = ( target, source ) => { | ||
const updateSignals = ( | ||
target: DeepSignal< any >, | ||
source: DeepSignal< any > | ||
) => { | ||
for ( const k in source ) { | ||
if ( | ||
isPlainObject( peek( target, k ) ) && | ||
|
@@ -146,23 +152,23 @@ const updateSignals = ( target, source ) => { | |
/** | ||
* Recursively clone the passed object. | ||
* | ||
* @param {Object} source Source object. | ||
* @return {Object} Cloned object. | ||
* @param source Source object. | ||
* @return Cloned object. | ||
*/ | ||
const deepClone = ( source ) => { | ||
function deepClone< T >( source: T ): T { | ||
if ( isPlainObject( source ) ) { | ||
return Object.fromEntries( | ||
Object.entries( source ).map( ( [ key, value ] ) => [ | ||
Object.entries( source as object ).map( ( [ key, value ] ) => [ | ||
key, | ||
deepClone( value ), | ||
] ) | ||
); | ||
) as T; | ||
} | ||
if ( Array.isArray( source ) ) { | ||
return source.map( ( i ) => deepClone( i ) ); | ||
return source.map( ( i ) => deepClone( i ) ) as T; | ||
} | ||
return source; | ||
}; | ||
} | ||
|
||
const newRule = | ||
/(?:([\u0080-\uFFFF\w-%@]+) *:? *([^{;]+?);|([^;}{]*?) *{)|(}\s*)/g; | ||
|
@@ -176,10 +182,12 @@ const empty = ' '; | |
* Made by Cristian Bote (@cristianbote) for Goober. | ||
* https://unpkg.com/browse/[email protected]/src/core/astish.js | ||
* | ||
* @param {string} val CSS string. | ||
* @return {Object} CSS object. | ||
* @param val CSS string. | ||
* @return CSS object. | ||
*/ | ||
const cssStringToObject = ( val ) => { | ||
const cssStringToObject = ( | ||
val: string | ||
): Record< string, string | number > => { | ||
const tree = [ {} ]; | ||
let block, left; | ||
|
||
|
@@ -203,10 +211,9 @@ const cssStringToObject = ( val ) => { | |
* Creates a directive that adds an event listener to the global window or | ||
* document object. | ||
* | ||
* @param {string} type 'window' or 'document' | ||
* @return {void} | ||
* @param type 'window' or 'document' | ||
*/ | ||
const getGlobalEventDirective = ( type ) => { | ||
const getGlobalEventDirective = ( type: 'window' | 'document' ) => { | ||
return ( { directives, evaluate } ) => { | ||
directives[ `on-${ type }` ] | ||
.filter( ( { suffix } ) => suffix !== 'default' ) | ||
|
@@ -217,7 +224,7 @@ const getGlobalEventDirective = ( type ) => { | |
const globalVar = type === 'window' ? window : document; | ||
globalVar.addEventListener( eventName, cb ); | ||
return () => globalVar.removeEventListener( eventName, cb ); | ||
}, [] ); | ||
} ); | ||
} ); | ||
}; | ||
}; | ||
|
@@ -333,9 +340,13 @@ export default () => { | |
* need deps because it only needs to do it the first time. | ||
*/ | ||
if ( ! result ) { | ||
element.ref.current.classList.remove( className ); | ||
( | ||
element.ref as RefObject< HTMLElement > | ||
).current!.classList.remove( className ); | ||
} else { | ||
element.ref.current.classList.add( className ); | ||
( | ||
element.ref as RefObject< HTMLElement > | ||
).current!.classList.add( className ); | ||
} | ||
} ); | ||
} ); | ||
|
@@ -368,9 +379,13 @@ export default () => { | |
* because it only needs to do it the first time. | ||
*/ | ||
if ( ! result ) { | ||
element.ref.current.style.removeProperty( styleProp ); | ||
( | ||
element.ref as RefObject< HTMLElement > | ||
).current!.style.removeProperty( styleProp ); | ||
} else { | ||
element.ref.current.style[ styleProp ] = result; | ||
( | ||
element.ref as RefObject< HTMLElement > | ||
).current!.style[ styleProp ] = result; | ||
} | ||
} ); | ||
} ); | ||
|
@@ -390,7 +405,8 @@ export default () => { | |
* first time. After that, Preact will handle the changes. | ||
*/ | ||
useInit( () => { | ||
const el = element.ref.current; | ||
const el = ( element.ref as RefObject< HTMLElement > ) | ||
.current!; | ||
|
||
/* | ||
* We set the value directly to the corresponding HTMLElement instance | ||
|
@@ -462,6 +478,8 @@ export default () => { | |
type: Type, | ||
props: { innerHTML, ...rest }, | ||
}, | ||
}: { | ||
element: any; | ||
} ) => { | ||
// Preserve the initial inner HTML. | ||
const cached = useMemo( () => innerHTML, [] ); | ||
|
@@ -477,6 +495,11 @@ export default () => { | |
// data-wp-text | ||
directive( 'text', ( { directives: { text }, element, evaluate } ) => { | ||
const entry = text.find( ( { suffix } ) => suffix === 'default' ); | ||
if ( ! entry ) { | ||
element.props.children = null; | ||
return; | ||
} | ||
|
||
try { | ||
const result = evaluate( entry ); | ||
element.props.children = | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.