From e75a738efbb1ba3983a8a00434f880d79f565d81 Mon Sep 17 00:00:00 2001 From: Willem Poortman Date: Thu, 1 Jun 2023 21:25:00 +0200 Subject: [PATCH] New overhauled loader implementation (#101) * Added value- & nested based syncInput notification label feature * Made the loader more composable * Making labels visible again * Concept to dispatch event on elements instead of window * Label splitting + translation is now being done inside the Loader Hydrator * Loader layout and binding restructure * Notification Messenger implementation * Notification messenger design completion * Notification messenger logic improvements * Message loading status busy / done icons * Notification System Configurations * StyleCI fixes * System config field comment improvement * Message failure implementation * Loader wildcard feature * AlpineJS v2 compatibility (thanks @Vinai) * Loader plugin documentation * StyleCI fix --------- Co-authored-by: Willem Poortman --- docs/Features.md | 44 ++-- src/Model/Hydrator/Loader.php | 16 +- src/Model/Magento/System/ConfigMagewire.php | 81 +++++++ src/ViewModel/Magewire.php | 10 +- src/etc/adminhtml/system.xml | 31 ++- src/etc/config.xml | 4 + src/view/frontend/layout/default_hyva.xml | 63 ++++- src/view/frontend/tailwind/tailwind.config.js | 6 +- src/view/frontend/templates/html/loader.phtml | 92 ++----- .../templates/html/loader/bindings.phtml | 34 +++ .../templates/html/loader/notifications.phtml | 92 +++---- .../html/loader/notifications/bindings.phtml | 77 ++++++ .../html/loader/notifications/messenger.phtml | 115 +++++++++ .../templates/html/loader/overlay.phtml | 41 ++++ .../templates/html/loader/spinner.phtml | 8 + .../templates/html/pagination/pager.phtml | 6 +- .../page/js/magewire-initialize.phtml | 142 ++++++----- .../templates/page/js/magewire-livewire.phtml | 5 +- .../page/js/magewire/plugin/loader.phtml | 229 +++++++++++------- 19 files changed, 764 insertions(+), 332 deletions(-) create mode 100644 src/Model/Magento/System/ConfigMagewire.php create mode 100644 src/view/frontend/templates/html/loader/bindings.phtml create mode 100644 src/view/frontend/templates/html/loader/notifications/bindings.phtml create mode 100644 src/view/frontend/templates/html/loader/notifications/messenger.phtml create mode 100644 src/view/frontend/templates/html/loader/overlay.phtml create mode 100644 src/view/frontend/templates/html/loader/spinner.phtml diff --git a/docs/Features.md b/docs/Features.md index 2c0b2ed..6943fa7 100644 --- a/docs/Features.md +++ b/docs/Features.md @@ -42,8 +42,10 @@ - [Indicator Customization](#indicator-customization) - [Indicator Removal](#indicator-removal) - [Custom Example](#custom-example-dls) + - [Notification Type Styling](#notification-type-styling) - [Plugins](#plugins) - [Plugin: Loader](#plugin--loader) + - [Loader System Settings](#loader--system-settings) - [Plugin: Error](#plugin--error) - [Custom onError callback](#custom-onerror-callback) - [Component Resolvers](#component-resolvers) @@ -847,16 +849,20 @@ class Explanation extends \Magewirephp\Magewire\Component **File**: html/magewire/loader.phtml ### Available Loader Window Events -```magewire:loader:start``` +**magewire:loader:start** > Dispatched as soon as the first ```$loader``` driven component is active. -```magewire:loader:tick``` +**Test**: ```Magewire.dispatchEvent('loader:start', { detail: { title: 'Hello world', type: 'syncInput', use: true, start: Date.now(), failed: false }})``` + +**magewire:loader:tick** > Dispatched when another component has ```$loader``` settings. -```magewire:loader:fail``` +**Test**: ```Magewire.dispatchEvent('loader:tick', { detail: { title: 'Hello world', type: 'syncInput', use: true, start: Date.now(), failed: false }})``` + +**magewire:loader:fail** > Dispatched when a ```$loader``` driven component failed for whatever reason. -```magewire:loader:stop``` +**magewire:loader:stop** > Dispatched as soon as all network requests were completed (this includes emitted requests). ### Indicator Removal @@ -894,16 +900,14 @@ public function start(int $seconds) ``` > **Note**: This is just an example. For a disabled state you should or could use the ```wire:loading``` directive. -## Plugins -> **Important**: This is still a proof of concept. It's possible this won't make it into the first official release. +### Notification Type Styling +Each notification item can be one of three types (syncInput, fireEvent, callAction). By default, a notification item +has the ```magewire-notification``` class. A related (kebab-cased) subclass will be bind dynamically based on the +notification type. -It's a best practice to add your custom additions to Magewire inside the designated ```magewire.plugin``` container. -This can come in handy when you need to check if a plugin gives any trouble after installation to just temporary remove -it. - -```xml - -``` +- ```magewire-notification fire-event``` +- ```magewire-notification sync-input``` +- ```magewire-notification call-method``` ### Plugin: Loader ```xml @@ -914,8 +918,18 @@ The Loader plugin is closely related to the ```$loader``` property within a comp either access the system configuration at **Store > Settings > Advanced > Developer > Magewire** or remove the block through layout XML. -The loader is divided into several child blocks, giving you greater flexibility in customizing the appearance of both -the spinner and notifications without having to overwrite all functionality. +#### Loader System Settings +> **Note**: All Magewire specific settings by default can be found at Store > Settings > Advanced > Developer > Magewire. + +- **Loader / Show:** Show or hide the global loading spinner. +- **Loader / Enable Notifications:** Show or hide optional notification messages. +- **Loader / Notifications / Message Fadeout Timeout:** Determine the duration for the message to fade out after its + target component has fully loaded. + +The loader is divided into several elements, giving you greater flexibility in customizing the appearance of both +the global spinner and notifications, without having to overwrite everything. + +All elements can be found in the Magewire core layout `default_hyva.xml` or be found in `Magewirephp_Magewire::html/loader`. ### Plugin: Error ```xml diff --git a/src/Model/Hydrator/Loader.php b/src/Model/Hydrator/Loader.php index c97cdb5..68e1a89 100644 --- a/src/Model/Hydrator/Loader.php +++ b/src/Model/Hydrator/Loader.php @@ -1,4 +1,4 @@ -functionsHelper->mapWithKeys(function ($value, $key) { - if (is_string($key) === false && is_string($value)) { - return [$value => true]; - } if (is_string($value)) { - $value = __($value); + $value = [$value]; + } + if (is_array($value)) { + $value = array_map('__', array_filter($value, 'is_string')); } return [$key => $value]; }, $loader); + } elseif (is_string($loader)) { + $loader = __($loader); } $response->effects['loader'] = $loader; diff --git a/src/Model/Magento/System/ConfigMagewire.php b/src/Model/Magento/System/ConfigMagewire.php new file mode 100644 index 0000000..d522830 --- /dev/null +++ b/src/Model/Magento/System/ConfigMagewire.php @@ -0,0 +1,81 @@ +scopeConfig = $scopeConfig; + $this->serializer = $serializer; + } + + public function canShowLoaderOverlay(): bool + { + return $this->isGroupFlag('enable', self::GROUP_LOADER) ?? true; + } + + public function canShowLoaderNotificationMessages(): bool + { + return $this->isGroupFlag('enable', self::GROUP_NOTIFICATIONS) ?? true; + } + + public function getNotificationMessageFadeoutTimeout(): int + { + return (int) $this->getGroupValue('message_fadeout_timeout', self::GROUP_NOTIFICATIONS) ?? 2500; + } + + public function pageRequiresLoaderPluginScript(): bool + { + return $this->canShowLoaderOverlay() || $this->canShowLoaderNotificationMessages(); + } + + /** + * Retrieve grouped config value by path and scope. + * + * @return mixed + */ + public function getGroupValue( + string $path, + string $group = null, + string $scopeType = ScopeInterface::SCOPE_STORE, + $scopeCode = null + ) { + return $this->scopeConfig->getValue($this->createPath($path, $group), $scopeType, $scopeCode); + } + + /** + * Retrieve grouped config flag by path and scope. + */ + public function isGroupFlag( + string $path, + string $group = null, + string $scopeType = ScopeInterface::SCOPE_STORE, + $scopeCode = null + ): bool { + return $this->scopeConfig->isSetFlag($this->createPath($path, $group), $scopeType, $scopeCode); + } + + protected function createPath(string $path, string $group = null) + { + return sprintf('dev/%s/%s', $group ? 'magewire/' . $group : 'magewire', trim($path)); + } +} diff --git a/src/ViewModel/Magewire.php b/src/ViewModel/Magewire.php index 60d5140..55a29f4 100644 --- a/src/ViewModel/Magewire.php +++ b/src/ViewModel/Magewire.php @@ -18,6 +18,7 @@ use Magento\Store\Model\StoreManagerInterface; use Magewirephp\Magewire\Model\ComponentFactory; use Magewirephp\Magewire\Model\LayoutRenderLifecycle; +use Magewirephp\Magewire\Model\Magento\System\ConfigMagewire as MagewireSystemConfig; /** * @api @@ -38,14 +39,14 @@ public function __construct( ProductMetadataInterface $productMetadata, StoreManagerInterface $storeManager, LayoutRenderLifecycle $layoutRenderLifecycle, - ComponentFactory $componentFactory + MagewireSystemConfig $magewireSystemConfig ) { $this->formKey = $formKey; $this->applicationState = $applicationState; $this->productMetaData = $productMetadata; $this->storeManager = $storeManager; $this->layoutRenderLifecycle = $layoutRenderLifecycle; - $this->componentFactory = $componentFactory; + $this->magewireSystemConfig = $magewireSystemConfig; } public function isDeveloperMode(): bool @@ -84,4 +85,9 @@ public function pageRequiresMagewire(): bool { return $this->layoutRenderLifecycle->hasHistory(); } + + public function getSystemConfig(): MagewireSystemConfig + { + return $this->magewireSystemConfig; + } } diff --git a/src/etc/adminhtml/system.xml b/src/etc/adminhtml/system.xml index 7dc56ce..4e645da 100644 --- a/src/etc/adminhtml/system.xml +++ b/src/etc/adminhtml/system.xml @@ -28,7 +28,8 @@ showInDefault="1" canRestore="1" > - + + Show a loading screen overlay while a component is busy loading. Magento\Config\Model\Config\Source\Yesno @@ -41,12 +42,38 @@ > Magento\Config\Model\Config\Source\Yesno - Display additional component notifications if available. + Display notification component messages when set. 1 + + + + + + 1 + + + + + Determine the duration, in milliseconds, for the message to fade out after its target component has fully loaded. + required-entry validate-digits validate-not-negative-number + + diff --git a/src/etc/config.xml b/src/etc/config.xml index a4bac4f..98c6ff6 100644 --- a/src/etc/config.xml +++ b/src/etc/config.xml @@ -8,6 +8,10 @@ 1 1 + + + 2500 + diff --git a/src/view/frontend/layout/default_hyva.xml b/src/view/frontend/layout/default_hyva.xml index a90aad6..e4d08a5 100644 --- a/src/view/frontend/layout/default_hyva.xml +++ b/src/view/frontend/layout/default_hyva.xml @@ -4,19 +4,65 @@ > - + template="Magewirephp_Magewire::html/loader.phtml" + > Magewirephp\Magewire\ViewModel\Magewire + + template="Magewirephp_Magewire::html/loader/notifications.phtml" + > + + + Magewirephp\Magewire\ViewModel\Magewire + + + + + + + + + + + + + + + + + + Magewirephp\Magewire\ViewModel\Magewire + + + + + + + + + @@ -47,9 +93,16 @@ + + template="Magewirephp_Magewire::page/js/magewire/plugin/loader.phtml"> + + + Magewirephp\Magewire\ViewModel\Magewire + + + + * Copyright © Willem Poortman 2021-present. All rights reserved. * - * For the full copyright and license information, please view the LICENSE.txt - * file that was distributed with this source code. + * Please read the README and LICENSE files for more + * details on copyrights and license information. */ declare(strict_types=1); @@ -13,83 +13,23 @@ declare(strict_types=1); use Magento\Framework\Escaper; use Magento\Framework\View\Element\Template; + $magewireScripts = $block->getViewModel(); ?> pageRequiresMagewire()): ?> -
-
+ x-spread="loader()" + + x-bind="loader()" + role="status" + aria-live="polite" > -
- - - - -
+ getChildHtml('overlay') ?> + getChildHtml('notifications') ?>
- getChildHtml('magewire.loader.notifications') ?> -
+ + getChildHtml('bindings') ?> diff --git a/src/view/frontend/templates/html/loader/bindings.phtml b/src/view/frontend/templates/html/loader/bindings.phtml new file mode 100644 index 0000000..fcd4f76 --- /dev/null +++ b/src/view/frontend/templates/html/loader/bindings.phtml @@ -0,0 +1,34 @@ + diff --git a/src/view/frontend/templates/html/loader/notifications.phtml b/src/view/frontend/templates/html/loader/notifications.phtml index ad2ea7f..1cbf8ba 100644 --- a/src/view/frontend/templates/html/loader/notifications.phtml +++ b/src/view/frontend/templates/html/loader/notifications.phtml @@ -1,72 +1,34 @@ - + * Copyright © Willem Poortman 2021-present. All rights reserved. * - * For the full copyright and license information, please view the LICENSE.txt - * file that was distributed with this source code. + * Please read the README and LICENSE files for more + * details on copyrights and license information. */ -declare(strict_types=1); +/** @var Magewire $magewireScripts */ +/** @var Escaper $escaper */ +/** @var Template $block */ -use Magewirephp\Magewire\Model\Action\SyncInput; -use Magewirephp\Magewire\Model\Action\CallMethod; -use Magewirephp\Magewire\Model\Action\FireEvent; -?> -