V4.12.3 features (#5595)

* refactor: remove ModelProviderIdType and update related types (#5549)

* perf: model provider

* fix eval create split (#5570)

* git rebase --continuedoc

* add more variable types (#5540)

* variable types

* password

* time picker

* internal var

* file

* fix-test

* time select default value & range

* password & type render

* fix

* fix build

* fix

* move method

* split date select

* icon

* perf: variable code

* prompt editor add markdown plugin (#5556)

* editor markdown

* fix build

* pnpm lock

* add props

* update code

* fix list

* editor ui

* fix variable reset (#5586)

* perf: variables type code

* customize lexical indent (#5588)

* perf: multiple selector

* perf: tab plugin

* doc

* refactor: update workflow constants to use ToolTypeEnum (#5491)

* refactor: replace FlowNodeTemplateTypeEnum with string literals in workflow templates

* perf: tool type

---------

Co-authored-by: archer <545436317@qq.com>

* update doc

* fix: make table's row more natural while dragging it (#5596)

* feat: add APIGetTemplate function and refactor template fetching logic (#5498)

* feat: add APIGetTemplate function and refactor template fetching logic

* chore: adjust the code

* chore: update sdk

---------

Co-authored-by: FinleyGe <m13203533462@163.com>

* perf init system

* doc

* remove log

* remove i18n

* perf: variables render

---------

Co-authored-by: Ctrlz <143257420+ctrlz526@users.noreply.github.com>
Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: 伍闲犬 <whoeverimf5@gmail.com>
Co-authored-by: FinleyGe <m13203533462@163.com>
This commit is contained in:
Archer
2025-09-07 14:41:48 +08:00
committed by GitHub
parent c747fc03ad
commit 3f9b0fa1d4
166 changed files with 3407 additions and 11604 deletions

View File

@@ -0,0 +1,216 @@
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
import {
KEY_TAB_COMMAND,
COMMAND_PRIORITY_EDITOR,
$getSelection,
$isRangeSelection,
$isTextNode
} from 'lexical';
import { $createTextNode } from 'lexical';
import { $isListNode, $isListItemNode } from '@lexical/list';
import { useEffect } from 'react';
export default function TabToSpacesPlugin(): null {
const [editor] = useLexicalComposerContext();
useEffect(() => {
return editor.registerCommand(
KEY_TAB_COMMAND,
(event) => {
try {
const selection = $getSelection();
if (!$isRangeSelection(selection)) {
return false;
}
// Check if we're in a list context
let isInList = false;
try {
const nodes = selection.getNodes();
isInList = nodes.some((node) => {
// Check if current node or any of its ancestors is a list or list item
let currentNode = node;
while (currentNode) {
try {
if ($isListNode(currentNode) || $isListItemNode(currentNode)) {
return true;
}
// @ts-ignore
currentNode = currentNode.getParent();
} catch (e) {
// If node is no longer valid, break the loop
break;
}
}
return false;
});
} catch (e) {
// If we can't get nodes safely, assume we're not in a list
isInList = false;
}
// If we're in a list, let the built-in list indentation handle it
if (isInList) {
return false;
}
// Only handle tab for non-list contexts
event.preventDefault();
const isShiftTab = event.shiftKey;
// Handle Shift+Tab (outdent)
if (isShiftTab) {
if (!selection.isCollapsed()) {
// For selected text, remove 4 spaces from the beginning of each line
try {
const selectedText = selection.getTextContent();
const lines = selectedText.split('\n');
const outdentedText = lines
.map((line) => {
// Remove up to 4 spaces from the beginning of the line
if (line.startsWith(' ')) {
return line.slice(4);
} else if (line.startsWith(' ')) {
return line.slice(3);
} else if (line.startsWith(' ')) {
return line.slice(2);
} else if (line.startsWith(' ')) {
return line.slice(1);
}
return line;
})
.join('\n');
// Insert the outdented text and let Lexical handle cursor positioning
selection.insertText(outdentedText);
// Schedule selection restoration in the next update cycle
setTimeout(() => {
editor.update(() => {
const currentSelection = $getSelection();
if ($isRangeSelection(currentSelection) && !currentSelection.isCollapsed()) {
// Selection is already maintained, do nothing
return;
}
// If selection was lost, try to select the inserted text
if ($isRangeSelection(currentSelection)) {
const currentOffset = currentSelection.anchor.offset;
const selectionStart = Math.max(0, currentOffset - outdentedText.length);
currentSelection.anchor.set(
currentSelection.anchor.key,
selectionStart,
'text'
);
currentSelection.focus.set(currentSelection.focus.key, currentOffset, 'text');
}
});
}, 0);
return true;
} catch (e) {
// If operation fails, do nothing
return true;
}
} else {
// For cursor position, try to remove spaces before cursor
try {
const anchorNode = selection.anchor.getNode();
const anchorOffset = selection.anchor.offset;
if ($isTextNode(anchorNode)) {
const textContent = anchorNode.getTextContent();
const beforeCursor = textContent.slice(0, anchorOffset);
const afterCursor = textContent.slice(anchorOffset);
// Check if there are spaces before cursor to remove
let spacesToRemove = 0;
for (let i = beforeCursor.length - 1; i >= 0 && spacesToRemove < 4; i--) {
if (beforeCursor[i] === ' ') {
spacesToRemove++;
} else {
break;
}
}
if (spacesToRemove > 0) {
const newTextContent =
beforeCursor.slice(0, beforeCursor.length - spacesToRemove) + afterCursor;
anchorNode.setTextContent(newTextContent);
selection.anchor.set(
anchorNode.getKey(),
anchorOffset - spacesToRemove,
'text'
);
selection.focus.set(anchorNode.getKey(), anchorOffset - spacesToRemove, 'text');
}
}
return true;
} catch (e) {
return true;
}
}
} else {
// Handle regular Tab (indent)
if (!selection.isCollapsed()) {
try {
const selectedText = selection.getTextContent();
const lines = selectedText.split('\n');
const indentedText = lines.map((line) => ' ' + line).join('\n');
// Insert the indented text and let Lexical handle cursor positioning
selection.insertText(indentedText);
// Schedule selection restoration in the next update cycle
setTimeout(() => {
editor.update(() => {
const currentSelection = $getSelection();
if ($isRangeSelection(currentSelection) && !currentSelection.isCollapsed()) {
// Selection is already maintained, do nothing
return;
}
// If selection was lost, try to select the inserted text
if ($isRangeSelection(currentSelection)) {
const currentOffset = currentSelection.anchor.offset;
const selectionStart = Math.max(0, currentOffset - indentedText.length);
currentSelection.anchor.set(
currentSelection.anchor.key,
selectionStart,
'text'
);
currentSelection.focus.set(currentSelection.focus.key, currentOffset, 'text');
}
});
}, 0);
return true;
} catch (e) {
// If selection operation fails, fall back to simple space insertion
const textNode = $createTextNode(' ');
selection.insertNodes([textNode]);
return true;
}
} else {
// For cursor position (no selection), insert 4 spaces
const textNode = $createTextNode(' '); // 4 spaces
selection.insertNodes([textNode]);
return true;
}
}
} catch (e) {
// If anything fails, just let the default behavior handle it
console.warn('TabToSpacesPlugin error:', e);
return false;
}
},
COMMAND_PRIORITY_EDITOR
);
}, [editor]);
return null;
}