2023-11-21 10:46:15 +00:00
|
|
|
// @ts-nocheck
|
|
|
|
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
2023-11-15 03:50:05 +00:00
|
|
|
import {
|
|
|
|
useContext,
|
|
|
|
useMemo,
|
|
|
|
useEffect,
|
|
|
|
useRef,
|
2023-11-21 10:46:15 +00:00
|
|
|
useLayoutEffect,
|
2023-11-15 03:50:05 +00:00
|
|
|
} from 'preact/hooks';
|
2023-02-20 16:48:33 +00:00
|
|
|
import { deepSignal, peek } from 'deepsignal';
|
2023-11-21 10:46:15 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
|
|
|
import { createPortal } from './portals';
|
2023-06-27 10:22:12 +00:00
|
|
|
import { useSignalEffect } from './utils';
|
2023-12-22 00:34:28 +00:00
|
|
|
import { directive, getScope, getEvaluate } from './hooks';
|
2023-11-21 10:46:15 +00:00
|
|
|
import { SlotProvider, Slot, Fill } from './slots';
|
|
|
|
import { navigate } from './router';
|
2023-01-26 11:39:25 +00:00
|
|
|
|
2023-02-20 16:48:33 +00:00
|
|
|
const isObject = ( item ) =>
|
|
|
|
item && typeof item === 'object' && ! Array.isArray( item );
|
|
|
|
|
2023-11-15 03:50:05 +00:00
|
|
|
const mergeDeepSignals = ( target, source, overwrite ) => {
|
2023-02-20 16:48:33 +00:00
|
|
|
for ( const k in source ) {
|
2023-11-15 03:50:05 +00:00
|
|
|
if ( isObject( peek( target, k ) ) && isObject( peek( source, k ) ) ) {
|
2023-02-20 16:48:33 +00:00
|
|
|
mergeDeepSignals(
|
|
|
|
target[ `$${ k }` ].peek(),
|
2023-11-15 03:50:05 +00:00
|
|
|
source[ `$${ k }` ].peek(),
|
|
|
|
overwrite
|
2023-02-20 16:48:33 +00:00
|
|
|
);
|
2023-12-22 00:34:28 +00:00
|
|
|
} else if ( typeof peek( target, k ) === 'undefined' ) {
|
2023-11-15 03:50:05 +00:00
|
|
|
target[ `$${ k }` ] = source[ `$${ k }` ];
|
2023-12-22 00:34:28 +00:00
|
|
|
} else if ( overwrite ) {
|
|
|
|
target[ k ] = peek( source, k );
|
2023-02-20 16:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-12-22 00:34:28 +00:00
|
|
|
const deepClone = ( o ) => {
|
|
|
|
if ( isObject( o ) )
|
|
|
|
return Object.fromEntries(
|
|
|
|
Object.entries( o ).map( ( [ k, v ] ) => [ k, deepClone( v ) ] )
|
|
|
|
);
|
|
|
|
if ( Array.isArray( o ) ) {
|
|
|
|
return [ ...o.map( ( i ) => deepClone( i ) ) ];
|
|
|
|
}
|
|
|
|
return o;
|
|
|
|
};
|
|
|
|
|
2023-01-26 11:39:25 +00:00
|
|
|
export default () => {
|
2023-06-27 10:22:12 +00:00
|
|
|
// data-wc-context
|
2023-01-26 11:39:25 +00:00
|
|
|
directive(
|
|
|
|
'context',
|
|
|
|
( {
|
2023-11-21 10:46:15 +00:00
|
|
|
directives: { context },
|
2023-01-26 11:39:25 +00:00
|
|
|
props: { children },
|
2023-11-15 03:50:05 +00:00
|
|
|
context: inheritedContext,
|
2023-01-26 11:39:25 +00:00
|
|
|
} ) => {
|
2023-11-15 03:50:05 +00:00
|
|
|
const { Provider } = inheritedContext;
|
|
|
|
const inheritedValue = useContext( inheritedContext );
|
|
|
|
const currentValue = useRef( deepSignal( {} ) );
|
2023-11-21 10:46:15 +00:00
|
|
|
const passedValues = context.map( ( { value } ) => value );
|
|
|
|
|
2023-11-15 03:50:05 +00:00
|
|
|
currentValue.current = useMemo( () => {
|
2023-11-21 10:46:15 +00:00
|
|
|
const newValue = context
|
2023-12-22 00:34:28 +00:00
|
|
|
.map( ( c ) =>
|
|
|
|
deepSignal( { [ c.namespace ]: deepClone( c.value ) } )
|
|
|
|
)
|
2023-11-21 10:46:15 +00:00
|
|
|
.reduceRight( mergeDeepSignals );
|
|
|
|
|
2023-11-15 03:50:05 +00:00
|
|
|
mergeDeepSignals( newValue, inheritedValue );
|
|
|
|
mergeDeepSignals( currentValue.current, newValue, true );
|
|
|
|
return currentValue.current;
|
2023-11-21 10:46:15 +00:00
|
|
|
}, [ inheritedValue, ...passedValues ] );
|
2023-02-20 16:48:33 +00:00
|
|
|
|
2023-11-15 03:50:05 +00:00
|
|
|
return (
|
|
|
|
<Provider value={ currentValue.current }>{ children }</Provider>
|
|
|
|
);
|
2023-06-27 10:22:12 +00:00
|
|
|
},
|
|
|
|
{ priority: 5 }
|
2023-01-26 11:39:25 +00:00
|
|
|
);
|
|
|
|
|
2023-11-21 10:46:15 +00:00
|
|
|
// data-wc-body
|
|
|
|
directive( 'body', ( { props: { children } } ) => {
|
|
|
|
return createPortal( children, document.body );
|
|
|
|
} );
|
|
|
|
|
|
|
|
// data-wc-watch--[name]
|
|
|
|
directive( 'watch', ( { directives: { watch }, evaluate } ) => {
|
|
|
|
watch.forEach( ( entry ) => {
|
|
|
|
useSignalEffect( () => evaluate( entry ) );
|
2023-01-26 11:39:25 +00:00
|
|
|
} );
|
|
|
|
} );
|
|
|
|
|
2023-09-05 12:37:38 +00:00
|
|
|
// data-wc-layout-init--[name]
|
|
|
|
directive(
|
|
|
|
'layout-init',
|
2023-11-21 10:46:15 +00:00
|
|
|
( { directives: { 'layout-init': layoutInit }, evaluate } ) => {
|
|
|
|
layoutInit.forEach( ( entry ) => {
|
|
|
|
useLayoutEffect( () => evaluate( entry ), [] );
|
2023-09-05 12:37:38 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2023-10-27 01:59:57 +00:00
|
|
|
// data-wc-init--[name]
|
2023-11-21 10:46:15 +00:00
|
|
|
directive( 'init', ( { directives: { init }, evaluate } ) => {
|
|
|
|
init.forEach( ( entry ) => {
|
|
|
|
useEffect( () => evaluate( entry ), [] );
|
2023-10-27 01:59:57 +00:00
|
|
|
} );
|
|
|
|
} );
|
|
|
|
|
2023-06-27 10:22:12 +00:00
|
|
|
// data-wc-on--[event]
|
2023-11-21 10:46:15 +00:00
|
|
|
directive( 'on', ( { directives: { on }, element, evaluate } ) => {
|
2023-11-27 04:26:01 +00:00
|
|
|
const events = new Map();
|
2023-11-21 10:46:15 +00:00
|
|
|
on.forEach( ( entry ) => {
|
2023-11-27 04:26:01 +00:00
|
|
|
const event = entry.suffix.split( '--' )[ 0 ];
|
|
|
|
if ( ! events.has( event ) ) events.set( event, new Set() );
|
|
|
|
events.get( event ).add( entry );
|
|
|
|
} );
|
|
|
|
|
|
|
|
events.forEach( ( entries, event ) => {
|
|
|
|
element.props[ `on${ event }` ] = ( event ) => {
|
|
|
|
entries.forEach( ( entry ) => {
|
|
|
|
evaluate( entry, event );
|
|
|
|
} );
|
2023-01-26 11:39:25 +00:00
|
|
|
};
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
|
2023-06-27 10:22:12 +00:00
|
|
|
// data-wc-class--[classname]
|
2023-01-26 11:39:25 +00:00
|
|
|
directive(
|
|
|
|
'class',
|
2023-11-21 10:46:15 +00:00
|
|
|
( { directives: { class: className }, element, evaluate } ) => {
|
|
|
|
className
|
|
|
|
.filter( ( { suffix } ) => suffix !== 'default' )
|
|
|
|
.forEach( ( entry ) => {
|
|
|
|
const name = entry.suffix;
|
|
|
|
const result = evaluate( entry, { className: name } );
|
2023-02-28 16:33:33 +00:00
|
|
|
const currentClass = element.props.class || '';
|
|
|
|
const classFinder = new RegExp(
|
|
|
|
`(^|\\s)${ name }(\\s|$)`,
|
|
|
|
'g'
|
|
|
|
);
|
2023-01-26 11:39:25 +00:00
|
|
|
if ( ! result )
|
2023-02-28 16:33:33 +00:00
|
|
|
element.props.class = currentClass
|
|
|
|
.replace( classFinder, ' ' )
|
2023-01-26 11:39:25 +00:00
|
|
|
.trim();
|
2023-02-28 16:33:33 +00:00
|
|
|
else if ( ! classFinder.test( currentClass ) )
|
|
|
|
element.props.class = currentClass
|
|
|
|
? `${ currentClass } ${ name }`
|
|
|
|
: name;
|
2023-01-26 11:39:25 +00:00
|
|
|
|
|
|
|
useEffect( () => {
|
2023-11-21 10:46:15 +00:00
|
|
|
// 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.
|
2023-01-26 11:39:25 +00:00
|
|
|
if ( ! result ) {
|
|
|
|
element.ref.current.classList.remove( name );
|
|
|
|
} else {
|
|
|
|
element.ref.current.classList.add( name );
|
|
|
|
}
|
|
|
|
}, [] );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2023-11-21 10:46:15 +00:00
|
|
|
const newRule =
|
|
|
|
/(?:([\u0080-\uFFFF\w-%@]+) *:? *([^{;]+?);|([^;}{]*?) *{)|(}\s*)/g;
|
|
|
|
const ruleClean = /\/\*[^]*?\*\/| +/g;
|
|
|
|
const ruleNewline = /\n+/g;
|
|
|
|
const empty = ' ';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert a css style string into a object.
|
|
|
|
*
|
|
|
|
* Made by Cristian Bote (@cristianbote) for Goober.
|
|
|
|
* https://unpkg.com/browse/goober@2.1.13/src/core/astish.js
|
|
|
|
*
|
|
|
|
* @param {string} val CSS string.
|
|
|
|
* @return {Object} CSS object.
|
|
|
|
*/
|
|
|
|
const cssStringToObject = ( val ) => {
|
|
|
|
const tree = [ {} ];
|
|
|
|
let block, left;
|
|
|
|
|
|
|
|
while ( ( block = newRule.exec( val.replace( ruleClean, '' ) ) ) ) {
|
|
|
|
if ( block[ 4 ] ) {
|
|
|
|
tree.shift();
|
|
|
|
} else if ( block[ 3 ] ) {
|
|
|
|
left = block[ 3 ].replace( ruleNewline, empty ).trim();
|
|
|
|
tree.unshift( ( tree[ 0 ][ left ] = tree[ 0 ][ left ] || {} ) );
|
|
|
|
} else {
|
|
|
|
tree[ 0 ][ block[ 1 ] ] = block[ 2 ]
|
|
|
|
.replace( ruleNewline, empty )
|
|
|
|
.trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return tree[ 0 ];
|
|
|
|
};
|
|
|
|
|
|
|
|
// data-wc-style--[style-key]
|
|
|
|
directive( 'style', ( { directives: { style }, element, evaluate } ) => {
|
|
|
|
style
|
|
|
|
.filter( ( { suffix } ) => suffix !== 'default' )
|
|
|
|
.forEach( ( entry ) => {
|
|
|
|
const key = entry.suffix;
|
|
|
|
const result = evaluate( entry, { key } );
|
|
|
|
element.props.style = element.props.style || {};
|
|
|
|
if ( typeof element.props.style === 'string' )
|
|
|
|
element.props.style = cssStringToObject(
|
|
|
|
element.props.style
|
|
|
|
);
|
|
|
|
if ( ! result ) delete element.props.style[ key ];
|
|
|
|
else element.props.style[ key ] = result;
|
|
|
|
|
|
|
|
useEffect( () => {
|
|
|
|
// This seems necessary because Preact doesn't change the styles 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.style.removeProperty( key );
|
|
|
|
} else {
|
|
|
|
element.ref.current.style[ key ] = result;
|
|
|
|
}
|
|
|
|
}, [] );
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
|
2023-06-27 10:22:12 +00:00
|
|
|
// data-wc-bind--[attribute]
|
2023-11-21 10:46:15 +00:00
|
|
|
directive( 'bind', ( { directives: { bind }, element, evaluate } ) => {
|
|
|
|
bind.filter( ( { suffix } ) => suffix !== 'default' ).forEach(
|
|
|
|
( entry ) => {
|
|
|
|
const attribute = entry.suffix;
|
|
|
|
const result = evaluate( entry );
|
|
|
|
element.props[ attribute ] = result;
|
|
|
|
// Preact doesn't handle the `role` attribute properly, as it doesn't remove it when `null`.
|
|
|
|
// We need this workaround until the following issue is solved:
|
|
|
|
// https://github.com/preactjs/preact/issues/4136
|
|
|
|
useLayoutEffect( () => {
|
|
|
|
if (
|
|
|
|
attribute === 'role' &&
|
|
|
|
( result === null || result === undefined )
|
|
|
|
) {
|
|
|
|
element.ref.current.removeAttribute( attribute );
|
|
|
|
}
|
|
|
|
}, [ attribute, result ] );
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
useEffect( () => {
|
|
|
|
const el = element.ref.current;
|
|
|
|
|
|
|
|
// We set the value directly to the corresponding
|
|
|
|
// HTMLElement instance property excluding the following
|
|
|
|
// special cases.
|
|
|
|
// We follow Preact's logic: https://github.com/preactjs/preact/blob/ea49f7a0f9d1ff2c98c0bdd66aa0cbc583055246/src/diff/props.js#L110-L129
|
|
|
|
if (
|
|
|
|
attribute !== 'width' &&
|
|
|
|
attribute !== 'height' &&
|
|
|
|
attribute !== 'href' &&
|
|
|
|
attribute !== 'list' &&
|
|
|
|
attribute !== 'form' &&
|
|
|
|
// Default value in browsers is `-1` and an empty string is
|
|
|
|
// cast to `0` instead
|
|
|
|
attribute !== 'tabIndex' &&
|
|
|
|
attribute !== 'download' &&
|
|
|
|
attribute !== 'rowSpan' &&
|
|
|
|
attribute !== 'colSpan' &&
|
|
|
|
attribute !== 'role' &&
|
|
|
|
attribute in el
|
|
|
|
) {
|
|
|
|
try {
|
|
|
|
el[ attribute ] =
|
|
|
|
result === null || result === undefined
|
2023-06-27 10:22:12 +00:00
|
|
|
? ''
|
2023-11-21 10:46:15 +00:00
|
|
|
: result;
|
|
|
|
return;
|
|
|
|
} catch ( err ) {}
|
|
|
|
}
|
|
|
|
// aria- and data- attributes have no boolean representation.
|
|
|
|
// A `false` value is different from the attribute not being
|
|
|
|
// present, so we can't remove it.
|
|
|
|
// We follow Preact's logic: https://github.com/preactjs/preact/blob/ea49f7a0f9d1ff2c98c0bdd66aa0cbc583055246/src/diff/props.js#L131C24-L136
|
|
|
|
if (
|
|
|
|
result !== null &&
|
|
|
|
result !== undefined &&
|
|
|
|
( result !== false || attribute[ 4 ] === '-' )
|
|
|
|
) {
|
|
|
|
el.setAttribute( attribute, result );
|
|
|
|
} else {
|
|
|
|
el.removeAttribute( attribute );
|
|
|
|
}
|
|
|
|
}, [] );
|
|
|
|
}
|
|
|
|
);
|
|
|
|
} );
|
2023-01-26 11:39:25 +00:00
|
|
|
|
2023-08-03 08:55:13 +00:00
|
|
|
// data-wc-navigation-link
|
2023-01-26 11:39:25 +00:00
|
|
|
directive(
|
2023-08-03 08:55:13 +00:00
|
|
|
'navigation-link',
|
2023-01-26 11:39:25 +00:00
|
|
|
( {
|
2023-11-21 10:46:15 +00:00
|
|
|
directives: { 'navigation-link': navigationLink },
|
2023-01-26 11:39:25 +00:00
|
|
|
props: { href },
|
|
|
|
element,
|
|
|
|
} ) => {
|
2023-11-21 10:46:15 +00:00
|
|
|
const { value: link } = navigationLink.find(
|
|
|
|
( { suffix } ) => suffix === 'default'
|
|
|
|
);
|
|
|
|
|
2023-12-22 00:34:28 +00:00
|
|
|
// For some reason this useEffect crashes in Preact internals in some cases.
|
|
|
|
// Since it is a no-op right now, we can just comment it out.
|
|
|
|
// useEffect( () => {
|
|
|
|
// // Prefetch the page if it is in the directive options.
|
|
|
|
// if ( link?.prefetch ) {
|
|
|
|
// // prefetch( href );
|
|
|
|
// }
|
|
|
|
// } );
|
2023-01-26 11:39:25 +00:00
|
|
|
|
|
|
|
// Don't do anything if it's falsy.
|
2023-08-03 08:55:13 +00:00
|
|
|
if ( link !== false ) {
|
2023-01-26 11:39:25 +00:00
|
|
|
element.props.onclick = async ( event ) => {
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
// Fetch the page (or return it from cache).
|
|
|
|
await navigate( href );
|
|
|
|
|
|
|
|
// Update the scroll, depending on the option. True by default.
|
|
|
|
if ( link?.scroll === 'smooth' ) {
|
|
|
|
window.scrollTo( {
|
|
|
|
top: 0,
|
|
|
|
left: 0,
|
|
|
|
behavior: 'smooth',
|
|
|
|
} );
|
|
|
|
} else if ( link?.scroll !== false ) {
|
|
|
|
window.scrollTo( 0, 0 );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
2023-06-27 10:22:12 +00:00
|
|
|
|
|
|
|
// data-wc-ignore
|
|
|
|
directive(
|
|
|
|
'ignore',
|
|
|
|
( {
|
|
|
|
element: {
|
|
|
|
type: Type,
|
|
|
|
props: { innerHTML, ...rest },
|
|
|
|
},
|
|
|
|
} ) => {
|
|
|
|
// Preserve the initial inner HTML.
|
|
|
|
const cached = useMemo( () => innerHTML, [] );
|
|
|
|
return (
|
|
|
|
<Type
|
|
|
|
dangerouslySetInnerHTML={ { __html: cached } }
|
|
|
|
{ ...rest }
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
// data-wc-text
|
2023-11-21 10:46:15 +00:00
|
|
|
directive( 'text', ( { directives: { text }, element, evaluate } ) => {
|
|
|
|
const entry = text.find( ( { suffix } ) => suffix === 'default' );
|
|
|
|
element.props.children = evaluate( entry );
|
|
|
|
} );
|
|
|
|
|
|
|
|
// data-wc-slot
|
2023-06-27 10:22:12 +00:00
|
|
|
directive(
|
2023-11-21 10:46:15 +00:00
|
|
|
'slot',
|
|
|
|
( { directives: { slot }, props: { children }, element } ) => {
|
|
|
|
const { value } = slot.find(
|
|
|
|
( { suffix } ) => suffix === 'default'
|
|
|
|
);
|
|
|
|
const name = typeof value === 'string' ? value : value.name;
|
|
|
|
const position = value.position || 'children';
|
|
|
|
|
|
|
|
if ( position === 'before' ) {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<Slot name={ name } />
|
|
|
|
{ children }
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if ( position === 'after' ) {
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
{ children }
|
|
|
|
<Slot name={ name } />
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if ( position === 'replace' ) {
|
|
|
|
return <Slot name={ name }>{ children }</Slot>;
|
|
|
|
}
|
|
|
|
if ( position === 'children' ) {
|
|
|
|
element.props.children = (
|
|
|
|
<Slot name={ name }>{ element.props.children }</Slot>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{ priority: 4 }
|
|
|
|
);
|
|
|
|
|
|
|
|
// data-wc-fill
|
|
|
|
directive(
|
|
|
|
'fill',
|
|
|
|
( { directives: { fill }, props: { children }, evaluate } ) => {
|
|
|
|
const entry = fill.find( ( { suffix } ) => suffix === 'default' );
|
|
|
|
const slot = evaluate( entry );
|
|
|
|
return <Fill slot={ slot }>{ children }</Fill>;
|
|
|
|
},
|
|
|
|
{ priority: 4 }
|
|
|
|
);
|
|
|
|
|
|
|
|
// data-wc-slot-provider
|
|
|
|
directive(
|
|
|
|
'slot-provider',
|
|
|
|
( { props: { children } } ) => (
|
|
|
|
<SlotProvider>{ children }</SlotProvider>
|
|
|
|
),
|
|
|
|
{ priority: 4 }
|
2023-06-27 10:22:12 +00:00
|
|
|
);
|
2023-12-22 00:34:28 +00:00
|
|
|
|
|
|
|
directive(
|
|
|
|
'each',
|
|
|
|
( {
|
|
|
|
directives: {
|
|
|
|
each,
|
|
|
|
'each-key': [ eachKey ],
|
|
|
|
},
|
|
|
|
context: inheritedContext,
|
|
|
|
element,
|
|
|
|
evaluate,
|
|
|
|
} ) => {
|
|
|
|
const { Provider } = inheritedContext;
|
|
|
|
const inheritedValue = useContext( inheritedContext );
|
|
|
|
|
|
|
|
const [ entry ] = each;
|
|
|
|
const { namespace, suffix } = entry;
|
|
|
|
|
|
|
|
const list = evaluate( entry );
|
|
|
|
return list.map( ( item ) => {
|
|
|
|
const mergedContext = deepSignal( {} );
|
|
|
|
|
|
|
|
const itemProp = suffix === 'default' ? 'item' : suffix;
|
|
|
|
const newValue = deepSignal( {
|
|
|
|
[ namespace ]: { [ itemProp ]: item },
|
|
|
|
} );
|
|
|
|
mergeDeepSignals( newValue, inheritedValue );
|
|
|
|
mergeDeepSignals( mergedContext, newValue, true );
|
|
|
|
|
|
|
|
const scope = { ...getScope(), context: mergedContext };
|
|
|
|
const key = getEvaluate( { scope } )( eachKey );
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Provider value={ mergedContext } key={ key }>
|
|
|
|
{ element.props.content }
|
|
|
|
</Provider>
|
|
|
|
);
|
|
|
|
} );
|
|
|
|
},
|
|
|
|
{ priority: 20 }
|
|
|
|
);
|
|
|
|
|
|
|
|
directive( 'each-child', () => null );
|
2023-01-26 11:39:25 +00:00
|
|
|
};
|