Skip to content

Commit

Permalink
AI Assistant: Fix inline extension styles on P2 and some themes (#37336)
Browse files Browse the repository at this point in the history
* generalize input positioning styling for P2

* fix input width on some themes

* changelog
  • Loading branch information
dhasilva authored May 10, 2024
1 parent 6875975 commit 90f0812
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: other

AI Assistant: Fix inline extension styles on P2 and some themes
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ExtensionAIControl } from '@automattic/jetpack-ai-client';
import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
import { useState, useEffect, useCallback, useMemo } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import classNames from 'classnames';
import React from 'react';
/*
* Internal dependencies
Expand Down Expand Up @@ -33,6 +34,11 @@ export type AiAssistantInputProps = {
tryAgain?: () => void;
};

const className = classNames(
'jetpack-ai-assistant-extension-ai-input',
'wp-block' // Some themes, like Twenty Twenty, use this class to set the element's side margins.
);

export default function AiAssistantInput( {
requestingState,
requestingError,
Expand Down Expand Up @@ -158,7 +164,7 @@ export default function AiAssistantInput( {

return (
<ExtensionAIControl
className="jetpack-ai-assistant-extension-ai-input"
className={ className }
placeholder={ placeholder }
disabled={ disabled }
value={ value }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ const blockControlsProps = {
group: 'block' as const,
};

const BLOCK_INPUT_GAP = 16;

type RequestOptions = {
promptType: PromptTypeProp;
options?: AiAssistantDropdownOnChangeOptionsArgProps;
Expand All @@ -60,8 +62,8 @@ const blockEditWithAiComponents = createHigherOrderComponent( BlockEdit => {
const controlRef: React.MutableRefObject< HTMLDivElement | null > = useRef( null );
const controlHeight = useRef< number >( 0 );
const controlObserver = useRef< ResizeObserver | null >( null );
// Ref to the original block style to reset it when the AI Control is closed.
const blockStyle = useRef< string >( '' );
// Ref to the original block padding to reset it when the AI Control is closed.
const blockPaddingBottom = useRef< string >( '' );
// Ref to the input element to focus on it when the AI Control is displayed or when a request is done.
// Also used to determine the ownerDocument, as the editor can be in an iframe.
const inputRef: React.MutableRefObject< HTMLInputElement | null > = useRef( null );
Expand Down Expand Up @@ -135,7 +137,13 @@ const blockEditWithAiComponents = createHigherOrderComponent( BlockEdit => {
const block = ownerDocument.current.getElementById( id );

if ( block && controlRef.current ) {
block.style.paddingBottom = `${ controlHeight.current + 16 }px`;
block.style.setProperty(
'padding-bottom',
`calc(${ controlHeight.current + BLOCK_INPUT_GAP }px + ${
blockPaddingBottom.current || '0px'
} )`,
'important'
);
}
},
[ id, onBlockSuggestion ]
Expand Down Expand Up @@ -285,25 +293,49 @@ const blockEditWithAiComponents = createHigherOrderComponent( BlockEdit => {

// Once when the AI Control is displayed
if ( showAiControl && ! controlObserver.current && controlRef.current ) {
// Save the block and control styles to adjust them later.
blockStyle.current = block.style.cssText;
// Save the block bottom padding to reset it later.
blockPaddingBottom.current = block.style.paddingBottom;

// Observe the control's height to adjust the block's bottom-padding.
// Observe the control's height to adjust the block's bottom padding.
controlObserver.current = new ResizeObserver( ( [ entry ] ) => {
// The block element can be replaced or changed, so we need to get it again.
block = ownerDocument.current.getElementById( id );
controlHeight.current = entry.contentRect.height;

if ( block && controlRef.current && controlHeight.current > 0 ) {
block.style.paddingBottom = `${ controlHeight.current + 16 }px`;
controlRef.current.style.marginTop = `-${ controlHeight.current }px`;
// The gap between the input and the block's bottom is set at BLOCK_INPUT_GAP, regardless of the theme
block.style.setProperty(
'padding-bottom',
`calc(${ controlHeight.current + BLOCK_INPUT_GAP }px + ${
blockPaddingBottom.current || '0px'
} )`,
'important'
);

const { marginBottom } = getComputedStyle( block );
const bottom = parseFloat( marginBottom );

// The control's margin-top is the negative of the control's height plus the block's bottom margin, to end up with the intended gap.
// P2 uses "!important", so we need to add it to override the theme's styles.
controlRef.current.style.setProperty(
'margin-top',
`-${ controlHeight.current + bottom }px`,
'important'
);

// The control's bottom margin is set to at least the same value as the block's bottom margin, to keep the distance to the next block.
// The gap height is added for a bit more space on themes with a smaller bottom margin.
controlRef.current.style.setProperty(
'margin-bottom',
`${ bottom + BLOCK_INPUT_GAP }px`,
'important'
);
}
} );

controlObserver.current.observe( controlRef.current );
} else if ( controlObserver.current ) {
// Reset the block's bottom-padding.
block.setAttribute( 'style', blockStyle.current );
block.style.paddingBottom = blockPaddingBottom.current;

controlObserver.current.disconnect();
controlObserver.current = null;
Expand Down

0 comments on commit 90f0812

Please sign in to comment.