Commit 38466d15615 for woocommerce

commit 38466d15615442d5278685d1c5f050d724c6fb77
Author: Ann <annchichi@users.noreply.github.com>
Date:   Tue May 12 15:53:24 2026 +0800

    Add email template canvas affordance (#64703)

    * Add email template canvas affordance

    * Add changelog entry for template canvas affordance

    * Refine email template affordance placement

    * Use editor accent color for template affordance

    * Fix email editor formatting

    * Fix template affordance target placement

    * Fix template affordance rendering and address review feedback

    The affordance lives in the canvas iframe via createPortal, but the
    SCSS bundle and React's synthetic event system both stay in the outer
    editor document. As a result the toolbar landed at the bottom of the
    canvas (no positional CSS applied) and real mouse clicks on the
    "Edit template" button never fired because Gutenberg's block list
    captured the pointer-start events. The component now injects its CSS
    into the iframe head and wires native click handlers via refs, with
    stopPropagation on mousedown/pointerdown so the click sequence
    survives.

    Also addresses review feedback: bail out cleanly when no
    core/site-logo or core/site-title block is present (the previous
    fallback walked from post-content and produced visually misleading
    highlights on the default Woo email template); cap the rAF retry
    loop in mount() so it doesn't spin for the lifetime of the editor;
    replace the role="button" div with a native <button> and expose
    aria-expanded / aria-controls; drop the duplicated aria-label and
    title on the toolbar label; clarify the empty catch around
    cross-origin iframe access; add fixture guards and a
    canEditTemplates: false test.

    * Bump template affordance changelog significance to minor

    This adds a new user-visible UI affordance, which per the
    @woocommerce/email-editor changelogger convention is a minor change
    rather than a patch.

    ---------

    Co-authored-by: Pavel Dohnal <pavel.dohnal@automattic.com>

diff --git a/packages/js/email-editor/changelog/add-template-canvas-affordance b/packages/js/email-editor/changelog/add-template-canvas-affordance
new file mode 100644
index 00000000000..79f4827cafb
--- /dev/null
+++ b/packages/js/email-editor/changelog/add-template-canvas-affordance
@@ -0,0 +1,4 @@
+Significance: minor
+Type: add
+
+Add a canvas affordance for editing the email template from email content mode.
diff --git a/packages/js/email-editor/src/components/block-editor/editor.tsx b/packages/js/email-editor/src/components/block-editor/editor.tsx
index d4eadae6e5f..7a7bc70e4b5 100644
--- a/packages/js/email-editor/src/components/block-editor/editor.tsx
+++ b/packages/js/email-editor/src/components/block-editor/editor.tsx
@@ -47,6 +47,7 @@ import { PublishSave } from '../../hacks/publish-save';
 import { EditorNotices } from '../notices';
 import { BlockCompatibilityWarnings } from '../sidebar';
 import { BackButtonContent } from '../header/back-button-content';
+import { TemplateCanvasAffordance } from '../template-canvas-affordance';
 import { recordEventOnce } from '../../events';

 export function InnerEditor( {
@@ -191,6 +192,7 @@ export function InnerEditor( {
 					<EditorKeyboardShortcutsRegister />
 					<PostLockedModal />
 					<TemplateSelection />
+					<TemplateCanvasAffordance />
 					<StylesSidebar />
 					<SendPreview />
 					<PreviewSaveGuard />
diff --git a/packages/js/email-editor/src/components/template-canvas-affordance/index.ts b/packages/js/email-editor/src/components/template-canvas-affordance/index.ts
new file mode 100644
index 00000000000..4ce1601605a
--- /dev/null
+++ b/packages/js/email-editor/src/components/template-canvas-affordance/index.ts
@@ -0,0 +1 @@
+export { TemplateCanvasAffordance } from './template-canvas-affordance';
diff --git a/packages/js/email-editor/src/components/template-canvas-affordance/template-canvas-affordance.tsx b/packages/js/email-editor/src/components/template-canvas-affordance/template-canvas-affordance.tsx
new file mode 100644
index 00000000000..f560ebfe052
--- /dev/null
+++ b/packages/js/email-editor/src/components/template-canvas-affordance/template-canvas-affordance.tsx
@@ -0,0 +1,481 @@
+/**
+ * External dependencies
+ */
+import { Button } from '@wordpress/components';
+import { useSelect } from '@wordpress/data';
+import { store as editorStore } from '@wordpress/editor';
+import {
+	createPortal,
+	useCallback,
+	useEffect,
+	useRef,
+	useState,
+} from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { Icon, layout } from '@wordpress/icons';
+
+/**
+ * Internal dependencies
+ */
+import { storeName } from '../../store';
+import { recordEvent } from '../../events';
+
+const SLOT_ID = 'woocommerce-email-editor-template-area-affordance-slot';
+const STYLE_ID = 'woocommerce-email-editor-template-area-affordance-style';
+const BLOCK_SELECTOR = '[data-block], .block-editor-block-list__block';
+
+// The block-editor style.scss is bundled into the outer editor document, but
+// the affordance lives inside the canvas iframe. The iframe is a separate
+// document, so we inject the positional/visual rules into its <head> directly.
+const CANVAS_STYLES = `
+.woocommerce-email-editor-template-area-affordance-slot {
+	box-sizing: border-box;
+	inset: 0 auto auto 0;
+	pointer-events: none;
+	position: absolute;
+	z-index: 29;
+}
+.woocommerce-email-editor-template-area-affordance {
+	align-items: stretch;
+	background: #fff;
+	border: 1px solid #1e1e1e;
+	border-radius: 2px;
+	box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);
+	display: inline-flex;
+	font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+	font-size: 13px;
+	line-height: 1;
+	pointer-events: auto;
+	position: absolute;
+	z-index: 30;
+}
+.woocommerce-email-editor-template-area-affordance__frame {
+	appearance: none;
+	background: transparent;
+	border: 1.5px solid transparent;
+	box-sizing: border-box;
+	cursor: pointer;
+	font: inherit;
+	margin: 0;
+	padding: 0;
+	pointer-events: auto;
+	position: absolute;
+	z-index: 29;
+}
+.woocommerce-email-editor-template-area-affordance__frame:hover,
+.woocommerce-email-editor-template-area-affordance__frame:focus-visible,
+.woocommerce-email-editor-template-area-affordance__frame.is-active {
+	border-color: var(--wp-components-color-accent, #3858e9);
+	outline: none;
+}
+.woocommerce-email-editor-template-area-affordance__label {
+	align-items: center;
+	border-right: 1px solid #ddd;
+	display: inline-flex;
+	font-weight: 500;
+	gap: 8px;
+	height: 48px;
+	padding: 0 16px;
+	white-space: nowrap;
+}
+.woocommerce-email-editor-template-area-affordance__label svg {
+	fill: currentColor;
+}
+.woocommerce-email-editor-template-area-affordance__button.components-button {
+	border-radius: 0;
+	box-shadow: none;
+	color: var(--wp-components-color-accent, #3858e9);
+	height: 48px;
+	padding: 0 18px;
+	white-space: nowrap;
+}
+.woocommerce-email-editor-template-area-affordance__button.components-button:hover:not(:disabled) {
+	color: var(--wp-components-color-accent, #3858e9);
+}
+.woocommerce-email-editor-template-area-affordance__button.components-button:focus-visible {
+	box-shadow: inset 0 0 0 1.5px var(--wp-components-color-accent, #3858e9);
+}
+`;
+
+function ensureCanvasStyles( canvasDocument: Document ): void {
+	if ( canvasDocument.getElementById( STYLE_ID ) ) {
+		return;
+	}
+
+	const style = canvasDocument.createElement( 'style' );
+	style.id = STYLE_ID;
+	style.textContent = CANVAS_STYLES;
+	canvasDocument.head.appendChild( style );
+}
+
+type NavigateToEntityRecord = ( params: {
+	postId: number | string;
+	postType: string;
+} ) => void;
+
+type AffordancePosition = {
+	frame: {
+		height: number;
+		left: number;
+		top: number;
+		width: number;
+	};
+	toolbar: {
+		left: number;
+		top: number;
+	};
+};
+
+function getCanvasDocument(): Document | null {
+	const frames = Array.from( document.querySelectorAll( 'iframe' ) );
+
+	for ( const frame of frames ) {
+		try {
+			const frameDocument = frame.contentDocument;
+
+			if (
+				frameDocument?.querySelector(
+					'.block-editor-block-list__layout.is-root-container, .is-root-container'
+				)
+			) {
+				return frameDocument;
+			}
+		} catch ( error ) {
+			// Accessing contentDocument throws SecurityError for cross-origin
+			// iframes; those frames cannot host the editor canvas, so skip
+			// them silently.
+		}
+	}
+
+	return null;
+}
+
+function getClosestBlock( element: Element ): Element {
+	return (
+		element.closest( BLOCK_SELECTOR ) ||
+		element.closest( '[data-type]' ) ||
+		element
+	);
+}
+
+function getTemplateTarget( canvasDocument: Document ): Element | null {
+	// We can only confidently identify a template area when the template
+	// renders one of the well-known site-identity blocks. Falling back to
+	// arbitrary nearby blocks produced visually misleading highlights — see
+	// https://github.com/woocommerce/woocommerce/pull/64703#discussion (manual
+	// QA on the default Woo email template).
+	const templateBlock = canvasDocument.querySelector(
+		'[data-type="core/site-logo"], [data-type="core/site-title"], .wp-block-site-logo, .wp-block-site-title'
+	);
+
+	if ( ! templateBlock ) {
+		return null;
+	}
+
+	return getClosestBlock( templateBlock );
+}
+
+function createSlot( canvasDocument: Document ): HTMLDivElement {
+	let slot = canvasDocument.getElementById(
+		SLOT_ID
+	) as HTMLDivElement | null;
+
+	if ( ! slot ) {
+		slot = canvasDocument.createElement( 'div' );
+		slot.id = SLOT_ID;
+		slot.className =
+			'woocommerce-email-editor-template-area-affordance-slot';
+		canvasDocument.body.appendChild( slot );
+	}
+
+	return slot;
+}
+
+export function TemplateCanvasAffordance() {
+	const [ isActive, setIsActive ] = useState( false );
+	const [ portalSlot, setPortalSlot ] = useState< HTMLDivElement | null >(
+		null
+	);
+	const [ position, setPosition ] = useState< AffordancePosition | null >(
+		null
+	);
+	const targetRef = useRef< Element | null >( null );
+
+	const {
+		canEditTemplates,
+		currentPostType,
+		onNavigateToEntityRecord,
+		template,
+	} = useSelect( ( select ) => {
+		const editorSettings = select( editorStore ).getEditorSettings();
+
+		return {
+			canEditTemplates: select( storeName ).canUserEditTemplates(),
+			currentPostType: select( editorStore ).getCurrentPostType(),
+			onNavigateToEntityRecord:
+				// @ts-expect-error onNavigateToEntityRecord is provided through email editor settings.
+				editorSettings?.onNavigateToEntityRecord as
+					| NavigateToEntityRecord
+					| undefined,
+			template: select( storeName ).getCurrentTemplate(),
+		};
+	}, [] );
+
+	const canShowAffordance =
+		currentPostType !== 'wp_template' &&
+		canEditTemplates &&
+		!! template?.id &&
+		!! onNavigateToEntityRecord;
+
+	const updatePosition = useCallback( () => {
+		const target = targetRef.current;
+		const canvasDocument = target?.ownerDocument;
+		const canvasWindow = canvasDocument?.defaultView;
+
+		if ( ! target || ! canvasDocument || ! canvasWindow ) {
+			setPosition( null );
+			return;
+		}
+
+		const rect = target.getBoundingClientRect();
+
+		if ( ! rect.width || ! rect.height ) {
+			setPosition( null );
+			return;
+		}
+
+		const scrollX = canvasWindow.scrollX;
+		const scrollY = canvasWindow.scrollY;
+		const toolbarHeight = 50;
+		const toolbarGap = 4;
+		const toolbarTop =
+			rect.top > toolbarHeight + toolbarGap
+				? rect.top + scrollY - toolbarHeight - toolbarGap
+				: rect.bottom + scrollY + toolbarGap;
+
+		setPosition( {
+			frame: {
+				height: rect.height + 2,
+				left: rect.left + scrollX - 1,
+				top: rect.top + scrollY - 1,
+				width: rect.width + 2,
+			},
+			toolbar: {
+				left: rect.left + scrollX - 1,
+				top: toolbarTop,
+			},
+		} );
+	}, [] );
+
+	useEffect( () => {
+		if ( ! canShowAffordance ) {
+			setIsActive( false );
+			setPortalSlot( null );
+			setPosition( null );
+			targetRef.current = null;
+			return undefined;
+		}
+
+		let animationFrame = 0;
+		let mountedSlot: HTMLDivElement | null = null;
+		// Bail out after roughly two seconds at 60fps. If the canvas hasn't
+		// rendered an identifiable template area by then, this email almost
+		// certainly doesn't have one — keep the loop bounded instead of
+		// retrying forever for the lifetime of the editor.
+		let retriesRemaining = 120;
+
+		const mount = () => {
+			const canvasDocument = getCanvasDocument();
+			const templateTarget =
+				canvasDocument && getTemplateTarget( canvasDocument );
+
+			if ( ! canvasDocument || ! templateTarget ) {
+				if ( retriesRemaining > 0 ) {
+					retriesRemaining--;
+					animationFrame = window.requestAnimationFrame( mount );
+				}
+				return;
+			}
+
+			ensureCanvasStyles( canvasDocument );
+			mountedSlot = createSlot( canvasDocument );
+			targetRef.current = templateTarget;
+			setPortalSlot( mountedSlot );
+			updatePosition();
+		};
+
+		mount();
+
+		return () => {
+			if ( animationFrame ) {
+				window.cancelAnimationFrame( animationFrame );
+			}
+
+			const ownerDocument = mountedSlot?.ownerDocument;
+			mountedSlot?.remove();
+			ownerDocument?.getElementById( STYLE_ID )?.remove();
+			setIsActive( false );
+			setPortalSlot( null );
+			setPosition( null );
+			targetRef.current = null;
+		};
+	}, [ canShowAffordance, updatePosition ] );
+
+	useEffect( () => {
+		const canvasDocument = portalSlot?.ownerDocument;
+		const canvasWindow = canvasDocument?.defaultView;
+
+		if ( ! portalSlot || ! canvasDocument || ! canvasWindow ) {
+			return undefined;
+		}
+
+		const closeOnOutsidePointerDown = ( event: MouseEvent ) => {
+			if (
+				event.target instanceof Node &&
+				portalSlot.contains( event.target )
+			) {
+				return;
+			}
+
+			setIsActive( false );
+		};
+
+		canvasDocument.addEventListener(
+			'mousedown',
+			closeOnOutsidePointerDown
+		);
+		canvasDocument.addEventListener( 'scroll', updatePosition, true );
+		canvasWindow.addEventListener( 'resize', updatePosition );
+		window.addEventListener( 'resize', updatePosition );
+		updatePosition();
+
+		return () => {
+			canvasDocument.removeEventListener(
+				'mousedown',
+				closeOnOutsidePointerDown
+			);
+			canvasDocument.removeEventListener(
+				'scroll',
+				updatePosition,
+				true
+			);
+			canvasWindow.removeEventListener( 'resize', updatePosition );
+			window.removeEventListener( 'resize', updatePosition );
+		};
+	}, [ portalSlot, updatePosition ] );
+
+	// React’s synthetic event system is attached to the outer document where
+	// the editor is mounted. The portal target lives inside the canvas iframe
+	// (a separate document), so onClick/onKeyDown handlers wired through React
+	// never receive real user-generated events on these nodes. We attach
+	// native listeners via refs to bypass the cross-document delegation gap.
+	const frameRef = useRef< HTMLButtonElement | null >( null );
+	const buttonRef = useRef< HTMLButtonElement | null >( null );
+
+	const activate = useCallback( () => setIsActive( true ), [] );
+
+	const handleEditTemplate = useCallback( () => {
+		if ( ! template?.id || ! onNavigateToEntityRecord ) {
+			return;
+		}
+
+		recordEvent( 'template_canvas_affordance_edit_template_clicked', {
+			templateId: template.id,
+		} );
+		onNavigateToEntityRecord( {
+			postId: template.id,
+			postType: 'wp_template',
+		} );
+	}, [ onNavigateToEntityRecord, template?.id ] );
+
+	// Gutenberg’s block list installs capture-phase pointerdown/mousedown
+	// handlers on the canvas to start block selection and drag gestures. If it
+	// captures the pointer here, the browser never dispatches a `click` event
+	// on the affordance, so we stop propagation on the pointer-start events
+	// to keep the click sequence intact.
+	const swallowPointerStart = useCallback( ( event: Event ) => {
+		event.stopPropagation();
+	}, [] );
+
+	useEffect( () => {
+		const node = frameRef.current;
+
+		if ( ! node ) {
+			return undefined;
+		}
+
+		// Native <button> elements handle Enter/Space activation themselves,
+		// so we only need to wire up the click and pointer-start listeners.
+		node.addEventListener( 'mousedown', swallowPointerStart );
+		node.addEventListener( 'pointerdown', swallowPointerStart );
+		node.addEventListener( 'click', activate );
+
+		return () => {
+			node.removeEventListener( 'mousedown', swallowPointerStart );
+			node.removeEventListener( 'pointerdown', swallowPointerStart );
+			node.removeEventListener( 'click', activate );
+		};
+	}, [ portalSlot, activate, swallowPointerStart ] );
+
+	useEffect( () => {
+		const node = buttonRef.current;
+
+		if ( ! node ) {
+			return undefined;
+		}
+
+		node.addEventListener( 'mousedown', swallowPointerStart );
+		node.addEventListener( 'pointerdown', swallowPointerStart );
+		node.addEventListener( 'click', handleEditTemplate );
+
+		return () => {
+			node.removeEventListener( 'mousedown', swallowPointerStart );
+			node.removeEventListener( 'pointerdown', swallowPointerStart );
+			node.removeEventListener( 'click', handleEditTemplate );
+		};
+	}, [ isActive, handleEditTemplate, swallowPointerStart ] );
+
+	if ( ! canShowAffordance || ! portalSlot || ! position ) {
+		return null;
+	}
+
+	const toolbarId = `${ SLOT_ID }-toolbar`;
+
+	return createPortal(
+		<>
+			<button
+				ref={ frameRef }
+				type="button"
+				className={
+					isActive
+						? 'woocommerce-email-editor-template-area-affordance__frame is-active'
+						: 'woocommerce-email-editor-template-area-affordance__frame'
+				}
+				aria-label={ __( 'Template area', 'woocommerce' ) }
+				aria-expanded={ isActive }
+				aria-controls={ isActive ? toolbarId : undefined }
+				style={ position.frame }
+			/>
+			{ isActive && (
+				<div
+					id={ toolbarId }
+					className="woocommerce-email-editor-template-area-affordance"
+					style={ position.toolbar }
+				>
+					<span className="woocommerce-email-editor-template-area-affordance__label">
+						<Icon icon={ layout } size={ 24 } />
+						<span>{ __( 'Template', 'woocommerce' ) }</span>
+					</span>
+					<Button
+						ref={ buttonRef }
+						className="woocommerce-email-editor-template-area-affordance__button"
+						variant="tertiary"
+					>
+						{ __( 'Edit template', 'woocommerce' ) }
+					</Button>
+				</div>
+			) }
+		</>,
+		portalSlot
+	);
+}
diff --git a/packages/js/email-editor/src/components/template-canvas-affordance/test/template-canvas-affordance.spec.tsx b/packages/js/email-editor/src/components/template-canvas-affordance/test/template-canvas-affordance.spec.tsx
new file mode 100644
index 00000000000..785e3506062
--- /dev/null
+++ b/packages/js/email-editor/src/components/template-canvas-affordance/test/template-canvas-affordance.spec.tsx
@@ -0,0 +1,331 @@
+/* eslint-disable @woocommerce/dependency-group -- because we import mocks first, we deactivate this rule to avoid ESLint errors */
+import '../../test/__mocks__/setup-shared-mocks';
+
+/**
+ * External dependencies
+ */
+import { fireEvent, render, waitFor } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import { useSelect } from '@wordpress/data';
+import { store as editorStore } from '@wordpress/editor';
+
+/**
+ * Internal dependencies
+ */
+import { TemplateCanvasAffordance } from '../template-canvas-affordance';
+import { storeName } from '../../../store';
+import { recordEvent } from '../../../events';
+
+jest.mock( '@wordpress/components', () => {
+	const { forwardRef: forwardRefImpl } =
+		jest.requireActual( '@wordpress/element' );
+
+	return {
+		Button: forwardRefImpl(
+			( { children, className, onClick, variant }, ref ) => (
+				<button
+					ref={ ref }
+					className={ `${ className } components-button is-${ variant }` }
+					onClick={ onClick }
+					type="button"
+				>
+					{ children }
+				</button>
+			)
+		),
+	};
+} );
+
+jest.mock( '@wordpress/icons', () => ( {
+	Icon: () => <span data-testid="template-area-icon" />,
+	layout: 'layout',
+} ) );
+
+jest.mock( '../../../events', () => ( {
+	recordEvent: jest.fn(),
+} ) );
+
+const useSelectMock = useSelect as jest.Mock;
+const recordEventMock = recordEvent as jest.Mock;
+
+const template = {
+	id: 'twentytwentyfive//wooemailtemplate',
+	title: 'Woo email template',
+};
+
+const setupUseSelectMock = ( {
+	canEditTemplates = true,
+	currentPostType = 'woo_email',
+	onNavigateToEntityRecord = jest.fn(),
+} = {} ) => {
+	useSelectMock.mockImplementation( ( selector ) =>
+		selector( ( store ) => {
+			if ( store === storeName ) {
+				return {
+					canUserEditTemplates: () => canEditTemplates,
+					getCurrentTemplate: () => template,
+				};
+			}
+
+			if ( store === editorStore ) {
+				return {
+					getCurrentPostType: () => currentPostType,
+					getEditorSettings: () => ( {
+						onNavigateToEntityRecord,
+					} ),
+				};
+			}
+
+			return {};
+		} )
+	);
+
+	return { onNavigateToEntityRecord };
+};
+
+const addEditorCanvas = ( {
+	headerAttributes = '',
+	headerContent = '<h1 class="wp-block-site-title">testingbun</h1>',
+} = {} ) => {
+	const iframe = document.createElement( 'iframe' );
+	document.body.appendChild( iframe );
+	iframe.contentDocument?.body.insertAdjacentHTML(
+		'beforeend',
+		[
+			'<div>',
+			'<div class="block-editor-block-list__layout is-root-container">',
+			'<div class="block-editor-block-list__block" data-block="outer-template">',
+			`<div class="block-editor-block-list__block" data-block="template-header" ${ headerAttributes }>`,
+			headerContent,
+			'</div>',
+			'<div class="block-editor-block-list__block" data-block="email-content-wrapper">',
+			'<div class="block-editor-block-list__block" data-block="email-content">',
+			'<div class="wp-block-post-content">New order</div>',
+			'</div>',
+			'</div>',
+			'<div class="block-editor-block-list__block" data-block="template-footer">',
+			'<p>Footer</p>',
+			'</div>',
+			'</div>',
+			'</div>',
+			'</div>',
+		].join( '' )
+	);
+
+	const templateHeader = iframe.contentDocument?.querySelector(
+		'[data-block="template-header"]'
+	);
+	const outerTemplate = iframe.contentDocument?.querySelector(
+		'[data-block="outer-template"]'
+	);
+
+	if ( ! outerTemplate || ! templateHeader ) {
+		throw new Error(
+			'Editor canvas fixture is missing expected template elements.'
+		);
+	}
+
+	Object.defineProperty( outerTemplate, 'getBoundingClientRect', {
+		value: () => ( {
+			bottom: 900,
+			height: 900,
+			left: 100,
+			right: 760,
+			top: 0,
+			width: 660,
+			x: 100,
+			y: 0,
+		} ),
+	} );
+
+	Object.defineProperty( templateHeader, 'getBoundingClientRect', {
+		value: () => ( {
+			bottom: 148,
+			height: 64,
+			left: 120,
+			right: 720,
+			top: 84,
+			width: 600,
+			x: 120,
+			y: 84,
+		} ),
+	} );
+
+	return iframe;
+};
+
+describe( 'TemplateCanvasAffordance', () => {
+	beforeEach( () => {
+		jest.clearAllMocks();
+		document.body.innerHTML = '';
+	} );
+
+	it( 'renders a selectable frame over the template area without showing the toolbar by default', async () => {
+		const iframe = addEditorCanvas();
+		setupUseSelectMock();
+
+		render( <TemplateCanvasAffordance /> );
+
+		await waitFor( () => {
+			expect(
+				iframe.contentDocument?.getElementById(
+					'woocommerce-email-editor-template-area-affordance-slot'
+				)
+			).toBeInTheDocument();
+		} );
+
+		expect(
+			iframe.contentDocument?.querySelector(
+				'.woocommerce-email-editor-template-area-affordance__frame'
+			)
+		).toBeInTheDocument();
+		expect( iframe.contentDocument?.body ).not.toHaveTextContent(
+			'Edit template'
+		);
+	} );
+
+	it( 'shows the toolbar after the template area is selected', async () => {
+		const iframe = addEditorCanvas();
+		setupUseSelectMock();
+
+		render( <TemplateCanvasAffordance /> );
+
+		await waitFor( () => {
+			expect(
+				iframe.contentDocument?.querySelector(
+					'.woocommerce-email-editor-template-area-affordance__frame'
+				)
+			).toBeInTheDocument();
+		} );
+
+		fireEvent.click(
+			iframe.contentDocument?.querySelector(
+				'.woocommerce-email-editor-template-area-affordance__frame'
+			) as HTMLButtonElement
+		);
+
+		expect( iframe.contentDocument?.body ).toHaveTextContent( 'Template' );
+		expect( iframe.contentDocument?.body ).toHaveTextContent(
+			'Edit template'
+		);
+	} );
+
+	it( 'anchors the affordance to editor block metadata when site title classes are not rendered', async () => {
+		const iframe = addEditorCanvas( {
+			headerAttributes: 'data-type="core/site-title"',
+			headerContent: '<h1>testingbun</h1>',
+		} );
+		setupUseSelectMock();
+
+		render( <TemplateCanvasAffordance /> );
+
+		await waitFor( () => {
+			expect(
+				iframe.contentDocument?.querySelector(
+					'.woocommerce-email-editor-template-area-affordance__frame'
+				)
+			).toBeInTheDocument();
+		} );
+
+		fireEvent.click(
+			iframe.contentDocument?.querySelector(
+				'.woocommerce-email-editor-template-area-affordance__frame'
+			) as HTMLButtonElement
+		);
+
+		expect(
+			iframe.contentDocument?.querySelector(
+				'.woocommerce-email-editor-template-area-affordance__frame'
+			)
+		).toHaveStyle( { top: '83px' } );
+		expect(
+			iframe.contentDocument?.querySelector(
+				'.woocommerce-email-editor-template-area-affordance'
+			)
+		).toHaveStyle( { top: '30px' } );
+	} );
+
+	it( 'does not render when no site-identity block is available to anchor to', async () => {
+		const iframe = addEditorCanvas( {
+			headerContent: '<h1>testingbun</h1>',
+		} );
+		setupUseSelectMock();
+
+		render( <TemplateCanvasAffordance /> );
+
+		// Give the rAF-driven mount loop a chance to run and bail out.
+		await new Promise( ( resolve ) => setTimeout( resolve, 50 ) );
+
+		expect(
+			iframe.contentDocument?.getElementById(
+				'woocommerce-email-editor-template-area-affordance-slot'
+			)
+		).not.toBeInTheDocument();
+	} );
+
+	it( 'does not render when the user cannot edit templates', async () => {
+		const iframe = addEditorCanvas();
+		setupUseSelectMock( { canEditTemplates: false } );
+
+		render( <TemplateCanvasAffordance /> );
+
+		await new Promise( ( resolve ) => setTimeout( resolve, 50 ) );
+
+		expect(
+			iframe.contentDocument?.getElementById(
+				'woocommerce-email-editor-template-area-affordance-slot'
+			)
+		).not.toBeInTheDocument();
+	} );
+
+	it( 'navigates to the current template when edit template is clicked', async () => {
+		const iframe = addEditorCanvas();
+		const { onNavigateToEntityRecord } = setupUseSelectMock();
+
+		render( <TemplateCanvasAffordance /> );
+
+		await waitFor( () => {
+			expect(
+				iframe.contentDocument?.querySelector(
+					'.woocommerce-email-editor-template-area-affordance__frame'
+				)
+			).toBeInTheDocument();
+		} );
+
+		fireEvent.click(
+			iframe.contentDocument?.querySelector(
+				'.woocommerce-email-editor-template-area-affordance__frame'
+			) as HTMLButtonElement
+		);
+
+		fireEvent.click(
+			iframe.contentDocument?.querySelector(
+				'.woocommerce-email-editor-template-area-affordance__button'
+			) as HTMLButtonElement
+		);
+
+		expect( recordEventMock ).toHaveBeenCalledWith(
+			'template_canvas_affordance_edit_template_clicked',
+			{ templateId: template.id }
+		);
+		expect( onNavigateToEntityRecord ).toHaveBeenCalledWith( {
+			postId: template.id,
+			postType: 'wp_template',
+		} );
+	} );
+
+	it( 'does not render while editing a template', async () => {
+		const iframe = addEditorCanvas();
+		setupUseSelectMock( { currentPostType: 'wp_template' } );
+
+		render( <TemplateCanvasAffordance /> );
+
+		await waitFor( () => {
+			expect(
+				iframe.contentDocument?.getElementById(
+					'woocommerce-email-editor-template-area-affordance-slot'
+				)
+			).not.toBeInTheDocument();
+		} );
+	} );
+} );
diff --git a/packages/js/email-editor/src/telemetry-tracking.md b/packages/js/email-editor/src/telemetry-tracking.md
index 62b7f7edd6b..65eb04934aa 100644
--- a/packages/js/email-editor/src/telemetry-tracking.md
+++ b/packages/js/email-editor/src/telemetry-tracking.md
@@ -15,11 +15,15 @@ addFilter(
 );

 // process events tracked in the editor
-addAction( 'woocommerce_email_editor_events', 'your_plugin_namespace', ( editorEvent ) => {
-	const { name, ...data } = editorEvent;
-	// Replace console.log with your tracking code
-  console.log( name, data );
-});
+addAction(
+	'woocommerce_email_editor_events',
+	'your_plugin_namespace',
+	( editorEvent ) => {
+		const { name, ...data } = editorEvent;
+		// Replace console.log with your tracking code
+		console.log( name, data );
+	}
+);
 ```

 ## Tracked events
@@ -28,78 +32,79 @@ All events are prefixed `email_editor_events_`.

 ### Table of events

-| Event Name | Data | Description |
-|------------|------|-------------|
-| `block_controls_personalization_tags_button_clicked` | - | Tracked when the personalization tags button is clicked in block controls |
-| `command_menu_opened` | - | Tracked when command menu is opened via click or a shortcut |
-| `command_menu_closed` | - | Tracked when command menu is closed |
-| `command_bar_command_clicked` | `{ command }` | Tracked when a command is selected by a click. |
-| `edit_template_modal_cancel_button_clicked` | - | Tracked when the cancel button is clicked in the edit template modal |
-| `edit_template_modal_closed` | - | Tracked when the edit template modal is closed |
-| `edit_template_modal_continue_button_clicked` | `{ templateId }` | Tracked when the continue button is clicked in the edit template modal |
-| `edit_template_modal_opened` | - | Tracked when the edit template modal is opened |
-| `editor_layout_loaded` | - | Tracked when the editor layout is loaded |
-| `editor_showed_email_sent_notice` | - | Tracked when the editor shows the email sent notice |
-| `header_blocks_tool_button_clicked` | `{ isOpened }` | Tracked when user clicks the blocks tool button in the header to toggle header block tools |
-| `header_close_button_clicked` | - | Tracked when user clicks the back button in the header |
-| `header_inserter_sidebar_clicked` | `{ isOpened }` | Tracked when user clicks the inserter sidebar button in the header |
-| `header_listview_sidebar_clicked` | `{ isOpened }` | Tracked when user clicks the listview sidebar button in the header |
-| `header_more_menu_dropdown_toggle` | `{ isOpened }` | Tracked when user toggles the more menu dropdown in the header |
-| `header_preview_dropdown_clicked` | `{ isOpened }` | Tracked when user clicks an action in the preview dropdown |
-| `header_preview_dropdown_${deviceType}_selected` | - | Tracked when a device type is selected from the header preview dropdown (e.g., desktop, mobile, tablet) |
-| `header_preview_dropdown_preview_in_new_tab_selected` | - | Tracked when the preview in new tab option is selected from the header preview dropdown |
-| `header_preview_dropdown_send_test_email_selected` | - | Tracked when the send test email option is selected from the header preview dropdown |
-| `header_save_button_clicked` | - | Tracked when user clicks the save button in the header |
-| `header_send_button_clicked` | - | Tracked when user clicks the send button in the header |
-| `personalization_tags_modal_category_menu_clicked` | `{ category, openedBy }` | Tracked when a category is selected in the personalization tags modal |
-| `personalization_tags_modal_closed` | `{ openedBy }` | Tracked when the personalization tags modal is closed |
-| `personalization_tags_modal_learn_more_link_clicked` | `{ openedBy }` | Tracked when the learn more link is clicked in the personalization tags modal |
-| `personalization_tags_modal_opened` | `{ openedBy }` | Tracked when the personalization tags modal is opened. The openedBy parameter indicates where it was opened from (e.g., 'block-controls', 'RichTextWithButton-BaseControl') |
-| `personalization_tags_modal_search_control_input_updated` | `{ openedBy }` | Tracked when the search input is updated in the personalization tags modal |
-| `personalization_tags_modal_tag_insert_button_clicked` | `{ insertedTag, activeCategory, openedBy }` | Tracked when a tag insert button is clicked in the personalization tags modal |
-| `preview_dropdown_rendering_mode_changed` | `{ renderingMode }` | Tracked when user toggles "Show template" in preview menu. Values are 'template-locked', 'post-only'. |
-| `rich_text_with_button_input_field_updated` | `{ attributeName }` | Tracked when the input field is updated in a rich text with button component |
-| `rich_text_with_button_personalization_tags_inserted` | `{ attributeName, value }` | Tracked when a personalization tag is inserted in a rich text with button component |
-| `rich_text_with_button_personalization_tags_shortcode_icon_clicked` | `{ attributeName, label }` | Tracked when the personalization tags shortcode icon is clicked in a rich text with button component |
-| `send_preview_email_modal_check_sending_method_configuration_link_clicked` | - | Tracked when the sending method configuration link is clicked in the send preview email modal |
-| `send_preview_email_modal_closed` | - | Tracked when the send preview email modal is closed |
-| `send_preview_email_modal_close_button_clicked` | - | Tracked when the close button is clicked in the send preview email modal |
-| `send_preview_email_modal_opened` | - | Tracked when the send preview email modal is opened |
-| `send_preview_email_modal_send_test_email_button_clicked` | - | Tracked when the send test email button is clicked in the send preview email modal |
-| `send_preview_email_modal_send_to_field_key_code_enter` | - | Tracked when the enter key is pressed in the send to field of the send preview email modal |
-| `send_preview_email_modal_send_to_field_updated` | - | Tracked when the send to field is updated in the send preview email modal |
-| `send_preview_email_modal_sign_up_for_mailpoet_sending_service_link_clicked` | - | Tracked when the sign up for MailPoet Sending Service link is clicked in the send preview email modal |
-| `sent_preview_email` | `{ postId, email }` | Tracked when a preview email is successfully sent |
-| `sent_preview_email_error` | `{ email }` | Tracked when there's an error sending a preview email |
-| `sidebar_tab_selected` | `{ tab: 'document' \| 'block' }` | Tracked when user selects a tab in the sidebar |
-| `styles_sidebar_navigation_click` | `{ path }` | Tracked when a navigation button is clicked in the styles sidebar (e.g., typography, colors, layout) |
-| `styles_sidebar_screen_colors_opened` | - | Tracked when the colors screen in styles sidebar is opened |
-| `styles_sidebar_screen_colors_styles_updated` | - | Tracked when colors are updated in the styles sidebar |
-| `styles_sidebar_screen_layout_dimensions_block_spacing_reset_clicked` | - | Tracked when the block spacing reset button is clicked in the dimensions panel |
-| `styles_sidebar_screen_layout_dimensions_block_spacing_updated` | `{ value }` | Tracked when block spacing is updated in the dimensions panel |
-| `styles_sidebar_screen_layout_dimensions_padding_reset_clicked` | - | Tracked when the padding reset button is clicked in the dimensions panel |
-| `styles_sidebar_screen_layout_dimensions_padding_updated` | `{ value }` | Tracked when padding is updated in the dimensions panel |
-| `styles_sidebar_screen_layout_dimensions_reset_all_selected` | - | Tracked when the reset all button is clicked in the dimensions panel |
-| `styles_sidebar_screen_layout_opened` | - | Tracked when the layout screen in styles sidebar is opened |
-| `styles_sidebar_screen_typography_button_click` | `{ element, label, path }` | Tracked when a typography element button is clicked in the typography panel |
-| `styles_sidebar_screen_typography_element_heading_level_selected` | `{ value }` | Tracked when a heading level is selected in the typography element screen |
-| `styles_sidebar_screen_typography_element_opened` | `{ element }` | Tracked when the typography screen in styles sidebar is opened |
-| `styles_sidebar_screen_typography_element_panel_reset_all_styles_selected` | `{ element, headingLevel }` | Tracked when the reset all styles button is clicked in the typography element panel |
-| `styles_sidebar_screen_typography_opened` | - | Tracked when the typography screen in styles sidebar is opened |
-| `template_select_modal_category_change` | `{ category }` | Tracked when user changes category in template select modal |
-| `template_select_modal_closed` | `{ templateSelectMode }` | Tracked when template select modal is closed. templateSelectMode tracks category which was opened. |
-| `template_select_modal_handle_close_without_template_selected` | - | Tracked when the template select modal is closed without explicitly selecting a template |
-| `template_select_modal_opened` | `{ templateSelectMode }` | Tracked when template select modal is opened |
-| `template_select_modal_start_from_scratch_clicked` | - | Tracked when the "Start from scratch" button is clicked in the template select modal |
-| `template_select_modal_template_selected` | `{ template }` | Tracked when user selects a template in the template select modal |
-| `trash_modal_move_to_trash_button_clicked` | - | Tracked when user clicks the move to trash button in the trash modal |
-| `styles_sidebar_screen_typography_element_panel_set_letter_spacing` | `{ element, newValue, selectedDefaultLetterSpacing }` | Tracked when letter spacing is changed in typography panel |
-| `styles_sidebar_screen_typography_element_panel_set_line_height` | `{ element, newValue, selectedDefaultLineHeight }` | Tracked when line height is changed in typography panel |
-| `styles_sidebar_screen_typography_element_panel_set_font_size` | `{ element, newValue, selectedDefaultFontSize }` | Tracked when font size is changed in typography panel |
-| `styles_sidebar_screen_typography_element_panel_set_font_family` | `{  element, newValue, selectedDefaultFontFamily }` | Tracked when font family is changed in typography panel |
-| `styles_sidebar_screen_typography_element_panel_set_text_decoration` | `{ element, newValue, selectedDefaultTextDecoration }` | Tracked when text decoration is changed in typography panel |
-| `styles_sidebar_screen_typography_element_panel_set_text_transform` | `{ element, newValue, selectedDefaultTextDecoration }` | Tracked when test transform is changed in typography panel |
-| `styles_sidebar_screen_typography_element_panel_set_font_appearance` | `{ element, newFontStyle, newFontWeight, selectedDefaultFontStyle, selectedDefaultFontWeight  }` | Tracked when font appearance is changed in typography panel |
-| `styles_sidebar_screen_typography_element_panel_reset_all_styles_selected` | - | Tracked when all styles are reset |
-| `{$inserter}_library_block_selected` | `{ blockName }` | Tracked when a block is inserted via an inserter. Inserter types: inserter_sidebar, quick_inserter, other_inserter. |
-| `{$inserter}_library_pattern_selected` | `{ patternName }` | Tracked when a pattern is inserted via an inserter. Inserter types: inserter_sidebar, quick_inserter, other_inserter. |
+| Event Name                                                                   | Data                                                                                             | Description                                                                                                                                                                 |
+| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `block_controls_personalization_tags_button_clicked`                         | -                                                                                                | Tracked when the personalization tags button is clicked in block controls                                                                                                   |
+| `command_menu_opened`                                                        | -                                                                                                | Tracked when command menu is opened via click or a shortcut                                                                                                                 |
+| `command_menu_closed`                                                        | -                                                                                                | Tracked when command menu is closed                                                                                                                                         |
+| `command_bar_command_clicked`                                                | `{ command }`                                                                                    | Tracked when a command is selected by a click.                                                                                                                              |
+| `edit_template_modal_cancel_button_clicked`                                  | -                                                                                                | Tracked when the cancel button is clicked in the edit template modal                                                                                                        |
+| `edit_template_modal_closed`                                                 | -                                                                                                | Tracked when the edit template modal is closed                                                                                                                              |
+| `edit_template_modal_continue_button_clicked`                                | `{ templateId }`                                                                                 | Tracked when the continue button is clicked in the edit template modal                                                                                                      |
+| `edit_template_modal_opened`                                                 | -                                                                                                | Tracked when the edit template modal is opened                                                                                                                              |
+| `editor_layout_loaded`                                                       | -                                                                                                | Tracked when the editor layout is loaded                                                                                                                                    |
+| `editor_showed_email_sent_notice`                                            | -                                                                                                | Tracked when the editor shows the email sent notice                                                                                                                         |
+| `header_blocks_tool_button_clicked`                                          | `{ isOpened }`                                                                                   | Tracked when user clicks the blocks tool button in the header to toggle header block tools                                                                                  |
+| `header_close_button_clicked`                                                | -                                                                                                | Tracked when user clicks the back button in the header                                                                                                                      |
+| `header_inserter_sidebar_clicked`                                            | `{ isOpened }`                                                                                   | Tracked when user clicks the inserter sidebar button in the header                                                                                                          |
+| `header_listview_sidebar_clicked`                                            | `{ isOpened }`                                                                                   | Tracked when user clicks the listview sidebar button in the header                                                                                                          |
+| `header_more_menu_dropdown_toggle`                                           | `{ isOpened }`                                                                                   | Tracked when user toggles the more menu dropdown in the header                                                                                                              |
+| `header_preview_dropdown_clicked`                                            | `{ isOpened }`                                                                                   | Tracked when user clicks an action in the preview dropdown                                                                                                                  |
+| `header_preview_dropdown_${deviceType}_selected`                             | -                                                                                                | Tracked when a device type is selected from the header preview dropdown (e.g., desktop, mobile, tablet)                                                                     |
+| `header_preview_dropdown_preview_in_new_tab_selected`                        | -                                                                                                | Tracked when the preview in new tab option is selected from the header preview dropdown                                                                                     |
+| `header_preview_dropdown_send_test_email_selected`                           | -                                                                                                | Tracked when the send test email option is selected from the header preview dropdown                                                                                        |
+| `header_save_button_clicked`                                                 | -                                                                                                | Tracked when user clicks the save button in the header                                                                                                                      |
+| `header_send_button_clicked`                                                 | -                                                                                                | Tracked when user clicks the send button in the header                                                                                                                      |
+| `personalization_tags_modal_category_menu_clicked`                           | `{ category, openedBy }`                                                                         | Tracked when a category is selected in the personalization tags modal                                                                                                       |
+| `personalization_tags_modal_closed`                                          | `{ openedBy }`                                                                                   | Tracked when the personalization tags modal is closed                                                                                                                       |
+| `personalization_tags_modal_learn_more_link_clicked`                         | `{ openedBy }`                                                                                   | Tracked when the learn more link is clicked in the personalization tags modal                                                                                               |
+| `personalization_tags_modal_opened`                                          | `{ openedBy }`                                                                                   | Tracked when the personalization tags modal is opened. The openedBy parameter indicates where it was opened from (e.g., 'block-controls', 'RichTextWithButton-BaseControl') |
+| `personalization_tags_modal_search_control_input_updated`                    | `{ openedBy }`                                                                                   | Tracked when the search input is updated in the personalization tags modal                                                                                                  |
+| `personalization_tags_modal_tag_insert_button_clicked`                       | `{ insertedTag, activeCategory, openedBy }`                                                      | Tracked when a tag insert button is clicked in the personalization tags modal                                                                                               |
+| `preview_dropdown_rendering_mode_changed`                                    | `{ renderingMode }`                                                                              | Tracked when user toggles "Show template" in preview menu. Values are 'template-locked', 'post-only'.                                                                       |
+| `rich_text_with_button_input_field_updated`                                  | `{ attributeName }`                                                                              | Tracked when the input field is updated in a rich text with button component                                                                                                |
+| `rich_text_with_button_personalization_tags_inserted`                        | `{ attributeName, value }`                                                                       | Tracked when a personalization tag is inserted in a rich text with button component                                                                                         |
+| `rich_text_with_button_personalization_tags_shortcode_icon_clicked`          | `{ attributeName, label }`                                                                       | Tracked when the personalization tags shortcode icon is clicked in a rich text with button component                                                                        |
+| `send_preview_email_modal_check_sending_method_configuration_link_clicked`   | -                                                                                                | Tracked when the sending method configuration link is clicked in the send preview email modal                                                                               |
+| `send_preview_email_modal_closed`                                            | -                                                                                                | Tracked when the send preview email modal is closed                                                                                                                         |
+| `send_preview_email_modal_close_button_clicked`                              | -                                                                                                | Tracked when the close button is clicked in the send preview email modal                                                                                                    |
+| `send_preview_email_modal_opened`                                            | -                                                                                                | Tracked when the send preview email modal is opened                                                                                                                         |
+| `send_preview_email_modal_send_test_email_button_clicked`                    | -                                                                                                | Tracked when the send test email button is clicked in the send preview email modal                                                                                          |
+| `send_preview_email_modal_send_to_field_key_code_enter`                      | -                                                                                                | Tracked when the enter key is pressed in the send to field of the send preview email modal                                                                                  |
+| `send_preview_email_modal_send_to_field_updated`                             | -                                                                                                | Tracked when the send to field is updated in the send preview email modal                                                                                                   |
+| `send_preview_email_modal_sign_up_for_mailpoet_sending_service_link_clicked` | -                                                                                                | Tracked when the sign up for MailPoet Sending Service link is clicked in the send preview email modal                                                                       |
+| `sent_preview_email`                                                         | `{ postId, email }`                                                                              | Tracked when a preview email is successfully sent                                                                                                                           |
+| `sent_preview_email_error`                                                   | `{ email }`                                                                                      | Tracked when there's an error sending a preview email                                                                                                                       |
+| `sidebar_tab_selected`                                                       | `{ tab: 'document' \| 'block' }`                                                                 | Tracked when user selects a tab in the sidebar                                                                                                                              |
+| `styles_sidebar_navigation_click`                                            | `{ path }`                                                                                       | Tracked when a navigation button is clicked in the styles sidebar (e.g., typography, colors, layout)                                                                        |
+| `styles_sidebar_screen_colors_opened`                                        | -                                                                                                | Tracked when the colors screen in styles sidebar is opened                                                                                                                  |
+| `styles_sidebar_screen_colors_styles_updated`                                | -                                                                                                | Tracked when colors are updated in the styles sidebar                                                                                                                       |
+| `styles_sidebar_screen_layout_dimensions_block_spacing_reset_clicked`        | -                                                                                                | Tracked when the block spacing reset button is clicked in the dimensions panel                                                                                              |
+| `styles_sidebar_screen_layout_dimensions_block_spacing_updated`              | `{ value }`                                                                                      | Tracked when block spacing is updated in the dimensions panel                                                                                                               |
+| `styles_sidebar_screen_layout_dimensions_padding_reset_clicked`              | -                                                                                                | Tracked when the padding reset button is clicked in the dimensions panel                                                                                                    |
+| `styles_sidebar_screen_layout_dimensions_padding_updated`                    | `{ value }`                                                                                      | Tracked when padding is updated in the dimensions panel                                                                                                                     |
+| `styles_sidebar_screen_layout_dimensions_reset_all_selected`                 | -                                                                                                | Tracked when the reset all button is clicked in the dimensions panel                                                                                                        |
+| `styles_sidebar_screen_layout_opened`                                        | -                                                                                                | Tracked when the layout screen in styles sidebar is opened                                                                                                                  |
+| `styles_sidebar_screen_typography_button_click`                              | `{ element, label, path }`                                                                       | Tracked when a typography element button is clicked in the typography panel                                                                                                 |
+| `styles_sidebar_screen_typography_element_heading_level_selected`            | `{ value }`                                                                                      | Tracked when a heading level is selected in the typography element screen                                                                                                   |
+| `styles_sidebar_screen_typography_element_opened`                            | `{ element }`                                                                                    | Tracked when the typography screen in styles sidebar is opened                                                                                                              |
+| `styles_sidebar_screen_typography_element_panel_reset_all_styles_selected`   | `{ element, headingLevel }`                                                                      | Tracked when the reset all styles button is clicked in the typography element panel                                                                                         |
+| `styles_sidebar_screen_typography_opened`                                    | -                                                                                                | Tracked when the typography screen in styles sidebar is opened                                                                                                              |
+| `template_select_modal_category_change`                                      | `{ category }`                                                                                   | Tracked when user changes category in template select modal                                                                                                                 |
+| `template_select_modal_closed`                                               | `{ templateSelectMode }`                                                                         | Tracked when template select modal is closed. templateSelectMode tracks category which was opened.                                                                          |
+| `template_select_modal_handle_close_without_template_selected`               | -                                                                                                | Tracked when the template select modal is closed without explicitly selecting a template                                                                                    |
+| `template_select_modal_opened`                                               | `{ templateSelectMode }`                                                                         | Tracked when template select modal is opened                                                                                                                                |
+| `template_select_modal_start_from_scratch_clicked`                           | -                                                                                                | Tracked when the "Start from scratch" button is clicked in the template select modal                                                                                        |
+| `template_select_modal_template_selected`                                    | `{ template }`                                                                                   | Tracked when user selects a template in the template select modal                                                                                                           |
+| `template_canvas_affordance_edit_template_clicked`                           | `{ templateId }`                                                                                 | Tracked when the edit template button in the canvas template affordance is clicked                                                                                          |
+| `trash_modal_move_to_trash_button_clicked`                                   | -                                                                                                | Tracked when user clicks the move to trash button in the trash modal                                                                                                        |
+| `styles_sidebar_screen_typography_element_panel_set_letter_spacing`          | `{ element, newValue, selectedDefaultLetterSpacing }`                                            | Tracked when letter spacing is changed in typography panel                                                                                                                  |
+| `styles_sidebar_screen_typography_element_panel_set_line_height`             | `{ element, newValue, selectedDefaultLineHeight }`                                               | Tracked when line height is changed in typography panel                                                                                                                     |
+| `styles_sidebar_screen_typography_element_panel_set_font_size`               | `{ element, newValue, selectedDefaultFontSize }`                                                 | Tracked when font size is changed in typography panel                                                                                                                       |
+| `styles_sidebar_screen_typography_element_panel_set_font_family`             | `{  element, newValue, selectedDefaultFontFamily }`                                              | Tracked when font family is changed in typography panel                                                                                                                     |
+| `styles_sidebar_screen_typography_element_panel_set_text_decoration`         | `{ element, newValue, selectedDefaultTextDecoration }`                                           | Tracked when text decoration is changed in typography panel                                                                                                                 |
+| `styles_sidebar_screen_typography_element_panel_set_text_transform`          | `{ element, newValue, selectedDefaultTextDecoration }`                                           | Tracked when test transform is changed in typography panel                                                                                                                  |
+| `styles_sidebar_screen_typography_element_panel_set_font_appearance`         | `{ element, newFontStyle, newFontWeight, selectedDefaultFontStyle, selectedDefaultFontWeight  }` | Tracked when font appearance is changed in typography panel                                                                                                                 |
+| `styles_sidebar_screen_typography_element_panel_reset_all_styles_selected`   | -                                                                                                | Tracked when all styles are reset                                                                                                                                           |
+| `{$inserter}_library_block_selected`                                         | `{ blockName }`                                                                                  | Tracked when a block is inserted via an inserter. Inserter types: inserter_sidebar, quick_inserter, other_inserter.                                                         |
+| `{$inserter}_library_pattern_selected`                                       | `{ patternName }`                                                                                | Tracked when a pattern is inserted via an inserter. Inserter types: inserter_sidebar, quick_inserter, other_inserter.                                                       |