Использование пользовательского контейнера Canvas App
Обновлено 15 января 2024
Дефолтный контейнер для смартапов типа Canvas App формируется во всплывающем окне. В примерах ниже показано, как можно задать собственный контейнер для Canvas App.
type CanvasContainerProps = {
app: AppInfo;
isChatOverCanvas?: boolean,
withNativeHeader?: boolean,
canvasReady: boolean;
onClose: () => void;
};
import React, { FC } from 'react';
import { createAssistantClient, AppInfo } from '@salutejs/client';
import { FloatingAssistantChatLottie } from '@sberdevices/assistant-web-sdk/floatingAssistantChatLottie';
import { useVisualViewport } from '@sberdevices/assistant-web-sdk';
const CustomCanvasContainer: FC<CanvasContainerProps> = ({ canvasReady, children, onClose }) => {
// Нужно для корректного и полноэкранного отображения Canvas App при использовании виртуальной клавиатуры на мобильных устройствах
// Документация к VisualViewport: https://github.com/web-platform-tests/interop-2022-viewport/blob/main/explainers/visual-viewport.md
const { height, offsetTop: top } = useVisualViewport();
return (
<div>
{!canvasReady && <div>Loading...</div>}
<div
style={{
bottom: 0,
display: canvasReady ? 'block' : 'hide',
height,
position: 'fixed',
right: 0,
top,
width: '100%',
}}
>
<button onClick={onClose}>Закрыть</button>
{children}
</div>
</div>
);
};
const client = createAssistantClient(...);
const FloatingChatWithAssistant: FC = () => (
<FloatingAssistantChatLottie assistant={client} onCanvasRender={CustomCanvasContainer} mobile={false} />
);
Также Canvas App можно встроить на страницу, используя ReactDOM.createPortal
:
import React, { FC } from 'react';
import ReactDOM from 'react-dom';
import { createAssistantClient } from '@salutejs/client';
import { FloatingAssistantChatLottie } from '@sberdevices/assistant-web-sdk/floatingAssistantChatLottie';
const CANVAS_CONTAINER_ID = 'canvas-container-root';
const CustomCanvasContainer: FC<CanvasContainerProps> = ({ canvasReady, onClose, children }) => (
<div>
{!canvasReady && (
<div>Loading...</div>
)}
<div className={canvasReady ? 'show' : 'hide'}>
<button onClick={onClose}>Закрыть</button>
{children}
</div>
</div>
);
const CanvasPortal: FC<CanvasContainerProps> = ({ ...props }) => {
const canvasContainerRef = useRef<HTMLDivElement>(document.getElementById(CANVAS_CONTAINER_ID));
if (!canvasContainerRef.current) {
return null;
}
return ReactDOM.createPortal(<CustomCanvasContainer {...props} />, canvasContainerRef.current);
}
const client = createAssistantClient(...);
const FloatingChatWithAssistant: FC = () => (
<FloatingAssistantChatLottie assistant={client} onCanvasRender={CanvasPortal} mobile={false} />
);
const App = () => (
<>
<Chat client={client} />
<div id={CANVAS_CONTAINER_ID} />
</>
);