From ec2c91306c2d4505287f49de4b84f007d036164d Mon Sep 17 00:00:00 2001 From: Miguel Lezama Date: Thu, 24 Apr 2025 15:39:25 -0300 Subject: [PATCH 1/4] working! --- .../contact-form/class-contact-form-block.php | 38 +-- .../blocks/contact-form/util/form-styles.js | 198 ++++++++++++++ .../util/fullscreen-link-generator.js | 243 ++++++++++++++++++ .../contact-form/util/fullscreen-validator.js | 147 +++++++++++ .../forms/src/blocks/contact-form/view.js | 229 +++++++++++++++++ 5 files changed, 839 insertions(+), 16 deletions(-) create mode 100644 projects/packages/forms/src/blocks/contact-form/util/fullscreen-link-generator.js create mode 100644 projects/packages/forms/src/blocks/contact-form/util/fullscreen-validator.js diff --git a/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php b/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php index 848a9bb9d1408..3a0c6090540cb 100644 --- a/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php +++ b/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php @@ -260,21 +260,6 @@ public static function load_editor_scripts() { return; } - $handle = 'jp-forms-blocks'; - - Assets::register_script( - $handle, - '../../../dist/blocks/editor.js', - __FILE__, - array( - 'in_footer' => true, - 'textdomain' => 'jetpack-forms', - 'enqueue' => true, - // Editor styles are loaded separately, see load_editor_styles(). - 'css_path' => null, - ) - ); - // Create a Contact_Form instance to get the default values $dashboard_view_switch = new Dashboard_View_Switch(); $contact_form = new Contact_Form( array() ); @@ -284,6 +269,27 @@ public static function load_editor_scripts() { $akismet_key_url = admin_url( 'admin.php?page=akismet-key-config' ); $preferred_view = $dashboard_view_switch->get_preferred_view(); + $asset_file = include plugin_dir_path( __FILE__ ) . 'js/editor.asset.php'; + $dependencies = $asset_file['dependencies']; + $version = $asset_file['version']; + + wp_enqueue_script( + 'jetpack-instant-forms', + plugins_url( 'js/editor.js', __FILE__ ), + $dependencies, + $version, + true + ); + + // Register the fullscreen link generator script + wp_enqueue_script( + 'jetpack-forms-fullscreen-link-generator', + plugins_url( 'util/fullscreen-link-generator.js', __FILE__ ), + array( 'wp-element', 'wp-components', 'wp-data', 'wp-i18n', 'wp-editor', 'wp-blocks', 'wp-plugins', 'wp-edit-post' ), + \Automattic\Jetpack\Forms\Jetpack_Forms::PACKAGE_VERSION, + true + ); + $data = array( 'defaults' => array( 'to' => $defaults['to'], @@ -297,7 +303,7 @@ public static function load_editor_scripts() { ), ); - wp_add_inline_script( $handle, 'window.jpFormsBlocks = ' . wp_json_encode( $data ) . ';', 'before' ); + wp_add_inline_script( 'jetpack-instant-forms', 'window.jpFormsBlocks = ' . wp_json_encode( $data ) . ';', 'before' ); } /** diff --git a/projects/packages/forms/src/blocks/contact-form/util/form-styles.js b/projects/packages/forms/src/blocks/contact-form/util/form-styles.js index 2121e7026af28..5530530c2c8fc 100644 --- a/projects/packages/forms/src/blocks/contact-form/util/form-styles.js +++ b/projects/packages/forms/src/blocks/contact-form/util/form-styles.js @@ -130,3 +130,201 @@ window.jetpackForms.generateStyleVariables = function ( formNode ) { '--jetpack--contact-form--button-outline--line-height': buttonOutlineLineHeight, }; }; + +// Add fullscreen form styles +const fullscreenStyles = ` +.jetpack-contact-form-fullscreen { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 999999; + background-color: rgba(255, 255, 255, 0.98); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + overflow: auto; + padding: 2rem; +} + +.jetpack-contact-form-fullscreen .contact-form { + max-width: 600px; + width: 100%; + box-shadow: 0 5px 30px rgba(0, 0, 0, 0.1); + border-radius: 8px; + padding: 40px; + background: #fff; + position: relative; +} + +.jetpack-contact-form-progress { + position: fixed; + top: 0; + left: 0; + height: 4px; + background-color: #0675c4; + transition: width 0.3s ease; +} + +.jetpack-contact-form-step { + transition: opacity 0.3s ease, transform 0.3s ease; + opacity: 1; + transform: translateY(0); +} + +.jetpack-contact-form-step:not(:first-child) { + opacity: 0; + transform: translateY(20px); +} + +.jetpack-contact-form-step:not(.is-active) { + animation: slide-in 0.4s forwards; +} + +@keyframes slide-in { + 0% { + opacity: 0; + transform: translateY(20px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} + +.jetpack-contact-form-nav { + display: flex; + justify-content: space-between; + margin-top: 30px; +} + +.jetpack-contact-form-prev, +.jetpack-contact-form-next { + background-color: #0675c4; + color: white; + border: none; + padding: 10px 20px; + border-radius: 4px; + cursor: pointer; + font-size: 16px; + transition: background-color 0.2s ease; +} + +.jetpack-contact-form-prev:disabled { + background-color: #ccc; + cursor: not-allowed; +} + +.jetpack-contact-form-prev:not(:disabled):hover, +.jetpack-contact-form-next:hover { + background-color: #055c9d; +} + +.jetpack-contact-form-close { + position: fixed; + top: 20px; + right: 20px; + width: 40px; + height: 40px; + background-color: rgba(0, 0, 0, 0.1); + border: none; + border-radius: 50%; + font-size: 24px; + line-height: 40px; + text-align: center; + cursor: pointer; + transition: background-color 0.2s ease; + z-index: 1000000; +} + +.jetpack-contact-form-close:hover { + background-color: rgba(0, 0, 0, 0.2); +} + +.jetpack-contact-form-fullscreen .grunion-field-wrap label { + font-size: 1.2em; + margin-bottom: 12px; + display: block; +} + +.jetpack-contact-form-fullscreen .grunion-field-wrap input[type="text"], +.jetpack-contact-form-fullscreen .grunion-field-wrap input[type="email"], +.jetpack-contact-form-fullscreen .grunion-field-wrap input[type="url"], +.jetpack-contact-form-fullscreen .grunion-field-wrap input[type="tel"], +.jetpack-contact-form-fullscreen .grunion-field-wrap textarea, +.jetpack-contact-form-fullscreen .grunion-field-wrap select { + width: 100%; + padding: 12px; + font-size: 16px; + border-radius: 4px; + border: 1px solid #ddd; +} + +.jetpack-contact-form-fullscreen .grunion-field-submit-wrap input[type="submit"] { + width: 100%; + padding: 12px 20px; + font-size: 16px; + border-radius: 4px; + background-color: #0675c4; + color: white; + border: none; + cursor: pointer; + transition: background-color 0.2s ease; +} + +.jetpack-contact-form-fullscreen .grunion-field-submit-wrap input[type="submit"]:hover { + background-color: #055c9d; +} + +/* Validation styling */ +.jetpack-contact-form-error-message { + color: #d63638; + font-size: 14px; + margin-top: 5px; + padding: 5px 0; + font-weight: 500; +} + +.jetpack-contact-form-fullscreen .grunion-field-wrap input.has-error, +.jetpack-contact-form-fullscreen .grunion-field-wrap textarea.has-error, +.jetpack-contact-form-fullscreen .grunion-field-wrap select.has-error { + border-color: #d63638; + box-shadow: 0 0 0 1px #d63638; +} + +.jetpack-contact-form-validation-errors { + background-color: #fcf0f1; + border-left: 4px solid #d63638; + color: #d63638; + margin: 0 0 15px 0; + padding: 8px 12px; + display: none; +} + +.jetpack-contact-form-fullscreen input[type="checkbox"].has-error + label, +.jetpack-contact-form-fullscreen input[type="radio"].has-error + label { + color: #d63638; +} + +/* Field animation */ +.jetpack-contact-form-step { + animation: form-field-appear 0.3s forwards; +} + +@keyframes form-field-appear { + 0% { + opacity: 0; + transform: translateY(10px); + } + 100% { + opacity: 1; + transform: translateY(0); + } +} +`; + +const style = document.createElement( 'style' ); +style.appendChild( document.createTextNode( fullscreenStyles ) ); +document.head.appendChild( style ); diff --git a/projects/packages/forms/src/blocks/contact-form/util/fullscreen-link-generator.js b/projects/packages/forms/src/blocks/contact-form/util/fullscreen-link-generator.js new file mode 100644 index 0000000000000..ccae45b6ea62f --- /dev/null +++ b/projects/packages/forms/src/blocks/contact-form/util/fullscreen-link-generator.js @@ -0,0 +1,243 @@ +/** + * Jetpack Contact Form Fullscreen Link Generator + * + * This module adds a utility to generate fullscreen form links. + * It can be used in the editor to create links that open forms in fullscreen mode. + */ + +( function () { + // Only run in admin context + if ( typeof wp === 'undefined' || ! wp.blocks || ! wp.element || ! wp.components ) { + return; + } + + const { registerPlugin } = wp.plugins; + const { PluginDocumentSettingPanel } = wp.editPost; + const { Fragment, useState, useEffect } = wp.element; + const { Button, TextControl, ClipboardButton, Notice } = wp.components; + const { select, subscribe } = wp.data; + + /** + * Check if the current post has a contact form + * + * @return {boolean} Whether the post has a contact form + */ + const postHasContactForm = () => { + const { getBlocks } = select( 'core/block-editor' ); + + if ( ! getBlocks ) { + return false; + } + + const blocks = getBlocks(); + + // Check if there's a contact form block + const hasContactForm = blocks.some( block => { + // Direct jetpack/contact-form block + if ( block.name === 'jetpack/contact-form' ) { + return true; + } + + // Check inner blocks recursively + if ( block.innerBlocks && block.innerBlocks.length ) { + return hasContactFormInnerBlocks( block.innerBlocks ); + } + + return false; + } ); + + return hasContactForm; + }; + + /** + * Check for contact form in inner blocks + * + * @param {Array} innerBlocks - The inner blocks to check + * @return {boolean} Whether inner blocks contain a contact form + */ + const hasContactFormInnerBlocks = innerBlocks => { + return innerBlocks.some( block => { + if ( block.name === 'jetpack/contact-form' ) { + return true; + } + + if ( block.innerBlocks && block.innerBlocks.length ) { + return hasContactFormInnerBlocks( block.innerBlocks ); + } + + return false; + } ); + }; + + /** + * Get all contact form IDs in the current post + * + * @return {Array} The form IDs + */ + const getFormIds = () => { + const { getBlocks } = select( 'core/block-editor' ); + + if ( ! getBlocks ) { + return []; + } + + const blocks = getBlocks(); + const forms = []; + + // Find contact form blocks + const findContactForms = blocksToSearch => { + blocksToSearch.forEach( block => { + if ( block.name === 'jetpack/contact-form' ) { + // Extract form ID from attributes or clientId + const formId = block.attributes.formId || block.clientId; + forms.push( { + id: formId, + title: block.attributes.title || 'Contact Form', + } ); + } + + if ( block.innerBlocks && block.innerBlocks.length ) { + findContactForms( block.innerBlocks ); + } + } ); + }; + + findContactForms( blocks ); + + return forms; + }; + + /** + * Generate fullscreen form link + * + * @param {string} formId - The form ID (optional) + * @return {string} The fullscreen form link + */ + const generateFullscreenLink = formId => { + const { getPermalink } = select( 'core/editor' ); + + if ( ! getPermalink ) { + return ''; + } + + const permalink = getPermalink(); + + if ( ! permalink ) { + return ''; + } + + const url = new URL( permalink ); + + if ( formId ) { + url.searchParams.set( 'fullscreen', formId ); + } else { + url.searchParams.set( 'fullscreen', 'true' ); + } + + return url.toString(); + }; + + /** + * Fullscreen Form Link Panel Component + */ + const FullscreenFormLinkPanel = () => { + const [ hasForm, setHasForm ] = useState( false ); + const [ forms, setForms ] = useState( [] ); + const [ copied, setCopied ] = useState( false ); + + // Check for contact forms whenever blocks change + useEffect( () => { + const unsubscribe = subscribe( () => { + const currentHasForm = postHasContactForm(); + if ( currentHasForm !== hasForm ) { + setHasForm( currentHasForm ); + } + + if ( currentHasForm ) { + setForms( getFormIds() ); + } + } ); + + return unsubscribe; + }, [ hasForm ] ); + + // Initial check + useEffect( () => { + setHasForm( postHasContactForm() ); + if ( postHasContactForm() ) { + setForms( getFormIds() ); + } + }, [] ); + + if ( ! hasForm ) { + return null; + } + + return ( + +

+ Generate links that will open this page's contact form in fullscreen mode, displaying one + field at a time like Typeform. +

+ + { forms.length === 0 ? ( + // For a post with a form but couldn't identify its ID + + + { + setCopied( true ); + setTimeout( () => setCopied( false ), 3000 ); + } } + > + { copied ? 'Copied!' : 'Copy Link' } + + + ) : ( + // For posts with identifiable forms + forms.map( form => ( +
+ + { + setCopied( form.id ); + setTimeout( () => setCopied( false ), 3000 ); + } } + > + { copied === form.id ? 'Copied!' : 'Copy Link' } + +
+ ) ) + ) } + + { copied && ( + + Link copied to clipboard! + + ) } + +

+ Use this link in navigation menus, buttons, or anywhere you want to provide a direct link + to your form in fullscreen mode. +

+
+ ); + }; + + // Register the plugin + registerPlugin( 'jetpack-contact-form-fullscreen-link', { + render: FullscreenFormLinkPanel, + icon: 'feedback', + } ); +} )(); diff --git a/projects/packages/forms/src/blocks/contact-form/util/fullscreen-validator.js b/projects/packages/forms/src/blocks/contact-form/util/fullscreen-validator.js new file mode 100644 index 0000000000000..48b75e1044e18 --- /dev/null +++ b/projects/packages/forms/src/blocks/contact-form/util/fullscreen-validator.js @@ -0,0 +1,147 @@ +/** + * Jetpack Contact Form Fullscreen Validator + * + * Handles form field validation in fullscreen mode to ensure + * each step is validated before proceeding to the next one. + */ + +/** + * Validate a form field + * + * @param {HTMLElement} field - The field wrapper element + * @return {boolean} - Whether the field is valid + */ +export function validateField( field ) { + const inputs = field.querySelectorAll( 'input, textarea, select' ); + let isValid = true; + + for ( const input of inputs ) { + // Skip fields that don't need validation + if ( input.type === 'button' || input.type === 'submit' || input.type === 'hidden' ) { + continue; + } + + // Check required fields + if ( input.required && ! input.value.trim() ) { + isValid = false; + showError( field, input, 'This field is required' ); + continue; + } + + // Check email format + if ( input.type === 'email' && input.value && ! isValidEmail( input.value ) ) { + isValid = false; + showError( field, input, 'Please enter a valid email address' ); + continue; + } + + // Check URL format + if ( input.type === 'url' && input.value && ! isValidURL( input.value ) ) { + isValid = false; + showError( field, input, 'Please enter a valid URL' ); + continue; + } + + // Check telephone format + if ( input.type === 'tel' && input.value && ! isValidTel( input.value ) ) { + isValid = false; + showError( field, input, 'Please enter a valid phone number' ); + continue; + } + + // Check radio/checkbox groups + if ( ( input.type === 'radio' || input.type === 'checkbox' ) && input.required ) { + const name = input.name; + const checked = field.querySelectorAll( `input[name="${ name }"]:checked` ).length > 0; + + if ( ! checked ) { + isValid = false; + showError( field, input, 'Please select an option' ); + continue; + } + } + + // If we got here, the field is valid + clearError( field, input ); + } + + return isValid; +} + +/** + * Show an error message for a field + * + * @param {HTMLElement} field - The field wrapper element + * @param {HTMLElement} input - The input element + * @param {string} message - The error message + */ +function showError( field, input, message ) { + // Clear existing errors first + clearError( field, input ); + + // Create error message + const errorElement = document.createElement( 'div' ); + errorElement.className = 'jetpack-contact-form-error-message'; + errorElement.textContent = message; + + // Add error class to input + input.classList.add( 'has-error' ); + + // Append error after the input + input.parentNode.insertBefore( errorElement, input.nextSibling ); +} + +/** + * Clear error messages for a field + * + * @param {HTMLElement} field - The field wrapper element + * @param {HTMLElement} input - The input element + */ +function clearError( field, input ) { + // Remove error class from input + input.classList.remove( 'has-error' ); + + // Remove error messages + const errorMessages = field.querySelectorAll( '.jetpack-contact-form-error-message' ); + for ( const error of errorMessages ) { + error.parentNode.removeChild( error ); + } +} + +/** + * Validate an email address + * + * @param {string} email - The email to validate + * @return {boolean} - Whether the email is valid + */ +function isValidEmail( email ) { + const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return pattern.test( email ); +} + +/** + * Validate a URL + * + * @param {string} url - The URL to validate + * @return {boolean} - Whether the URL is valid + */ +function isValidURL( url ) { + try { + new URL( url ); + return true; + } catch ( e ) { + return false; + } +} + +/** + * Validate a telephone number + * + * @param {string} tel - The telephone number to validate + * @return {boolean} - Whether the telephone number is valid + */ +function isValidTel( tel ) { + // Allow a variety of formats, this is a simple check + const pattern = /^[+]?[(]?[0-9]{3}[)]?[-\s.]?[0-9]{3}[-\s.]?[0-9]{4,6}$/; + return pattern.test( tel.replace( /\s/g, '' ) ); +} diff --git a/projects/packages/forms/src/blocks/contact-form/view.js b/projects/packages/forms/src/blocks/contact-form/view.js index a617b0ef4f231..ea1aff5de12f6 100644 --- a/projects/packages/forms/src/blocks/contact-form/view.js +++ b/projects/packages/forms/src/blocks/contact-form/view.js @@ -1,4 +1,5 @@ import './util/form-styles'; +import { validateField } from './util/fullscreen-validator'; const { generateStyleVariables } = window.jetpackForms; const FRONTEND_SELECTOR = '.wp-block-jetpack-contact-form-container'; @@ -6,11 +7,13 @@ const FRONTEND_SELECTOR = '.wp-block-jetpack-contact-form-container'; //Fallback in case of the page load event takes too long to fire up const fallbackTimer = setTimeout( () => { handleFormStyles(); + initFullscreenMode(); }, 3000 ); window.addEventListener( 'load', () => { clearTimeout( fallbackTimer ); handleFormStyles(); + initFullscreenMode(); } ); function handleFormStyles() { @@ -28,3 +31,229 @@ function handleFormStyles() { } } } + +function initFullscreenMode() { + // Check for fullscreen query parameter + const urlParams = new URLSearchParams( window.location.search ); + const fullscreenParam = urlParams.get( 'fullscreen' ); + + if ( ! fullscreenParam ) { + return; + } + + const formId = fullscreenParam === 'true' ? null : fullscreenParam; + const forms = document.querySelectorAll( '.contact-form' ); + + forms.forEach( form => { + // If formId is specified, only transform that specific form + if ( formId && form.id !== `contact-form-${ formId }` ) { + return; + } + + transformToFullscreenForm( form ); + } ); +} + +function transformToFullscreenForm( form ) { + // Create fullscreen container + const fullscreenContainer = document.createElement( 'div' ); + fullscreenContainer.className = 'jetpack-contact-form-fullscreen'; + document.body.appendChild( fullscreenContainer ); + + // Create progress bar + const progressBar = document.createElement( 'div' ); + progressBar.className = 'jetpack-contact-form-progress'; + fullscreenContainer.appendChild( progressBar ); + + // Move the form into the fullscreen container + fullscreenContainer.appendChild( form ); + + // Find all form fields (not hidden fields, buttons, or submit) + const fields = Array.from( form.querySelectorAll( '.grunion-field-wrap' ) ).filter( field => { + const input = field.querySelector( 'input, textarea, select' ); + return ( + input && + input.type !== 'hidden' && + input.type !== 'submit' && + ! field.classList.contains( 'grunion-field-submit-wrap' ) + ); + } ); + + // Find submit button wrap + const submitWrap = form.querySelector( '.grunion-field-submit-wrap' ); + + // Setup for step navigation + let currentStep = 0; + const totalSteps = fields.length; + + // Create step navigation controls + const navControls = document.createElement( 'div' ); + navControls.className = 'jetpack-contact-form-nav'; + + const prevButton = document.createElement( 'button' ); + prevButton.type = 'button'; + prevButton.className = 'jetpack-contact-form-prev'; + prevButton.textContent = '← Previous'; + prevButton.disabled = true; + + const nextButton = document.createElement( 'button' ); + nextButton.type = 'button'; + nextButton.className = 'jetpack-contact-form-next'; + nextButton.textContent = 'Next →'; + + navControls.appendChild( prevButton ); + navControls.appendChild( nextButton ); + + // Add error message area + const errorContainer = document.createElement( 'div' ); + errorContainer.className = 'jetpack-contact-form-validation-errors'; + errorContainer.style.display = 'none'; + navControls.insertBefore( errorContainer, nextButton ); + + // Hide all fields except the first one + fields.forEach( ( field, index ) => { + field.classList.add( 'jetpack-contact-form-step' ); + if ( index !== 0 ) { + field.style.display = 'none'; + } + } ); + + // Hide submit wrap initially + if ( submitWrap ) { + submitWrap.style.display = 'none'; + } + + // Update progress bar + const updateProgress = () => { + const progress = ( ( currentStep + 1 ) / ( totalSteps + 1 ) ) * 100; + progressBar.style.width = `${ progress }%`; + }; + + // Navigate to step + const goToStep = step => { + // Validate current field before proceeding + if ( step > currentStep && ! validateField( fields[ currentStep ] ) ) { + return false; + } + + // Hide current step + fields[ currentStep ].style.display = 'none'; + + // Show new step + currentStep = step; + fields[ currentStep ].style.display = 'block'; + + // Update buttons + prevButton.disabled = currentStep === 0; + + // If last field, show submit instead of next + if ( currentStep === totalSteps - 1 ) { + nextButton.style.display = 'none'; + if ( submitWrap ) { + submitWrap.style.display = 'block'; + } + } else { + nextButton.style.display = 'block'; + if ( submitWrap ) { + submitWrap.style.display = 'none'; + } + } + + // Update progress + updateProgress(); + + // Focus on field input + const input = fields[ currentStep ].querySelector( 'input, textarea, select' ); + if ( input ) { + setTimeout( () => input.focus(), 100 ); + } + + return true; + }; + + // Add event listeners for navigation + prevButton.addEventListener( 'click', () => { + if ( currentStep > 0 ) { + goToStep( currentStep - 1 ); + } + } ); + + nextButton.addEventListener( 'click', () => { + if ( currentStep < totalSteps - 1 ) { + goToStep( currentStep + 1 ); + } + } ); + + // Add keyboard navigation + document.addEventListener( 'keydown', e => { + if ( e.key === 'Enter' && currentStep < totalSteps - 1 ) { + e.preventDefault(); + goToStep( currentStep + 1 ); + } + } ); + + // Add form submit handler to validate all fields + form.addEventListener( 'submit', e => { + // Validate current field + if ( ! validateField( fields[ currentStep ] ) ) { + e.preventDefault(); + return; + } + + // Check if all fields are valid + let allValid = true; + for ( let i = 0; i < fields.length; i++ ) { + // Temporarily show field to validate + const wasHidden = fields[ i ].style.display === 'none'; + if ( wasHidden ) { + fields[ i ].style.display = 'block'; + } + + // Validate field + if ( ! validateField( fields[ i ] ) ) { + allValid = false; + // Go to the first invalid field + if ( i !== currentStep ) { + goToStep( i ); + } + + // Hide other fields again + for ( let j = 0; j < fields.length; j++ ) { + if ( j !== i && fields[ j ].style.display !== 'none' ) { + fields[ j ].style.display = 'none'; + } + } + + break; + } + + // Hide field again if it was hidden before + if ( wasHidden ) { + fields[ i ].style.display = 'none'; + } + } + + if ( ! allValid ) { + e.preventDefault(); + } + } ); + + // Append navigation controls to form + form.appendChild( navControls ); + + // Initialize first step + updateProgress(); + + // Add close button + const closeButton = document.createElement( 'button' ); + closeButton.type = 'button'; + closeButton.className = 'jetpack-contact-form-close'; + closeButton.textContent = '×'; + closeButton.title = 'Close form'; + closeButton.addEventListener( 'click', () => { + const url = new URL( window.location ); + url.searchParams.delete( 'fullscreen' ); + window.location.href = url.toString(); + } ); + fullscreenContainer.appendChild( closeButton ); +} From e9179970b4b85709bc4fc78f6a86528f7b8918e9 Mon Sep 17 00:00:00 2001 From: Miguel Lezama Date: Thu, 24 Apr 2025 15:53:50 -0300 Subject: [PATCH 2/4] changelog --- projects/packages/forms/changelog/add-forms-fullscreen-mode | 4 ++++ projects/plugins/jetpack/changelog/add-forms-fullscreen-mode | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 projects/packages/forms/changelog/add-forms-fullscreen-mode create mode 100644 projects/plugins/jetpack/changelog/add-forms-fullscreen-mode diff --git a/projects/packages/forms/changelog/add-forms-fullscreen-mode b/projects/packages/forms/changelog/add-forms-fullscreen-mode new file mode 100644 index 0000000000000..c499f8ef5c780 --- /dev/null +++ b/projects/packages/forms/changelog/add-forms-fullscreen-mode @@ -0,0 +1,4 @@ +Significance: patch +Type: added + +Forms: Full screen mode diff --git a/projects/plugins/jetpack/changelog/add-forms-fullscreen-mode b/projects/plugins/jetpack/changelog/add-forms-fullscreen-mode new file mode 100644 index 0000000000000..65161d31e1bd0 --- /dev/null +++ b/projects/plugins/jetpack/changelog/add-forms-fullscreen-mode @@ -0,0 +1,4 @@ +Significance: minor +Type: enhancement + +Forms: Add fullscreen mode From cb6258f922db29f714758ec8cf2e7ac92dc0e978 Mon Sep 17 00:00:00 2001 From: Miguel Lezama Date: Thu, 24 Apr 2025 20:06:27 -0300 Subject: [PATCH 3/4] fix js loading --- .../contact-form/class-contact-form-block.php | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php b/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php index 3a0c6090540cb..ef98e75e37a42 100644 --- a/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php +++ b/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php @@ -269,16 +269,19 @@ public static function load_editor_scripts() { $akismet_key_url = admin_url( 'admin.php?page=akismet-key-config' ); $preferred_view = $dashboard_view_switch->get_preferred_view(); - $asset_file = include plugin_dir_path( __FILE__ ) . 'js/editor.asset.php'; - $dependencies = $asset_file['dependencies']; - $version = $asset_file['version']; + $handle = 'jp-forms-blocks'; - wp_enqueue_script( - 'jetpack-instant-forms', - plugins_url( 'js/editor.js', __FILE__ ), - $dependencies, - $version, - true + Assets::register_script( + $handle, + '../../../dist/blocks/editor.js', + __FILE__, + array( + 'in_footer' => true, + 'textdomain' => 'jetpack-forms', + 'enqueue' => true, + // Editor styles are loaded separately, see load_editor_styles(). + 'css_path' => null, + ) ); // Register the fullscreen link generator script @@ -303,7 +306,7 @@ public static function load_editor_scripts() { ), ); - wp_add_inline_script( 'jetpack-instant-forms', 'window.jpFormsBlocks = ' . wp_json_encode( $data ) . ';', 'before' ); + wp_add_inline_script( $handle, 'window.jpFormsBlocks = ' . wp_json_encode( $data ) . ';', 'before' ); } /** From f5db4518081c5d34c077f187d810bbe43c554122 Mon Sep 17 00:00:00 2001 From: Miguel Lezama Date: Thu, 24 Apr 2025 20:16:15 -0300 Subject: [PATCH 4/4] fix admin --- .../src/blocks/contact-form/class-contact-form-block.php | 9 --------- projects/packages/forms/src/blocks/contact-form/edit.js | 1 + .../contact-form/util/fullscreen-link-generator.js | 2 +- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php b/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php index ef98e75e37a42..717ec8df6408a 100644 --- a/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php +++ b/projects/packages/forms/src/blocks/contact-form/class-contact-form-block.php @@ -284,15 +284,6 @@ public static function load_editor_scripts() { ) ); - // Register the fullscreen link generator script - wp_enqueue_script( - 'jetpack-forms-fullscreen-link-generator', - plugins_url( 'util/fullscreen-link-generator.js', __FILE__ ), - array( 'wp-element', 'wp-components', 'wp-data', 'wp-i18n', 'wp-editor', 'wp-blocks', 'wp-plugins', 'wp-edit-post' ), - \Automattic\Jetpack\Forms\Jetpack_Forms::PACKAGE_VERSION, - true - ); - $data = array( 'defaults' => array( 'to' => $defaults['to'], diff --git a/projects/packages/forms/src/blocks/contact-form/edit.js b/projects/packages/forms/src/blocks/contact-form/edit.js index a3482941b8b58..1612a069d47be 100644 --- a/projects/packages/forms/src/blocks/contact-form/edit.js +++ b/projects/packages/forms/src/blocks/contact-form/edit.js @@ -36,6 +36,7 @@ import NewsletterIntegrationSettings from './components/jetpack-newsletter-integ import SalesforceLeadFormSettings from './components/jetpack-salesforce-lead-form/jetpack-salesforce-lead-form-settings'; import VariationPicker from './variation-picker'; import './util/form-styles.js'; +import './util/fullscreen-link-generator.js'; const validFields = filter( childBlocks, ( { settings } ) => { return ( diff --git a/projects/packages/forms/src/blocks/contact-form/util/fullscreen-link-generator.js b/projects/packages/forms/src/blocks/contact-form/util/fullscreen-link-generator.js index ccae45b6ea62f..17cce6da1d072 100644 --- a/projects/packages/forms/src/blocks/contact-form/util/fullscreen-link-generator.js +++ b/projects/packages/forms/src/blocks/contact-form/util/fullscreen-link-generator.js @@ -12,7 +12,7 @@ } const { registerPlugin } = wp.plugins; - const { PluginDocumentSettingPanel } = wp.editPost; + const { PluginDocumentSettingPanel } = wp.editor; const { Fragment, useState, useEffect } = wp.element; const { Button, TextControl, ClipboardButton, Notice } = wp.components; const { select, subscribe } = wp.data;