diff --git a/web/package.json b/web/package.json index 2e34ea14aa..13bdd56d82 100644 --- a/web/package.json +++ b/web/package.json @@ -106,6 +106,7 @@ "@emotion/react": "11.11.0", "@emotion/styled": "11.11.0", "@floating-ui/react": "0.24.7", + "@lexical/react": "0.12.0", "@mapbox/vector-tile": "1.3.1", "@monaco-editor/react": "4.5.1", "@popperjs/core": "2.11.7", @@ -144,6 +145,7 @@ "jsonpath-plus": "7.2.0", "jszip": "3.10.1", "leaflet": "1.9.3", + "lexical": "0.12.0", "localforage": "1.10.0", "lodash-es": "4.17.21", "lru-cache": "8.0.4", diff --git a/web/src/beta/features/Editor/StoryPanel/Block/builtin/Text/Editor.tsx b/web/src/beta/features/Editor/StoryPanel/Block/builtin/Text/Editor.tsx new file mode 100644 index 0000000000..919eb496d1 --- /dev/null +++ b/web/src/beta/features/Editor/StoryPanel/Block/builtin/Text/Editor.tsx @@ -0,0 +1,31 @@ +import { debounce } from "lodash-es"; +import { useMemo, useContext } from "react"; + +import RichTextEditor from "@reearth/beta/lib/lexical/RichTextEditor"; + +import { BlockContext } from "../common/Wrapper"; + +export type Props = { + text?: string; + onUpdate?: (text: string) => void; +}; + +const TextBlockEditor: React.FC = ({ text, onUpdate }) => { + const debouncedHandleTextUpdate = useMemo( + () => (onUpdate ? debounce(onUpdate, 1000) : undefined), + [onUpdate], + ); + + const context = useContext(BlockContext); + + return ( + + ); +}; + +export default TextBlockEditor; diff --git a/web/src/beta/features/Editor/StoryPanel/Block/builtin/Text/index.tsx b/web/src/beta/features/Editor/StoryPanel/Block/builtin/Text/index.tsx index 50b3ef25f2..7324fc9e68 100644 --- a/web/src/beta/features/Editor/StoryPanel/Block/builtin/Text/index.tsx +++ b/web/src/beta/features/Editor/StoryPanel/Block/builtin/Text/index.tsx @@ -1,20 +1,38 @@ -import { useMemo } from "react"; +import { useCallback, useMemo } from "react"; -import Text from "@reearth/beta/components/Text"; import { ValueTypes } from "@reearth/beta/utils/value"; import { getFieldValue } from "../../../utils"; import { CommonProps as BlockProps } from "../../types"; +import usePropertyValueUpdate from "../common/usePropertyValueUpdate"; import BlockWrapper from "../common/Wrapper"; +import TextBlockEditor from "./Editor"; + export type Props = BlockProps; +// Text block is very special, it will not edit values with field components +// from the common editor panel, but manage it by itself directly. + const TextBlock: React.FC = ({ block, isSelected, ...props }) => { const text = useMemo( () => getFieldValue(block?.property?.items ?? [], "text") as ValueTypes["string"], [block?.property?.items], ); + const { handlePropertyValueUpdate } = usePropertyValueUpdate(); + + const handleTextUpdate = useCallback( + (text: string) => { + const schemaGroup = block?.property?.items?.find( + i => i.schemaGroup === "default", + )?.schemaGroup; + if (!block?.property?.id || !schemaGroup) return; + handlePropertyValueUpdate(schemaGroup, block?.property?.id, "text", "string")(text); + }, + [block?.property?.id, block?.property?.items, handlePropertyValueUpdate], + ); + return ( = ({ block, isSelected, ...props }) => { isSelected={isSelected} propertyId={block?.property?.id} propertyItems={block?.property?.items} + settingsEnabled={false} {...props}> - {text && ( - - {text} - - )} + ); }; diff --git a/web/src/beta/features/Editor/StoryPanel/Block/builtin/common/Wrapper.tsx b/web/src/beta/features/Editor/StoryPanel/Block/builtin/common/Wrapper.tsx index 6589a2f304..7b1087d7db 100644 --- a/web/src/beta/features/Editor/StoryPanel/Block/builtin/common/Wrapper.tsx +++ b/web/src/beta/features/Editor/StoryPanel/Block/builtin/common/Wrapper.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from "react"; +import { ReactNode, createContext } from "react"; import FieldComponents from "@reearth/beta/components/fields/PropertyFields"; import { stopClickPropagation } from "@reearth/beta/utils/events"; @@ -10,6 +10,8 @@ import Template from "../../Template"; import useHooks from "./hooks"; +export const BlockContext = createContext<{ editMode?: boolean } | undefined>(undefined); + type Spacing = { top: number; bottom: number; @@ -25,6 +27,7 @@ type Props = { propertyId?: string; propertyItems?: Item[]; dndEnabled?: boolean; + settingsEnabled?: boolean; onClick?: () => void; onClickAway?: () => void; onRemove?: () => void; @@ -38,6 +41,7 @@ const BlockWrapper: React.FC = ({ propertyId, propertyItems, dndEnabled = true, + settingsEnabled = true, onClick, onClickAway, onRemove, @@ -58,29 +62,31 @@ const BlockWrapper: React.FC = ({ }); return ( - - - {children ??