Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ebba7b4
Add interactivity runtime
luisherranz Apr 21, 2023
af59781
Add it to the image block
luisherranz Apr 21, 2023
cca3d60
Add a separate webpack config
luisherranz Apr 21, 2023
160a029
Make sure the runtime is imported only once
luisherranz Apr 21, 2023
7f16f27
Use sideEffects instead of init
luisherranz Apr 21, 2023
f4b2ee8
Move script registration to a general file
luisherranz Apr 21, 2023
378b041
Add `defer` to the interactivity scripts
luisherranz Apr 21, 2023
409d161
Revert changes of the image block
luisherranz Apr 21, 2023
29e11ab
Fix init import name
luisherranz Apr 21, 2023
f4b6c0a
Move and refactor the interactive scritps registration
gziolo Apr 28, 2023
3d94473
Fix code style violations
gziolo Apr 28, 2023
6ae760f
Use `wp-interactivity-` prefix for script handles
gziolo Apr 28, 2023
9d6869e
Improve the matcher for side effects in `package.json`
gziolo Apr 28, 2023
c6d02d8
Add custom useSignalEffect
DAreRodz May 4, 2023
af55917
Call `init` after `store` has been initialized
DAreRodz May 4, 2023
7c1f2d1
Add lightbox to image block
artemiomorales Apr 3, 2023
9507199
Add logic for hiding lightbox on esc key press and overlay click
artemiomorales Apr 3, 2023
3f89d9b
Improve styles and add note to add conditional for lightbox markup
artemiomorales Apr 5, 2023
cb7f89a
Add editor UI and attribute for toggling lightbox
artemiomorales Apr 13, 2023
437d873
Remove image translation animation and add fade instead
artemiomorales Apr 19, 2023
7bd6b25
Add accessibility; clean up styles; fix bug regarding ref in directives
artemiomorales Apr 21, 2023
109344c
Configure image to use new Interactivity API runtime included in Gute…
artemiomorales Apr 26, 2023
f95a2cd
Remove viewScript from image config
artemiomorales Apr 26, 2023
e37e228
Add Portal directive to Interactivity API runtime
artemiomorales Apr 26, 2023
e17e564
Set scrim to site background color
artemiomorales Apr 26, 2023
f481a35
Remove extraneous image CSS declaration
artemiomorales Apr 26, 2023
848a8fa
Improve aria labeling
artemiomorales May 2, 2023
2204a50
Code cleanup; simplify syntax, consolidate code
artemiomorales May 3, 2023
6244e14
Refactor code, remove event listeners, consolidate logic
artemiomorales May 3, 2023
c388721
Fix formatting in SCSS file
artemiomorales May 3, 2023
9754edb
Change CheckboxControl to a ToggleControl; update API docs
artemiomorales May 3, 2023
b337272
Update wp_enqueue_script to correctly add interactivity runtime
artemiomorales May 3, 2023
ee679e6
Fix linter errors
artemiomorales May 4, 2023
ddbf32c
Update to use core.image namespace
artemiomorales May 4, 2023
f82d8f5
Pause closing of lightbox slightly when using the mousewheel
artemiomorales May 4, 2023
8ce00cd
Rename portal directive to 'wp-body' and remove unused reference
artemiomorales May 4, 2023
1427e8a
Add internal dependencies flag; update comment
artemiomorales May 4, 2023
58b0ef5
Remove extraneous code
artemiomorales May 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add interactivity runtime
Co-authored-by: David Arenas <[email protected]>
  • Loading branch information
2 people authored and gziolo committed Apr 28, 2023
commit ebba7b4f68d8ad0b79f7d92ff5c7640cb7207cb3
64 changes: 52 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/block-library/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
],
"dependencies": {
"@babel/runtime": "^7.16.0",
"@preact/signals": "^1.1.3",
"@wordpress/a11y": "file:../a11y",
"@wordpress/api-fetch": "file:../api-fetch",
"@wordpress/autop": "file:../autop",
Expand Down Expand Up @@ -63,12 +64,14 @@
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.7.0",
"deepsignal": "^1.3.0",
"escape-html": "^1.0.3",
"fast-average-color": "^9.1.1",
"fast-deep-equal": "^3.1.3",
"lodash": "^4.17.21",
"memize": "^1.1.0",
"micromodal": "^0.4.10",
"preact": "^10.13.2",
"remove-accents": "^0.4.2"
},
"peerDependencies": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const directivePrefix = 'data-wp-';
178 changes: 178 additions & 0 deletions packages/block-library/src/utils/interactivity/directives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/**
* External dependencies
*/
import { useContext, useMemo, useEffect } from 'preact/hooks';
import { useSignalEffect } from '@preact/signals';
import { deepSignal, peek } from 'deepsignal';
/**
* Internal dependencies
*/
import { directive } from './hooks';

const isObject = ( item ) =>
item && typeof item === 'object' && ! Array.isArray( item );

const mergeDeepSignals = ( target, source ) => {
for ( const k in source ) {
if ( typeof peek( target, k ) === 'undefined' ) {
target[ `$${ k }` ] = source[ `$${ k }` ];
} else if (
isObject( peek( target, k ) ) &&
isObject( peek( source, k ) )
) {
mergeDeepSignals(
target[ `$${ k }` ].peek(),
source[ `$${ k }` ].peek()
);
}
}
};

export default () => {
// data-wp-context
directive(
'context',
( {
directives: {
context: { default: context },
},
props: { children },
context: inherited,
} ) => {
const { Provider } = inherited;
const inheritedValue = useContext( inherited );
const value = useMemo( () => {
const localValue = deepSignal( context );
mergeDeepSignals( localValue, inheritedValue );
return localValue;
}, [ context, inheritedValue ] );

return <Provider value={ value }>{ children }</Provider>;
}
);

// data-wp-effect.[name]
directive( 'effect', ( { directives: { effect }, context, evaluate } ) => {
const contextValue = useContext( context );
Object.values( effect ).forEach( ( path ) => {
useSignalEffect( () => {
return evaluate( path, { context: contextValue } );
} );
} );
} );

// data-wp-init.[name]
directive( 'init', ( { directives: { init }, context, evaluate } ) => {
const contextValue = useContext( context );
Object.values( init ).forEach( ( path ) => {
useEffect( () => {
return evaluate( path, { context: contextValue } );
}, [] );
} );
} );

// data-wp-on.[event]
directive( 'on', ( { directives: { on }, element, evaluate, context } ) => {
const contextValue = useContext( context );
Object.entries( on ).forEach( ( [ name, path ] ) => {
element.props[ `on${ name }` ] = ( event ) => {
return evaluate( path, { event, context: contextValue } );
};
} );
} );

// data-wp-class.[classname]
directive(
'class',
( {
directives: { class: className },
element,
evaluate,
context,
} ) => {
const contextValue = useContext( context );
Object.keys( className )
.filter( ( n ) => n !== 'default' )
.forEach( ( name ) => {
const result = evaluate( className[ name ], {
className: name,
context: contextValue,
} );
const currentClass = element.props.class || '';
const classFinder = new RegExp(
`(^|\\s)${ name }(\\s|$)`,
'g'
);
if ( ! result )
element.props.class = currentClass
.replace( classFinder, ' ' )
.trim();
else if ( ! classFinder.test( currentClass ) )
element.props.class = currentClass
? `${ currentClass } ${ name }`
: name;

useEffect( () => {
// This seems necessary because Preact doesn't change the class
// names on the hydration, so we have to do it manually. It doesn't
// need deps because it only needs to do it the first time.
if ( ! result ) {
element.ref.current.classList.remove( name );
} else {
element.ref.current.classList.add( name );
}
}, [] );
} );
}
);

// data-wp-bind.[attribute]
directive(
'bind',
( { directives: { bind }, element, context, evaluate } ) => {
const contextValue = useContext( context );
Object.entries( bind )
.filter( ( n ) => n !== 'default' )
.forEach( ( [ attribute, path ] ) => {
const result = evaluate( path, {
context: contextValue,
} );
element.props[ attribute ] = result;

useEffect( () => {
// This seems necessary because Preact doesn't change the attributes
// on the hydration, so we have to do it manually. It doesn't need
// deps because it only needs to do it the first time.
if ( result === false ) {
element.ref.current.removeAttribute( attribute );
} else {
element.ref.current.setAttribute(
attribute,
result === true ? '' : result
);
}
}, [] );
} );
}
);

// data-wp-ignore
directive(
'ignore',
( {
element: {
type: Type,
props: { innerHTML, ...rest },
},
} ) => {
// Preserve the initial inner HTML.
const cached = useMemo( () => innerHTML, [] );
return (
<Type
dangerouslySetInnerHTML={ { __html: cached } }
{ ...rest }
/>
);
}
);
};
Loading