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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Forms: Add input styles to image select field
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import useAddImageOption from '../shared/hooks/use-add-image-option';
import useFormWrapper from '../shared/hooks/use-form-wrapper';
import useJetpackFieldStyles from '../shared/hooks/use-jetpack-field-styles';
import './style.scss';
import './editor.scss';
/**
* Types
*/
Expand Down
22 changes: 22 additions & 0 deletions projects/packages/forms/src/blocks/field-image-select/editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Editor-only styles.

// There is a high specificity flex rule for form fields
// that we need to override to show the image options
// in a grid.
.wp-block-jetpack-contact-form
.jetpack-contact-form
.jetpack-fieldset-image-options__wrapper
.jetpack-input-image-option {
flex-basis: unset;
}

// There is no outer block in the editor, so we apply
// the styles directly to the input image option.
.jetpack-input-image-option {
display: flex;
width: calc(( 1 / 4 ) * 100% - var(--jetpack-field-image-options-gap) * ( 3 / 4 ));

&.is-supersized {
width: calc(( 1 / 2 ) * 100% - var(--jetpack-field-image-options-gap) * ( 1 / 2 ));
}
}
42 changes: 31 additions & 11 deletions projects/packages/forms/src/blocks/field-image-select/style.scss
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
@use "../shared/styles/visually-hidden" as *;

// There is a high specificity flex rule that we
// need to override in the block editor only.
.wp-block-jetpack-contact-form
.jetpack-contact-form
.jetpack-fieldset-image-options__wrapper
.jetpack-input-image-option {
flex-basis: unset;
}

// Themes target the image block directly to fit their needs,
// not expecting it to be inside an image select field.
.wp-block-jetpack-input-image-option
Expand All @@ -33,6 +24,7 @@ figure.wp-block-image {
flex-wrap: wrap;
gap: var(--jetpack-field-image-options-gap);

// Frontend-only wrapper element for background color change on hover.
.jetpack-input-image-option__outer {
display: flex;
width: calc(( 1 / 4 ) * 100% - var(--jetpack-field-image-options-gap) * ( 3 / 4 ));
Expand All @@ -46,10 +38,10 @@ figure.wp-block-image {
box-sizing: border-box;
display: flex;
flex-direction: column;
width: 100%;
overflow: hidden;

&:not(.wp-block):hover {
&:not(.wp-block):hover,
&.is-checked {
backdrop-filter: contrast(0.9) saturate(1.2);
cursor: pointer;
}
Expand All @@ -59,6 +51,34 @@ figure.wp-block-image {
overflow: hidden;
position: relative;

.jetpack-input-image-option__input[type="checkbox"],
.jetpack-input-image-option__input[type="radio"] {
font-size: inherit;
padding: 0;
appearance: none;
border: solid 1px currentColor;
color: currentColor;
outline-offset: 1px;
border-radius: 4px;

&:checked {
background-color: currentColor;
}

&::before {
width: 0.25em;
height: 0.5em;
content: "";
display: block;
margin-left: 50%;
margin-top: 50%;
border: solid currentColor;
border-width: 0 2px 2px 0;
transform: translate(-50%, -60%) rotate(40deg);
filter: invert(1) contrast(2) brightness(1.5);
}
}

.jetpack-input-image-option__input {
position: absolute;
top: 4px;
Expand Down
33 changes: 13 additions & 20 deletions projects/packages/forms/src/blocks/input-image-option/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,12 @@ export default function ImageOptionInputEdit( props ) {
// Use the block's own synced attributes for styling
const { blockStyle } = useJetpackFieldStyles( attributes );

const outerClassName = useMemo( () => {
return clsx( 'jetpack-input-image-option__outer', {
'is-supersized': isSupersized,
} );
}, [ isSupersized ] );

const blockProps = useBlockProps( {
className: clsx( 'jetpack-field jetpack-input-image-option', {
'is-selected': isSelected || isInnerBlockSelected,
'has-image': !! imageBlockAttributes?.url,
[ `is-${ selectionType }` ]: !! selectionType,
'is-supersized': isSupersized,
} ),
style: blockStyle,
} );
Expand Down Expand Up @@ -116,20 +111,18 @@ export default function ImageOptionInputEdit( props ) {
);

return (
<div className={ outerClassName }>
<div { ...blockProps }>
<div { ...innerBlocksProps } />
<div className="jetpack-input-image-option__label-wrapper">
<div className="jetpack-input-image-option__label-code">{ positionLetter }</div>
<RichText
tagName="span"
className={ labelClassName }
value={ label }
placeholder={ __( 'Add option…', 'jetpack-forms' ) }
__unstableDisableFormats
onChange={ ( newLabel: string ) => setAttributes( { label: newLabel } ) }
/>
</div>
<div { ...blockProps }>
<div { ...innerBlocksProps } />
<div className="jetpack-input-image-option__label-wrapper">
<div className="jetpack-input-image-option__label-code">{ positionLetter }</div>
<RichText
tagName="span"
className={ labelClassName }
value={ label }
placeholder={ __( 'Add option…', 'jetpack-forms' ) }
__unstableDisableFormats
onChange={ ( newLabel: string ) => setAttributes( { label: newLabel } ) }
/>
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1930,24 +1930,26 @@ public function render_image_select_field( $id, $label, $value, $class, $require

// To be able to apply the backdrop-filter for the hover effect, we need to separate the background into an outer div.
// This outer div needs the color styles separately, and also the border radius to match the inner div without sticking out.
$option_outer_classes = "jetpack-input-image-option__outer {$option['classcolor']}";
$option_outer_classes = 'jetpack-input-image-option__outer ' . ( isset( $option['classcolor'] ) ? $option['classcolor'] : '' );

if ( $is_supersized ) {
$option_outer_classes .= ' is-supersized';
}

$border_styles = '';
preg_match( '/border-radius:([^;]+)/', $option['style'], $radius_match );
preg_match( '/border-width:([^;]+)/', $option['style'], $width_match );

if ( ! empty( $radius_match[1] ) ) {
$radius_value = trim( $radius_match[1] );

if ( ! empty( $width_match[1] ) ) {
$width_value = trim( $width_match[1] );
$border_styles = "border-radius:calc({$radius_value} + {$width_value});";
} else {
$border_styles = "border-radius:{$radius_value};";
if ( ! empty( $option['style'] ) ) {
preg_match( '/border-radius:([^;]+)/', $option['style'], $radius_match );
preg_match( '/border-width:([^;]+)/', $option['style'], $width_match );

if ( ! empty( $radius_match[1] ) ) {
$radius_value = trim( $radius_match[1] );

if ( ! empty( $width_match[1] ) ) {
$width_value = trim( $width_match[1] );
$border_styles = "border-radius:calc({$radius_value} + {$width_value});";
} else {
$border_styles = "border-radius:{$radius_value};";
}
}
}

Expand Down
18 changes: 16 additions & 2 deletions projects/packages/forms/src/modules/form/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,21 +305,35 @@ const { state, actions } = store( NAMESPACE, {
},

onImageOptionClick: event => {
// Find the parent container that has the data-wp-on--click attribute
// Find the block container
let target = event.target;

while ( target && ! target.classList.contains( 'jetpack-input-image-option' ) ) {
target = target.parentElement;
}

if ( target ) {
// Find the input inside this container
const input = target.querySelector( '.jetpack-input-image-option__input' );

if ( input ) {
// Toggle the input state
if ( input.type === 'checkbox' ) {
input.checked = ! input.checked;
target.classList.toggle( 'is-checked', input.checked );
} else if ( input.type === 'radio' ) {
input.checked = true;

// Find all image options in the same fieldset and toggle the checked class
const fieldset = target.closest( '.jetpack-fieldset-image-options__wrapper' );

if ( fieldset ) {
const imageOptions = fieldset.querySelectorAll( '.jetpack-input-image-option' );

imageOptions.forEach( imageOption => {
const imageOptionInput = imageOption.querySelector( 'input' );
imageOption.classList.toggle( 'is-checked', imageOptionInput.id === input.id );
} );
}
}

// Dispatch change event to trigger any change handlers
Expand Down
Loading