import { useRef, useEffect, useState } from "react";
import { elementId } from "src/utils/elementId";
import { useReplicache, useEntity } from "src/replicache";
import { isVisible } from "src/utils/isVisible";
import { EditorState, TextSelection } from "prosemirror-state";
import { RenderYJSFragment } from "./RenderYJSFragment";
import { useInitialPageLoad } from "components/InitialPageLoadProvider";
import { BlockProps } from "../Block";
import { focusBlock } from "src/utils/focusBlock";
import { useUIState } from "src/useUIState";
import { addBlueskyPostBlock, addLinkBlock } from "src/utils/addLinkBlock";
import { BlockCommandBar } from "components/Blocks/BlockCommandBar";
import { useEditorStates } from "src/state/useEditorState";
import { useEntitySetContext } from "components/EntitySetProvider";
import { TooltipButton } from "components/Buttons";
import { blockCommands } from "../BlockCommands";
import { betterIsUrl } from "src/utils/isURL";
import { useSmoker } from "components/Toast";
import { AddTiny } from "components/Icons/AddTiny";
import { BlockDocPageSmall } from "components/Icons/BlockDocPageSmall";
import { BlockImageSmall } from "components/Icons/BlockImageSmall";
import { isIOS } from "src/utils/isDevice";
import { useLeafletPublicationData } from "components/PageSWRDataProvider";
import { DotLoader } from "components/utils/DotLoader";
import { useMountProsemirror } from "./mountProsemirror";
const HeadingStyle = {
1: "text-xl font-bold",
2: "text-lg font-bold",
3: "text-base font-bold text-secondary ",
} as { [level: number]: string };
export function TextBlock(
props: BlockProps & {
className?: string;
preview?: boolean;
},
) {
let isLocked = useEntity(props.entityID, "block/is-locked");
let initialized = useInitialPageLoad();
let first = props.previousBlock === null;
let permission = useEntitySetContext().permissions.write;
return (
<>
{(!initialized ||
!permission ||
props.preview ||
isLocked?.data.value) && (
{
if (
["***", "---", "___"].includes(
editorState?.doc.textContent.trim() || "",
)
) {
await rep.rep?.mutate.assertFact({
entity: props.entityID,
attribute: "block/type",
data: { type: "block-type-union", value: "horizontal-rule" },
});
}
if (actionTimeout.current) {
rep.undoManager.endGroup();
window.clearTimeout(actionTimeout.current);
actionTimeout.current = null;
}
}}
onFocus={() => {
setTimeout(() => {
useUIState.getState().setSelectedBlock(props);
useUIState.setState(() => ({
focusedEntity: {
entityType: "block",
entityID: props.entityID,
parent: props.parent,
},
}));
}, 5);
}}
id={elementId.block(props.entityID).text}
// unless we break *only* on urls, this is better than tailwind 'break-all'
// b/c break-all can cause breaks in the middle of words, but break-word still
// forces break if a single text string (e.g. a url) spans more than a full line
style={{ wordBreak: "break-word" }}
className={`
${alignmentClass}
grow resize-none align-top whitespace-pre-wrap bg-transparent
outline-hidden
${props.type === "heading" ? HeadingStyle[headingLevel?.data.value || 1] : ""}
${props.className}`}
ref={mountRef}
/>
{editorState?.doc.textContent.length === 0 &&
props.previousBlock === null &&
props.nextBlock === null ? (
// if this is the only block on the page and is empty or is a canvas, show placeholder
{props.type === "text"
? "write something..."
: headingLevel?.data.value === 3
? "Subheader"
: headingLevel?.data.value === 2
? "Header"
: "Title"}
or type "/" to add a block
) : editorState?.doc.textContent.length === 0 && focused ? (
// if not the only block on page but is the block is empty and selected, but NOT multiselected show add button
) : null}
{editorState?.doc.textContent.startsWith("/") && selected && (
)}