woocommerce/plugins/woocommerce-blocks/assets/js/interactivity/portals.js

101 lines
2.5 KiB
JavaScript
Raw Normal View History

Interactivity API: implement the new `store()` API (https://github.com/woocommerce/woocommerce-blocks/pull/11071) * Sync Interactivity API code with Gutenberg * New store() API * Store raw actions * Update wc-interactivity-store implementation * Replace `wc_store` with `wc_initial_state` * Parse and populate initial state * Allow store parts in `store()` * Accept namespaces in directive paths * Add $$namespace to directives' object values * Make namespace parsing more robust * Use DeepPartial type for store parts * Do not pass `rawStore` to `afterLoad` callbacks * Simplify `store()` a bit * Implement `privateStore()` * Sync context directive with Gutenberg * Refactor scope and extract getters per scope * Add namespace to getters and actions * Remove current privateStore implementation * Remove `afterLoad` option from `store` * Use same proxy handlers for ns, getters and actions * Set scope inside `evaluate` * Refactor proxy handlers * Improve types a bit * Catch errors in async actions * Implement stacks for scopes and namespaces * Implement `getElement` * Change directives object structure * Remove unnecessary import * Implement private stores * Return value from sync actions * Minor optimizations and improved comments * Don't use async inside `data-wp-watch` * Use a single Provider in context directive * Remove DeepPartial type * Do not check if element exists * Add the `current` prop of state inside the scope * Move getters outside scope * Fix wc-key assignment * Fix missing `navigate` in directives * Fix namespace not being picked in the same element * Deep merge raw stores instead of proxied ones * Fix namespace assignment * Allow forward slashes in namespaces * Migration of Product Collection and Product Button blocks to the new `store()` API (https://github.com/woocommerce/woocommerce-blocks/pull/11558) * Refactor Product Button with new store() API * Use `wc_initial_state` in Product Button * Fix namespace * Remove unnecessary state * Test namespaces in directive paths * Add test context with namespace * Simplify woo-test context * Move addToCart and animations to a file * Do not pass `rawStore` to `afterLoad` callbacks * Move callbacks and actions back to the main file Because the animation was broken. * Remove selectors in favor of state * Use default ns in `getContext` for state and actions * Remove `afterLoad` callback * Remove unnecessary ns * Fix getContext in add-to-cart * Replace namespace and delete unnecessary store * Pass context types only once * Use an alternative for requestIdleCallback * Add previous react code for notices * Add namespace to Product Collection block * Replace getTextButton with getButtonText * Add block name to the ProductCollection namespace * fix style HTML code * Remove circular deps error on the Interactivity API * Product Gallery block: Migrate to new Interactivity API store (https://github.com/woocommerce/woocommerce-blocks/pull/11721) * Migrate Product Gallery block to new Interactivity API store * Fix some references * Add missing data-wc-interactive * Fix an additional namespace * Remove unnecessary click handler * Dialog working * Refactor action names * Reindex PHP array There was some missing indexes, which turned the array into an object in JS. * Remove unused event handlers * Move next/previous logic to external function * Move StorePart util to the types folder * Rename namespace to `woocommerce/product-gallery` * Undo product collection namespace renaming * Remove unnecessary namespace * Don't hide the large image on page load * Minor refactorings * Fix eslint error * Fix php cs errors with spacing and double arrows alignment * Disable no-use-before-define rule for eslint * Disable @typescript-eslint/ban-types rule for eslint * Fix parsed context error in e2e tests * Fix context parser for Thumbnail image * Move store to the top of the frontend file * Add interactivity api utils to the @woocommerce/utils alias * Replace deprecated event attribute --------- Co-authored-by: Luis Herranz <luisherranz@gmail.com> Co-authored-by: David Arenas <david.arenas@automattic.com> Co-authored-by: roykho <roykho77@gmail.com> --------- Co-authored-by: David Arenas <david.arenas@automattic.com> Co-authored-by: Luigi Teschio <gigitux@gmail.com> Co-authored-by: Alexandre Lara <allexandrelara@gmail.com> Co-authored-by: roykho <roykho77@gmail.com> * Fix error when closing product gallery dialog with keyboard escape key * use wc_initial_state instead of wc_store --------- Co-authored-by: Luis Herranz <luisherranz@gmail.com> Co-authored-by: Luigi Teschio <gigitux@gmail.com> Co-authored-by: Alexandre Lara <allexandrelara@gmail.com> Co-authored-by: roykho <roykho77@gmail.com>
2023-11-21 10:46:15 +00:00
// @ts-nocheck
/**
* External dependencies
*/
import { createElement, render } from 'preact';
/**
* @param {import('../../src/index').RenderableProps<{ context: any }>} props
*/
function ContextProvider( props ) {
this.getChildContext = () => props.context;
return props.children;
}
/**
* Portal component
*
* @this {import('./internal').Component}
* @param {object | null | undefined} props
*
* TODO: use createRoot() instead of fake root
*/
function Portal( props ) {
const _this = this;
const container = props._container;
_this.componentWillUnmount = function () {
render( null, _this._temp );
_this._temp = null;
_this._container = null;
};
// When we change container we should clear our old container and
// indicate a new mount.
if ( _this._container && _this._container !== container ) {
_this.componentWillUnmount();
}
// When props.vnode is undefined/false/null we are dealing with some kind of
// conditional vnode. This should not trigger a render.
if ( props._vnode ) {
if ( ! _this._temp ) {
_this._container = container;
// Create a fake DOM parent node that manages a subset of `container`'s children:
_this._temp = {
nodeType: 1,
parentNode: container,
childNodes: [],
appendChild( child ) {
this.childNodes.push( child );
_this._container.appendChild( child );
},
insertBefore( child ) {
this.childNodes.push( child );
_this._container.appendChild( child );
},
removeChild( child ) {
this.childNodes.splice(
// eslint-disable-next-line no-bitwise
this.childNodes.indexOf( child ) >>> 1,
1
);
_this._container.removeChild( child );
},
};
}
// Render our wrapping element into temp.
render(
createElement(
ContextProvider,
{ context: _this.context },
props._vnode
),
_this._temp
);
}
// When we come from a conditional render, on a mounted
// portal we should clear the DOM.
else if ( _this._temp ) {
_this.componentWillUnmount();
}
}
/**
* Create a `Portal` to continue rendering the vnode tree at a different DOM node
*
* @param {import('./internal').VNode} vnode The vnode to render
* @param {import('./internal').PreactElement} container The DOM node to continue rendering in to.
*/
export function createPortal( vnode, container ) {
const el = createElement( Portal, {
_vnode: vnode,
_container: container,
} );
el.containerInfo = container;
return el;
}