diff --git a/block-hydration-experiments.php b/block-hydration-experiments.php index 39e191be..6ed2656d 100644 --- a/block-hydration-experiments.php +++ b/block-hydration-experiments.php @@ -2,83 +2,110 @@ /** * Plugin Name: block-hydration-experiments * Version: 0.1.0 - * Requires at least: 5.9 - * Requires PHP: 7.0 + * Requires at least: 6.0 + * Requires PHP: 5.6 * Author: Gutenberg Team * License: GPL-2.0-or-later * License URI: https://www.gnu.org/licenses/gpl-2.0.html * Text Domain: block-hydration-experiments */ -function block_hydration_experiments_init() { - register_block_type( plugin_dir_path( __FILE__ ) . 'build/blocks/block-hydration-experiments-child/' ); - register_block_type( plugin_dir_path( __FILE__ ) . 'build/blocks/block-hydration-experiments-parent/' ); +function block_hydration_experiments_init() +{ + register_block_type( + plugin_dir_path(__FILE__) . 'build/blocks/interactive-child/' + ); + register_block_type( + plugin_dir_path(__FILE__) . 'build/blocks/interactive-parent/' + ); + register_block_type( + plugin_dir_path(__FILE__) . 'build/blocks/non-interactive-parent/' + ); } -add_action( 'init', 'block_hydration_experiments_init' ); +add_action('init', 'block_hydration_experiments_init'); -function bhe_block_wrapper( $block_content, $block, $instance ) { +function bhe_block_wrapper($block_content, $block, $instance) +{ // We might want to use a flag from block.json as the criterion here. - if ( ! in_array( - $block['blockName'], - array( - 'bhe/block-hydration-experiments-parent', - 'bhe/block-hydration-experiments-child' - ), - true - ) ) { + if ( + !in_array( + $block['blockName'], + [ + 'bhe/interactive-parent', + 'bhe/interactive-child', + 'bhe/non-interactive-parent', + ], + true + ) + ) { return $block_content; } $block_type = $instance->block_type; $attr_definitions = $block_type->attributes; - $attributes = array(); - $sourced_attributes = array(); - foreach( $attr_definitions as $attr => $definition ) { - if ( ! empty( $definition['frontend'] ) ) { - if ( ! empty( $definition['source'] ) ) { - $sourced_attributes[ $attr ] = array( - "selector" => $definition['selector'], // TODO: Guard against unset. - "source" => $definition['source'] - ); + $attributes = []; + $sourced_attributes = []; + foreach ($attr_definitions as $attr => $definition) { + if (!empty($definition['frontend'])) { + if (!empty($definition['source'])) { + $sourced_attributes[$attr] = [ + 'selector' => $definition['selector'], // TODO: Guard against unset. + 'source' => $definition['source'], + ]; } else { - if ( array_key_exists ( $attr, $block['attrs'] ) ) { - $attributes[ $attr ] = $block['attrs'][$attr]; - } else if ( isset( $definition['default'] ) ) { - $attributes[ $attr ] = $definition['default']; + if (array_key_exists($attr, $block['attrs'])) { + $attributes[$attr] = $block['attrs'][$attr]; + } elseif (isset($definition['default'])) { + $attributes[$attr] = $definition['default']; } } } } - $previous_block_to_render = WP_Block_Supports::$block_to_render; - // TODO: The following is a bit hacky. If we stick with this technique, we might + // We might want to use a flag from block.json as the criterion here. + $hydration_technique = in_array( + $block['blockName'], + ['bhe/interactive-parent', 'bhe/interactive-child'], + true + ) + ? 'idle' + : false; + + // The following is a bit hacky. If we stick with this technique, we might // want to change apply_block_supports() to accepts a block as its argument. + $previous_block_to_render = WP_Block_Supports::$block_to_render; WP_Block_Supports::$block_to_render = $block; - $block_supports_attributes = WP_Block_Supports::get_instance()->apply_block_supports(); + $block_props = WP_Block_Supports::get_instance()->apply_block_supports(); WP_Block_Supports::$block_to_render = $previous_block_to_render; - $block_wrapper = sprintf( - '', - esc_attr( $block['blockName'] ), - esc_attr( json_encode( $block_type->uses_context ) ), - esc_attr( json_encode( $block_type->provides_context ) ), - esc_attr( json_encode( $attributes ) ), - esc_attr( json_encode( $sourced_attributes ) ), - esc_attr( json_encode( $block_supports_attributes ) ) - ) . '%1$s'; + $block_wrapper = + sprintf( + '', + esc_attr($block['blockName']), + esc_attr(json_encode($block_type->uses_context)), + esc_attr(json_encode($block_type->provides_context)), + esc_attr(json_encode($attributes)), + esc_attr(json_encode($sourced_attributes)), + esc_attr(json_encode($block_props)), + esc_attr($hydration_technique) + ) . '%1$s'; - $template_wrapper = ''; + $template_wrapper = + ''; - $empty_template = sprintf( $template_wrapper, '' ); - $template = sprintf( $template_wrapper, sprintf( $block_wrapper, $block_content . $empty_template ) ); - return sprintf( $block_wrapper, $block_content . $template ); + $empty_template = sprintf($template_wrapper, ''); + $template = sprintf( + $template_wrapper, + sprintf($block_wrapper, $block_content . $empty_template) + ); + return sprintf($block_wrapper, $block_content); } -add_filter( 'render_block', 'bhe_block_wrapper', 10, 3 ); \ No newline at end of file +add_filter('render_block', 'bhe_block_wrapper', 10, 3); diff --git a/package-lock.json b/package-lock.json index d2e747dc..78e43365 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2386,6 +2386,17 @@ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, + "@prettier/plugin-php": { + "version": "0.18.9", + "resolved": "https://registry.npmjs.org/@prettier/plugin-php/-/plugin-php-0.18.9.tgz", + "integrity": "sha512-d1uE9v3JsQ9uBLWlssZhO02RLI8u8jRBFPCO5ud4VbveCpSZbDRnGpSuK3IqSWHdM/OnuySz0yWr5M9/9mINvw==", + "dev": true, + "requires": { + "linguist-languages": "^7.21.0", + "mem": "^8.0.0", + "php-parser": "3.1.0-beta.11" + } + }, "@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -11334,6 +11345,12 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, + "linguist-languages": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/linguist-languages/-/linguist-languages-7.21.0.tgz", + "integrity": "sha512-KrWJJbFOvlDhjlt5OhUipVlXg+plUfRurICAyij1ZVxQcqPt/zeReb9KiUVdGUwwhS/2KS9h3TbyfYLA5MDlxQ==", + "dev": true + }, "linkify-it": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", @@ -11481,6 +11498,15 @@ "tmpl": "1.0.5" } }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, "map-obj": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", @@ -11628,6 +11654,24 @@ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, + "mem": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz", + "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^3.1.0" + }, + "dependencies": { + "mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "dev": true + } + } + }, "memfs": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.3.tgz", @@ -12479,6 +12523,12 @@ "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", "dev": true }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "dev": true + }, "p-event": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", @@ -12659,6 +12709,12 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "php-parser": { + "version": "3.1.0-beta.11", + "resolved": "https://registry.npmjs.org/php-parser/-/php-parser-3.1.0-beta.11.tgz", + "integrity": "sha512-aKhWHXun6FKa0MX+GcJtEoLPSWuGQTiEkNgckVjT95OAnKG33c+zsDQEpXx4R74PQ030YZLNq9XV7odKapbOsg==", + "dev": true + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", diff --git a/package.json b/package.json index ec9950df..04cff562 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,13 @@ "bracketSameLine": false, "bracketSpacing": true, "semi": true, - "arrowParens": "always" + "arrowParens": "always", + "phpVersion": "5.6" }, "devDependencies": { "@babel/core": "^7.17.10", "@babel/preset-env": "^7.17.10", + "@prettier/plugin-php": "^0.18.9", "@types/jest": "^27.5.1", "@wordpress/blocks": "^11.7.0", "@wordpress/element": "^4.3.0", diff --git a/src/blocks/block-hydration-experiments-child/style.scss b/src/blocks/block-hydration-experiments-child/style.scss deleted file mode 100644 index 608dce0d..00000000 --- a/src/blocks/block-hydration-experiments-child/style.scss +++ /dev/null @@ -1,9 +0,0 @@ -.wp-block-bhe-block-hydration-experiments-child { - padding: 15px 10px 15px 50px; - background-color: rgb(238, 237, 237); -} - -gutenberg-block, -gutenberg-inner-blocks { - display: contents; -} diff --git a/src/blocks/block-hydration-experiments-parent/edit.js b/src/blocks/block-hydration-experiments-parent/edit.js deleted file mode 100644 index 0877b69c..00000000 --- a/src/blocks/block-hydration-experiments-parent/edit.js +++ /dev/null @@ -1,32 +0,0 @@ -// This import is needed to ensure that the `wp.blockEditor` global is available -// by the time this component gets loaded. The `Title` component consumes the -// global but cannot import it because it shouldn't be loaded on the frontend of -// the site. -import '@wordpress/block-editor'; - -import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; -import Button from './shared/button'; -import Title from './shared/title'; - -export default function Edit({ - attributes: { counter, message }, - setAttributes, -}) { - const blockProps = useBlockProps(); - return ( - <> -
- setAttributes({ message: val })} - placeholder="Enter the Title" - /> - <Button /> - <button onClick={() => setAttributes({ counter: counter + 1 })}> - {counter} - </button> - <InnerBlocks /> - </div> - </> - ); -} diff --git a/src/blocks/block-hydration-experiments-parent/frontend/index.js b/src/blocks/block-hydration-experiments-parent/frontend/index.js deleted file mode 100644 index f48994e4..00000000 --- a/src/blocks/block-hydration-experiments-parent/frontend/index.js +++ /dev/null @@ -1,40 +0,0 @@ -import Counter from '../../../context/counter'; -import Theme from '../../../context/theme'; -import { useState } from '../../../gutenberg-packages/wordpress-element'; -import Button from '../shared/button'; -import Title from '../shared/title'; - -const Frontend = ({ - blockProps: { - className, - style: { fontWeight, ...otherStyle }, - }, - attributes: { counter: initialCounter, message }, - children, -}) => { - const [show, setShow] = useState(true); - const [counter, setCounter] = useState(initialCounter); - - return ( - <Counter.Provider value={counter}> - <Theme.Provider value="cool theme"> - <div - className={`${className} ${show ? 'show' : 'hide'}`} - style={{ - ...otherStyle, - fontWeight: show ? 1000 : fontWeight, - }} - > - <Title message={message} /> - <Button handler={() => setShow(!show)} /> - <button onClick={() => setCounter(counter + 1)}> - {counter} - </button> - {show && children} - </div> - </Theme.Provider> - </Counter.Provider> - ); -}; - -export default Frontend; diff --git a/src/blocks/block-hydration-experiments-parent/shared/button.js b/src/blocks/block-hydration-experiments-parent/shared/button.js deleted file mode 100644 index f5b4242a..00000000 --- a/src/blocks/block-hydration-experiments-parent/shared/button.js +++ /dev/null @@ -1,5 +0,0 @@ -const Button = ({ handler }) => { - return <button onClick={handler}>Show</button>; -}; - -export default Button; diff --git a/src/blocks/block-hydration-experiments-parent/style.scss b/src/blocks/block-hydration-experiments-parent/style.scss deleted file mode 100644 index 9e2a2039..00000000 --- a/src/blocks/block-hydration-experiments-parent/style.scss +++ /dev/null @@ -1,9 +0,0 @@ -.wp-block-bhe-block-hydration-experiments-parent { - padding: 15px 10px 15px 50px; - background-color: rgb(238, 237, 237); -} - -gutenberg-block, -gutenberg-inner-blocks { - display: contents; -} diff --git a/src/blocks/block-hydration-experiments-child/block.json b/src/blocks/interactive-child/block.json similarity index 66% rename from src/blocks/block-hydration-experiments-child/block.json rename to src/blocks/interactive-child/block.json index 26d8385a..aee5271c 100644 --- a/src/blocks/block-hydration-experiments-child/block.json +++ b/src/blocks/interactive-child/block.json @@ -1,13 +1,13 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 2, - "name": "bhe/block-hydration-experiments-child", + "name": "bhe/interactive-child", "version": "0.1.0", - "title": "BHE - Child", + "title": "BHE - Interactive Child", "category": "text", "icon": "flag", "description": "", - "usesContext": ["bhe/title"], + "usesContext": ["bhe/interactive-title", "bhe/non-interactive-title"], "supports": { "color": { "text": true @@ -17,7 +17,7 @@ }, "html": true }, - "textdomain": "block-hydration-experiments-child", + "textdomain": "block-hydration-experiments", "editorScript": "file:./index.js", "style": "file:./style-index.css", "viewScript": "file:./view.js" diff --git a/src/blocks/block-hydration-experiments-child/edit.js b/src/blocks/interactive-child/edit.js similarity index 52% rename from src/blocks/block-hydration-experiments-child/edit.js rename to src/blocks/interactive-child/edit.js index 62865646..ccad5926 100644 --- a/src/blocks/block-hydration-experiments-child/edit.js +++ b/src/blocks/interactive-child/edit.js @@ -5,15 +5,17 @@ import '@wordpress/block-editor'; import { useBlockProps } from '@wordpress/block-editor'; -const Edit = ({ context }) => { - const blockProps = useBlockProps(); - - return ( - <div {...blockProps}> - <p>Child block</p> - <p>Block Context - "bhe/title": {context['bhe/title']}</p> - </div> - ); -}; +const Edit = ({ context }) => ( + <div {...useBlockProps()}> + <p> + Block Context from interactive parent - "bhe/interactive-title":{' '} + {context['bhe/interactive-title']} + </p> + <p> + Block Context from non-interactive parent - + "bhe/non-interactive-title": {context['bhe/non-interactive-title']} + </p> + </div> +); export default Edit; diff --git a/src/blocks/block-hydration-experiments-child/frontend.js b/src/blocks/interactive-child/frontend.js similarity index 63% rename from src/blocks/block-hydration-experiments-child/frontend.js rename to src/blocks/interactive-child/frontend.js index fe95b379..d738c420 100644 --- a/src/blocks/block-hydration-experiments-child/frontend.js +++ b/src/blocks/interactive-child/frontend.js @@ -8,8 +8,15 @@ const Frontend = ({ blockProps, context }) => { return ( <div {...blockProps}> - <p>Child block</p> - <p>Block Context - "bhe/title": {context['bhe/title']}</p> + <p> + Block Context from interactive parent - "bhe/interactive-title":{' '} + {context['bhe/interactive-title']} + </p> + <p> + Block Context from non-interactive parent - + "bhe/non-interactive-title":{' '} + {context['bhe/non-interactive-title']} + </p> <p>React Context - "counter": {counter}</p> <p>React Context - "theme": {theme}</p> </div> diff --git a/src/blocks/block-hydration-experiments-child/index.js b/src/blocks/interactive-child/index.js similarity index 81% rename from src/blocks/block-hydration-experiments-child/index.js rename to src/blocks/interactive-child/index.js index a9737d28..8c88ccbc 100644 --- a/src/blocks/block-hydration-experiments-child/index.js +++ b/src/blocks/interactive-child/index.js @@ -3,7 +3,7 @@ import Edit from './edit'; import Frontend from './frontend'; import './style.scss'; -registerBlockType('bhe/block-hydration-experiments-child', { +registerBlockType('bhe/interactive-child', { edit: Edit, // The Save component is derived from the Frontend component. frontend: Frontend, diff --git a/src/blocks/interactive-child/style.scss b/src/blocks/interactive-child/style.scss new file mode 100644 index 00000000..bd891aa0 --- /dev/null +++ b/src/blocks/interactive-child/style.scss @@ -0,0 +1,23 @@ +.wp-block-bhe-interactive-child { + padding: 15px 10px 15px 50px; + border: 1px solid rgb(255, 162, 0); + position: relative; +} + +.wp-block-bhe-interactive-child::before { + position: absolute; + top: 0; + right: 0; + border: 1px solid rgb(255, 162, 0); + background-color: rgb(255, 162, 0); + color: white; + margin: -1px; + padding: 0px 5px; + font-size: 9px; + content: 'BHE - Interactive Child'; +} + +gutenberg-block, +gutenberg-inner-blocks { + display: contents; +} diff --git a/src/blocks/block-hydration-experiments-child/view.js b/src/blocks/interactive-child/view.js similarity index 78% rename from src/blocks/block-hydration-experiments-child/view.js rename to src/blocks/interactive-child/view.js index b8fb70bc..cc7038be 100644 --- a/src/blocks/block-hydration-experiments-child/view.js +++ b/src/blocks/interactive-child/view.js @@ -3,6 +3,6 @@ import ThemeContext from '../../context/theme'; import { registerBlockType } from '../../gutenberg-packages/frontend'; import Frontend from './frontend'; -registerBlockType('bhe/block-hydration-experiments-child', Frontend, { +registerBlockType('bhe/interactive-child', Frontend, { usesContext: [ThemeContext, CounterContext], }); diff --git a/src/blocks/block-hydration-experiments-parent/block.json b/src/blocks/interactive-parent/block.json similarity index 60% rename from src/blocks/block-hydration-experiments-parent/block.json rename to src/blocks/interactive-parent/block.json index 82ccfc6a..50a87993 100644 --- a/src/blocks/block-hydration-experiments-parent/block.json +++ b/src/blocks/interactive-parent/block.json @@ -1,9 +1,9 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 2, - "name": "bhe/block-hydration-experiments-parent", + "name": "bhe/interactive-parent", "version": "0.1.0", - "title": "BHE - Parent", + "title": "BHE - Interactive Parent", "category": "text", "icon": "flag", "description": "", @@ -13,11 +13,15 @@ "default": 0, "frontend": true }, - "message": { + "title": { "type": "string", "source": "text", "selector": ".title", "frontend": true + }, + "secret": { + "type": "string", + "default": "fa4e3d47e4e0a38c5c57533391855013" } }, "supports": { @@ -26,16 +30,17 @@ }, "typography": { "fontSize": true, - "__experimentalFontWeight": true + "__experimentalFontWeight": true, + "__experimentalLetterSpacing": true }, "html": true }, "providesContext": { - "bhe/title": "message" + "bhe/interactive-title": "title" }, - "textdomain": "block-hydration-experiments-parent", + "usesContext": ["bhe/non-interactive-title"], + "textdomain": "block-hydration-experiments", "editorScript": "file:./index.js", - "editorStyle": "file:./index.css", "style": "file:./style-index.css", "viewScript": "file:./view.js" } diff --git a/src/blocks/interactive-parent/edit.js b/src/blocks/interactive-parent/edit.js new file mode 100644 index 00000000..49a07e4b --- /dev/null +++ b/src/blocks/interactive-parent/edit.js @@ -0,0 +1,33 @@ +// This import is needed to ensure that the `wp.blockEditor` global is available +// by the time this component gets loaded. The `Title` component consumes the +// global but cannot import it because it shouldn't be loaded on the frontend of +// the site. +import '@wordpress/block-editor'; + +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; +import Button from './shared/button'; +import Title from './shared/title'; + +const Edit = ({ attributes: { counter, title, secret }, setAttributes }) => ( + <> + <div {...useBlockProps()}> + <Title + onChange={(val) => setAttributes({ title: val })} + placeholder="This will be passed through context to child blocks" + > + {title} + + + +
+ This is a secret attribute that should not be serialized:{' '} + {secret} +
+ +
+ +); + +export default Edit; diff --git a/src/blocks/interactive-parent/frontend.js b/src/blocks/interactive-parent/frontend.js new file mode 100644 index 00000000..632f99be --- /dev/null +++ b/src/blocks/interactive-parent/frontend.js @@ -0,0 +1,42 @@ +import Counter from '../../context/counter'; +import Theme from '../../context/theme'; +import { useState } from '../../gutenberg-packages/wordpress-element'; +import Button from './shared/button'; +import Title from './shared/title'; + +const Frontend = ({ + blockProps: { + className, + style: { fontWeight, ...style }, + }, + attributes: { counter: initialCounter, title }, + children, +}) => { + const [show, setShow] = useState(true); + const [bold, setBold] = useState(true); + const [counter, setCounter] = useState(initialCounter); + + return ( + + +
+ {title} + + + + {show && children} +
+
+
+ ); +}; + +export default Frontend; diff --git a/src/blocks/block-hydration-experiments-parent/index.js b/src/blocks/interactive-parent/index.js similarity index 81% rename from src/blocks/block-hydration-experiments-parent/index.js rename to src/blocks/interactive-parent/index.js index eea543f6..a9f5db57 100644 --- a/src/blocks/block-hydration-experiments-parent/index.js +++ b/src/blocks/interactive-parent/index.js @@ -3,7 +3,7 @@ import Edit from './edit'; import Frontend from './frontend'; import './style.scss'; -registerBlockType('bhe/block-hydration-experiments-parent', { +registerBlockType('bhe/interactive-parent', { edit: Edit, // The Save component is derived from the Frontend component. frontend: Frontend, diff --git a/src/blocks/interactive-parent/shared/button.js b/src/blocks/interactive-parent/shared/button.js new file mode 100644 index 00000000..2384a54a --- /dev/null +++ b/src/blocks/interactive-parent/shared/button.js @@ -0,0 +1,5 @@ +const Button = ({ handler, children }) => { + return ; +}; + +export default Button; diff --git a/src/blocks/block-hydration-experiments-parent/shared/title.js b/src/blocks/interactive-parent/shared/title.js similarity index 75% rename from src/blocks/block-hydration-experiments-parent/shared/title.js rename to src/blocks/interactive-parent/shared/title.js index 78bf7859..de3caf96 100644 --- a/src/blocks/block-hydration-experiments-parent/shared/title.js +++ b/src/blocks/interactive-parent/shared/title.js @@ -1,8 +1,8 @@ import { RichText } from '../../../gutenberg-packages/wordpress-blockeditor'; -const Title = ({ message, ...props }) => ( +const Title = ({ children, ...props }) => ( - {message} + {children} ); diff --git a/src/blocks/interactive-parent/style.scss b/src/blocks/interactive-parent/style.scss new file mode 100644 index 00000000..95cfe66a --- /dev/null +++ b/src/blocks/interactive-parent/style.scss @@ -0,0 +1,23 @@ +.wp-block-bhe-interactive-parent { + padding: 15px 10px 15px 50px; + border: 1px solid rgb(31, 185, 64); + position: relative; +} + +.wp-block-bhe-interactive-parent::before { + position: absolute; + top: 0; + right: 0; + background-color: rgb(31, 185, 64); + border: 1px solid rgb(31, 185, 64); + color: white; + margin: -1px; + padding: 0px 5px; + font-size: 10px; + content: 'BHE - Interactive Parent'; +} + +gutenberg-block, +gutenberg-inner-blocks { + display: contents; +} diff --git a/src/blocks/block-hydration-experiments-parent/view.js b/src/blocks/interactive-parent/view.js similarity index 78% rename from src/blocks/block-hydration-experiments-parent/view.js rename to src/blocks/interactive-parent/view.js index 9fe91d25..6a65088e 100644 --- a/src/blocks/block-hydration-experiments-parent/view.js +++ b/src/blocks/interactive-parent/view.js @@ -3,6 +3,6 @@ import ThemeContext from '../../context/theme'; import { registerBlockType } from '../../gutenberg-packages/frontend'; import Frontend from './frontend'; -registerBlockType('bhe/block-hydration-experiments-parent', Frontend, { +registerBlockType('bhe/interactive-parent', Frontend, { providesContext: [ThemeContext, CounterContext], }); diff --git a/src/blocks/non-interactive-parent/block.json b/src/blocks/non-interactive-parent/block.json new file mode 100644 index 00000000..fa0ba0fc --- /dev/null +++ b/src/blocks/non-interactive-parent/block.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "bhe/non-interactive-parent", + "version": "0.1.0", + "title": "BHE - Non Interactive Parent", + "category": "text", + "icon": "flag", + "description": "", + "attributes": { + "title": { + "type": "string", + "source": "text", + "selector": ".title", + "frontend": true + } + }, + "providesContext": { + "bhe/non-interactive-title": "title" + }, + "supports": { + "color": { + "text": true + }, + "html": true + }, + "textdomain": "block-hydration-experiments", + "editorScript": "file:./index.js", + "style": "file:./style-index.css" +} diff --git a/src/blocks/non-interactive-parent/edit.js b/src/blocks/non-interactive-parent/edit.js new file mode 100644 index 00000000..6871ad27 --- /dev/null +++ b/src/blocks/non-interactive-parent/edit.js @@ -0,0 +1,18 @@ +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; +import { RichText } from '../../gutenberg-packages/wordpress-blockeditor'; + +const Edit = ({ attributes, setAttributes }) => ( +
+ setAttributes({ title: val })} + placeholder="This will be passed through context to child blocks" + value={attributes.title} + > + {attributes.title} + + +
+); +export default Edit; diff --git a/src/blocks/non-interactive-parent/frontend.js b/src/blocks/non-interactive-parent/frontend.js new file mode 100644 index 00000000..70a54e0f --- /dev/null +++ b/src/blocks/non-interactive-parent/frontend.js @@ -0,0 +1,8 @@ +const Frontend = ({ attributes, blockProps, children }) => ( +
+

{attributes.title}

+ {children} +
+); + +export default Frontend; diff --git a/src/blocks/non-interactive-parent/index.js b/src/blocks/non-interactive-parent/index.js new file mode 100644 index 00000000..d7fdfae3 --- /dev/null +++ b/src/blocks/non-interactive-parent/index.js @@ -0,0 +1,9 @@ +import { registerBlockType } from '../../gutenberg-packages/wordpress-blocks'; +import metadata from './block.json'; +import edit from './edit'; +import frontend from './frontend'; +import './style.scss'; + +const { name } = metadata; + +registerBlockType(name, { edit, frontend }); diff --git a/src/blocks/non-interactive-parent/style.scss b/src/blocks/non-interactive-parent/style.scss new file mode 100644 index 00000000..c2c61eef --- /dev/null +++ b/src/blocks/non-interactive-parent/style.scss @@ -0,0 +1,23 @@ +.wp-block-bhe-non-interactive-parent { + border: 1px solid rgb(34, 168, 235); + position: relative; + padding: 25px 10px; +} + +.wp-block-bhe-non-interactive-parent::before { + content: 'BHE - Non Interactive Parent'; + position: absolute; + top: 0; + right: 0; + border: 1px solid rgb(34, 168, 235); + background-color: rgb(34, 168, 235); + color: white; + margin: -1px; + padding: 0px 5px; + font-size: 10px; +} + +gutenberg-block, +gutenberg-inner-blocks { + display: contents; +} diff --git a/src/gutenberg-packages/frontend.js b/src/gutenberg-packages/frontend.js index e3817b3a..74298fb6 100644 --- a/src/gutenberg-packages/frontend.js +++ b/src/gutenberg-packages/frontend.js @@ -27,9 +27,6 @@ const Wrappers = ({ wrappers, children }) => { class GutenbergBlock extends HTMLElement { connectedCallback() { setTimeout(() => { - const blockContext = {}; - const Providers = []; - // Get the block attributes. const attributes = JSON.parse( this.getAttribute('data-gutenberg-attributes') @@ -46,6 +43,7 @@ class GutenbergBlock extends HTMLElement { } // Get the Block Context from their parents. + const blockContext = {}; const usesBlockContext = JSON.parse( this.getAttribute('data-gutenberg-uses-block-context') ); @@ -64,7 +62,7 @@ class GutenbergBlock extends HTMLElement { ); } - // Prepare to share the Block Context with their children. + // Share the Block Context with their children. const providesBlockContext = JSON.parse( this.getAttribute('data-gutenberg-provides-block-context') ); @@ -83,102 +81,118 @@ class GutenbergBlock extends HTMLElement { }); } - // Get the block type, block props, inner blocks, frontend component and - // options. - const blockType = this.getAttribute('data-gutenberg-block-type'); - const { class: className, style: styleString } = JSON.parse( - this.getAttribute('data-gutenberg-block-props') - ); - - const temporaryElement = document.createElement('div'); - temporaryElement.style.cssText = styleString; + // Hydrate the interactive blocks. + const hydration = this.getAttribute('data-gutenberg-hydration'); - const innerBlocks = this.querySelector('gutenberg-inner-blocks'); - const { Component, options } = blockTypes.get(blockType); + if (hydration) { + const Providers = []; - // Get the React Context from their parents. - options?.usesContext?.forEach((context) => { - const event = new CustomEvent('gutenberg-react-context', { - detail: { context }, - bubbles: true, - cancelable: true, + // Get the block type, block props (class and style), inner blocks, + // frontend component and options. + const blockType = this.getAttribute( + 'data-gutenberg-block-type' + ); + const innerBlocks = this.querySelector( + 'gutenberg-inner-blocks' + ); + const { Component, options } = blockTypes.get(blockType); + const { class: className, style } = JSON.parse( + this.getAttribute('data-gutenberg-block-props') + ); + // Temporary element to translate style strings to style objects. + const el = document.createElement('div'); + el.style.cssText = style; + const blockProps = { className, style: el.style }; + el.remove(); + + // Get the React Context from their parents. + options?.usesContext?.forEach((context) => { + const event = new CustomEvent('gutenberg-react-context', { + detail: { context }, + bubbles: true, + cancelable: true, + }); + this.dispatchEvent(event); + Providers.push(event.detail.Provider); }); - this.dispatchEvent(event); - Providers.push(event.detail.Provider); - }); - - // Prepare to share the React Context with their children. - if (options?.providesContext?.length > 0) { - this.addEventListener('gutenberg-react-context', (event) => { - for (const context of options.providesContext) { - // We compare the provided context with the received context. - if (event.detail.context === context) { - // If there's a match, we stop propagation. - event.stopPropagation(); - - // We return a Provider that is subscribed to the parent Provider. - event.detail.Provider = createProvider({ - element: this, - context, - }); - - // We can stop the iteration. - break; + + // Share the React Context with their children. + if (options?.providesContext?.length > 0) { + this.addEventListener( + 'gutenberg-react-context', + (event) => { + for (const context of options.providesContext) { + // We compare the provided context with the received context. + if (event.detail.context === context) { + // If there's a match, we stop propagation. + event.stopPropagation(); + + // We return a Provider that is subscribed to the parent Provider. + event.detail.Provider = createProvider({ + element: this, + context, + }); + + // We can stop the iteration. + break; + } + } } - } - }); - } + ); + } - // Get the hydration technique. - const technique = this.getAttribute('data-gutenberg-hydrate'); - const media = this.getAttribute('data-gutenberg-media'); - const hydrationOptions = { technique, media }; - - hydrate( - - {/* Wrap the component with all the React Providers */} - - - {/* Update the value each time one of the React Contexts changes */} - {options?.providesContext?.map((context, index) => ( - - ))} - - {/* Render the inner blocks */} - {innerBlocks && ( - - )} - - - -