From ec1f9e529ccc7ce231184538bb7b7f0322cd2ed8 Mon Sep 17 00:00:00 2001 From: David Arenas Date: Wed, 19 Oct 2022 14:30:58 +0200 Subject: [PATCH 01/20] Hardcode transitions initially --- src/runtime/router.js | 13 ++++++--- src/runtime/transitions.js | 51 +++++++++++++++++++++++++++++++++ transition-styles.css | 58 ++++++++++++++++++++++++++++++++++++++ wp-directives.php | 6 ++++ 4 files changed, 124 insertions(+), 4 deletions(-) create mode 100644 src/runtime/transitions.js create mode 100644 transition-styles.css diff --git a/src/runtime/router.js b/src/runtime/router.js index e8b35d7f..996f3085 100644 --- a/src/runtime/router.js +++ b/src/runtime/router.js @@ -1,6 +1,7 @@ import { hydrate, render } from 'preact'; import toVdom from './vdom'; import { createRootFragment } from './utils'; +import { startTransition } from './transitions'; // The root to render the vdom (document.body). let rootFragment; @@ -63,8 +64,10 @@ export const navigate = async (href) => { const url = cleanUrl(href); prefetch(url); const { body, head } = await pages.get(url); - document.head.replaceChildren(...head); - render(body, rootFragment); + await startTransition(url, () => { + document.head.replaceChildren(...head); + render(body, rootFragment); + }); window.history.pushState({ wp: { clientNavigation: true } }, '', href); }; @@ -74,8 +77,10 @@ window.addEventListener('popstate', async () => { const url = cleanUrl(window.location); // Remove hash. if (pages.has(url)) { const { body, head } = await pages.get(url); - document.head.replaceChildren(...head); - render(body, rootFragment); + await startTransition(url, () => { + document.head.replaceChildren(...head); + render(body, rootFragment); + }); } else { window.location.reload(); } diff --git a/src/runtime/transitions.js b/src/runtime/transitions.js new file mode 100644 index 00000000..80b30065 --- /dev/null +++ b/src/runtime/transitions.js @@ -0,0 +1,51 @@ +let previousURL; + +export const startTransition = async (url, updateDomCallback) => { + if (!document.createDocumentTransition) { + updateDomCallback(); + return; + } + + const toSingle = + /\/(movies|actors)\/\w+\//.test(url) || /\?(movies|actors)=/.test(url); + + // Select the element we are going to transition from. + const initialPicture = toSingle + ? document.querySelector(`a[href$="${url}"] > img`) + : document.querySelector(`.wp-block-post-featured-image > img`); + + if (initialPicture) { + initialPicture.style.pageTransitionTag = 'picture'; + } + + const transition = document.createDocumentTransition(); + + let finalPicture; + await transition + .start(() => { + // Remove transition tag. + if (initialPicture) { + initialPicture.style.pageTransitionTag = ''; + } + + updateDomCallback(); + + window.scrollTo(0, 0); + + // Select new element. + finalPicture = toSingle + ? document.querySelector(`.wp-block-post-featured-image > img`) + : document.querySelector(`a[href$="${previousURL}"] > img`); + + if (finalPicture) { + finalPicture.style.pageTransitionTag = 'picture'; + } + }) + .then(() => { + if (finalPicture) { + finalPicture.style.pageTransitionTag = ''; + } + // Update previous URL. This works as long as we make a transition for each navigation. + previousURL = url; + }); +}; diff --git a/transition-styles.css b/transition-styles.css new file mode 100644 index 00000000..40067c25 --- /dev/null +++ b/transition-styles.css @@ -0,0 +1,58 @@ +@keyframes fade-in { + from { + opacity: 0; + } +} + +@keyframes fade-out { + to { + opacity: 0; + } +} + +@keyframes slide-from-right { + from { + transform: translateX(30px); + } +} + +@keyframes slide-to-left { + to { + transform: translateX(-30px); + } +} + +::page-transition-outgoing-image(main) { + animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out, 300ms cubic-bezier(0.4, + 0, + 0.2, + 1) both slide-to-left; +} + +::page-transition-incoming-image(main) { + animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right; +} + +::page-transition-outgoing-image(picture), +::page-transition-incoming-image(picture) { + animation: none; + mix-blend-mode: normal; +} + +::page-transition-image-wrapper(picture) { + isolation: none; +} + +header { + page-transition-tag: header; + contain: paint; +} + +main { + page-transition-tag: main; + contain: paint; +} + +.wp-block-post-featured-image img { + contain: paint; +} \ No newline at end of file diff --git a/wp-directives.php b/wp-directives.php index 5298a26b..70dbbfac 100644 --- a/wp-directives.php +++ b/wp-directives.php @@ -33,6 +33,12 @@ function wp_directives_register_scripts() // For now we can always enqueue the runtime. We'll figure out how to // conditionally enqueue directives later. wp_enqueue_script('wp-directive-runtime'); + + wp_register_style( + 'transition-styles', + plugin_dir_url(__FILE__) . '/transition-styles.css' + ); + wp_enqueue_style('transition-styles'); } add_action('wp_enqueue_scripts', 'wp_directives_register_scripts'); From 148580b8f518ce31cb65286209049f87cf426caa Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 20 Oct 2022 12:21:29 +0200 Subject: [PATCH 02/20] Add initial block --- src/blocks/test/block.json | 12 +++++ src/blocks/test/index.js | 8 ++++ src/blocks/test/view.js | 1 + webpack.config.js | 95 ++++++++++++++++++++------------------ wp-directives.php | 37 +++++++++++++-- 5 files changed, 104 insertions(+), 49 deletions(-) create mode 100644 src/blocks/test/block.json create mode 100644 src/blocks/test/index.js create mode 100644 src/blocks/test/view.js diff --git a/src/blocks/test/block.json b/src/blocks/test/block.json new file mode 100644 index 00000000..c74d7deb --- /dev/null +++ b/src/blocks/test/block.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "test/test", + "version": "0.1.0", + "title": "Test block", + "category": "text", + "icon": "flag", + "description": "", + "textdomain": "test", + "editorScript": "file:./index.js" +} diff --git a/src/blocks/test/index.js b/src/blocks/test/index.js new file mode 100644 index 00000000..d9f529b4 --- /dev/null +++ b/src/blocks/test/index.js @@ -0,0 +1,8 @@ +import { registerBlockType } from '@wordpress/blocks'; + +const Edit = () =>
hola
; + +registerBlockType('test/test', { + edit: Edit, + save: () => null, +}); diff --git a/src/blocks/test/view.js b/src/blocks/test/view.js new file mode 100644 index 00000000..fe9256e2 --- /dev/null +++ b/src/blocks/test/view.js @@ -0,0 +1 @@ +console.log('view of the block'); diff --git a/webpack.config.js b/webpack.config.js index c2070f52..75752fb8 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,54 +1,59 @@ +const defaultConfig = require('@wordpress/scripts/config/webpack.config'); const { resolve } = require('path'); -module.exports = { - entry: { - runtime: './src/runtime', - }, - output: { - filename: '[name].js', - path: resolve(process.cwd(), 'build'), - }, - optimization: { - runtimeChunk: { - name: 'vendors', +module.exports = [ + defaultConfig, + { + entry: { + runtime: './src/runtime', + 'blocks/test/view': './src/blocks/test/view', + }, + output: { + filename: '[name].js', + path: resolve(process.cwd(), 'build'), }, - splitChunks: { - cacheGroups: { - vendors: { - test: /[\\/]node_modules[\\/]/, - name: 'vendors', - minSize: 0, - chunks: 'all', + optimization: { + runtimeChunk: { + name: 'vendors', + }, + splitChunks: { + cacheGroups: { + vendors: { + test: /[\\/]node_modules[\\/]/, + name: 'vendors', + minSize: 0, + chunks: 'all', + }, }, }, }, - }, - module: { - rules: [ - { - test: /\.(j|t)sx?$/, - exclude: /node_modules/, - use: [ - { - loader: require.resolve('babel-loader'), - options: { - cacheDirectory: - process.env.BABEL_CACHE_DIRECTORY || true, - babelrc: false, - configFile: false, - presets: [ - [ - '@babel/preset-react', - { - runtime: 'automatic', - importSource: 'preact', - }, + module: { + rules: [ + { + test: /\.(j|t)sx?$/, + exclude: /node_modules/, + use: [ + { + loader: require.resolve('babel-loader'), + options: { + cacheDirectory: + process.env.BABEL_CACHE_DIRECTORY || true, + babelrc: false, + configFile: false, + presets: [ + [ + '@babel/preset-react', + { + runtime: 'automatic', + importSource: 'preact', + }, + ], ], - ], + }, }, - }, - ], - }, - ], + ], + }, + ], + }, }, -}; +]; diff --git a/wp-directives.php b/wp-directives.php index 68bb435a..2424fd45 100644 --- a/wp-directives.php +++ b/wp-directives.php @@ -75,8 +75,14 @@ function wp_directives_add_wp_link_attribute($block_content) $link = parse_url($w->get_attribute('href')); if (!isset($link['host']) || $link['host'] === $site_url['host']) { $classes = $w->get_attribute('class'); - if (str_contains($classes, 'query-pagination') || str_contains($classes, 'page-numbers')) { - $w->set_attribute('wp-link', '{ "prefetch": true, "scroll": false }'); + if ( + str_contains($classes, 'query-pagination') || + str_contains($classes, 'page-numbers') + ) { + $w->set_attribute( + 'wp-link', + '{ "prefetch": true, "scroll": false }' + ); } else { $w->set_attribute('wp-link', '{ "prefetch": true }'); } @@ -85,8 +91,18 @@ function wp_directives_add_wp_link_attribute($block_content) return (string) $w; } // We go only through the Query Loops and the template parts until we find a better solution. -add_filter('render_block_core/query', 'wp_directives_add_wp_link_attribute', 10, 1); -add_filter('render_block_core/template-part', 'wp_directives_add_wp_link_attribute', 10, 1); +add_filter( + 'render_block_core/query', + 'wp_directives_add_wp_link_attribute', + 10, + 1 +); +add_filter( + 'render_block_core/template-part', + 'wp_directives_add_wp_link_attribute', + 10, + 1 +); function wp_directives_client_site_transitions_meta_tag() { @@ -106,3 +122,16 @@ function wp_directives_client_site_transitions_option() 'client_side_transitions', 'wp_directives_client_site_transitions_option' ); + +/* WP Movies Demo */ +add_action('init', function () { + register_block_type(__DIR__ . '/build/blocks/test'); +}); + +add_filter('render_block_test/test', function ($content) { + wp_enqueue_script( + 'test/test', + plugin_dir_url(__FILE__) . 'build/blocks/test/view.js' + ); + return $content; +}); From 4487079a81f84b261814512ee9841977e9b2282a Mon Sep 17 00:00:00 2001 From: David Arenas Date: Thu, 20 Oct 2022 12:30:35 +0200 Subject: [PATCH 03/20] Add different transition cases --- src/runtime/router.js | 13 ++++--- src/runtime/transitions.js | 72 +++++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/runtime/router.js b/src/runtime/router.js index cb8dc28d..9f2a19d4 100644 --- a/src/runtime/router.js +++ b/src/runtime/router.js @@ -70,10 +70,9 @@ export const prefetch = (url) => { export const navigate = async (href) => { const url = cleanUrl(href); prefetch(url); - window.history.pushState({ wp: { clientNavigation: true } }, '', href); const page = await pages.get(url); if (page) { - await startTransition(url, () => { + await startTransition(href, () => { document.head.replaceChildren(...page.head); render(page.body, rootFragment); }); @@ -87,11 +86,11 @@ export const navigate = async (href) => { // cache. window.addEventListener('popstate', async () => { const url = cleanUrl(window.location); // Remove hash. - const page = pages.has(url) && (await pages.get(url)); - if (page) { - await startTransition(url, () => { - document.head.replaceChildren(...page.head); - render(page.body, rootFragment); + if (pages.has(url)) { + const { body, head } = await pages.get(url); + await startTransition(window.location.href, () => { + document.head.replaceChildren(...head); + render(body, rootFragment); }); } else { window.location.reload(); diff --git a/src/runtime/transitions.js b/src/runtime/transitions.js index 80b30065..107ca4e7 100644 --- a/src/runtime/transitions.js +++ b/src/runtime/transitions.js @@ -1,18 +1,53 @@ -let previousURL; +let previousHref = window.location.href; -export const startTransition = async (url, updateDomCallback) => { +export const startTransition = async (href, updateDomCallback) => { if (!document.createDocumentTransition) { updateDomCallback(); return; } - const toSingle = - /\/(movies|actors)\/\w+\//.test(url) || /\?(movies|actors)=/.test(url); + // Transition types: + + // Small to big: + // From movies to movie + // From actors to actor + // From movie to actor + + // Big to small: + // From movie to movies + // From actor to actors + + const previousPathname = new URL(previousHref, window.location.href) + .pathname; + const isFromMovie = /^\/movies\/[\w-]+\/$/.test(previousPathname); + const isFromMovies = /^\/(movies\/)?$/.test(previousPathname); + const isFromActor = /^\/actors\/[\w-]+\/$/.test(previousPathname); + const isFromActors = /^\/actors\/$/.test(previousPathname); + + const nextPathname = new URL(href, window.location.href).pathname; + const isToMovie = /^\/movies\/[\w-]+\/$/.test(nextPathname); + const isToMovies = /^\/(movies\/)?$/.test(nextPathname); + const isToActor = /^\/actors\/[\w-]+\/$/.test(nextPathname); + const isToActors = /^\/actors\/$/.test(nextPathname); // Select the element we are going to transition from. - const initialPicture = toSingle - ? document.querySelector(`a[href$="${url}"] > img`) - : document.querySelector(`.wp-block-post-featured-image > img`); + let initialPicture; + + // Small to big -> Initial picture is the small one. + if ( + (isFromMovies && isToMovie) || + (isFromActors && isToActor) || + (isFromMovie && isToActor) + ) { + initialPicture = document.querySelector(`a[href$="${href}"] > img`); + } + + // Big to small -> Initial picture is the big one. + else if ((isFromMovie && isToMovies) || (isFromActor && isToActors)) { + initialPicture = document.querySelector( + `.wp-block-post-featured-image > img` + ); + } if (initialPicture) { initialPicture.style.pageTransitionTag = 'picture'; @@ -32,10 +67,23 @@ export const startTransition = async (url, updateDomCallback) => { window.scrollTo(0, 0); - // Select new element. - finalPicture = toSingle - ? document.querySelector(`.wp-block-post-featured-image > img`) - : document.querySelector(`a[href$="${previousURL}"] > img`); + // Small to big -> final picture is the big one. + if ( + (isFromMovies && isToMovie) || + (isFromActors && isToActor) || + (isFromMovie && isToActor) + ) { + finalPicture = document.querySelector( + `.wp-block-post-featured-image > img` + ); + } + + // Big to small -> Final picture is the small one. + if ((isFromMovie && isToMovies) || (isFromActor && isToActors)) { + finalPicture = document.querySelector( + `a[href$="${previousHref}"] > img` + ); + } if (finalPicture) { finalPicture.style.pageTransitionTag = 'picture'; @@ -46,6 +94,6 @@ export const startTransition = async (url, updateDomCallback) => { finalPicture.style.pageTransitionTag = ''; } // Update previous URL. This works as long as we make a transition for each navigation. - previousURL = url; + previousHref = href; }); }; From 0c30ee39c6007faef165074f78e744a8b0b8a0d1 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 20 Oct 2022 13:02:20 +0200 Subject: [PATCH 04/20] Add reactive state --- .babelrc | 10 ++++++++++ src/blocks/test/index.js | 10 ++++++++-- src/blocks/test/view.js | 21 ++++++++++++++++++++- src/runtime/deepsignal.js | 20 +++++++++++--------- src/runtime/directives.js | 16 ++++++++++++---- src/runtime/wpx.js | 10 ++++++++++ 6 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 .babelrc create mode 100644 src/runtime/wpx.js diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..3a05da56 --- /dev/null +++ b/.babelrc @@ -0,0 +1,10 @@ +{ + "presets": [ + [ + "@babel/preset-react", + { + "throwIfNamespace": false + } + ] + ] +} diff --git a/src/blocks/test/index.js b/src/blocks/test/index.js index d9f529b4..fe3ac6eb 100644 --- a/src/blocks/test/index.js +++ b/src/blocks/test/index.js @@ -1,8 +1,14 @@ import { registerBlockType } from '@wordpress/blocks'; -const Edit = () =>
hola
; +const Edit = () =>
Favorites blocks
; registerBlockType('test/test', { edit: Edit, - save: () => null, + save: () => ( + + + + ), }); diff --git a/src/blocks/test/view.js b/src/blocks/test/view.js index fe9256e2..c7d27152 100644 --- a/src/blocks/test/view.js +++ b/src/blocks/test/view.js @@ -1 +1,20 @@ -console.log('view of the block'); +import wpx from '../../runtime/wpx'; + +wpx({ + state: { + favorites: { + posts: [], + }, + }, + actions: { + favorites: { + togglePost: ({ state, context }) => { + const index = state.favorites.posts.findIndex( + (post) => post === context.post.id + ); + if (index === -1) state.favorites.posts.push(context.post.id); + else state.favorites.posts.splice(index, 1); + }, + }, + }, +}); diff --git a/src/runtime/deepsignal.js b/src/runtime/deepsignal.js index 84901785..08742367 100644 --- a/src/runtime/deepsignal.js +++ b/src/runtime/deepsignal.js @@ -1,25 +1,27 @@ import { signal } from '@preact/signals'; -import { knownSymbols, shouldWrap } from './utils'; const proxyToSignals = new WeakMap(); const objToProxy = new WeakMap(); -const returnSignal = /^\$/; export const deepSignal = (obj) => new Proxy(obj, handlers); +export const options = { returnSignal: /^\$/ }; const handlers = { get(target, prop, receiver) { - if (typeof prop === 'symbol' && knownSymbols.has(prop)) - return Reflect.get(target, prop, receiver); - const shouldReturnSignal = returnSignal.test(prop); - const key = shouldReturnSignal ? prop.replace(returnSignal, '') : prop; + const returnSignal = options.returnSignal.test(prop); + const key = returnSignal + ? prop.replace(options.returnSignal, '') + : prop; if (!proxyToSignals.has(receiver)) proxyToSignals.set(receiver, new Map()); const signals = proxyToSignals.get(receiver); if (!signals.has(key)) { let val = Reflect.get(target, key, receiver); - if (typeof val === 'object' && val !== null && shouldWrap(val)) - val = new Proxy(val, handlers); + if (typeof val === 'object' && val !== null) { + if (!objToProxy.has(val)) + objToProxy.set(val, new Proxy(val, handlers)); + val = objToProxy.get(val); + } signals.set(key, signal(val)); } return returnSignal ? signals.get(key) : signals.get(key).value; @@ -27,7 +29,7 @@ const handlers = { set(target, prop, val, receiver) { let internal = val; - if (typeof val === 'object' && val !== null && shouldWrap(val)) { + if (typeof val === 'object' && val !== null) { if (!objToProxy.has(val)) objToProxy.set(val, new Proxy(val, handlers)); internal = objToProxy.get(val); diff --git a/src/runtime/directives.js b/src/runtime/directives.js index 5741046d..ab3b62aa 100644 --- a/src/runtime/directives.js +++ b/src/runtime/directives.js @@ -34,7 +34,12 @@ export default () => { Object.values(effect).forEach((callback) => { useSignalEffect(() => { const cb = getCallback(callback); - cb({ context, tick, ref: element.ref.current }); + cb({ + context, + tick, + ref: element.ref.current, + state: window.wpx.state, + }); }); }); } @@ -46,7 +51,7 @@ export default () => { Object.entries(on).forEach(([name, callback]) => { element.props[`on${name}`] = (event) => { const cb = getCallback(callback); - cb({ context, event }); + cb({ context, event, state: window.wpx.state }); }; }); }); @@ -64,7 +69,7 @@ export default () => { .filter((n) => n !== 'default') .forEach((name) => { const cb = getCallback(className[name]); - const result = cb({ context }); + const result = cb({ context, state: window.wpx.state }); if (!result) element.props.class.replace(name, ''); else if (!element.props.class.includes(name)) element.props.class += ` ${name}`; @@ -81,7 +86,10 @@ export default () => { .filter((n) => n !== 'default') .forEach(([attribute, callback]) => { const cb = getCallback(callback); - element.props[attribute] = cb({ context }); + element.props[attribute] = cb({ + context, + state: window.wpx.state, + }); }); } ); diff --git a/src/runtime/wpx.js b/src/runtime/wpx.js new file mode 100644 index 00000000..6f7c1b47 --- /dev/null +++ b/src/runtime/wpx.js @@ -0,0 +1,10 @@ +import { deepSignal } from './deepsignal'; +import { deepMerge } from './utils'; + +const rawState = {}; +window.wpx = { state: deepSignal(rawState) }; + +export default ({ state, ...block }) => { + deepMerge(window.wpx, block); + deepMerge(rawState, state); +}; From 7a5ed15f4cf3c46e79235de066dc35de127326f8 Mon Sep 17 00:00:00 2001 From: David Arenas Date: Thu, 20 Oct 2022 13:26:50 +0200 Subject: [PATCH 05/20] Use a different transition tag for each content --- transition-styles.css | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/transition-styles.css b/transition-styles.css index 40067c25..86c61fdb 100644 --- a/transition-styles.css +++ b/transition-styles.css @@ -22,14 +22,20 @@ } } -::page-transition-outgoing-image(main) { +::page-transition-outgoing-image(main-movies), +::page-transition-outgoing-image(main-movie), +::page-transition-outgoing-image(main-actors), +::page-transition-outgoing-image(main-actor) { animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out, 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left; } -::page-transition-incoming-image(main) { +::page-transition-incoming-image(main-movies), +::page-transition-incoming-image(main-movie), +::page-transition-incoming-image(main-actors), +::page-transition-incoming-image(main-actor) { animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right; } @@ -49,10 +55,24 @@ header { } main { - page-transition-tag: main; contain: paint; } +.home main { + page-transition-tag: main-movies; +} +.single-movies main { + page-transition-tag: main-movie; +} + +.post-type-archive-actors main { + page-transition-tag: main-actors; +} +.single-actors main { + page-transition-tag: main-actor; +} + + .wp-block-post-featured-image img { contain: paint; } \ No newline at end of file From 7d86ee491114cb698404a5529eeeac3b81ed2c4e Mon Sep 17 00:00:00 2001 From: David Arenas Date: Thu, 20 Oct 2022 14:02:00 +0200 Subject: [PATCH 06/20] Handle scroll inside startTransition --- src/runtime/directives.js | 13 +------------ src/runtime/router.js | 14 +++++++++----- src/runtime/transitions.js | 13 +++++++++++-- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/runtime/directives.js b/src/runtime/directives.js index 5741046d..8a4a23ad 100644 --- a/src/runtime/directives.js +++ b/src/runtime/directives.js @@ -109,18 +109,7 @@ export default () => { 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); - } + await navigate(href, link?.scroll); }; } } diff --git a/src/runtime/router.js b/src/runtime/router.js index 9f2a19d4..1b0bb1d8 100644 --- a/src/runtime/router.js +++ b/src/runtime/router.js @@ -67,15 +67,19 @@ export const prefetch = (url) => { }; // Navigate to a new page. -export const navigate = async (href) => { +export const navigate = async (href, scroll) => { const url = cleanUrl(href); prefetch(url); const page = await pages.get(url); if (page) { - await startTransition(href, () => { - document.head.replaceChildren(...page.head); - render(page.body, rootFragment); - }); + await startTransition( + href, + () => { + document.head.replaceChildren(...page.head); + render(page.body, rootFragment); + }, + scroll + ); window.history.pushState({}, '', href); } else { window.location.assign(href); diff --git a/src/runtime/transitions.js b/src/runtime/transitions.js index 107ca4e7..015bacca 100644 --- a/src/runtime/transitions.js +++ b/src/runtime/transitions.js @@ -1,6 +1,6 @@ let previousHref = window.location.href; -export const startTransition = async (href, updateDomCallback) => { +export const startTransition = async (href, updateDomCallback, scroll) => { if (!document.createDocumentTransition) { updateDomCallback(); return; @@ -65,7 +65,16 @@ export const startTransition = async (href, updateDomCallback) => { updateDomCallback(); - window.scrollTo(0, 0); + // Update the scroll, depending on the option. True by default. + if (scroll === 'smooth') { + window.scrollTo({ + top: 0, + left: 0, + behavior: 'smooth', + }); + } else if (scroll !== false) { + window.scrollTo(0, 0); + } // Small to big -> final picture is the big one. if ( From 66058b8e1f0d56dfcabd2bca887092499f16e40e Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Thu, 20 Oct 2022 14:24:33 +0200 Subject: [PATCH 07/20] Add favorite post blocks --- src/blocks/favorites-number/block.json | 15 ++++++++++++ src/blocks/favorites-number/edit.js | 19 +++++++++++++++ src/blocks/favorites-number/index.js | 8 +++++++ src/blocks/favorites-number/render.php | 14 +++++++++++ src/blocks/favorites-number/style.scss | 4 ++++ src/blocks/favorites-number/view.js | 32 ++++++++++++++++++++++++++ src/blocks/post-favorite/block.json | 15 ++++++++++++ src/blocks/post-favorite/edit.js | 18 +++++++++++++++ src/blocks/post-favorite/index.js | 8 +++++++ src/blocks/post-favorite/render.php | 16 +++++++++++++ src/blocks/post-favorite/style.scss | 4 ++++ src/blocks/test/block.json | 12 ---------- src/blocks/test/index.js | 14 ----------- src/blocks/test/view.js | 20 ---------------- webpack.config.js | 4 +++- wp-directives.php | 9 ++++---- 16 files changed, 161 insertions(+), 51 deletions(-) create mode 100644 src/blocks/favorites-number/block.json create mode 100644 src/blocks/favorites-number/edit.js create mode 100644 src/blocks/favorites-number/index.js create mode 100644 src/blocks/favorites-number/render.php create mode 100644 src/blocks/favorites-number/style.scss create mode 100644 src/blocks/favorites-number/view.js create mode 100644 src/blocks/post-favorite/block.json create mode 100644 src/blocks/post-favorite/edit.js create mode 100644 src/blocks/post-favorite/index.js create mode 100644 src/blocks/post-favorite/render.php create mode 100644 src/blocks/post-favorite/style.scss delete mode 100644 src/blocks/test/block.json delete mode 100644 src/blocks/test/index.js delete mode 100644 src/blocks/test/view.js diff --git a/src/blocks/favorites-number/block.json b/src/blocks/favorites-number/block.json new file mode 100644 index 00000000..2b7216a6 --- /dev/null +++ b/src/blocks/favorites-number/block.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "bhe/favorites-number", + "version": "0.1.0", + "title": "BHE - Favorites Number", + "category": "text", + "icon": "heart", + "description": "", + "textdomain": "bhe", + "editorScript": "file:./index.js", + "editorStyle": "file:./style.css", + "style": "file:./style-index.css", + "render": "file:./render.php" +} diff --git a/src/blocks/favorites-number/edit.js b/src/blocks/favorites-number/edit.js new file mode 100644 index 00000000..0ed27f42 --- /dev/null +++ b/src/blocks/favorites-number/edit.js @@ -0,0 +1,19 @@ +import '@wordpress/block-editor'; +import { useBlockProps } from '@wordpress/block-editor'; + +const Edit = () => { + return ( +
+ :heart: + 5 +
+ ); +}; + +export default Edit; diff --git a/src/blocks/favorites-number/index.js b/src/blocks/favorites-number/index.js new file mode 100644 index 00000000..468e578a --- /dev/null +++ b/src/blocks/favorites-number/index.js @@ -0,0 +1,8 @@ +import { registerBlockType } from '@wordpress/blocks'; +import Edit from './edit'; +import './style.scss'; + +registerBlockType('bhe/favorites-number', { + edit: Edit, + save: () => null, +}); diff --git a/src/blocks/favorites-number/render.php b/src/blocks/favorites-number/render.php new file mode 100644 index 00000000..752134e7 --- /dev/null +++ b/src/blocks/favorites-number/render.php @@ -0,0 +1,14 @@ +
+ :heart: + + +
\ No newline at end of file diff --git a/src/blocks/favorites-number/style.scss b/src/blocks/favorites-number/style.scss new file mode 100644 index 00000000..cadd0f72 --- /dev/null +++ b/src/blocks/favorites-number/style.scss @@ -0,0 +1,4 @@ +.wp-block-bhe-favorites-number { + border: 1px solid rgb(209, 21, 21); + position: relative; +} \ No newline at end of file diff --git a/src/blocks/favorites-number/view.js b/src/blocks/favorites-number/view.js new file mode 100644 index 00000000..7044a767 --- /dev/null +++ b/src/blocks/favorites-number/view.js @@ -0,0 +1,32 @@ +import wpx from '../../runtime/wpx'; + +wpx({ + state: { + favorites: { + posts: [], + count: ({ state }) => state.favorites.posts.length, + }, + }, + actions: { + favorites: { + togglePost: ({ state, context }) => { + const index = state.favorites.posts.findIndex( + (post) => post === context.post.id + ); + if (index === -1) state.favorites.posts.push(context.post.id); + else state.favorites.posts.splice(index, 1); + }, + isPostIncluded: ({ state, context }) => { + return state.favorites.posts.includes(context.post.id) + ? 'https://s.w.org/images/core/emoji/14.0.0/svg/2764.svg' + : 'https://s.w.org/images/core/emoji/14.0.0/svg/1f90d.svg'; + }, + isFavoritePostsEmpty: ({ state }) => { + debugger; + return state.favorites.posts.length !== 0 + ? 'https://s.w.org/images/core/emoji/14.0.0/svg/2764.svg' + : 'https://s.w.org/images/core/emoji/14.0.0/svg/1f90d.svg'; + }, + }, + }, +}); diff --git a/src/blocks/post-favorite/block.json b/src/blocks/post-favorite/block.json new file mode 100644 index 00000000..e2c77c94 --- /dev/null +++ b/src/blocks/post-favorite/block.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "bhe/post-favorite", + "version": "0.1.0", + "title": "BHE - Post Favorite", + "category": "text", + "icon": "heart", + "description": "", + "textdomain": "bhe", + "editorScript": "file:./index.js", + "editorStyle": "file:./style.css", + "style": "file:./style-index.css", + "render": "file:./render.php" +} diff --git a/src/blocks/post-favorite/edit.js b/src/blocks/post-favorite/edit.js new file mode 100644 index 00000000..d555f2fc --- /dev/null +++ b/src/blocks/post-favorite/edit.js @@ -0,0 +1,18 @@ +import '@wordpress/block-editor'; +import { useBlockProps } from '@wordpress/block-editor'; + +const Edit = () => { + return ( +
+ :heart: +
+ ); +}; + +export default Edit; diff --git a/src/blocks/post-favorite/index.js b/src/blocks/post-favorite/index.js new file mode 100644 index 00000000..31831a71 --- /dev/null +++ b/src/blocks/post-favorite/index.js @@ -0,0 +1,8 @@ +import { registerBlockType } from '@wordpress/blocks'; +import Edit from './edit'; +import './style.scss'; + +registerBlockType('bhe/post-favorite', { + edit: Edit, + save: () => null, +}); diff --git a/src/blocks/post-favorite/render.php b/src/blocks/post-favorite/render.php new file mode 100644 index 00000000..5666a11f --- /dev/null +++ b/src/blocks/post-favorite/render.php @@ -0,0 +1,16 @@ + + + + + wp-on:click="actions.favorites.togglePost" + draggable="false" + role="img" + class="emoji" + alt=":heart:" + wp-bind:src="actions.favorites.isPostIncluded" + /> + \ No newline at end of file diff --git a/src/blocks/post-favorite/style.scss b/src/blocks/post-favorite/style.scss new file mode 100644 index 00000000..7e2c2e16 --- /dev/null +++ b/src/blocks/post-favorite/style.scss @@ -0,0 +1,4 @@ +.wp-block-bhe-post-favorite { + width: 1rem; + cursor: pointer; +} \ No newline at end of file diff --git a/src/blocks/test/block.json b/src/blocks/test/block.json deleted file mode 100644 index c74d7deb..00000000 --- a/src/blocks/test/block.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, - "name": "test/test", - "version": "0.1.0", - "title": "Test block", - "category": "text", - "icon": "flag", - "description": "", - "textdomain": "test", - "editorScript": "file:./index.js" -} diff --git a/src/blocks/test/index.js b/src/blocks/test/index.js deleted file mode 100644 index fe3ac6eb..00000000 --- a/src/blocks/test/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import { registerBlockType } from '@wordpress/blocks'; - -const Edit = () =>
Favorites blocks
; - -registerBlockType('test/test', { - edit: Edit, - save: () => ( - - - - ), -}); diff --git a/src/blocks/test/view.js b/src/blocks/test/view.js deleted file mode 100644 index c7d27152..00000000 --- a/src/blocks/test/view.js +++ /dev/null @@ -1,20 +0,0 @@ -import wpx from '../../runtime/wpx'; - -wpx({ - state: { - favorites: { - posts: [], - }, - }, - actions: { - favorites: { - togglePost: ({ state, context }) => { - const index = state.favorites.posts.findIndex( - (post) => post === context.post.id - ); - if (index === -1) state.favorites.posts.push(context.post.id); - else state.favorites.posts.splice(index, 1); - }, - }, - }, -}); diff --git a/webpack.config.js b/webpack.config.js index 75752fb8..a86ef4fc 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,9 +4,11 @@ const { resolve } = require('path'); module.exports = [ defaultConfig, { + ...defaultConfig, entry: { runtime: './src/runtime', - 'blocks/test/view': './src/blocks/test/view', + 'blocks/favorites-number/view': + './src/blocks/favorites-number/view', }, output: { filename: '[name].js', diff --git a/wp-directives.php b/wp-directives.php index ab8967fc..3a32573a 100644 --- a/wp-directives.php +++ b/wp-directives.php @@ -131,13 +131,14 @@ function wp_directives_client_site_transitions_option() /* WP Movies Demo */ add_action('init', function () { - register_block_type(__DIR__ . '/build/blocks/test'); + register_block_type(__DIR__ . '/build/blocks/post-favorite'); + register_block_type(__DIR__ . '/build/blocks/favorites-number'); }); -add_filter('render_block_test/test', function ($content) { +add_filter('render_block_bhe/favorites-number', function ($content) { wp_enqueue_script( - 'test/test', - plugin_dir_url(__FILE__) . 'build/blocks/test/view.js' + 'bhe/favorites-number', + plugin_dir_url(__FILE__) . 'build/blocks/favorites-number/view.js' ); return $content; }); From 856297711d0bd254dd4578ee2a831bdac4f4b291 Mon Sep 17 00:00:00 2001 From: David Arenas Date: Thu, 20 Oct 2022 14:31:10 +0200 Subject: [PATCH 08/20] Fix scroll when there are no client transitions --- src/runtime/transitions.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/runtime/transitions.js b/src/runtime/transitions.js index 015bacca..9cf9e4ea 100644 --- a/src/runtime/transitions.js +++ b/src/runtime/transitions.js @@ -3,6 +3,18 @@ let previousHref = window.location.href; export const startTransition = async (href, updateDomCallback, scroll) => { if (!document.createDocumentTransition) { updateDomCallback(); + + // Update the scroll, depending on the option. True by default. + if (scroll === 'smooth') { + window.scrollTo({ + top: 0, + left: 0, + behavior: 'smooth', + }); + } else if (scroll !== false) { + window.scrollTo(0, 0); + } + return; } From 384729e969a841b58925db14b7b3dc7557880a20 Mon Sep 17 00:00:00 2001 From: Mario Santos Date: Thu, 20 Oct 2022 14:40:33 +0200 Subject: [PATCH 09/20] Add default values to favorites blocks --- src/blocks/favorites-number/render.php | 1 + src/blocks/post-favorite/render.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/blocks/favorites-number/render.php b/src/blocks/favorites-number/render.php index 752134e7..6b809a62 100644 --- a/src/blocks/favorites-number/render.php +++ b/src/blocks/favorites-number/render.php @@ -10,5 +10,6 @@ class="emoji" + 0 \ No newline at end of file diff --git a/src/blocks/post-favorite/render.php b/src/blocks/post-favorite/render.php index 5666a11f..7633d0a6 100644 --- a/src/blocks/post-favorite/render.php +++ b/src/blocks/post-favorite/render.php @@ -11,6 +11,7 @@ role="img" class="emoji" alt=":heart:" + src="https://s.w.org/images/core/emoji/14.0.0/svg/1f90d.svg" wp-bind:src="actions.favorites.isPostIncluded" /> \ No newline at end of file From 1d659fa7ec92f381c1832f12c728a4403bdd62d7 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 20 Oct 2022 16:10:39 +0200 Subject: [PATCH 10/20] Minor fixes --- src/blocks/favorites-number/render.php | 5 +---- src/blocks/favorites-number/view.js | 23 ++++++++++++----------- src/blocks/post-favorite/render.php | 9 +++------ src/runtime/components.js | 2 +- src/runtime/directives.js | 5 ++++- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/blocks/favorites-number/render.php b/src/blocks/favorites-number/render.php index 6b809a62..f86d3658 100644 --- a/src/blocks/favorites-number/render.php +++ b/src/blocks/favorites-number/render.php @@ -1,11 +1,8 @@
:heart: state.favorites.posts.length, }, }, + selectors: { + favorites: { + isPostIncluded: ({ state, context: { post } }) => + `https://s.w.org/images/core/emoji/14.0.0/svg/${ + state.favorites.posts.includes(post.id) ? '2764' : '1f90' + }.svg`, + isFavoritePostsEmpty: ({ state }) => + `https://s.w.org/images/core/emoji/14.0.0/svg/${ + state.favorites.posts.length !== 0 ? '2764' : '1f90' + }.svg`, + }, + }, actions: { favorites: { togglePost: ({ state, context }) => { @@ -16,17 +28,6 @@ wpx({ if (index === -1) state.favorites.posts.push(context.post.id); else state.favorites.posts.splice(index, 1); }, - isPostIncluded: ({ state, context }) => { - return state.favorites.posts.includes(context.post.id) - ? 'https://s.w.org/images/core/emoji/14.0.0/svg/2764.svg' - : 'https://s.w.org/images/core/emoji/14.0.0/svg/1f90d.svg'; - }, - isFavoritePostsEmpty: ({ state }) => { - debugger; - return state.favorites.posts.length !== 0 - ? 'https://s.w.org/images/core/emoji/14.0.0/svg/2764.svg' - : 'https://s.w.org/images/core/emoji/14.0.0/svg/1f90d.svg'; - }, }, }, }); diff --git a/src/blocks/post-favorite/render.php b/src/blocks/post-favorite/render.php index 7633d0a6..4917428c 100644 --- a/src/blocks/post-favorite/render.php +++ b/src/blocks/post-favorite/render.php @@ -3,15 +3,12 @@ $wrapper_attributes = get_block_wrapper_attributes(); ?> - + + wp-on:click="actions.favorites.togglePost" - draggable="false" - role="img" - class="emoji" alt=":heart:" src="https://s.w.org/images/core/emoji/14.0.0/svg/1f90d.svg" - wp-bind:src="actions.favorites.isPostIncluded" + wp-bind:src="selectors.favorites.isPostIncluded" /> \ No newline at end of file diff --git a/src/runtime/components.js b/src/runtime/components.js index 8edcf5f4..acc75298 100644 --- a/src/runtime/components.js +++ b/src/runtime/components.js @@ -4,7 +4,7 @@ import { component } from './hooks'; export default () => { const WpContext = ({ children, data, context: { Provider } }) => { - const signals = useMemo(() => deepSignal(JSON.parse(data)), []); + const signals = useMemo(() => deepSignal(JSON.parse(data)), [data]); return {children}; }; component('wp-context', WpContext); diff --git a/src/runtime/directives.js b/src/runtime/directives.js index a854bf6c..808b7aa4 100644 --- a/src/runtime/directives.js +++ b/src/runtime/directives.js @@ -21,7 +21,10 @@ export default () => { props: { children }, context: { Provider }, }) => { - const signals = useMemo(() => deepSignal(context.default), []); + const signals = useMemo( + () => deepSignal(context.default), + [JSON.stringify(context.default)] + ); return {children}; } ); From 2e06a0a45045e348a56682349e67352f40ae4cba Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 20 Oct 2022 16:16:18 +0200 Subject: [PATCH 11/20] Fix image url --- src/blocks/favorites-number/view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/blocks/favorites-number/view.js b/src/blocks/favorites-number/view.js index a5d3ccc3..59cdc6b5 100644 --- a/src/blocks/favorites-number/view.js +++ b/src/blocks/favorites-number/view.js @@ -11,11 +11,11 @@ wpx({ favorites: { isPostIncluded: ({ state, context: { post } }) => `https://s.w.org/images/core/emoji/14.0.0/svg/${ - state.favorites.posts.includes(post.id) ? '2764' : '1f90' + state.favorites.posts.includes(post.id) ? '2764' : '1f90d' }.svg`, isFavoritePostsEmpty: ({ state }) => `https://s.w.org/images/core/emoji/14.0.0/svg/${ - state.favorites.posts.length !== 0 ? '2764' : '1f90' + state.favorites.posts.length !== 0 ? '2764' : '1f90d' }.svg`, }, }, From e017eda1b837884236264dcbfda3fe57b397b3be Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 20 Oct 2022 16:20:34 +0200 Subject: [PATCH 12/20] Fix image class --- src/blocks/favorites-number/render.php | 1 + src/blocks/post-favorite/render.php | 1 + 2 files changed, 2 insertions(+) diff --git a/src/blocks/favorites-number/render.php b/src/blocks/favorites-number/render.php index f86d3658..2be8f8a8 100644 --- a/src/blocks/favorites-number/render.php +++ b/src/blocks/favorites-number/render.php @@ -1,5 +1,6 @@
:heart: wp-on:click="actions.favorites.togglePost" + class="emoji" alt=":heart:" src="https://s.w.org/images/core/emoji/14.0.0/svg/1f90d.svg" wp-bind:src="selectors.favorites.isPostIncluded" From 2a57a7fdee896ef4f77f051beeb51e9909ab6165 Mon Sep 17 00:00:00 2001 From: David Arenas Date: Thu, 20 Oct 2022 18:02:31 +0200 Subject: [PATCH 13/20] Save and restore favorites --- src/blocks/favorites-number/render.php | 2 +- src/blocks/favorites-number/view.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/blocks/favorites-number/render.php b/src/blocks/favorites-number/render.php index 2be8f8a8..05743133 100644 --- a/src/blocks/favorites-number/render.php +++ b/src/blocks/favorites-number/render.php @@ -1,4 +1,4 @@ -
+
:heart: { + localStorage.setItem( + 'wpmoviesdemo.favorites', + JSON.stringify(state.favorites) + ); + }, + restore: ({ state }) => { + deepMerge( + state.favorites, + JSON.parse( + localStorage.getItem('wpmoviesdemo.favorites') + ) || {} + ); + }, }, }, }); From 403a19576309d89bb86fe776c7a0bb599cc3b7f3 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Fri, 21 Oct 2022 11:22:53 +0200 Subject: [PATCH 14/20] Preserve the client component in the DOM --- src/runtime/hooks.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/runtime/hooks.js b/src/runtime/hooks.js index 46e4012d..617f6009 100644 --- a/src/runtime/hooks.js +++ b/src/runtime/hooks.js @@ -38,8 +38,11 @@ options.vnode = (vnode) => { const wp = vnode.props.wp; if (typeof type === 'string' && type.startsWith('wp-')) { - vnode.type = components[type]; - vnode.props.context = context; + vnode.props.children = h( + components[type], + { ...vnode.props, context }, + vnode.props.children + ); } if (wp) { From 34961c702822fcc45e604d7ab13ddc293cac6d70 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 3 Nov 2022 10:49:20 +0100 Subject: [PATCH 15/20] Remove transitions --- src/runtime/router.js | 19 ++---- src/runtime/transitions.js | 120 ------------------------------------- transition-styles.css | 78 ------------------------ wp-directives.php | 6 -- 4 files changed, 5 insertions(+), 218 deletions(-) delete mode 100644 src/runtime/transitions.js delete mode 100644 transition-styles.css diff --git a/src/runtime/router.js b/src/runtime/router.js index 1b0bb1d8..81ae1bcc 100644 --- a/src/runtime/router.js +++ b/src/runtime/router.js @@ -1,7 +1,6 @@ import { hydrate, render } from 'preact'; import toVdom from './vdom'; import { createRootFragment } from './utils'; -import { startTransition } from './transitions'; // The root to render the vdom (document.body). let rootFragment; @@ -67,19 +66,13 @@ export const prefetch = (url) => { }; // Navigate to a new page. -export const navigate = async (href, scroll) => { +export const navigate = async (href) => { const url = cleanUrl(href); prefetch(url); const page = await pages.get(url); if (page) { - await startTransition( - href, - () => { - document.head.replaceChildren(...page.head); - render(page.body, rootFragment); - }, - scroll - ); + document.head.replaceChildren(...page.head); + render(page.body, rootFragment); window.history.pushState({}, '', href); } else { window.location.assign(href); @@ -92,10 +85,8 @@ window.addEventListener('popstate', async () => { const url = cleanUrl(window.location); // Remove hash. if (pages.has(url)) { const { body, head } = await pages.get(url); - await startTransition(window.location.href, () => { - document.head.replaceChildren(...head); - render(body, rootFragment); - }); + document.head.replaceChildren(...head); + render(body, rootFragment); } else { window.location.reload(); } diff --git a/src/runtime/transitions.js b/src/runtime/transitions.js deleted file mode 100644 index 9cf9e4ea..00000000 --- a/src/runtime/transitions.js +++ /dev/null @@ -1,120 +0,0 @@ -let previousHref = window.location.href; - -export const startTransition = async (href, updateDomCallback, scroll) => { - if (!document.createDocumentTransition) { - updateDomCallback(); - - // Update the scroll, depending on the option. True by default. - if (scroll === 'smooth') { - window.scrollTo({ - top: 0, - left: 0, - behavior: 'smooth', - }); - } else if (scroll !== false) { - window.scrollTo(0, 0); - } - - return; - } - - // Transition types: - - // Small to big: - // From movies to movie - // From actors to actor - // From movie to actor - - // Big to small: - // From movie to movies - // From actor to actors - - const previousPathname = new URL(previousHref, window.location.href) - .pathname; - const isFromMovie = /^\/movies\/[\w-]+\/$/.test(previousPathname); - const isFromMovies = /^\/(movies\/)?$/.test(previousPathname); - const isFromActor = /^\/actors\/[\w-]+\/$/.test(previousPathname); - const isFromActors = /^\/actors\/$/.test(previousPathname); - - const nextPathname = new URL(href, window.location.href).pathname; - const isToMovie = /^\/movies\/[\w-]+\/$/.test(nextPathname); - const isToMovies = /^\/(movies\/)?$/.test(nextPathname); - const isToActor = /^\/actors\/[\w-]+\/$/.test(nextPathname); - const isToActors = /^\/actors\/$/.test(nextPathname); - - // Select the element we are going to transition from. - let initialPicture; - - // Small to big -> Initial picture is the small one. - if ( - (isFromMovies && isToMovie) || - (isFromActors && isToActor) || - (isFromMovie && isToActor) - ) { - initialPicture = document.querySelector(`a[href$="${href}"] > img`); - } - - // Big to small -> Initial picture is the big one. - else if ((isFromMovie && isToMovies) || (isFromActor && isToActors)) { - initialPicture = document.querySelector( - `.wp-block-post-featured-image > img` - ); - } - - if (initialPicture) { - initialPicture.style.pageTransitionTag = 'picture'; - } - - const transition = document.createDocumentTransition(); - - let finalPicture; - await transition - .start(() => { - // Remove transition tag. - if (initialPicture) { - initialPicture.style.pageTransitionTag = ''; - } - - updateDomCallback(); - - // Update the scroll, depending on the option. True by default. - if (scroll === 'smooth') { - window.scrollTo({ - top: 0, - left: 0, - behavior: 'smooth', - }); - } else if (scroll !== false) { - window.scrollTo(0, 0); - } - - // Small to big -> final picture is the big one. - if ( - (isFromMovies && isToMovie) || - (isFromActors && isToActor) || - (isFromMovie && isToActor) - ) { - finalPicture = document.querySelector( - `.wp-block-post-featured-image > img` - ); - } - - // Big to small -> Final picture is the small one. - if ((isFromMovie && isToMovies) || (isFromActor && isToActors)) { - finalPicture = document.querySelector( - `a[href$="${previousHref}"] > img` - ); - } - - if (finalPicture) { - finalPicture.style.pageTransitionTag = 'picture'; - } - }) - .then(() => { - if (finalPicture) { - finalPicture.style.pageTransitionTag = ''; - } - // Update previous URL. This works as long as we make a transition for each navigation. - previousHref = href; - }); -}; diff --git a/transition-styles.css b/transition-styles.css deleted file mode 100644 index 86c61fdb..00000000 --- a/transition-styles.css +++ /dev/null @@ -1,78 +0,0 @@ -@keyframes fade-in { - from { - opacity: 0; - } -} - -@keyframes fade-out { - to { - opacity: 0; - } -} - -@keyframes slide-from-right { - from { - transform: translateX(30px); - } -} - -@keyframes slide-to-left { - to { - transform: translateX(-30px); - } -} - -::page-transition-outgoing-image(main-movies), -::page-transition-outgoing-image(main-movie), -::page-transition-outgoing-image(main-actors), -::page-transition-outgoing-image(main-actor) { - animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out, 300ms cubic-bezier(0.4, - 0, - 0.2, - 1) both slide-to-left; -} - -::page-transition-incoming-image(main-movies), -::page-transition-incoming-image(main-movie), -::page-transition-incoming-image(main-actors), -::page-transition-incoming-image(main-actor) { - animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right; -} - -::page-transition-outgoing-image(picture), -::page-transition-incoming-image(picture) { - animation: none; - mix-blend-mode: normal; -} - -::page-transition-image-wrapper(picture) { - isolation: none; -} - -header { - page-transition-tag: header; - contain: paint; -} - -main { - contain: paint; -} - -.home main { - page-transition-tag: main-movies; -} -.single-movies main { - page-transition-tag: main-movie; -} - -.post-type-archive-actors main { - page-transition-tag: main-actors; -} -.single-actors main { - page-transition-tag: main-actor; -} - - -.wp-block-post-featured-image img { - contain: paint; -} \ No newline at end of file diff --git a/wp-directives.php b/wp-directives.php index 3a32573a..30a73e4d 100644 --- a/wp-directives.php +++ b/wp-directives.php @@ -60,12 +60,6 @@ function wp_directives_register_scripts() // For now we can always enqueue the runtime. We'll figure out how to // conditionally enqueue directives later. wp_enqueue_script('wp-directive-runtime'); - - wp_register_style( - 'transition-styles', - plugin_dir_url(__FILE__) . '/transition-styles.css' - ); - wp_enqueue_style('transition-styles'); } add_action('wp_enqueue_scripts', 'wp_directives_register_scripts'); From 28a67ebe29df8d160af4c2f59237d60bf29f938b Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 3 Nov 2022 11:16:22 +0100 Subject: [PATCH 16/20] Add tabs block --- src/blocks/tabs/block.json | 15 +++++++++++++++ src/blocks/tabs/edit.js | 7 +++++++ src/blocks/tabs/index.js | 8 ++++++++ src/blocks/tabs/render.php | 3 +++ src/blocks/tabs/style.scss | 2 ++ wp-directives.php | 3 ++- 6 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/blocks/tabs/block.json create mode 100644 src/blocks/tabs/edit.js create mode 100644 src/blocks/tabs/index.js create mode 100644 src/blocks/tabs/render.php create mode 100644 src/blocks/tabs/style.scss diff --git a/src/blocks/tabs/block.json b/src/blocks/tabs/block.json new file mode 100644 index 00000000..0b3716d4 --- /dev/null +++ b/src/blocks/tabs/block.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "bhe/tabs", + "version": "0.1.0", + "title": "BHE - Tabs", + "category": "text", + "icon": "tab", + "description": "Tabs", + "textdomain": "bhe", + "editorScript": "file:./index.js", + "editorStyle": "file:./style.css", + "style": "file:./style-index.css", + "render": "file:./render.php" +} diff --git a/src/blocks/tabs/edit.js b/src/blocks/tabs/edit.js new file mode 100644 index 00000000..60a9952f --- /dev/null +++ b/src/blocks/tabs/edit.js @@ -0,0 +1,7 @@ +import { useBlockProps } from '@wordpress/block-editor'; + +const Edit = () => { + return
I'm a tab
; +}; + +export default Edit; diff --git a/src/blocks/tabs/index.js b/src/blocks/tabs/index.js new file mode 100644 index 00000000..2bd23955 --- /dev/null +++ b/src/blocks/tabs/index.js @@ -0,0 +1,8 @@ +import { registerBlockType } from '@wordpress/blocks'; +import Edit from './edit'; +import './style.scss'; + +registerBlockType('bhe/tabs', { + edit: Edit, + save: () => null, +}); diff --git a/src/blocks/tabs/render.php b/src/blocks/tabs/render.php new file mode 100644 index 00000000..becabd74 --- /dev/null +++ b/src/blocks/tabs/render.php @@ -0,0 +1,3 @@ +

The tabs

+
I should be shown
+
I should not be shown
\ No newline at end of file diff --git a/src/blocks/tabs/style.scss b/src/blocks/tabs/style.scss new file mode 100644 index 00000000..e4736146 --- /dev/null +++ b/src/blocks/tabs/style.scss @@ -0,0 +1,2 @@ +.wp-block-bhe-tabs { +} diff --git a/wp-directives.php b/wp-directives.php index 30a73e4d..bd3134bd 100644 --- a/wp-directives.php +++ b/wp-directives.php @@ -123,10 +123,11 @@ function wp_directives_client_site_transitions_option() 'wp_directives_client_site_transitions_option' ); -/* WP Movies Demo */ +/* Blocks */ add_action('init', function () { register_block_type(__DIR__ . '/build/blocks/post-favorite'); register_block_type(__DIR__ . '/build/blocks/favorites-number'); + register_block_type(__DIR__ . '/build/blocks/tabs'); }); add_filter('render_block_bhe/favorites-number', function ($content) { From 26da281df208c9810dd1de42f6d6b37e10221a52 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 3 Nov 2022 12:10:32 +0100 Subject: [PATCH 17/20] Add initial SSR for wp-show Co-authored-by: Mario Santos --- package.json | 6 ++++-- src/blocks/tabs/render.php | 2 +- src/runtime/components.js | 5 +++++ ssr/index.mjs | 31 +++++++++++++++++++++++++++++++ wp-directives.php | 29 +++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 ssr/index.mjs diff --git a/package.json b/package.json index d0c60e63..9573210d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "test": "jest", "test:watch": "jest --watch", "plugin-zip": "wp-scripts plugin-zip", - "wp-env": "wp-env" + "wp-env": "wp-env", + "ssr": "node ssr/index.mjs" }, "prettier": { "useTabs": true, @@ -39,6 +40,7 @@ "dependencies": { "@preact/signals": "^1.1.2", "hpq": "^1.3.0", - "preact": "^10.10.6" + "preact": "^10.10.6", + "ultrahtml": "^0.4.0" } } diff --git a/src/blocks/tabs/render.php b/src/blocks/tabs/render.php index becabd74..aba68760 100644 --- a/src/blocks/tabs/render.php +++ b/src/blocks/tabs/render.php @@ -1,3 +1,3 @@ -

The tabs

+

The tabs!

I should be shown
I should not be shown
\ No newline at end of file diff --git a/src/runtime/components.js b/src/runtime/components.js index acc75298..a45512cf 100644 --- a/src/runtime/components.js +++ b/src/runtime/components.js @@ -8,4 +8,9 @@ export default () => { return {children}; }; component('wp-context', WpContext); + + const WpShow = ({ children }) => { + return children; + }; + component('wp-show', WpShow); }; diff --git a/ssr/index.mjs b/ssr/index.mjs new file mode 100644 index 00000000..2207183a --- /dev/null +++ b/ssr/index.mjs @@ -0,0 +1,31 @@ +import { transform, html } from 'ultrahtml'; +import { readFile, writeFile } from 'fs/promises'; + +const file = '/blocks/tabs/render.php'; + +const propsToArray = (props) => { + let result = '['; + Object.entries(props).forEach(([key, value]) => { + result += `["${key}", "${value}"]`; + }); + result += ']'; + return result; +}; + +const start = async () => { + const php = await readFile('./src' + file, { + encoding: 'utf8', + }); + const output = await transform(php, { + components: { + 'wp-show': (props, children) => + html` + ${children} + `, + }, + }); + await writeFile('./build' + file, output); + console.log('done!'); +}; + +start(); diff --git a/wp-directives.php b/wp-directives.php index bd3134bd..066b6902 100644 --- a/wp-directives.php +++ b/wp-directives.php @@ -137,3 +137,32 @@ function wp_directives_client_site_transitions_option() ); return $content; }); + +function wpx_props_array_to_object($props) +{ + $array = []; + foreach ($props as list($key, $value)) { + $array[$key] = $value; + } + return $array; +} + +function wpx_tag_open($tag, $args) +{ + $props = wpx_props_array_to_object($args); + if ($props['when'] !== 'false') { + echo "<$tag>"; + } else { + echo "<$tag>"; + } +} From 668f5306b29c77c7dd03fc4f6107def949277ce1 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 3 Nov 2022 12:30:32 +0100 Subject: [PATCH 18/20] Add state to wpx in PHP Co-authored-by: Mario Santos --- src/blocks/tabs/render.php | 12 ++++++++++-- wp-directives.php | 27 +++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/blocks/tabs/render.php b/src/blocks/tabs/render.php index aba68760..28a22996 100644 --- a/src/blocks/tabs/render.php +++ b/src/blocks/tabs/render.php @@ -1,3 +1,11 @@ + [ + 'show' => true, + 'dontShow' => false, + ], +]); ?> +

The tabs!

-
I should be shown
-
I should not be shown
\ No newline at end of file +
I should be shown
+
I should not be shown
\ No newline at end of file diff --git a/wp-directives.php b/wp-directives.php index 066b6902..01f5fb5c 100644 --- a/wp-directives.php +++ b/wp-directives.php @@ -149,8 +149,10 @@ function wpx_props_array_to_object($props) function wpx_tag_open($tag, $args) { + global $wpx; $props = wpx_props_array_to_object($args); - if ($props['when'] !== 'false') { + $callback = wpx_get_callback($props['when']); + if ($callback) { echo "<$tag>"; } else { echo "<$tag>"; } } + +$GLOBALS['wpx'] = []; + +function wpx($block) +{ + global $wpx; + $wpx = array_merge_recursive($wpx, $block); +} + +function wpx_get_callback($path) +{ + global $wpx; + $current = $wpx; + $array = explode('.', $path); + foreach ($array as $p) { + $current = $current[$p]; + } + return $current; +} From 55294740f32a7fe91aa5ff69464c7c72007fef35 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 3 Nov 2022 15:58:49 +0100 Subject: [PATCH 19/20] Add attributes back to the HTML --- ssr/index.mjs | 4 +-- wp-directives.php | 63 +++++++++++++++++++++++++++++------------------ 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/ssr/index.mjs b/ssr/index.mjs index 2207183a..03c4062d 100644 --- a/ssr/index.mjs +++ b/ssr/index.mjs @@ -19,9 +19,9 @@ const start = async () => { const output = await transform(php, { components: { 'wp-show': (props, children) => - html` + html` ${children} - `, + `, }, }); await writeFile('./build' + file, output); diff --git a/wp-directives.php b/wp-directives.php index 01f5fb5c..60fb3e11 100644 --- a/wp-directives.php +++ b/wp-directives.php @@ -138,48 +138,45 @@ function wp_directives_client_site_transitions_option() return $content; }); -function wpx_props_array_to_object($props) -{ - $array = []; - foreach ($props as list($key, $value)) { - $array[$key] = $value; - } - return $array; -} +/** + * SSR in PHP + */ -function wpx_tag_open($tag, $args) +// wp-show +function wpx_show_open_tag($prop_entries) { global $wpx; - $props = wpx_props_array_to_object($args); - $callback = wpx_get_callback($props['when']); - if ($callback) { - echo "<$tag>"; + $props = wpx_prop_entries_to_array($prop_entries); + $attributes = wpx_prop_entries_to_attributes($prop_entries); + $value = wpx_get_state($props['when']); + if ($value) { + echo ""; } else { - echo "<$tag>'; } } +// Utils $GLOBALS['wpx'] = []; - -function wpx($block) +function wpx($data) { global $wpx; - $wpx = array_merge_recursive($wpx, $block); + $wpx = array_merge_recursive($wpx, $data); } -function wpx_get_callback($path) +function wpx_get_state($path) { global $wpx; $current = $wpx; @@ -189,3 +186,21 @@ function wpx_get_callback($path) } return $current; } + +function wpx_prop_entries_to_array($prop_entries) +{ + $array = []; + foreach ($prop_entries as list($key, $value)) { + $array[$key] = $value; + } + return $array; +} + +function wpx_prop_entries_to_attributes($prop_entries) +{ + $attributes = ''; + foreach ($prop_entries as list($key, $value)) { + $attributes .= "$key='$value'"; + } + return $attributes; +} From e21762559446fe00aba8f9a5f58107eee353fdb7 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 3 Nov 2022 16:00:01 +0100 Subject: [PATCH 20/20] Rename ssr.mjs --- package.json | 3 +-- ssr/index.mjs => ssr.mjs | 0 2 files changed, 1 insertion(+), 2 deletions(-) rename ssr/index.mjs => ssr.mjs (100%) diff --git a/package.json b/package.json index 9573210d..dff3a556 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "version": "0.1.0", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", - "main": "build/index.js", "scripts": { "build": "webpack --mode=production", "start": "webpack --mode=development --watch", @@ -12,7 +11,7 @@ "test:watch": "jest --watch", "plugin-zip": "wp-scripts plugin-zip", "wp-env": "wp-env", - "ssr": "node ssr/index.mjs" + "ssr": "node ssr.mjs" }, "prettier": { "useTabs": true, diff --git a/ssr/index.mjs b/ssr.mjs similarity index 100% rename from ssr/index.mjs rename to ssr.mjs