-
-
Notifications
You must be signed in to change notification settings - Fork 91
feat: virtual list for graphical editor #615
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||||||
| import { parseScene } from "./parser"; | ||||||||||||||||||
| import axios from "axios"; | ||||||||||||||||||
| import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"; | ||||||||||||||||||
| import { useVirtualizer } from "@tanstack/react-virtual"; | ||||||||||||||||||
| import { EditorPreviewClient } from "../../../utils/editorPreviewClient"; | ||||||||||||||||||
| import { mergeToString, splitToArray } from "./utils/sceneTextProcessor"; | ||||||||||||||||||
| import styles from "./graphicalEditor.module.scss"; | ||||||||||||||||||
|
|
@@ -18,7 +19,7 @@ import { api } from "@/api"; | |||||||||||||||||
| import { GlobalTerrePanel } from "./components/TerrePanel"; | ||||||||||||||||||
| import { getArgByKey } from "./utils/getArgByKey"; | ||||||||||||||||||
|
|
||||||||||||||||||
| import type { DropResult } from '@hello-pangea/dnd'; | ||||||||||||||||||
| import type { DragStart, DraggableProvided, DropResult } from '@hello-pangea/dnd'; | ||||||||||||||||||
|
|
||||||||||||||||||
| interface IGraphicalEditorProps { | ||||||||||||||||||
| targetPath: string; | ||||||||||||||||||
|
|
@@ -31,6 +32,24 @@ interface SentenceItem { | |||||||||||||||||
| show: boolean; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| interface SentenceRowProps { | ||||||||||||||||||
| sentence: ISentence; | ||||||||||||||||||
| sentenceItem: SentenceItem; | ||||||||||||||||||
| index: number; | ||||||||||||||||||
| linkedWithPrevious: boolean; | ||||||||||||||||||
| targetPath: string; | ||||||||||||||||||
| sceneLabels: string[]; | ||||||||||||||||||
| onAddBefore: (titleText: string, insertIndex: number) => void; | ||||||||||||||||||
| onDelete: (index: number) => void; | ||||||||||||||||||
| onSync: (index: number) => void; | ||||||||||||||||||
| onToggleShow: (index: number) => void; | ||||||||||||||||||
| onUpdate: (newContent: string, updateIndex: number) => void; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| interface SentenceRowContentProps extends SentenceRowProps { | ||||||||||||||||||
| provided: DraggableProvided; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| const inlineArgOptionCommands = new Set<commandType>([ | ||||||||||||||||||
| commandType.changeBg, | ||||||||||||||||||
| commandType.changeFigure, | ||||||||||||||||||
|
|
@@ -43,6 +62,8 @@ const inlineArgOptionCommands = new Set<commandType>([ | |||||||||||||||||
| export default function GraphicalEditor(props: IGraphicalEditorProps) { | ||||||||||||||||||
| const [sentenceData, setSentenceData] = useState<SentenceItem[]>([]); | ||||||||||||||||||
| const sentenceDataRef = useRef<SentenceItem[]>([]); | ||||||||||||||||||
| const scrollElementRef = useRef<HTMLDivElement | null>(null); | ||||||||||||||||||
| const [draggingId, setDraggingId] = useState<string | null>(null); | ||||||||||||||||||
| const [addSentenceDialog, setAddSentenceDialog] = useState<{ | ||||||||||||||||||
| titleText: string; | ||||||||||||||||||
| insertIndex: number; | ||||||||||||||||||
|
|
@@ -173,7 +194,12 @@ export default function GraphicalEditor(props: IGraphicalEditorProps) { | |||||||||||||||||
| submitScene(newSentences, endIndex); | ||||||||||||||||||
| }, [submitScene, updateSentenceData]); | ||||||||||||||||||
|
|
||||||||||||||||||
| const onDragStart = useCallback((start: DragStart) => { | ||||||||||||||||||
| setDraggingId(start.draggableId); | ||||||||||||||||||
| }, []); | ||||||||||||||||||
|
|
||||||||||||||||||
| const onDragEnd = useCallback((result: DropResult) => { | ||||||||||||||||||
| setDraggingId(null); | ||||||||||||||||||
| if (!result.destination) { | ||||||||||||||||||
| return; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
@@ -219,22 +245,6 @@ export default function GraphicalEditor(props: IGraphicalEditorProps) { | |||||||||||||||||
| }; | ||||||||||||||||||
| }, [syncCurrentLine]); | ||||||||||||||||||
|
|
||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| const targetLine = editorLineHolder.getSceneLine(props.targetPath); | ||||||||||||||||||
| const scrollToFunc = () => { | ||||||||||||||||||
| const targetBlock = document.querySelector(`.sentence-block-${targetLine}`); | ||||||||||||||||||
| if (targetBlock) { | ||||||||||||||||||
| targetBlock?.scrollIntoView?.({ behavior: 'auto' }); | ||||||||||||||||||
| } else { | ||||||||||||||||||
| console.log('Retry scroll to in 50ms'); | ||||||||||||||||||
| setTimeout(() => scrollToFunc(), 50); | ||||||||||||||||||
| } | ||||||||||||||||||
| }; | ||||||||||||||||||
| if (targetLine > 3) { | ||||||||||||||||||
| scrollToFunc(); | ||||||||||||||||||
| } | ||||||||||||||||||
| }, [props.targetPath]); | ||||||||||||||||||
|
|
||||||||||||||||||
| const addNewSentenceAttach = useCallback((sentence: string) => { | ||||||||||||||||||
| addOneSentence(sentence, sentenceDataRef.current.length); | ||||||||||||||||||
| }, [addOneSentence]); | ||||||||||||||||||
|
|
@@ -275,6 +285,21 @@ export default function GraphicalEditor(props: IGraphicalEditorProps) { | |||||||||||||||||
| .filter(Boolean), | ||||||||||||||||||
| [parsedScene] | ||||||||||||||||||
| ); | ||||||||||||||||||
| const rowVirtualizer = useVirtualizer<HTMLDivElement, HTMLDivElement>({ | ||||||||||||||||||
| count: parsedScene.sentenceList.length, | ||||||||||||||||||
| getScrollElement: () => scrollElementRef.current, | ||||||||||||||||||
| estimateSize: (index) => sentenceData[index]?.show ? 120 : 48, | ||||||||||||||||||
| getItemKey: (index) => sentenceData[index]?.id ?? index, | ||||||||||||||||||
| overscan: 8, | ||||||||||||||||||
| }); | ||||||||||||||||||
| const virtualRows = rowVirtualizer.getVirtualItems(); | ||||||||||||||||||
|
|
||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| const targetLine = editorLineHolder.getSceneLine(props.targetPath); | ||||||||||||||||||
| if (targetLine > 3 && targetLine <= parsedScene.sentenceList.length) { | ||||||||||||||||||
| rowVirtualizer.scrollToIndex(targetLine - 1, { align: 'start' }); | ||||||||||||||||||
| } | ||||||||||||||||||
| }, [parsedScene.sentenceList.length, props.targetPath, rowVirtualizer]); | ||||||||||||||||||
|
Comment on lines
+297
to
+302
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The current scroll-to-target-line logic triggers as soon as To fix this, we should use a ref to track the last scrolled path and only trigger the scroll once |
||||||||||||||||||
|
|
||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||
| const handleDragUpdate = (data: any) => { | ||||||||||||||||||
|
|
@@ -290,49 +315,76 @@ export default function GraphicalEditor(props: IGraphicalEditorProps) { | |||||||||||||||||
| eventBus.off('editor:drag-update-scene', handleDragUpdate); | ||||||||||||||||||
| }; | ||||||||||||||||||
| }, [fetchScene]); | ||||||||||||||||||
|
|
||||||||||||||||||
| const getSentenceRowProps = (i: number): SentenceRowProps | null => { | ||||||||||||||||||
| const sentence = parsedScene.sentenceList[i]; | ||||||||||||||||||
| const sentenceItem = sentenceData[i]; | ||||||||||||||||||
| if (!sentence || !sentenceItem) return null; | ||||||||||||||||||
| return { | ||||||||||||||||||
| sentence, | ||||||||||||||||||
| sentenceItem, | ||||||||||||||||||
| index: i, | ||||||||||||||||||
| linkedWithPrevious: i > 0 && getArgByKey(parsedScene.sentenceList[i - 1], "next") === true, | ||||||||||||||||||
| targetPath: props.targetPath, | ||||||||||||||||||
| sceneLabels, | ||||||||||||||||||
| onAddBefore: openAddSentenceDialog, | ||||||||||||||||||
| onDelete: deleteOneSentence, | ||||||||||||||||||
| onSync: syncToIndex, | ||||||||||||||||||
| onToggleShow: changeShowSentence, | ||||||||||||||||||
| onUpdate: updateSentenceByIndex, | ||||||||||||||||||
| }; | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| const renderSentenceRow = (provided: DraggableProvided, i: number) => { | ||||||||||||||||||
| const rowProps = getSentenceRowProps(i); | ||||||||||||||||||
| return rowProps && <SentenceRowContent provided={provided} {...rowProps} />; | ||||||||||||||||||
| }; | ||||||||||||||||||
|
Comment on lines
+338
to
+341
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When rendering the clone for the dragging item under the cursor, we should pass
Suggested change
|
||||||||||||||||||
|
|
||||||||||||||||||
| return <div className={styles.main} id="graphical-editor-main"> | ||||||||||||||||||
| <div style={{ flex: 1, padding: '14px 4px 0 4px' }}> | ||||||||||||||||||
| <DragDropContext onDragEnd={onDragEnd}> | ||||||||||||||||||
| <Droppable droppableId="droppable"> | ||||||||||||||||||
| {(provided) => ( | ||||||||||||||||||
| // 下面开始书写容器 | ||||||||||||||||||
| <div style={{ height: "100%" }} | ||||||||||||||||||
| // provided.droppableProps应用的相同元素. | ||||||||||||||||||
| {...provided.droppableProps} | ||||||||||||||||||
| // 为了使 droppable 能够正常工作必须 绑定到最高可能的DOM节点中provided.innerRef. | ||||||||||||||||||
| ref={provided.innerRef} | ||||||||||||||||||
| > | ||||||||||||||||||
| {parsedScene.sentenceList.map((sentence, i) => { | ||||||||||||||||||
| const sentenceItem = sentenceData[i]; | ||||||||||||||||||
| if (!sentenceItem) return null; | ||||||||||||||||||
| return <SentenceRow | ||||||||||||||||||
| key={sentenceItem.id} | ||||||||||||||||||
| sentence={sentence} | ||||||||||||||||||
| sentenceItem={sentenceItem} | ||||||||||||||||||
| index={i} | ||||||||||||||||||
| linkedWithPrevious={i > 0 && getArgByKey(parsedScene.sentenceList[i - 1], "next") === true} | ||||||||||||||||||
| targetPath={props.targetPath} | ||||||||||||||||||
| sceneLabels={sceneLabels} | ||||||||||||||||||
| onAddBefore={openAddSentenceDialog} | ||||||||||||||||||
| onDelete={deleteOneSentence} | ||||||||||||||||||
| onSync={syncToIndex} | ||||||||||||||||||
| onToggleShow={changeShowSentence} | ||||||||||||||||||
| onUpdate={updateSentenceByIndex} | ||||||||||||||||||
| />; | ||||||||||||||||||
| <DragDropContext onDragStart={onDragStart} onDragEnd={onDragEnd}> | ||||||||||||||||||
| <Droppable | ||||||||||||||||||
| droppableId="droppable" | ||||||||||||||||||
| mode="virtual" | ||||||||||||||||||
| renderClone={(provided, _, rubric) => renderSentenceRow(provided, rubric.source.index)} | ||||||||||||||||||
| > | ||||||||||||||||||
| {(provided) => ( | ||||||||||||||||||
| <div | ||||||||||||||||||
| className={styles.virtualScroller} | ||||||||||||||||||
| {...provided.droppableProps} | ||||||||||||||||||
| ref={(element) => { | ||||||||||||||||||
| scrollElementRef.current = element; | ||||||||||||||||||
| provided.innerRef(element); | ||||||||||||||||||
| }} | ||||||||||||||||||
| > | ||||||||||||||||||
| <div className={styles.virtualCanvas} style={{ height: `${rowVirtualizer.getTotalSize()}px` }}> | ||||||||||||||||||
| {virtualRows.map((virtualRow) => { | ||||||||||||||||||
| const rowProps = getSentenceRowProps(virtualRow.index); | ||||||||||||||||||
| if (!rowProps) return null; | ||||||||||||||||||
| return <div | ||||||||||||||||||
| key={rowProps.sentenceItem.id} | ||||||||||||||||||
| className={styles.virtualItem} | ||||||||||||||||||
| data-index={virtualRow.index} | ||||||||||||||||||
| ref={rowVirtualizer.measureElement} | ||||||||||||||||||
| style={{ | ||||||||||||||||||
| transform: `translateY(${virtualRow.start}px)`, | ||||||||||||||||||
| height: rowProps.sentenceItem.id === draggingId ? `${virtualRow.size}px` : undefined, | ||||||||||||||||||
| }} | ||||||||||||||||||
| > | ||||||||||||||||||
| <SentenceRow {...rowProps} /> | ||||||||||||||||||
| </div>; | ||||||||||||||||||
| })} | ||||||||||||||||||
| {provided.placeholder} | ||||||||||||||||||
| <div className={styles.addWrapper}> | ||||||||||||||||||
| <AddSentenceButton | ||||||||||||||||||
| titleText={t`添加语句`} | ||||||||||||||||||
| type={addSentenceType.backward} | ||||||||||||||||||
| onClick={() => openAddSentenceDialog(t`添加语句`, sentenceData.length)} | ||||||||||||||||||
| /> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| )} | ||||||||||||||||||
| </Droppable> | ||||||||||||||||||
| </DragDropContext> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.addWrapper}> | ||||||||||||||||||
| <AddSentenceButton | ||||||||||||||||||
| titleText={t`添加语句`} | ||||||||||||||||||
| type={addSentenceType.backward} | ||||||||||||||||||
| onClick={() => openAddSentenceDialog(t`添加语句`, sentenceData.length)} | ||||||||||||||||||
| /> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| )} | ||||||||||||||||||
| </Droppable> | ||||||||||||||||||
| </DragDropContext> | ||||||||||||||||||
| <AddSentenceDialog | ||||||||||||||||||
| open={!!addSentenceDialog} | ||||||||||||||||||
| titleText={addSentenceDialog?.titleText ?? ""} | ||||||||||||||||||
|
|
@@ -345,20 +397,8 @@ export default function GraphicalEditor(props: IGraphicalEditorProps) { | |||||||||||||||||
|
|
||||||||||||||||||
| const StableGlobalTerrePanel = memo(GlobalTerrePanel); | ||||||||||||||||||
|
|
||||||||||||||||||
| const SentenceRow = memo((props: { | ||||||||||||||||||
| sentence: ISentence; | ||||||||||||||||||
| sentenceItem: SentenceItem; | ||||||||||||||||||
| index: number; | ||||||||||||||||||
| linkedWithPrevious: boolean; | ||||||||||||||||||
| targetPath: string; | ||||||||||||||||||
| sceneLabels: string[]; | ||||||||||||||||||
| onAddBefore: (titleText: string, insertIndex: number) => void; | ||||||||||||||||||
| onDelete: (index: number) => void; | ||||||||||||||||||
| onSync: (index: number) => void; | ||||||||||||||||||
| onToggleShow: (index: number) => void; | ||||||||||||||||||
| onUpdate: (newContent: string, updateIndex: number) => void; | ||||||||||||||||||
| }) => { | ||||||||||||||||||
| const { sentence, sentenceItem, index: i, linkedWithPrevious, targetPath, sceneLabels } = props; | ||||||||||||||||||
| const SentenceRowContent = (props: SentenceRowContentProps) => { | ||||||||||||||||||
| const { provided, sentence, sentenceItem, index: i, linkedWithPrevious, targetPath, sceneLabels } = props; | ||||||||||||||||||
| const index = i + 1; | ||||||||||||||||||
| const sentenceConfig = sentenceEditorConfig.find((e) => e.type === sentence.command) ?? sentenceEditorDefault; | ||||||||||||||||||
| const SentenceEditor = sentenceConfig.component; | ||||||||||||||||||
|
Comment on lines
+400
to
404
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When an item is being dragged in a virtual list, We should check |
||||||||||||||||||
|
|
@@ -375,71 +415,73 @@ const SentenceRow = memo((props: { | |||||||||||||||||
| />; | ||||||||||||||||||
| const inlineArgOption = inlineArgOptionCommands.has(sentence.command); | ||||||||||||||||||
|
|
||||||||||||||||||
| return <Draggable key={sentenceItem.id} draggableId={sentenceItem.id} index={i}> | ||||||||||||||||||
| {(provided) => ( | ||||||||||||||||||
| <div className={`${styles.sentenceEditorWrapper} sentence-block-${index}`} | ||||||||||||||||||
| ref={provided.innerRef} | ||||||||||||||||||
| {...provided.draggableProps} | ||||||||||||||||||
| > | ||||||||||||||||||
| <div className={styles.addForwardArea}> | ||||||||||||||||||
| {linkedWithPrevious && <div className={styles.nextChain} title={t`由上一句的 next 连续执行`}><LinkOne theme="outline" size="20" strokeWidth={3} /></div>} | ||||||||||||||||||
| <div className={styles.addForwardAreaButtonGroup}> | ||||||||||||||||||
| <div className={styles.addForwardAreaButton}> | ||||||||||||||||||
| <AddSentenceButton | ||||||||||||||||||
| titleText={t`本句前插入句子`} | ||||||||||||||||||
| type={addSentenceType.forward} | ||||||||||||||||||
| onClick={() => props.onAddBefore(t`本句前插入句子`, i)} | ||||||||||||||||||
| /> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| return <div className={`${styles.sentenceEditorWrapper} sentence-block-${index}`} | ||||||||||||||||||
| ref={provided.innerRef} | ||||||||||||||||||
| {...provided.draggableProps} | ||||||||||||||||||
| > | ||||||||||||||||||
| <div className={styles.addForwardArea}> | ||||||||||||||||||
| {linkedWithPrevious && <div className={styles.nextChain} title={t`由上一句的 next 连续执行`}><LinkOne theme="outline" size="20" strokeWidth={3} /></div>} | ||||||||||||||||||
| <div className={styles.addForwardAreaButtonGroup}> | ||||||||||||||||||
| <div className={styles.addForwardAreaButton}> | ||||||||||||||||||
| <AddSentenceButton | ||||||||||||||||||
| titleText={t`本句前插入句子`} | ||||||||||||||||||
| type={addSentenceType.forward} | ||||||||||||||||||
| onClick={() => props.onAddBefore(t`本句前插入句子`, i)} | ||||||||||||||||||
| /> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.sentenceEditorContent}> | ||||||||||||||||||
| <div className={styles.lineNumber}><span style={{ padding: "0 6px 0 0" }}>{index}</span> | ||||||||||||||||||
| <Sort {...provided.dragHandleProps} style={{ padding: "5px 0 0 0" }} theme="outline" size="22" | ||||||||||||||||||
| strokeWidth={3} /> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.sentenceEditorContent}> | ||||||||||||||||||
| <div className={styles.lineNumber}><span style={{ padding: "0 6px 0 0" }}>{index}</span> | ||||||||||||||||||
| <Sort {...provided.dragHandleProps} style={{ padding: "5px 0 0 0" }} theme="outline" size="22" | ||||||||||||||||||
| strokeWidth={3} /> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.seArea}> | ||||||||||||||||||
| <div className={styles.head}> | ||||||||||||||||||
| <div className={styles.title}> | ||||||||||||||||||
| {sentenceConfig.title()} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.seArea}> | ||||||||||||||||||
| <div className={styles.head}> | ||||||||||||||||||
| <div className={styles.title}> | ||||||||||||||||||
| {sentenceConfig.title()} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.optionButton} | ||||||||||||||||||
| onClick={() => props.onToggleShow(i)}> | ||||||||||||||||||
| {sentenceItem.show ? | ||||||||||||||||||
| <DownOne strokeWidth={3} theme="outline" size="18" | ||||||||||||||||||
| fill="#005CAF" /> : | ||||||||||||||||||
| <RightOne strokeWidth={3} theme="outline" size="18" | ||||||||||||||||||
| fill="#005CAF" />} | ||||||||||||||||||
| <div className={styles.optionButton} | ||||||||||||||||||
| onClick={() => props.onToggleShow(i)}> | ||||||||||||||||||
| {sentenceItem.show ? | ||||||||||||||||||
| <DownOne strokeWidth={3} theme="outline" size="18" | ||||||||||||||||||
| fill="#005CAF" /> : | ||||||||||||||||||
| <RightOne strokeWidth={3} theme="outline" size="18" | ||||||||||||||||||
| fill="#005CAF" />} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.optionButtonContainer}> | ||||||||||||||||||
| <div className={styles.optionButton} | ||||||||||||||||||
| onClick={() => props.onDelete(i)}> | ||||||||||||||||||
| <DeleteFive strokeWidth={3} style={{ padding: "2px 4px 0 0" }} theme="outline" size="14" | ||||||||||||||||||
| fill="var(--text)" /> | ||||||||||||||||||
| <div> | ||||||||||||||||||
| {t`删除本句`} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.optionButtonContainer}> | ||||||||||||||||||
| <div className={styles.optionButton} | ||||||||||||||||||
| onClick={() => props.onDelete(i)}> | ||||||||||||||||||
| <DeleteFive strokeWidth={3} style={{ padding: "2px 4px 0 0" }} theme="outline" size="14" | ||||||||||||||||||
| fill="var(--text)" /> | ||||||||||||||||||
| <div> | ||||||||||||||||||
| {t`删除本句`} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.optionButton} | ||||||||||||||||||
| onClick={() => props.onSync(i)}> | ||||||||||||||||||
| <Play strokeWidth={3} style={{ padding: "2px 4px 0 0" }} theme="outline" size="14" | ||||||||||||||||||
| fill="var(--text)" /> | ||||||||||||||||||
| <div> | ||||||||||||||||||
| {t`执行到此句`} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| <div className={styles.optionButton} | ||||||||||||||||||
| onClick={() => props.onSync(i)}> | ||||||||||||||||||
| <Play strokeWidth={3} style={{ padding: "2px 4px 0 0" }} theme="outline" size="14" | ||||||||||||||||||
| fill="var(--text)" /> | ||||||||||||||||||
| <div> | ||||||||||||||||||
| {t`执行到此句`} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| {sentenceItem.show && <div className={styles.sentenceEditBody}> | ||||||||||||||||||
| <SentenceEditor sentence={sentence} index={index} onSubmit={(newSentence) => { | ||||||||||||||||||
| props.onUpdate(newSentence, i); | ||||||||||||||||||
| }} targetPath={targetPath} sceneLabels={sceneLabels} extraOptions={inlineArgOption ? argOption : undefined} /> | ||||||||||||||||||
| {!inlineArgOption && argOption} | ||||||||||||||||||
| </div>} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div> | ||||||||||||||||||
| {sentenceItem.show && <div className={styles.sentenceEditBody}> | ||||||||||||||||||
| <SentenceEditor sentence={sentence} index={index} onSubmit={(newSentence) => { | ||||||||||||||||||
| props.onUpdate(newSentence, i); | ||||||||||||||||||
| }} targetPath={targetPath} sceneLabels={sceneLabels} extraOptions={inlineArgOption ? argOption : undefined} /> | ||||||||||||||||||
| {!inlineArgOption && argOption} | ||||||||||||||||||
| </div>} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| )} | ||||||||||||||||||
| </div> | ||||||||||||||||||
| </div>; | ||||||||||||||||||
| }; | ||||||||||||||||||
|
|
||||||||||||||||||
| const SentenceRow = memo((props: SentenceRowProps) => { | ||||||||||||||||||
| return <Draggable key={props.sentenceItem.id} draggableId={props.sentenceItem.id} index={props.index}> | ||||||||||||||||||
| {(provided) => <SentenceRowContent provided={provided} {...props} />} | ||||||||||||||||||
| </Draggable>; | ||||||||||||||||||
|
Comment on lines
+482
to
485
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pass
Suggested change
|
||||||||||||||||||
| }, (prev, next) => ( | ||||||||||||||||||
| prev.sentence === next.sentence && | ||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add
isDraggingPlaceholdertoSentenceRowContentPropsto allow hiding the content of the original item in the list while it is being dragged.