Skip to content

Commit

Permalink
Revert "Interactivity API: Remove data-wp-slot and data-wp-fill (#…
Browse files Browse the repository at this point in the history
…57854)"

This reverts commit f6d29bd.
  • Loading branch information
DAreRodz committed Nov 14, 2024
1 parent 204fa39 commit e57bc5f
Show file tree
Hide file tree
Showing 6 changed files with 391 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "test/directive-slots",
"title": "E2E Interactivity tests - directive slots",
"category": "text",
"icon": "heart",
"description": "",
"supports": {
"interactivity": true
},
"textdomain": "e2e-interactivity",
"viewScript": "directive-slots-view",
"render": "file:./render.php"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
/**
* HTML for testing the directive `data-wp-bind`.
*
* @package gutenberg-test-interactive-blocks
*/

gutenberg_enqueue_module( 'directive-slots-view' );
?>

<div
data-wp-interactive='{ "namespace": "directive-slots" }'
data-wp-slot-provider
data-wp-context='{ "text": "fill" }'
>
<div data-testid="slots" data-wp-context='{ "text": "fill inside slots" }'>
<div
data-testid="slot-1"
data-wp-key="slot-1"
data-wp-slot="slot-1"
data-wp-context='{ "text": "fill inside slot 1" }'
>[1]</div>
<div
data-testid="slot-2"
data-wp-key="slot-2"
data-wp-slot='{ "name": "slot-2", "position": "before" }'
data-wp-context='{ "text": "[2]" }'
data-wp-text='context.text'
data-wp-on--click="actions.updateSlotText"
>[2]</div>
<div
data-testid="slot-3"
data-wp-key="slot-3"
data-wp-slot='{ "name": "slot-3", "position": "after" }'
data-wp-context='{ "text": "[3]" }'
data-wp-text='context.text'
data-wp-on--click="actions.updateSlotText"
>[3]</div>
<div
data-testid="slot-4"
data-wp-key="slot-4"
data-wp-slot='{ "name": "slot-4", "position": "children" }'
data-wp-context='{ "text": "fill inside slot 4" }'
>[4]</div>
<div
data-testid="slot-5"
data-wp-key="slot-5"
data-wp-slot='{ "name": "slot-5", "position": "replace" }'
data-wp-context='{ "text": "fill inside slot 5" }'
>[5]</div>
</div>

<div data-testid="fill-container">
<span
data-testid="fill"
data-wp-fill="state.slot"
data-wp-text="context.text"
>initial</span>
</div>

<div data-wp-on--click="actions.changeSlot">
<button data-testid="slot-1-button" data-slot="slot-1">slot-1</button>
<button data-testid="slot-2-button" data-slot="slot-2">slot-2</button>
<button data-testid="slot-3-button" data-slot="slot-3">slot-3</button>
<button data-testid="slot-4-button" data-slot="slot-4">slot-4</button>
<button data-testid="slot-5-button" data-slot="slot-5">slot-5</button>
<button data-testid="reset" data-slot="">reset</button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* WordPress dependencies
*/
import { store, getContext } from '@wordpress/interactivity';

const { state } = store( 'directive-slots', {
state: {
slot: '',
},
actions: {
changeSlot( event ) {
state.slot = event.target.dataset.slot;
},
updateSlotText() {
const context = getContext();
const n = context.text[ 1 ];
context.text = `[${ n } updated]`;
},
},
} );
65 changes: 64 additions & 1 deletion packages/interactivity/src/directives.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/**
* External dependencies
*/
import { h as createElement, type RefObject } from 'preact';
import { h as createElement, Fragment, type RefObject } from 'preact';
import { useContext, useMemo, useRef } from 'preact/hooks';

/**
Expand All @@ -28,6 +28,7 @@ import {
} from './hooks';
import { getScope } from './scopes';
import { proxifyState, proxifyContext, deepMerge } from './proxies';
import { SlotProvider, Slot, Fill } from './slots';

/**
* Recursively clone the passed object.
Expand Down Expand Up @@ -607,4 +608,66 @@ export default () => {
);

directive( 'each-child', () => null, { priority: 1 } );

// data-wp-slot
directive(
'slot',
( { directives: { slot }, props: { children }, element } ) => {
const entry = slot.find( ( { suffix } ) => suffix === null )!;
const value = entry.value as
| string
| { name: string; position: string };

const name = typeof value === 'string' ? value : value.name;
const position =
typeof value === 'string'
? 'children'
: value.position || 'children';

if ( position === 'before' ) {
return createElement( Fragment, {}, [
createElement( Slot, { name } ),
children,
] );
}
if ( position === 'after' ) {
return createElement( Fragment, {}, [
children,
createElement( Slot, { name } ),
] );
}
if ( position === 'replace' ) {
return createElement( Slot, { name }, children );
}
if ( position === 'children' ) {
element.props.children = createElement(
Slot,
{ name },
element.props.children
);
}

return undefined;
},
{ priority: 4 }
);

// data-wp-fill
directive(
'fill',
( { directives: { fill }, props: { children }, evaluate } ) => {
const entry = fill.find( ( { suffix } ) => suffix === null )!;
const slot = evaluate( entry );
return createElement( Fill, { slot }, children );
},
{ priority: 4 }
);

// data-wp-slot-provider
directive(
'slot-provider',
( { props: { children } } ) =>
createElement( SlotProvider, null, children ),
{ priority: 4 }
);
};
37 changes: 37 additions & 0 deletions packages/interactivity/src/slots.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* External dependencies
*/
import { h, createContext } from 'preact';
import { useContext, useEffect } from 'preact/hooks';
import { signal } from '@preact/signals';

const slotsContext = createContext( { value: {} } );

export const Fill = ( { slot, children = null } ) => {
const slots = useContext( slotsContext );

useEffect( () => {
if ( slot ) {
slots.value = { ...slots.value, [ slot ]: children };
return () => {
slots.value = { ...slots.value, [ slot ]: null };
};
}
return undefined;
}, [ slots, slot, children ] );

return !! slot ? null : children;
};

export const SlotProvider = ( { children } ) => {
return (
// TODO: We can change this to use deepsignal once this PR is merged.
// https://github.com/luisherranz/deepsignal/pull/38
h( slotsContext.Provider, { value: signal( {} ) }, children )
);
};

export const Slot = ( { name, children = null } ) => {
const slots = useContext( slotsContext );
return slots.value[ name ] || children;
};
Loading

0 comments on commit e57bc5f

Please sign in to comment.