Skip to content

Commit

Permalink
chore(web): add story text block (#653)
Browse files Browse the repository at this point in the history
  • Loading branch information
airslice committed Sep 5, 2023
1 parent 708833b commit 6abb7b0
Show file tree
Hide file tree
Showing 106 changed files with 4,789 additions and 45 deletions.
2 changes: 2 additions & 0 deletions web/package.json
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
@@ -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<Props> = ({ text, onUpdate }) => {
const debouncedHandleTextUpdate = useMemo(
() => (onUpdate ? debounce(onUpdate, 1000) : undefined),
[onUpdate],
);

const context = useContext(BlockContext);

return (
<RichTextEditor
editMode={!!context?.editMode}
text={text}
onChange={debouncedHandleTextUpdate}
scrollableContainerId="story-page"
/>
);
};

export default TextBlockEditor;
@@ -1,33 +1,48 @@
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<Props> = ({ 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 (
<BlockWrapper
title={block?.title}
icon={block?.extensionId}
isSelected={isSelected}
propertyId={block?.property?.id}
propertyItems={block?.property?.items}
settingsEnabled={false}
{...props}>
{text && (
<Text size="body" customColor>
{text}
</Text>
)}
<TextBlockEditor text={text} onUpdate={handleTextUpdate} />
</BlockWrapper>
);
};
Expand Down
@@ -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";
Expand All @@ -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;
Expand All @@ -25,6 +27,7 @@ type Props = {
propertyId?: string;
propertyItems?: Item[];
dndEnabled?: boolean;
settingsEnabled?: boolean;
onClick?: () => void;
onClickAway?: () => void;
onRemove?: () => void;
Expand All @@ -38,6 +41,7 @@ const BlockWrapper: React.FC<Props> = ({
propertyId,
propertyItems,
dndEnabled = true,
settingsEnabled = true,
onClick,
onClickAway,
onRemove,
Expand All @@ -58,29 +62,31 @@ const BlockWrapper: React.FC<Props> = ({
});

return (
<SelectableArea
title={title}
icon={icon}
isSelected={isSelected}
propertyId={propertyId}
dndEnabled={dndEnabled}
showSettings={showSettings}
propertyItems={propertyItems}
editMode={editMode}
setEditMode={setEditMode}
onEditModeToggle={handleEditModeToggle}
onSettingsToggle={handleSettingsToggle}
onRemove={onRemove}
onClickAway={onClickAway}>
<Block padding={padding} onClick={handleBlockClick}>
{children ?? <Template icon={icon} />}
</Block>
{editMode && propertyId && defaultSettings && (
<EditorPanel onClick={stopClickPropagation}>
<FieldComponents propertyId={propertyId} item={defaultSettings} />
</EditorPanel>
)}
</SelectableArea>
<BlockContext.Provider value={{ editMode }}>
<SelectableArea
title={title}
icon={icon}
isSelected={isSelected}
propertyId={propertyId}
dndEnabled={dndEnabled}
showSettings={showSettings}
propertyItems={propertyItems}
editMode={editMode}
setEditMode={setEditMode}
onEditModeToggle={handleEditModeToggle}
onSettingsToggle={handleSettingsToggle}
onRemove={onRemove}
onClickAway={onClickAway}>
<Block padding={padding} onClick={handleBlockClick}>
{children ?? <Template icon={icon} />}
</Block>
{editMode && propertyId && defaultSettings && settingsEnabled && (
<EditorPanel onClick={stopClickPropagation}>
<FieldComponents propertyId={propertyId} item={defaultSettings} />
</EditorPanel>
)}
</SelectableArea>
</BlockContext.Provider>
);
};

Expand All @@ -99,11 +105,5 @@ const Block = styled.div<{ padding?: Spacing }>`
const EditorPanel = styled.div`
background: ${({ theme }) => theme.bg[1]};
color: ${({ theme }) => theme.content.main};
height: 100px;
padding: 12px;
z-index: 100;
position: absolute;
top: 100%;
left: -1px;
right: -1px;
`;
Expand Up @@ -24,10 +24,10 @@ export default ({ isSelected, propertyItems, onClick }: Props) => {
const handleBlockClick = useCallback(
(e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
if (showSettings && isSelected) return;
if ((showSettings && isSelected) || editMode) return;
onClick?.();
},
[onClick, showSettings, isSelected],
[onClick, showSettings, isSelected, editMode],
);

const defaultSettings: Item | undefined = useMemo(
Expand Down
@@ -0,0 +1,29 @@
import { useCallback } from "react";

import { ValueType, ValueTypes } from "@reearth/beta/utils/value";
import { usePropertyFetcher } from "@reearth/services/api";

// Unlick common story blocks which will use the auto generted field components editor,
// Some special story blocks will use the custom editor components and need to update date directly.
export default () => {
const { useUpdatePropertyValue } = usePropertyFetcher();

const handlePropertyValueUpdate = useCallback(
(
schemaGroupId: string,
propertyId: string,
fieldId: string,
vt: ValueType,
itemId?: string,
) => {
return async (v?: ValueTypes[ValueType]) => {
await useUpdatePropertyValue(propertyId, schemaGroupId, itemId, fieldId, "en", v, vt);
};
},
[useUpdatePropertyValue],
);

return {
handlePropertyValueUpdate,
};
};
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,5 @@
Bootstrap Icons
https://icons.getbootstrap.com

Licensed under MIT license
https://github.com/twbs/icons/blob/main/LICENSE.md
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 6abb7b0

Please sign in to comment.