-
-
Notifications
You must be signed in to change notification settings - Fork 694
Closed
Description
As part of a website-CMS I needed a way to define a background image for an element and overlay two blocks of text. This is what I came up with:
// import type { FileBlockConfig } from "@blocknote/core"
import { createReactBlockSpec, FilePanel } from "@blocknote/react"
import { useEffect, useRef, useState } from "react"
// interface FileAndContentBlockConfig extends Omit<FileBlockConfig, "content"> {
// content: "inline"
// }
export const BackgroundScroller = createReactBlockSpec(
{
type: "backgroundScroller",
propSchema: {
// caption: {
// default: ""
// },
heading: {
default: ""
},
url: {
default: ""
},
name: {
default: ""
}
},
content: "inline",
// isFileBlock: true,
fileBlockAccept: ["image/*"]
},
{
render: (props) => {
const [isFilePanelOpen, setIsFilePanelOpen] = useState(false)
const inputClassName = "block !p-2 !text-center !text-white bg-gray-600/60 rounded-lg"
const filePanelRef = useRef<HTMLDivElement>(null)
// Update non-content props
const handleUpdate = (propName: "heading") => (e: React.ChangeEvent<HTMLInputElement>) => {
props.editor.updateBlock(props.block, {
type: "backgroundScroller",
props: {
...props.block.props,
[propName]: e.target.value
}
})
}
// Close file panel when clicking outside of it
useEffect(() => {
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
if (filePanelRef.current && !filePanelRef.current.contains(event.target as Node)) {
setIsFilePanelOpen(false)
}
}
if (isFilePanelOpen) {
document.addEventListener("mousedown", handleClickOutside)
document.addEventListener("touchstart", handleClickOutside)
} else {
document.removeEventListener("mousedown", handleClickOutside)
document.removeEventListener("touchstart", handleClickOutside)
}
return () => {
document.removeEventListener("mousedown", handleClickOutside)
document.removeEventListener("touchstart", handleClickOutside)
}
}, [isFilePanelOpen])
// Close file panel after file upload
// biome-ignore lint/correctness/useExhaustiveDependencies: 🤷🏼♂️
useEffect(() => {
setIsFilePanelOpen(false)
}, [props.block.props.url])
return (
<div
className="relative min-h-52 !p-0 flex flex-col justify-center items-center flex-grow rounded space-y-3 bg-lime-500"
style={
props.block.props.url && (props.block.props.url as string).length > 0
? {
backgroundImage: `url('${props.block.props.url}')`,
backgroundSize: "cover",
backgroundPosition: "center",
backgroundRepeat: "no-repeat"
}
: {}
}
>
<input
type="text"
value={props.block.props.heading}
placeholder="Heading"
className={inputClassName}
size={(props.block.props.heading && (props.block.props.heading as string).length) || 10}
onChange={handleUpdate("heading")}
/>
<div
className={
"inline-content text-2xl font-medium text-center text-white bg-gray-600/60 p-2 rounded-lg"
}
ref={props.contentRef}
/>
<button
type="button"
className="absolute top-2 right-2 !m-0 !btn !btn-sm !btn-primary"
onClick={() => setIsFilePanelOpen(true)}
>
Bild hochladen
</button>
{isFilePanelOpen && (
<div className="absolute top-9 right-2" ref={filePanelRef}>
{/* @ts-ignore */}
<FilePanel block={props.block} />
</div>
)}
</div>
)
}
}
)This seems to work fine, but feels slightly hacky: I had to suppress one TS and one Biome error and probably there is a better way to implement the handleClickOutside. Would be lovely to have an example in this direction. 🙂
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels