mirror of
https://github.com/WenPai-org/wpmind.git
synced 2025-08-03 19:19:46 +08:00
added hack for preview to prevent preview blinking and jumping
This commit is contained in:
parent
e4aefcdaf9
commit
295ecf6aa5
3 changed files with 116 additions and 34 deletions
|
@ -1,4 +1,5 @@
|
||||||
import { isEqual } from 'lodash';
|
import { isEqual } from 'lodash';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Styles
|
* Styles
|
||||||
|
@ -8,49 +9,123 @@ import './style.scss';
|
||||||
/**
|
/**
|
||||||
* WordPress dependencies
|
* WordPress dependencies
|
||||||
*/
|
*/
|
||||||
import { memo } from '@wordpress/element';
|
import { memo, useState, useEffect, useRef } from '@wordpress/element';
|
||||||
import { BlockPreview } from '@wordpress/block-editor';
|
import { BlockPreview } from '@wordpress/block-editor';
|
||||||
|
|
||||||
|
function RenderPreview({ response, className, style }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx('mind-popup-response__preview', className)}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<BlockPreview
|
||||||
|
// Since the preview does not render properly first block align full, we need to create the wrapper Group block with our custom styles.
|
||||||
|
// Align classes rendered properly only for the inner blocks.
|
||||||
|
blocks={[
|
||||||
|
{
|
||||||
|
name: 'core/group',
|
||||||
|
clientId: 'a9b75f7e-55c7-4f2b-93bb-00cf24181278',
|
||||||
|
isValid: true,
|
||||||
|
attributes: {
|
||||||
|
align: 'full',
|
||||||
|
layout: {
|
||||||
|
type: 'constrained',
|
||||||
|
},
|
||||||
|
className: 'alignfull',
|
||||||
|
},
|
||||||
|
innerBlocks: response,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
viewportWidth={0}
|
||||||
|
additionalStyles={[
|
||||||
|
{
|
||||||
|
css: `
|
||||||
|
.is-root-container > div {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const AIResponse = memo(
|
const AIResponse = memo(
|
||||||
function AIResponse({ response, loading }) {
|
function AIResponse({ response, loading }) {
|
||||||
|
const [activePreview, setActivePreview] = useState(1);
|
||||||
|
const [preview1Data, setPreview1Data] = useState([]);
|
||||||
|
const [preview2Data, setPreview2Data] = useState([]);
|
||||||
|
const transitionTimeoutRef = useRef(null);
|
||||||
|
|
||||||
|
// This implementation make me cry, but it works for now.
|
||||||
|
// In short, when we have a single preview and update the response,
|
||||||
|
// it rerenders and we see a blink. To avoid this, we have two previews
|
||||||
|
// and we switch between them on each update.
|
||||||
|
useEffect(() => {
|
||||||
|
if (!response.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear any existing timeout
|
||||||
|
if (transitionTimeoutRef.current) {
|
||||||
|
clearTimeout(transitionTimeoutRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the inactive preview with new data
|
||||||
|
if (activePreview === 1) {
|
||||||
|
setPreview2Data(response);
|
||||||
|
} else {
|
||||||
|
setPreview1Data(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the next frame to start transition.
|
||||||
|
// Small delay to ensure new content is rendered.
|
||||||
|
transitionTimeoutRef.current = setTimeout(() => {
|
||||||
|
setActivePreview(activePreview === 1 ? 2 : 1);
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (transitionTimeoutRef.current) {
|
||||||
|
clearTimeout(transitionTimeoutRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [response]);
|
||||||
|
|
||||||
if (!response.length && !loading) {
|
if (!response.length && !loading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hiddenPreviewStyles = {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mind-popup-response">
|
<div className="mind-popup-response">
|
||||||
{response.length > 0 && (
|
{(preview1Data.length > 0 || preview2Data.length > 0) && (
|
||||||
<div className="mind-popup-response__preview">
|
<div style={{ position: 'relative' }}>
|
||||||
<BlockPreview
|
<RenderPreview
|
||||||
// Since the preview does not render properly first block align full, we need to create the wrapper Group block with our custom styles.
|
response={preview1Data}
|
||||||
// Align classes rendered properly only for the inner blocks.
|
style={{
|
||||||
blocks={[
|
...(activePreview === 1
|
||||||
{
|
? {}
|
||||||
name: 'core/group',
|
: hiddenPreviewStyles),
|
||||||
clientId:
|
opacity: activePreview === 1 ? 1 : 0,
|
||||||
'a9b75f7e-55c7-4f2b-93bb-00cf24181278',
|
zIndex: activePreview === 1 ? 2 : 1,
|
||||||
isValid: true,
|
}}
|
||||||
attributes: {
|
/>
|
||||||
// "tagName": "div",
|
<RenderPreview
|
||||||
align: 'full',
|
response={preview2Data}
|
||||||
layout: {
|
style={{
|
||||||
type: 'constrained',
|
...(activePreview === 2
|
||||||
},
|
? {}
|
||||||
className: 'alignfull',
|
: hiddenPreviewStyles),
|
||||||
},
|
opacity: activePreview === 2 ? 1 : 0,
|
||||||
innerBlocks: response,
|
zIndex: activePreview === 2 ? 2 : 1,
|
||||||
},
|
}}
|
||||||
]}
|
|
||||||
viewportWidth={0}
|
|
||||||
additionalStyles={[
|
|
||||||
{
|
|
||||||
css: `
|
|
||||||
.is-root-container > div {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -12,6 +12,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mind-popup-response__preview {
|
||||||
|
/* GPU acceleration */
|
||||||
|
will-change: opacity;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
transform: translateZ(0);
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes mind-cursor-blink {
|
@keyframes mind-cursor-blink {
|
||||||
0%,
|
0%,
|
||||||
100% {
|
100% {
|
||||||
|
|
|
@ -13,7 +13,7 @@ export default class BlocksStreamProcessor {
|
||||||
// Add throttled dispatch
|
// Add throttled dispatch
|
||||||
this.throttledDispatch = this.throttle(
|
this.throttledDispatch = this.throttle(
|
||||||
this.performDispatch.bind(this),
|
this.performDispatch.bind(this),
|
||||||
150
|
200
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue