Files
contentstack-imagevault/rte/components/ImageElement.tsx

134 lines
3.6 KiB
TypeScript

import { Icon, Tooltip, cbModal } from "@contentstack/venus-components"
import React, { PropsWithChildren, useCallback, useEffect } from "react"
import EmbedBtn from "./EmbedBtn"
import ImageEditModal from "./ImageEditModal"
import type {
IRteElementType,
IRteParam,
} from "@contentstack/app-sdk/dist/src/RTE/types"
import type { ImageVaultAsset, InsertResponse } from "~/types/imagevault"
import {
getImageVaultAssetFromData,
isInsertResponse,
} from "~/utils/imagevault"
type ImageElementProps = PropsWithChildren & {
element: IRteElementType & { attrs: ImageVaultAsset | InsertResponse }
rte: IRteParam
}
export function ImageElement({ children, element, rte }: ImageElementProps) {
const imageVaultAsset = getImageVaultAssetFromData(element.attrs)
const isSelected = rte.selection.isSelected()
const isFocused = rte.selection.isFocused()
const path = rte.getPath(element)
const isHighlight = isFocused && isSelected
const handleMedia = useCallback(
(asset: ImageVaultAsset) => {
rte._adv.Transforms.setNodes<IRteElementType>(
rte._adv.editor,
{
attrs: { ...asset },
},
{ at: path }
)
},
[rte, path]
)
const handleEdit = useCallback(() => {
cbModal({
// @ts-expect-error: Component is badly typed
component: (compProps) => (
<ImageEditModal
element={element}
setData={handleMedia}
{...compProps}
/>
),
modalProps: {
size: "max",
style: {
content: {
maxHeight: "90dvh",
maxWidth: "90dvw",
width: "auto",
},
overlay: {},
},
},
})
}, [element, handleMedia])
// The existing data might still be in InsertResponse format if the user has not edited it yet.
// We'll convert it to ImageVaultAsset when the user edits the RTE.
useEffect(() => {
if (isInsertResponse(element.attrs) && imageVaultAsset) {
handleMedia(imageVaultAsset)
}
}, [element.attrs, imageVaultAsset, handleMedia])
const ToolTipButtons = () => {
return (
<div contentEditable={false} className="embed--btn-group">
<EmbedBtn title="edit" content="Edit" onClick={handleEdit}>
<Icon icon="Rename" />
</EmbedBtn>
<EmbedBtn
title="remove"
content={"Remove"}
onClick={() => rte.removeNode(element)}
>
<Icon icon="Trash" />
</EmbedBtn>
</div>
)
}
if (!imageVaultAsset) {
return <>{children}</>
}
return (
<Tooltip
zIndex={909}
className="p-0"
style={{ marginBottom: "10px" }}
position="top"
variantType="light"
offset={[0, -15]}
content={<ToolTipButtons />}
>
<span data-type="asset" contentEditable={false}>
<div
contentEditable={false}
style={{
width: "280px",
height: "auto",
...(isHighlight ? { border: "1px solid #6c5ce7" } : {}),
}}
>
<img
src={imageVaultAsset.url}
onError={(event) => {
event.currentTarget.src = "https://placehold.co/600x400"
}}
style={{
width: "100%",
height: "auto",
aspectRatio: imageVaultAsset.dimensions.aspectRatio,
borderRadius: "8px",
}}
alt={imageVaultAsset.meta.alt}
title={`Id: ${imageVaultAsset.imageVaultId} - ${imageVaultAsset.fileName}`}
/>
</div>
{children}
</span>
</Tooltip>
)
}