메일 본문 내용 사용자 경험 개선
This commit is contained in:
parent
1ee1287b8a
commit
ece7f21bd3
|
|
@ -0,0 +1,309 @@
|
|||
"use client";
|
||||
|
||||
/**
|
||||
* 변수 태그 에디터 컴포넌트
|
||||
* TipTap 기반으로 본문 내에서 변수를 시각적 태그로 표시하고 삽입할 수 있는 에디터
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import { useEditor, EditorContent, BubbleMenu } from "@tiptap/react";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import Placeholder from "@tiptap/extension-placeholder";
|
||||
import {
|
||||
VariableTagExtension,
|
||||
textToEditorContent,
|
||||
editorContentToText,
|
||||
} from "./VariableTagExtension";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@/components/ui/command";
|
||||
import { Plus, Variable, X, Search } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
// 변수 정보 타입
|
||||
export interface VariableInfo {
|
||||
name: string; // 실제 변수명 (예: customerName)
|
||||
displayName: string; // 표시명 (예: 고객명)
|
||||
type?: string; // 데이터 타입 (예: string, number)
|
||||
description?: string; // 설명
|
||||
}
|
||||
|
||||
interface VariableTagEditorProps {
|
||||
value: string; // 현재 값 (예: "안녕하세요, {{customerName}} 님")
|
||||
onChange: (value: string) => void; // 값 변경 콜백
|
||||
variables: VariableInfo[]; // 사용 가능한 변수 목록
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
minHeight?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export function VariableTagEditor({
|
||||
value,
|
||||
onChange,
|
||||
variables,
|
||||
placeholder = "내용을 입력하세요...",
|
||||
className,
|
||||
minHeight = "150px",
|
||||
disabled = false,
|
||||
}: VariableTagEditorProps) {
|
||||
const [isVariablePopoverOpen, setIsVariablePopoverOpen] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
|
||||
// 변수명 → 표시명 맵 생성
|
||||
const variableMap = useMemo(() => {
|
||||
const map: Record<string, string> = {};
|
||||
variables.forEach((v) => {
|
||||
map[v.name] = v.displayName;
|
||||
});
|
||||
return map;
|
||||
}, [variables]);
|
||||
|
||||
// 필터된 변수 목록
|
||||
const filteredVariables = useMemo(() => {
|
||||
if (!searchQuery) return variables;
|
||||
const query = searchQuery.toLowerCase();
|
||||
return variables.filter(
|
||||
(v) =>
|
||||
v.name.toLowerCase().includes(query) ||
|
||||
v.displayName.toLowerCase().includes(query)
|
||||
);
|
||||
}, [variables, searchQuery]);
|
||||
|
||||
// TipTap 에디터 초기화
|
||||
const editor = useEditor({
|
||||
extensions: [
|
||||
StarterKit.configure({
|
||||
// 불필요한 기능 비활성화
|
||||
heading: false,
|
||||
bulletList: false,
|
||||
orderedList: false,
|
||||
blockquote: false,
|
||||
codeBlock: false,
|
||||
horizontalRule: false,
|
||||
}),
|
||||
VariableTagExtension,
|
||||
Placeholder.configure({
|
||||
placeholder,
|
||||
emptyEditorClass: "is-editor-empty",
|
||||
}),
|
||||
],
|
||||
content: textToEditorContent(value, variableMap),
|
||||
editable: !disabled,
|
||||
onUpdate: ({ editor }) => {
|
||||
const json = editor.getJSON();
|
||||
const text = editorContentToText(json);
|
||||
onChange(text);
|
||||
},
|
||||
editorProps: {
|
||||
attributes: {
|
||||
class: cn(
|
||||
"prose prose-sm max-w-none focus:outline-none",
|
||||
"min-h-[100px] p-3",
|
||||
disabled && "opacity-50 cursor-not-allowed"
|
||||
),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// 외부 value 변경 시 에디터 동기화
|
||||
useEffect(() => {
|
||||
if (editor && !editor.isFocused) {
|
||||
const currentText = editorContentToText(editor.getJSON());
|
||||
if (currentText !== value) {
|
||||
editor.commands.setContent(textToEditorContent(value, variableMap));
|
||||
}
|
||||
}
|
||||
}, [value, editor, variableMap]);
|
||||
|
||||
// 변수 삽입
|
||||
const insertVariable = useCallback(
|
||||
(variable: VariableInfo) => {
|
||||
if (!editor) return;
|
||||
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.insertContent({
|
||||
type: "variableTag",
|
||||
attrs: {
|
||||
variableName: variable.name,
|
||||
displayName: variable.displayName,
|
||||
},
|
||||
})
|
||||
.run();
|
||||
|
||||
setIsVariablePopoverOpen(false);
|
||||
setSearchQuery("");
|
||||
},
|
||||
[editor]
|
||||
);
|
||||
|
||||
// @ 키 입력 시 변수 팝업 표시
|
||||
useEffect(() => {
|
||||
if (!editor) return;
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === "@" || (event.key === "/" && !event.shiftKey)) {
|
||||
event.preventDefault();
|
||||
setIsVariablePopoverOpen(true);
|
||||
}
|
||||
};
|
||||
|
||||
const editorElement = editor.view.dom;
|
||||
editorElement.addEventListener("keydown", handleKeyDown);
|
||||
|
||||
return () => {
|
||||
editorElement.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, [editor]);
|
||||
|
||||
if (!editor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn("relative rounded-md border", className)}>
|
||||
{/* 툴바 */}
|
||||
<div className="flex items-center justify-between border-b bg-gray-50 px-2 py-1">
|
||||
<div className="flex items-center gap-1">
|
||||
<Popover
|
||||
open={isVariablePopoverOpen}
|
||||
onOpenChange={setIsVariablePopoverOpen}
|
||||
>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-7 gap-1 text-xs"
|
||||
disabled={disabled}
|
||||
>
|
||||
<Variable className="h-3.5 w-3.5" />
|
||||
변수 삽입
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[280px] p-0" align="start">
|
||||
<Command>
|
||||
<CommandInput
|
||||
placeholder="변수 검색..."
|
||||
value={searchQuery}
|
||||
onValueChange={setSearchQuery}
|
||||
/>
|
||||
<CommandList>
|
||||
<CommandEmpty>검색 결과가 없습니다</CommandEmpty>
|
||||
<CommandGroup heading="사용 가능한 변수">
|
||||
{filteredVariables.map((variable) => (
|
||||
<CommandItem
|
||||
key={variable.name}
|
||||
value={`${variable.name}-${variable.displayName}`}
|
||||
onSelect={() => insertVariable(variable)}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="rounded bg-blue-100 px-1.5 py-0.5 text-xs font-medium text-blue-700">
|
||||
{variable.displayName}
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">
|
||||
{variable.name}
|
||||
</span>
|
||||
</div>
|
||||
{variable.description && (
|
||||
<span className="mt-0.5 text-xs text-gray-400">
|
||||
{variable.description}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<div className="text-xs text-gray-400">
|
||||
<kbd className="rounded bg-gray-200 px-1">@</kbd> 또는{" "}
|
||||
<kbd className="rounded bg-gray-200 px-1">/</kbd> 로 변수 삽입
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 에디터 영역 */}
|
||||
<div style={{ minHeight }}>
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
|
||||
{/* 스타일 */}
|
||||
<style jsx global>{`
|
||||
/* 변수 태그 스타일 */
|
||||
.variable-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
background-color: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
margin: 0 1px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.variable-tag:hover {
|
||||
background-color: #bfdbfe;
|
||||
}
|
||||
|
||||
/* 선택된 태그 */
|
||||
.variable-tag.ProseMirror-selectednode {
|
||||
outline: 2px solid #3b82f6;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
/* 플레이스홀더 스타일 */
|
||||
.is-editor-empty:first-child::before {
|
||||
content: attr(data-placeholder);
|
||||
float: left;
|
||||
color: #9ca3af;
|
||||
pointer-events: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/* 에디터 기본 스타일 */
|
||||
.ProseMirror {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ProseMirror p {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
.ProseMirror p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ProseMirror p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default VariableTagEditor;
|
||||
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
/**
|
||||
* TipTap 변수 태그 확장
|
||||
* 본문 내에서 {{변수명}} 형태의 변수를 시각적 태그로 표시
|
||||
*/
|
||||
|
||||
import { Node, mergeAttributes } from "@tiptap/core";
|
||||
import { ReactNodeViewRenderer } from "@tiptap/react";
|
||||
|
||||
// 변수 태그 노드 타입
|
||||
export interface VariableTagOptions {
|
||||
HTMLAttributes: Record<string, any>;
|
||||
}
|
||||
|
||||
// 변수 태그 속성
|
||||
export interface VariableTagAttributes {
|
||||
variableName: string; // 실제 변수명 (예: customerName)
|
||||
displayName: string; // 표시명 (예: 고객명)
|
||||
}
|
||||
|
||||
/**
|
||||
* 변수 태그 TipTap 확장
|
||||
*/
|
||||
export const VariableTagExtension = Node.create<VariableTagOptions>({
|
||||
name: "variableTag",
|
||||
|
||||
group: "inline",
|
||||
|
||||
inline: true,
|
||||
|
||||
// atom: true로 설정하면 커서가 태그 내부로 들어가지 않음
|
||||
atom: true,
|
||||
|
||||
// 선택 가능하도록 설정
|
||||
selectable: true,
|
||||
|
||||
// 드래그 가능하도록 설정
|
||||
draggable: true,
|
||||
|
||||
addOptions() {
|
||||
return {
|
||||
HTMLAttributes: {},
|
||||
};
|
||||
},
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
variableName: {
|
||||
default: "",
|
||||
parseHTML: (element) => element.getAttribute("data-variable-name"),
|
||||
renderHTML: (attributes) => ({
|
||||
"data-variable-name": attributes.variableName,
|
||||
}),
|
||||
},
|
||||
displayName: {
|
||||
default: "",
|
||||
parseHTML: (element) => element.getAttribute("data-display-name"),
|
||||
renderHTML: (attributes) => ({
|
||||
"data-display-name": attributes.displayName,
|
||||
}),
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
parseHTML() {
|
||||
return [
|
||||
{
|
||||
tag: 'span[data-type="variable-tag"]',
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return [
|
||||
"span",
|
||||
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
|
||||
"data-type": "variable-tag",
|
||||
class: "variable-tag",
|
||||
}),
|
||||
HTMLAttributes["data-display-name"] || HTMLAttributes["data-variable-name"],
|
||||
];
|
||||
},
|
||||
|
||||
// 키보드 명령어 추가 (Backspace로 삭제)
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
Backspace: () =>
|
||||
this.editor.commands.command(({ tr, state }) => {
|
||||
let isVariableTag = false;
|
||||
const { selection } = state;
|
||||
const { empty, anchor } = selection;
|
||||
|
||||
if (!empty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state.doc.nodesBetween(anchor - 1, anchor, (node, pos) => {
|
||||
if (node.type.name === this.name) {
|
||||
isVariableTag = true;
|
||||
tr.delete(pos, pos + node.nodeSize);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return isVariableTag;
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 텍스트를 에디터 JSON으로 변환
|
||||
* "안녕하세요, {{customerName}} 님" → TipTap JSON
|
||||
*/
|
||||
export function textToEditorContent(
|
||||
text: string,
|
||||
variableMap: Record<string, string> // { customerName: "고객명" }
|
||||
): any {
|
||||
if (!text) {
|
||||
return {
|
||||
type: "doc",
|
||||
content: [{ type: "paragraph" }],
|
||||
};
|
||||
}
|
||||
|
||||
const regex = /\{\{(\w+)\}\}/g;
|
||||
const content: any[] = [];
|
||||
let lastIndex = 0;
|
||||
let match;
|
||||
|
||||
while ((match = regex.exec(text)) !== null) {
|
||||
// 변수 앞의 일반 텍스트
|
||||
if (match.index > lastIndex) {
|
||||
const beforeText = text.slice(lastIndex, match.index);
|
||||
if (beforeText) {
|
||||
content.push({ type: "text", text: beforeText });
|
||||
}
|
||||
}
|
||||
|
||||
// 변수 태그
|
||||
const variableName = match[1];
|
||||
const displayName = variableMap[variableName] || variableName;
|
||||
content.push({
|
||||
type: "variableTag",
|
||||
attrs: {
|
||||
variableName,
|
||||
displayName,
|
||||
},
|
||||
});
|
||||
|
||||
lastIndex = regex.lastIndex;
|
||||
}
|
||||
|
||||
// 마지막 텍스트
|
||||
if (lastIndex < text.length) {
|
||||
content.push({ type: "text", text: text.slice(lastIndex) });
|
||||
}
|
||||
|
||||
// content가 비어있으면 빈 paragraph 추가
|
||||
if (content.length === 0) {
|
||||
return {
|
||||
type: "doc",
|
||||
content: [{ type: "paragraph" }],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: "doc",
|
||||
content: [
|
||||
{
|
||||
type: "paragraph",
|
||||
content,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 에디터 JSON을 텍스트로 변환
|
||||
* TipTap JSON → "안녕하세요, {{customerName}} 님"
|
||||
*/
|
||||
export function editorContentToText(json: any): string {
|
||||
if (!json || !json.content) {
|
||||
return "";
|
||||
}
|
||||
|
||||
let result = "";
|
||||
|
||||
const processNode = (node: any) => {
|
||||
if (node.type === "text") {
|
||||
result += node.text || "";
|
||||
} else if (node.type === "variableTag") {
|
||||
result += `{{${node.attrs?.variableName || ""}}}`;
|
||||
} else if (node.type === "paragraph") {
|
||||
if (node.content) {
|
||||
node.content.forEach(processNode);
|
||||
}
|
||||
result += "\n";
|
||||
} else if (node.type === "hardBreak") {
|
||||
result += "\n";
|
||||
} else if (node.content) {
|
||||
node.content.forEach(processNode);
|
||||
}
|
||||
};
|
||||
|
||||
json.content.forEach(processNode);
|
||||
|
||||
// 마지막 줄바꿈 제거
|
||||
return result.replace(/\n$/, "");
|
||||
}
|
||||
|
||||
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
/**
|
||||
* 메일 발송 액션 노드
|
||||
* SMTP를 통해 이메일을 발송하는 노드
|
||||
* 등록된 메일 계정을 선택하여 이메일을 발송하는 노드
|
||||
*/
|
||||
|
||||
import { memo } from "react";
|
||||
import { Handle, Position, NodeProps } from "reactflow";
|
||||
import { Mail, Server } from "lucide-react";
|
||||
import { Mail, User, CheckCircle } from "lucide-react";
|
||||
import type { EmailActionNodeData } from "@/types/node-editor";
|
||||
|
||||
export const EmailActionNode = memo(({ data, selected }: NodeProps<EmailActionNodeData>) => {
|
||||
const hasSmtpConfig = data.smtpConfig?.host && data.smtpConfig?.port;
|
||||
const hasAccount = !!data.accountId;
|
||||
const hasRecipient = data.to && data.to.trim().length > 0;
|
||||
const hasSubject = data.subject && data.subject.trim().length > 0;
|
||||
|
||||
|
|
@ -38,16 +38,17 @@ export const EmailActionNode = memo(({ data, selected }: NodeProps<EmailActionNo
|
|||
|
||||
{/* 본문 */}
|
||||
<div className="space-y-2 p-3">
|
||||
{/* SMTP 설정 상태 */}
|
||||
{/* 발송 계정 상태 */}
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<Server className="h-3 w-3 text-gray-400" />
|
||||
<User className="h-3 w-3 text-gray-400" />
|
||||
<span className="text-gray-600">
|
||||
{hasSmtpConfig ? (
|
||||
<span className="text-green-600">
|
||||
{data.smtpConfig.host}:{data.smtpConfig.port}
|
||||
{hasAccount ? (
|
||||
<span className="flex items-center gap-1 text-green-600">
|
||||
<CheckCircle className="h-3 w-3" />
|
||||
계정 선택됨
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-orange-500">SMTP 설정 필요</span>
|
||||
<span className="text-orange-500">발송 계정 선택 필요</span>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@
|
|||
/**
|
||||
* 메일 발송 노드 속성 편집
|
||||
* - 메일관리에서 등록한 계정을 선택하여 발송
|
||||
* - 변수 태그 에디터로 본문 편집
|
||||
*/
|
||||
|
||||
import { useEffect, useState, useCallback } from "react";
|
||||
import { useEffect, useState, useCallback, useMemo } from "react";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
|
@ -18,6 +19,7 @@ import { Plus, Trash2, Mail, Server, FileText, Settings, RefreshCw, CheckCircle,
|
|||
import { useFlowEditorStore } from "@/lib/stores/flowEditorStore";
|
||||
import { getMailAccounts, type MailAccount } from "@/lib/api/mail";
|
||||
import type { EmailActionNodeData } from "@/types/node-editor";
|
||||
import { VariableTagEditor, type VariableInfo } from "../../editors/VariableTagEditor";
|
||||
|
||||
interface EmailActionPropertiesProps {
|
||||
nodeId: string;
|
||||
|
|
@ -25,13 +27,92 @@ interface EmailActionPropertiesProps {
|
|||
}
|
||||
|
||||
export function EmailActionProperties({ nodeId, data }: EmailActionPropertiesProps) {
|
||||
const { updateNode } = useFlowEditorStore();
|
||||
const { updateNode, nodes, edges } = useFlowEditorStore();
|
||||
|
||||
// 메일 계정 목록
|
||||
const [mailAccounts, setMailAccounts] = useState<MailAccount[]>([]);
|
||||
const [isLoadingAccounts, setIsLoadingAccounts] = useState(false);
|
||||
const [accountError, setAccountError] = useState<string | null>(null);
|
||||
|
||||
// 🆕 플로우에서 사용 가능한 변수 목록 계산
|
||||
const availableVariables = useMemo<VariableInfo[]>(() => {
|
||||
const variables: VariableInfo[] = [];
|
||||
|
||||
// 기본 시스템 변수
|
||||
variables.push(
|
||||
{ name: "timestamp", displayName: "현재 시간", description: "메일 발송 시점의 타임스탬프" },
|
||||
{ name: "sourceData", displayName: "소스 데이터", description: "전체 소스 데이터 (JSON)" }
|
||||
);
|
||||
|
||||
// 현재 노드에 연결된 소스 노드들에서 필드 정보 수집
|
||||
const incomingEdges = edges.filter((e) => e.target === nodeId);
|
||||
|
||||
for (const edge of incomingEdges) {
|
||||
const sourceNode = nodes.find((n) => n.id === edge.source);
|
||||
if (!sourceNode) continue;
|
||||
|
||||
const nodeData = sourceNode.data as any;
|
||||
|
||||
// 테이블 소스 노드인 경우
|
||||
if (sourceNode.type === "tableSource" && nodeData.fields) {
|
||||
const tableName = nodeData.tableName || "테이블";
|
||||
nodeData.fields.forEach((field: any) => {
|
||||
variables.push({
|
||||
name: field.name,
|
||||
displayName: field.displayName || field.label || field.name,
|
||||
type: field.type,
|
||||
description: `${tableName} 테이블의 필드`,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 외부 DB 소스 노드인 경우
|
||||
if (sourceNode.type === "externalDBSource" && nodeData.fields) {
|
||||
const tableName = nodeData.tableName || "외부 테이블";
|
||||
nodeData.fields.forEach((field: any) => {
|
||||
variables.push({
|
||||
name: field.name,
|
||||
displayName: field.displayName || field.label || field.name,
|
||||
type: field.type,
|
||||
description: `${tableName} (외부 DB) 필드`,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// REST API 소스 노드인 경우
|
||||
if (sourceNode.type === "restAPISource" && nodeData.responseFields) {
|
||||
nodeData.responseFields.forEach((field: any) => {
|
||||
variables.push({
|
||||
name: field.name,
|
||||
displayName: field.displayName || field.label || field.name,
|
||||
type: field.type,
|
||||
description: "REST API 응답 필드",
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 데이터 변환 노드인 경우 - 출력 필드 추가
|
||||
if (sourceNode.type === "dataTransform" && nodeData.transformations) {
|
||||
nodeData.transformations.forEach((transform: any) => {
|
||||
if (transform.targetField) {
|
||||
variables.push({
|
||||
name: transform.targetField,
|
||||
displayName: transform.targetField,
|
||||
description: "데이터 변환 결과 필드",
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 중복 제거
|
||||
const uniqueVariables = variables.filter(
|
||||
(v, index, self) => index === self.findIndex((t) => t.name === v.name)
|
||||
);
|
||||
|
||||
return uniqueVariables;
|
||||
}, [nodes, edges, nodeId]);
|
||||
|
||||
// 로컬 상태
|
||||
const [displayName, setDisplayName] = useState(data.displayName || "메일 발송");
|
||||
|
||||
|
|
@ -473,31 +554,71 @@ export function EmailActionProperties({ nodeId, data }: EmailActionPropertiesPro
|
|||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="text">텍스트</SelectItem>
|
||||
<SelectItem value="html">HTML</SelectItem>
|
||||
<SelectItem value="text">텍스트 (변수 태그 에디터)</SelectItem>
|
||||
<SelectItem value="html">HTML (직접 입력)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs">본문 내용</Label>
|
||||
<Textarea
|
||||
value={body}
|
||||
onChange={(e) => setBody(e.target.value)}
|
||||
onBlur={updateMailContent}
|
||||
placeholder={bodyType === "html" ? "<html><body>...</body></html>" : "메일 본문 내용"}
|
||||
className="min-h-[200px] text-sm font-mono"
|
||||
/>
|
||||
|
||||
{/* 텍스트 형식: 변수 태그 에디터 사용 */}
|
||||
{bodyType === "text" && (
|
||||
<VariableTagEditor
|
||||
value={body}
|
||||
onChange={(newBody) => {
|
||||
setBody(newBody);
|
||||
updateNodeData({ body: newBody });
|
||||
}}
|
||||
variables={availableVariables}
|
||||
placeholder="메일 본문을 입력하세요. @ 또는 / 키로 변수를 삽입할 수 있습니다."
|
||||
minHeight="200px"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* HTML 형식: 직접 입력 */}
|
||||
{bodyType === "html" && (
|
||||
<Textarea
|
||||
value={body}
|
||||
onChange={(e) => setBody(e.target.value)}
|
||||
onBlur={updateMailContent}
|
||||
placeholder="<html><body>...</body></html>"
|
||||
className="min-h-[200px] text-sm font-mono"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Card className="bg-gray-50">
|
||||
<CardContent className="p-3 text-xs text-gray-600">
|
||||
<div className="font-medium mb-1">사용 가능한 템플릿 변수:</div>
|
||||
<code className="block">{"{{sourceData}}"}</code>
|
||||
<code className="block">{"{{timestamp}}"}</code>
|
||||
<code className="block">{"{{필드명}}"}</code>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{/* 변수 안내 (HTML 모드에서만 표시) */}
|
||||
{bodyType === "html" && (
|
||||
<Card className="bg-gray-50">
|
||||
<CardContent className="p-3 text-xs text-gray-600">
|
||||
<div className="font-medium mb-1">사용 가능한 템플릿 변수:</div>
|
||||
{availableVariables.slice(0, 5).map((v) => (
|
||||
<code key={v.name} className="block">
|
||||
{`{{${v.name}}}`} - {v.displayName}
|
||||
</code>
|
||||
))}
|
||||
{availableVariables.length > 5 && (
|
||||
<span className="text-gray-400">...외 {availableVariables.length - 5}개</span>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 변수 태그 에디터 안내 (텍스트 모드에서만 표시) */}
|
||||
{bodyType === "text" && (
|
||||
<Card className="bg-blue-50 border-blue-200">
|
||||
<CardContent className="p-3 text-xs text-blue-700">
|
||||
<div className="font-medium mb-1">변수 삽입 방법:</div>
|
||||
<ul className="list-disc list-inside space-y-0.5">
|
||||
<li><kbd className="bg-blue-100 px-1 rounded">@</kbd> 또는 <kbd className="bg-blue-100 px-1 rounded">/</kbd> 키를 눌러 변수 목록 열기</li>
|
||||
<li>툴바의 "변수 삽입" 버튼 클릭</li>
|
||||
<li>삽입된 변수는 파란색 태그로 표시됩니다</li>
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</TabsContent>
|
||||
|
||||
{/* 옵션 탭 */}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@
|
|||
"@react-three/fiber": "^9.4.0",
|
||||
"@tanstack/react-query": "^5.86.0",
|
||||
"@tanstack/react-table": "^8.21.3",
|
||||
"@tiptap/extension-placeholder": "^2.11.5",
|
||||
"@tiptap/pm": "^2.11.5",
|
||||
"@tiptap/react": "^2.11.5",
|
||||
"@tiptap/starter-kit": "^2.11.5",
|
||||
"@turf/buffer": "^7.2.0",
|
||||
"@turf/helpers": "^7.2.0",
|
||||
"@turf/intersect": "^7.2.0",
|
||||
|
|
@ -1349,6 +1353,16 @@
|
|||
"url": "https://opencollective.com/pkgr"
|
||||
}
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@prisma/config": {
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.18.0.tgz",
|
||||
|
|
@ -2886,6 +2900,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@remirror/core-constants": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz",
|
||||
"integrity": "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rtsao/scc": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
|
||||
|
|
@ -3280,6 +3300,405 @@
|
|||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/core": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.27.1.tgz",
|
||||
"integrity": "sha512-nkerkl8syHj44ZzAB7oA2GPmmZINKBKCa79FuNvmGJrJ4qyZwlkDzszud23YteFZEytbc87kVd/fP76ROS6sLg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-blockquote": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.27.1.tgz",
|
||||
"integrity": "sha512-QrUX3muElDrNjKM3nqCSAtm3H3pT33c6ON8kwRiQboOAjT/9D57Cs7XEVY7r6rMaJPeKztrRUrNVF9w/w/6B0A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bold": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.27.1.tgz",
|
||||
"integrity": "sha512-g4l4p892x/r7mhea8syp3fNYODxsDrimgouQ+q4DKXIgQmm5+uNhyuEPexP3I8TFNXqQ4DlMNFoM9yCqk97etQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bubble-menu": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.27.1.tgz",
|
||||
"integrity": "sha512-ki1R27VsSvY2tT9Q2DIlcATwLOoEjf5DsN+5sExarQ8S/ZxT/tvIjRxB8Dx7lb2a818W5f/NER26YchGtmHfpg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tippy.js": "^6.3.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-bullet-list": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.27.1.tgz",
|
||||
"integrity": "sha512-5FmnfXkJ76wN4EbJNzBhAlmQxho8yEMIJLchTGmXdsD/n/tsyVVtewnQYaIOj/Z7naaGySTGDmjVtLgTuQ+Sxw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.27.1.tgz",
|
||||
"integrity": "sha512-i65wUGJevzBTIIUBHBc1ggVa27bgemvGl/tY1/89fEuS/0Xmre+OQjw8rCtSLevoHSiYYLgLRlvjtUSUhE4kgg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-code-block": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.27.1.tgz",
|
||||
"integrity": "sha512-wCI5VIOfSAdkenCWFvh4m8FFCJ51EOK+CUmOC/PWUjyo2Dgn8QC8HMi015q8XF7886T0KvYVVoqxmxJSUDAYNg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-document": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.27.1.tgz",
|
||||
"integrity": "sha512-NtJzJY7Q/6XWjpOm5OXKrnEaofrcc1XOTYlo/SaTwl8k2bZo918Vl0IDBWhPVDsUN7kx767uHwbtuQZ+9I82hA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-dropcursor": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.27.1.tgz",
|
||||
"integrity": "sha512-3MBQRGHHZ0by3OT0CWbLKS7J3PH9PpobrXjmIR7kr0nde7+bHqxXiVNuuIf501oKU9rnEUSedipSHkLYGkmfsA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-floating-menu": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.27.1.tgz",
|
||||
"integrity": "sha512-nUk/8DbiXO69l6FDwkWso94BTf52IBoWALo+YGWT6o+FO6cI9LbUGghEX2CdmQYXCvSvwvISF2jXeLQWNZvPZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tippy.js": "^6.3.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-gapcursor": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.27.1.tgz",
|
||||
"integrity": "sha512-A9e1jr+jGhDWzNSXtIO6PYVYhf5j/udjbZwMja+wCE/3KvZU9V3IrnGKz1xNW+2Q2BDOe1QO7j5uVL9ElR6nTA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-hard-break": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.27.1.tgz",
|
||||
"integrity": "sha512-W4hHa4Io6QCTwpyTlN6UAvqMIQ7t56kIUByZhyY9EWrg/+JpbfpxE1kXFLPB4ZGgwBknFOw+e4bJ1j3oAbTJFw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-heading": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.27.1.tgz",
|
||||
"integrity": "sha512-6xoC7igZlW1EmnQ5WVH9IL7P1nCQb3bBUaIDLvk7LbweEogcTUECI4Xg1vxMOVmj9tlDe1I4BsgfcKpB5KEsZw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-history": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.27.1.tgz",
|
||||
"integrity": "sha512-K8PHC9gegSAt0wzSlsd4aUpoEyIJYOmVVeyniHr1P1mIblW1KYEDbRGbDlrLALTyUEfMcBhdIm8zrB9X2Nihvg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-horizontal-rule": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.27.1.tgz",
|
||||
"integrity": "sha512-WxXWGEEsqDmGIF2o9av+3r9Qje4CKrqrpeQY6aRO5bxvWX9AabQCfasepayBok6uwtvNzh3Xpsn9zbbSk09dNA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-italic": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.27.1.tgz",
|
||||
"integrity": "sha512-rcm0GyniWW0UhcNI9+1eIK64GqWQLyIIrWGINslvqSUoBc+WkfocLvv4CMpRkzKlfsAxwVIBuH2eLxHKDtAREA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-list-item": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.27.1.tgz",
|
||||
"integrity": "sha512-dtsxvtzxfwOJP6dKGf0vb2MJAoDF2NxoiWzpq0XTvo7NGGYUHfuHjX07Zp0dYqb4seaDXjwsi5BIQUOp3+WMFQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-ordered-list": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.27.1.tgz",
|
||||
"integrity": "sha512-U1/sWxc2TciozQsZjH35temyidYUjvroHj3PUPzPyh19w2fwKh1NSbFybWuoYs6jS3XnMSwnM2vF52tOwvfEmA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-paragraph": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.27.1.tgz",
|
||||
"integrity": "sha512-R3QdrHcUdFAsdsn2UAIvhY0yWyHjqGyP/Rv8RRdN0OyFiTKtwTPqreKMHKJOflgX4sMJl/OpHTpNG1Kaf7Lo2A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-placeholder": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-placeholder/-/extension-placeholder-2.27.1.tgz",
|
||||
"integrity": "sha512-UbXaibHHFE+lOTlw/vs3jPzBoj1sAfbXuTAhXChjgYIcTTY5Cr6yxwcymLcimbQ79gf04Xkua2FCN3YsJxIFmw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-strike": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.27.1.tgz",
|
||||
"integrity": "sha512-S9I//K8KPgfFTC5I5lorClzXk0g4lrAv9y5qHzHO5EOWt7AFl0YTg2oN8NKSIBK4bHRnPIrjJJKv+dDFnUp5jQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.27.1.tgz",
|
||||
"integrity": "sha512-a4GCT+GZ9tUwl82F4CEum9/+WsuW0/De9Be/NqrMmi7eNfAwbUTbLCTFU0gEvv25WMHCoUzaeNk/qGmzeVPJ1Q==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/extension-text-style": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.27.1.tgz",
|
||||
"integrity": "sha512-NagQ9qLk0Ril83gfrk+C65SvTqPjL3WVnLF2arsEVnCrxcx3uDOvdJW67f/K5HEwEHsoqJ4Zq9Irco/koXrOXA==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/pm": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-2.27.1.tgz",
|
||||
"integrity": "sha512-ijKo3+kIjALthYsnBmkRXAuw2Tswd9gd7BUR5OMfIcjGp8v576vKxOxrRfuYiUM78GPt//P0sVc1WV82H5N0PQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-changeset": "^2.3.0",
|
||||
"prosemirror-collab": "^1.3.1",
|
||||
"prosemirror-commands": "^1.6.2",
|
||||
"prosemirror-dropcursor": "^1.8.1",
|
||||
"prosemirror-gapcursor": "^1.3.2",
|
||||
"prosemirror-history": "^1.4.1",
|
||||
"prosemirror-inputrules": "^1.4.0",
|
||||
"prosemirror-keymap": "^1.2.2",
|
||||
"prosemirror-markdown": "^1.13.1",
|
||||
"prosemirror-menu": "^1.2.4",
|
||||
"prosemirror-model": "^1.23.0",
|
||||
"prosemirror-schema-basic": "^1.2.3",
|
||||
"prosemirror-schema-list": "^1.4.1",
|
||||
"prosemirror-state": "^1.4.3",
|
||||
"prosemirror-tables": "^1.6.4",
|
||||
"prosemirror-trailing-node": "^3.0.0",
|
||||
"prosemirror-transform": "^1.10.2",
|
||||
"prosemirror-view": "^1.37.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/react": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/react/-/react-2.27.1.tgz",
|
||||
"integrity": "sha512-leJximSjYJuhLJQv9azOP9R7w6zuxVgKOHYT4w83Gte7GhWMpNL6xRWzld280vyq/YW/cSYjPb/8ESEOgKNBdQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tiptap/extension-bubble-menu": "^2.27.1",
|
||||
"@tiptap/extension-floating-menu": "^2.27.1",
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"fast-deep-equal": "^3",
|
||||
"use-sync-external-store": "^1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.7.0",
|
||||
"@tiptap/pm": "^2.7.0",
|
||||
"react": "^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/starter-kit": {
|
||||
"version": "2.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.27.1.tgz",
|
||||
"integrity": "sha512-uQQlP0Nmn9eq19qm8YoOeloEfmcGbPpB1cujq54Q6nPgxaBozR7rE7tXbFTinxRW2+Hr7XyNWhpjB7DMNkdU2Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tiptap/core": "^2.27.1",
|
||||
"@tiptap/extension-blockquote": "^2.27.1",
|
||||
"@tiptap/extension-bold": "^2.27.1",
|
||||
"@tiptap/extension-bullet-list": "^2.27.1",
|
||||
"@tiptap/extension-code": "^2.27.1",
|
||||
"@tiptap/extension-code-block": "^2.27.1",
|
||||
"@tiptap/extension-document": "^2.27.1",
|
||||
"@tiptap/extension-dropcursor": "^2.27.1",
|
||||
"@tiptap/extension-gapcursor": "^2.27.1",
|
||||
"@tiptap/extension-hard-break": "^2.27.1",
|
||||
"@tiptap/extension-heading": "^2.27.1",
|
||||
"@tiptap/extension-history": "^2.27.1",
|
||||
"@tiptap/extension-horizontal-rule": "^2.27.1",
|
||||
"@tiptap/extension-italic": "^2.27.1",
|
||||
"@tiptap/extension-list-item": "^2.27.1",
|
||||
"@tiptap/extension-ordered-list": "^2.27.1",
|
||||
"@tiptap/extension-paragraph": "^2.27.1",
|
||||
"@tiptap/extension-strike": "^2.27.1",
|
||||
"@tiptap/extension-text": "^2.27.1",
|
||||
"@tiptap/extension-text-style": "^2.27.1",
|
||||
"@tiptap/pm": "^2.27.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ueberdosis"
|
||||
}
|
||||
},
|
||||
"node_modules/@turf/along": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@turf/along/-/along-7.2.0.tgz",
|
||||
|
|
@ -5625,6 +6044,28 @@
|
|||
"@types/geojson": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/markdown-it": {
|
||||
"version": "14.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz",
|
||||
"integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/linkify-it": "^5",
|
||||
"@types/mdurl": "^2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.24",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.24.tgz",
|
||||
|
|
@ -6495,7 +6936,6 @@
|
|||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true,
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/aria-hidden": {
|
||||
|
|
@ -7242,6 +7682,12 @@
|
|||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/crelt": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-env": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||
|
|
@ -8342,7 +8788,6 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
|
|
@ -10600,6 +11045,15 @@
|
|||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uc.micro": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
|
||||
|
|
@ -10724,6 +11178,35 @@
|
|||
"integrity": "sha512-gz6nNQoVK7Lkh2pZulrT4qd4347S/toG9RXH2pyzhLgkL5mLkBoqgv4EvAGXcV0ikDW72n/OQb3Xe8bGagQZCg==",
|
||||
"license": "AGPL-3.0"
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
||||
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "^4.4.0",
|
||||
"linkify-it": "^5.0.0",
|
||||
"mdurl": "^2.0.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"uc.micro": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"markdown-it": "bin/markdown-it.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it/node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
|
|
@ -10739,6 +11222,12 @@
|
|||
"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
|
|
@ -11154,6 +11643,12 @@
|
|||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/orderedmap": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.1.1.tgz",
|
||||
"integrity": "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/own-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz",
|
||||
|
|
@ -11616,6 +12111,201 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/prosemirror-changeset": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.3.1.tgz",
|
||||
"integrity": "sha512-j0kORIBm8ayJNl3zQvD1TTPHJX3g042et6y/KQhZhnPrruO8exkTgG8X+NRpj7kIyMMEx74Xb3DyMIBtO0IKkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-transform": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-collab": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz",
|
||||
"integrity": "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-commands": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.7.1.tgz",
|
||||
"integrity": "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.10.2"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-dropcursor": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.2.tgz",
|
||||
"integrity": "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.1.0",
|
||||
"prosemirror-view": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-gapcursor": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.4.0.tgz",
|
||||
"integrity": "sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-keymap": "^1.0.0",
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-view": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-history": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.5.0.tgz",
|
||||
"integrity": "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.2.2",
|
||||
"prosemirror-transform": "^1.0.0",
|
||||
"prosemirror-view": "^1.31.0",
|
||||
"rope-sequence": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-inputrules": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-inputrules/-/prosemirror-inputrules-1.5.1.tgz",
|
||||
"integrity": "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-keymap": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.3.tgz",
|
||||
"integrity": "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"w3c-keyname": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-markdown": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-markdown/-/prosemirror-markdown-1.13.2.tgz",
|
||||
"integrity": "sha512-FPD9rHPdA9fqzNmIIDhhnYQ6WgNoSWX9StUZ8LEKapaXU9i6XgykaHKhp6XMyXlOWetmaFgGDS/nu/w9/vUc5g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/markdown-it": "^14.0.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
"prosemirror-model": "^1.25.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-menu": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-menu/-/prosemirror-menu-1.2.5.tgz",
|
||||
"integrity": "sha512-qwXzynnpBIeg1D7BAtjOusR+81xCp53j7iWu/IargiRZqRjGIlQuu1f3jFi+ehrHhWMLoyOQTSRx/IWZJqOYtQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"crelt": "^1.0.0",
|
||||
"prosemirror-commands": "^1.0.0",
|
||||
"prosemirror-history": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-model": {
|
||||
"version": "1.25.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz",
|
||||
"integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"orderedmap": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-schema-basic": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.4.tgz",
|
||||
"integrity": "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.25.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-schema-list": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.5.1.tgz",
|
||||
"integrity": "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.7.3"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-state": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz",
|
||||
"integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.0.0",
|
||||
"prosemirror-transform": "^1.0.0",
|
||||
"prosemirror-view": "^1.27.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-tables": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-tables/-/prosemirror-tables-1.8.3.tgz",
|
||||
"integrity": "sha512-wbqCR/RlRPRe41a4LFtmhKElzBEfBTdtAYWNIGHM6X2e24NN/MTNUKyXjjphfAfdQce37Kh/5yf765mLPYDe7Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-keymap": "^1.2.3",
|
||||
"prosemirror-model": "^1.25.4",
|
||||
"prosemirror-state": "^1.4.4",
|
||||
"prosemirror-transform": "^1.10.5",
|
||||
"prosemirror-view": "^1.41.4"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-trailing-node": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-trailing-node/-/prosemirror-trailing-node-3.0.0.tgz",
|
||||
"integrity": "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@remirror/core-constants": "3.0.0",
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"prosemirror-model": "^1.22.1",
|
||||
"prosemirror-state": "^1.4.2",
|
||||
"prosemirror-view": "^1.33.8"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-transform": {
|
||||
"version": "1.10.5",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.10.5.tgz",
|
||||
"integrity": "sha512-RPDQCxIDhIBb1o36xxwsaeAvivO8VLJcgBtzmOwQ64bMtsVFh5SSuJ6dWSxO1UsHTiTXPCgQm3PDJt7p6IOLbw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/prosemirror-view": {
|
||||
"version": "1.41.4",
|
||||
"resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.4.tgz",
|
||||
"integrity": "sha512-WkKgnyjNncri03Gjaz3IFWvCAE94XoiEgvtr0/r2Xw7R8/IjK3sKLSiDoCHWcsXSAinVaKlGRZDvMCsF1kbzjA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.20.0",
|
||||
"prosemirror-state": "^1.0.0",
|
||||
"prosemirror-transform": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
|
|
@ -11631,6 +12321,15 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode.js": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pure-rand": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
|
||||
|
|
@ -12256,6 +12955,12 @@
|
|||
"integrity": "sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg==",
|
||||
"license": "Unlicense"
|
||||
},
|
||||
"node_modules/rope-sequence": {
|
||||
"version": "1.3.4",
|
||||
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
|
||||
"integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
|
|
@ -13125,6 +13830,15 @@
|
|||
"integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/tippy.js": {
|
||||
"version": "6.3.7",
|
||||
"resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
|
||||
"integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tldts": {
|
||||
"version": "7.0.17",
|
||||
"resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.17.tgz",
|
||||
|
|
@ -13441,6 +14155,12 @@
|
|||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unbox-primitive": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
|
||||
|
|
@ -13629,6 +14349,12 @@
|
|||
"d3-timer": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-keyname": {
|
||||
"version": "2.2.8",
|
||||
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/w3c-xmlserializer": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
"test:dataflow": "jest lib/services/__tests__/buttonDataflowPerformance.test.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tiptap/extension-placeholder": "^2.11.5",
|
||||
"@tiptap/pm": "^2.11.5",
|
||||
"@tiptap/react": "^2.11.5",
|
||||
"@tiptap/starter-kit": "^2.11.5",
|
||||
"@dnd-kit/core": "^6.3.1",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
|
|
|
|||
Loading…
Reference in New Issue