Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions bin/tests/e2e/alpine.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { expect, test } from '@wordpress/e2e-test-utils-playwright';
import type { Page } from '@playwright/test';
import { homeUrl, runId } from '../../support/site';

/**
* What a visitor sees before Alpine starts. With the theme's scripts held back, as they
* are for a moment on every load, nothing Alpine hides with x-show may be on screen:
* every such element carries x-cloak, which the theme's stylesheet hides until Alpine
* removes it. Without that, the cart drawer, the mobile menu, the add-to-cart modal and
* the product accordion flashed on each page load.
*/

type Product = { id: number; permalink: string };

let product: Product;

test.beforeAll(async ({ requestUtils }) => {
product = await requestUtils.rest({
method: 'POST',
path: '/wc/v3/products',
data: { name: `E2E cloak ${runId}`, type: 'simple', regular_price: '5.00', status: 'publish', description: 'Described.' },
});
});

test.afterAll(async ({ requestUtils }) => {
await requestUtils.rest({ method: 'DELETE', path: `/wc/v3/products/${product.id}`, params: { force: true } });
});

test.use({ storageState: { cookies: [], origins: [] } });

async function visibleBeforeAlpine(page: Page, url: string): Promise<string[]> {
// The theme's built scripts, Alpine among them; its stylesheet still loads.
await page.route(/\/build\/theme\/[^/]+\/assets\/.+\.js(\?.*)?$/, (route) => route.abort());
await page.goto(url);

return page.evaluate(() => [...document.querySelectorAll('[x-show]')]
.filter((element) => element.checkVisibility())
.map((element) => `<${element.tagName.toLowerCase()} x-show="${element.getAttribute('x-show')}">`));
}

test('the home page shows nothing Alpine hides, before Alpine starts', async ({ page }) => {
expect(await visibleBeforeAlpine(page, homeUrl('/'))).toEqual([]);
});

test('a product page shows nothing Alpine hides, before Alpine starts', async ({ page }) => {
expect(await visibleBeforeAlpine(page, product.permalink)).toEqual([]);
});
6 changes: 6 additions & 0 deletions resources/assets/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@
@import './frontend/components/wc-blocks.css';
@import './frontend/layout/single-product.css';

/* Alpine removes x-cloak once it has initialised an element. Until then,
whatever it hides with x-show stays hidden instead of flashing on load. */
[x-cloak] {
display: none !important;
}

@theme {
/* Primary action color — buttons, links, active states */
--color-primary: var(--wp--preset--color--primary, #1f2937);
Expand Down
2 changes: 1 addition & 1 deletion resources/views/parts/header/cart-drawer.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
x-on:panel-close.window="open = false"
@keydown.window.escape="if (open) { window.dispatchEvent(new CustomEvent('panel-close')); }"
class="fixed inset-y-0 right-0 pl-4 sm:pl-10 max-w-full flex z-40">
<div x-show="open"
<div x-show="open" x-cloak
x-transition:enter="transform transition ease-in-out duration-500 sm:duration-700" x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0"
x-transition:leave="transform transition ease-in-out duration-500 sm:duration-700" x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full"
role="dialog" aria-modal="true" aria-label="{{ __('Shopping cart', '%theme_name%') }}" class="w-screen max-w-md">
Expand Down
2 changes: 1 addition & 1 deletion resources/views/parts/header/mobile-nav.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
x-on:panel-open.window="open = ($event.detail.panel === 'menu')"
x-on:panel-close.window="open = false"
@keydown.window.escape="if (open) { window.dispatchEvent(new CustomEvent('panel-close')); }"
x-show="open"
x-show="open" x-cloak
x-transition:enter="transform transition ease-in-out duration-300"
x-transition:enter-start="-translate-x-full"
x-transition:enter-end="translate-x-0"
Expand Down
2 changes: 1 addition & 1 deletion resources/views/parts/header/overlay.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div x-data="{ visible: false }"
x-on:panel-open.window="visible = true"
x-on:panel-close.window="visible = false"
x-show="visible"
x-show="visible" x-cloak
x-transition:enter="transition-opacity ease-linear duration-300" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
x-transition:leave="transition-opacity ease-linear duration-300" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black/25 z-20"
Expand Down
4 changes: 2 additions & 2 deletions resources/views/parts/header/search-overlay.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
x-on:panel-open.window="panelOpen = ($event.detail.panel === 'search')"
x-on:panel-close.window="panelOpen = false"
@keydown.window.escape="if (panelOpen) { window.dispatchEvent(new CustomEvent('panel-close')); }"
x-show="panelOpen"
x-show="panelOpen" x-cloak
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 -translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
Expand Down Expand Up @@ -36,7 +36,7 @@ class="w-full pl-12 pr-10 py-3 text-base bg-surface border border-outline rounde
<input type="hidden" name="post_type" value="product">

{{-- Loading spinner inside input --}}
<svg x-show="loading" class="absolute right-4 top-1/2 -translate-y-1/2 animate-spin size-4 text-subtle" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" aria-hidden="true" style="display: none;">
<svg x-show="loading" x-cloak class="absolute right-4 top-1/2 -translate-y-1/2 animate-spin size-4 text-subtle" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" aria-hidden="true" style="display: none;">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Expand Down
10 changes: 5 additions & 5 deletions resources/views/parts/header/search-results.blade.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{{-- Search suggestions dropdown --}}
<div x-show="showResults"
<div x-show="showResults" x-cloak
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0 translate-y-1"
x-transition:enter-end="opacity-100 translate-y-0"
Expand All @@ -11,20 +11,20 @@ class="absolute z-50 left-0 right-0 mt-2 bg-white border border-outline rounded-
style="display: none;">

{{-- Loading indicator --}}
<div x-show="loading && results.length === 0" class="px-4 py-6 text-center text-sm text-muted">
<div x-show="loading && results.length === 0" x-cloak class="px-4 py-6 text-center text-sm text-muted">
<svg class="animate-spin size-5 mx-auto text-subtle" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" aria-hidden="true">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>

{{-- No results --}}
<div x-show="!loading && results.length === 0" class="px-4 py-6 text-center text-sm text-muted" style="display: none;">
<div x-show="!loading && results.length === 0" x-cloak class="px-4 py-6 text-center text-sm text-muted" style="display: none;">
{{ __('No products found.', 'woocommerce') }}
</div>

{{-- Results list --}}
<ul x-show="results.length > 0" class="divide-y divide-outline max-h-80 overflow-y-auto" role="listbox" style="display: none;">
<ul x-show="results.length > 0" x-cloak class="divide-y divide-outline max-h-80 overflow-y-auto" role="listbox" style="display: none;">
<template x-for="(item, index) in results" :key="item.id">
<li role="option"
:aria-selected="activeIndex === index"
Expand All @@ -47,7 +47,7 @@ class="size-10 rounded-lg object-cover bg-surface shrink-0"
</ul>

{{-- View all link --}}
<div x-show="results.length > 0" class="border-t border-outline" style="display: none;">
<div x-show="results.length > 0" x-cloak class="border-t border-outline" style="display: none;">
<button type="submit" class="w-full px-4 py-2.5 text-center text-sm font-medium text-primary hover:bg-surface transition-colors">
{{ __('View all results', 'woocommerce') }}
</button>
Expand Down
2 changes: 1 addition & 1 deletion resources/views/parts/header/top-bar.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class="w-full pl-10 pr-4 py-2.5 text-sm bg-surface border border-outline rounded
<input type="hidden" name="post_type" value="product">

{{-- Loading spinner inside input --}}
<svg x-show="loading" class="absolute right-3.5 top-1/2 -translate-y-1/2 animate-spin size-4 text-subtle" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" aria-hidden="true" style="display: none;">
<svg x-show="loading" x-cloak class="absolute right-3.5 top-1/2 -translate-y-1/2 animate-spin size-4 text-subtle" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" aria-hidden="true" style="display: none;">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
Expand Down
2 changes: 1 addition & 1 deletion resources/views/parts/toast-container.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
aria-live="polite"
class="fixed top-4 right-4 z-50 flex flex-col items-end gap-3 pointer-events-none">
<template x-for="toast in $store.toasts.list" :key="toast.id">
<div x-show="toast.visible"
<div x-show="toast.visible" x-cloak
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

{{-- Address card (compact view — shown when pre-filled and not editing) --}}
@if ( $prefilled )
<div x-show="!editing" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" class="border border-outline rounded-xl p-4 flex items-start justify-between gap-4">
<div x-show="!editing" @unless ( $prefilled ) x-cloak @endunless x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100" class="border border-outline rounded-xl p-4 flex items-start justify-between gap-4">
<address class="not-italic min-w-0">
<span class="block text-sm font-medium text-foreground">{{ $full_name }}</span>
<span class="block text-sm text-muted mt-0.5">{{ $address_line }}</span>
Expand Down
6 changes: 3 additions & 3 deletions resources/views/woocommerce/global/form-login.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
}
@endphp

<div x-show="loginModalOpen" class="first-hidden-state fixed inset-0 z-10 overflow-y-auto" aria-labelledby="modal-title"
<div x-show="loginModalOpen" x-cloak class="fixed inset-0 z-10 overflow-y-auto" aria-labelledby="modal-title"
x-ref="dialog" aria-modal="true">
<div class="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">

<div x-show="loginModalOpen"
<div x-show="loginModalOpen" x-cloak
class="fixed inset-0 bg-foreground/75 transition-opacity"
@click="loginModalOpen = false"
x-transition:enter="ease-out duration-300" x-transition:enter-start="opacity-0"
Expand All @@ -37,7 +37,7 @@ class="fixed inset-0 bg-foreground/75 transition-opacity"

<span class="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true">&ZeroWidthSpace;</span>

<div x-show="loginModalOpen"
<div x-show="loginModalOpen" x-cloak
class="bg-white rounded-md inline-block transform overflow-hidden px-4 pt-5 pb-4 text-left align-bottom shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
Expand Down
12 changes: 6 additions & 6 deletions resources/views/woocommerce/parts/modal-add-to-cart.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ class="fixed inset-0 z-50 overflow-y-auto"
@keydown.window.escape="if (open) close()">

{{-- Backdrop --}}
<div x-show="open"
<div x-show="open" x-cloak
x-transition:enter="ease-out duration-300" x-transition:enter-start="opacity-0" x-transition:enter-end="opacity-100"
x-transition:leave="ease-in duration-200" x-transition:leave-start="opacity-100" x-transition:leave-end="opacity-0"
class="fixed inset-0 bg-black/40"
@click="close()"></div>

{{-- Modal panel --}}
<div class="flex min-h-full items-center justify-center p-4">
<div x-show="open"
<div x-show="open" x-cloak
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
x-transition:enter-end="opacity-100 translate-y-0 sm:scale-100"
Expand Down Expand Up @@ -47,15 +47,15 @@ class="absolute top-4 right-4 p-1.5 text-subtle hover:text-foreground transition
</div>

{{-- Product card --}}
<div class="flex gap-4" x-show="product">
<div class="flex gap-4" x-show="product" x-cloak>
<div class="shrink-0 size-20 sm:size-24 rounded-lg overflow-hidden bg-surface-alt">
<img :src="product?.image" :alt="product?.name" class="size-full object-cover" />
</div>
<div class="flex-1 min-w-0">
<h4 class="text-sm font-semibold text-foreground leading-snug" x-text="product?.name"></h4>
<p class="mt-0.5 text-xs text-muted" x-show="product?.variation" x-text="product?.variation"></p>
<div class="mt-1 text-xs text-muted line-clamp-2" x-show="product?.description" x-html="product?.description"></div>
<div class="mt-2 text-sm font-semibold text-foreground" x-show="product?.price" x-html="product?.price"></div>
<p class="mt-0.5 text-xs text-muted" x-show="product?.variation" x-cloak x-text="product?.variation"></p>
<div class="mt-1 text-xs text-muted line-clamp-2" x-show="product?.description" x-cloak x-html="product?.description"></div>
<div class="mt-2 text-sm font-semibold text-foreground" x-show="product?.price" x-cloak x-html="product?.price"></div>
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class="h-5 w-5 shrink-0 text-muted transition-transform duration-200"
</button>
<div
id="accordion-{{ $key }}"
x-show="open === '{{ $key }}'"
x-show="open === '{{ $key }}'" x-cloak
x-collapse
class="pb-4 prose prose-sm text-muted max-w-none"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
x-on:sticky-bar-hide.window="visible = false; expanded = false"
x-on:panel-open.window="panelOpen = true; visible = false; expanded = false"
x-on:panel-close.window="panelOpen = false; $nextTick(() => { const btn = document.querySelector('.single_add_to_cart_button'); if (btn && btn.getBoundingClientRect().bottom < 0) visible = true; })"
x-show="visible"
x-show="visible" x-cloak
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="translate-y-full"
x-transition:enter-end="translate-y-0"
Expand All @@ -53,7 +53,7 @@ class="fixed bottom-0 inset-x-0 z-40 bg-white border-t border-outline shadow-[0_

{{-- Expandable panel for complex products --}}
@if ($isComplex)
<div x-show="expanded"
<div x-show="expanded" x-cloak
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 max-h-0"
x-transition:enter-end="opacity-100 max-h-[50vh]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
</div>
</div>
@foreach ( $product_tabs as $key => $product_tab )
<div id="tab-{!! esc_attr( $key ) !!}" class="-mb-10" x-description="'{{ $product_tab['title'] }}' panel, show/hide based on tab state" x-data="Components.tabPanel(0)" aria-labelledby="tab-title-{!! esc_attr( $key ) !!}" x-init="init()" x-show="selected" @tab-select.window="onTabSelect" role="tabpanel" tabindex="0">
<div id="tab-{!! esc_attr( $key ) !!}" class="-mb-10" x-description="'{{ $product_tab['title'] }}' panel, show/hide based on tab state" x-data="Components.tabPanel(0)" aria-labelledby="tab-title-{!! esc_attr( $key ) !!}" x-init="init()" x-show="selected" x-cloak @tab-select.window="onTabSelect" role="tabpanel" tabindex="0">
@if ( isset( $product_tab['callback'] ) )
{!! call_user_func( $product_tab['callback'], $key, $product_tab ) !!}
@endif
Expand Down
Loading