From f485bcc55873d2d89ba12fd5314d9590574d82df Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 14:00:52 +0900 Subject: [PATCH 01/19] =?UTF-8?q?build:=20uuid=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/client/package.json b/client/package.json index 29a4a505..b09a94e6 100644 --- a/client/package.json +++ b/client/package.json @@ -29,6 +29,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.14", "prettier": "^3.0.0", + "uuid": "^11.0.3", "vite": "^5.4.10", "vite-tsconfig-paths": "^5.1.0" } From 5d2ff9361740a56299a119852b60ea5b3fcfd872 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 14:06:22 +0900 Subject: [PATCH 02/19] =?UTF-8?q?feat:=20=EC=97=90=EB=94=94=ED=84=B0=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B8=94=EB=A1=9D=20=ED=83=80=EC=9E=85,=20?= =?UTF-8?q?=EC=97=B0=EA=B2=B0=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=20=EB=B8=94=EB=A1=9D=20=EA=B5=AC=EC=A1=B0=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/types/markdown.ts | 45 +++++++++++ client/src/utils/linkedLIstBlock.ts | 121 ++++++++++++++++++++++++++++ pnpm-lock.yaml | 9 +++ 3 files changed, 175 insertions(+) create mode 100644 client/src/types/markdown.ts create mode 100644 client/src/utils/linkedLIstBlock.ts diff --git a/client/src/types/markdown.ts b/client/src/types/markdown.ts new file mode 100644 index 00000000..738219a9 --- /dev/null +++ b/client/src/types/markdown.ts @@ -0,0 +1,45 @@ +export type ElementType = "p" | "h1" | "h2" | "h3" | "ul" | "ol" | "li" | "input" | "blockquote"; + +export interface ListProperties { + index?: number; + bulletStyle?: string; +} + +export interface MarkdownElement { + type: ElementType; + attributes?: Record; +} + +export interface EditorNode { + id: string; + type: ElementType; + content: string; + attributes?: Record; + + // 수평 연결 (같은 레벨의 노드들 간 연결) + prevNode: EditorNode | null; + nextNode: EditorNode | null; + + // 수직 연결 (부모-자식 관계) + parentNode: EditorNode | null; + firstChild: EditorNode | null; // 배열 대신 첫 번째 자식만 참조 + + // 형제 노드 간 연결 (같은 부모를 가진 노드들 간 연결) + prevSibling: EditorNode | null; + nextSibling: EditorNode | null; + + depth: number; + order: number; + listProperties?: ListProperties; +} + +export interface EditorState { + rootNode: EditorNode | null; + currentNode: EditorNode | null; +} + +export interface MarkdownPattern { + regex: RegExp; + length: number; + createElement: () => MarkdownElement; +} diff --git a/client/src/utils/linkedLIstBlock.ts b/client/src/utils/linkedLIstBlock.ts new file mode 100644 index 00000000..72e32d75 --- /dev/null +++ b/client/src/utils/linkedLIstBlock.ts @@ -0,0 +1,121 @@ +import { v4 as uuidv4 } from "uuid"; +import { EditorNode, ElementType } from "../types/markdown"; + +export class LinkedListBlock { + root: EditorNode | null; + current: EditorNode | null; + + constructor() { + const initialNode = this.createNode("p", "", null, null); + this.root = initialNode; + this.current = initialNode; + } + // 새로운 노드 생성 + createNode( + type: ElementType = "p", + content: string = "", + prevNode: EditorNode | null, + nextNode: EditorNode | null, + depth: number = 0, + ): EditorNode { + return { + id: uuidv4(), + type, + content, + prevNode, + nextNode, + parentNode: null, + firstChild: null, + prevSibling: null, + nextSibling: null, + depth, + order: 0, + listProperties: + type === "ul" ? { bulletStyle: "disc" } : type === "ol" ? { index: 1 } : undefined, + }; + } + + // 노드를 다른 노드 뒤에 삽입 + insertAfter(newNode: EditorNode, afterNode: EditorNode): void { + newNode.prevNode = afterNode; + newNode.nextNode = afterNode.nextNode; + + if (afterNode.nextNode) { + afterNode.nextNode.prevNode = newNode; + } + + afterNode.nextNode = newNode; + } + + // 노드 삭제 + removeNode(node: EditorNode): void { + if (node.prevNode) { + node.prevNode.nextNode = node.nextNode; + } + if (node.nextNode) { + node.nextNode.prevNode = node.prevNode; + } + + // root 노드인 경우 업데이트 + if (node === this.root) { + this.root = node.nextNode; + } + + Object.keys(node).forEach((key) => { + delete (node as any)[key]; + }); + } + + // 특정 ID를 가진 노드 찾기 + findNodeById(id: string): EditorNode | null { + const find = (node: EditorNode | null): EditorNode | null => { + if (!node) return null; + if (node.id === id) return node; + if (node.type === "ul" || node.type === "ol") { + let child = node.firstChild; + while (child) { + if (child.id === id) return child; + child = child.nextSibling; + } + } + return find(node.nextNode); + }; + + return find(this.root); + } + + // 마지막 자식 노드 찾기 + getLastChild(node: EditorNode): EditorNode { + let lastChild = node.firstChild!; + if (!lastChild.nextSibling?.id) { + return lastChild; + } else { + while (lastChild.nextSibling?.id) { + lastChild = lastChild.nextSibling; + } + return lastChild; + } + } + + // 노드를 순회하며 배열로 변환 + traverseNodes(): EditorNode[] { + const result: EditorNode[] = []; + const visited = new Set(); // 방문한 노드 추적 + + let current = this.root; + while (current) { + // 이미 방문한 노드라면 순환 참조로 판단하고 중단 + if (visited.has(current.id)) { + console.error("순환참조 에러 -> 뭐임?"); + break; + } + + visited.add(current.id); + result.push(current); + current = current.nextNode; + } + + return result; + } +} + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 789a39b5..f38feb06 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -105,6 +105,9 @@ importers: prettier: specifier: ^3.0.0 version: 3.3.3 + uuid: + specifier: ^11.0.3 + version: 11.0.3 vite: specifier: ^5.4.10 version: 5.4.10(@types/node@20.17.6)(lightningcss@1.25.1)(terser@5.36.0) @@ -4355,6 +4358,10 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + uuid@11.0.3: + resolution: {integrity: sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==} + hasBin: true + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -9511,6 +9518,8 @@ snapshots: utils-merge@1.0.1: {} + uuid@11.0.3: {} + v8-compile-cache-lib@3.0.1: {} v8-to-istanbul@9.3.0: From d82f7298c0c606aec08d54a5d15c38a9cb61c57a Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 14:07:46 +0900 Subject: [PATCH 03/19] =?UTF-8?q?feat:=20=EB=A7=88=ED=81=AC=EB=8B=A4?= =?UTF-8?q?=EC=9A=B4=20=ED=8C=A8=ED=84=B4=20=EB=B6=84=EC=84=9D=20=EC=A0=95?= =?UTF-8?q?=EA=B7=9C=ED=91=9C=ED=98=84=EC=8B=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/utils/markdownPattersn.ts | 50 ++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 client/src/utils/markdownPattersn.ts diff --git a/client/src/utils/markdownPattersn.ts b/client/src/utils/markdownPattersn.ts new file mode 100644 index 00000000..1a7deafd --- /dev/null +++ b/client/src/utils/markdownPattersn.ts @@ -0,0 +1,50 @@ +import { MarkdownElement, MarkdownPattern } from "../types/markdown"; + +const MARKDOWN_PATTERNS: Record = { + h1: { + regex: /^#$/, + length: 1, + createElement: () => ({ type: "h1" }), + }, + h2: { + regex: /^##$/, + length: 2, + createElement: () => ({ type: "h2" }), + }, + h3: { + regex: /^###$/, + length: 3, + createElement: () => ({ type: "h3" }), + }, + ul: { + regex: /^-$/, + length: 1, + createElement: () => ({ type: "ul" }), + }, + ol: { + regex: /^\d\.$/, + length: 2, + createElement: () => ({ type: "ol" }), + }, + blockquote: { + regex: /^>$/, + length: 1, + createElement: () => ({ type: "blockquote" }), + }, + checkbox: { + regex: /^>$/, + length: 1, + createElement: () => ({ type: "input" }), + }, +}; + +export const checkMarkdownPattern = (text: string): MarkdownElement | null => { + if (!text) return null; + + for (const pattern of Object.values(MARKDOWN_PATTERNS)) { + if (pattern.regex.test(text)) { + return pattern.createElement(); + } + } + return null; +}; From fd9bbc8b72a0b56d36b065e5dbb737892f6db0c6 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 14:09:52 +0900 Subject: [PATCH 04/19] =?UTF-8?q?feat:=20=EC=BA=90=EB=9F=BF=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=9B=85=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useCaretManager.ts | 52 +++++++++++++++++++ ...arkdownPattersn.ts => markdownPatterns.ts} | 0 2 files changed, 52 insertions(+) create mode 100644 client/src/hooks/useCaretManager.ts rename client/src/utils/{markdownPattersn.ts => markdownPatterns.ts} (100%) diff --git a/client/src/hooks/useCaretManager.ts b/client/src/hooks/useCaretManager.ts new file mode 100644 index 00000000..d13470ab --- /dev/null +++ b/client/src/hooks/useCaretManager.ts @@ -0,0 +1,52 @@ +import { useCallback, useRef } from "react"; + +export const useCaretManager = () => { + const caretRangeRef = useRef(null); + + // 커서 위치 저장 함수 + const saveCaretPosition = useCallback(() => { + const selection = window.getSelection(); + if (selection && selection.rangeCount > 0) { + caretRangeRef.current = selection.getRangeAt(0); + } + }, []); + + // 커서 위치 복원 함수 + const restoreCaretPosition = useCallback(() => { + const selection = window.getSelection(); + if (selection && caretRangeRef.current) { + selection.removeAllRanges(); + selection.addRange(caretRangeRef.current); + } + }, []); + + // 커서 위치 설정 함수 + const setCaretPosition = useCallback((element: HTMLElement | null, position: number = 0) => { + if (!element) return; + + const selection = window.getSelection(); + if (!selection) return; + + selection.removeAllRanges(); + + const range = document.createRange(); + + let textNode: Text; + if (element.firstChild && element.firstChild.nodeType === Node.TEXT_NODE) { + textNode = element.firstChild as Text; + } else { + textNode = document.createTextNode(element.textContent || ""); + element.appendChild(textNode); + } + + const actualPosition = Math.min(position, textNode.length); + + range.setStart(textNode, actualPosition); + range.collapse(true); + + selection.addRange(range); + element.focus(); + }, []); + + return { saveCaretPosition, restoreCaretPosition, setCaretPosition }; +}; \ No newline at end of file diff --git a/client/src/utils/markdownPattersn.ts b/client/src/utils/markdownPatterns.ts similarity index 100% rename from client/src/utils/markdownPattersn.ts rename to client/src/utils/markdownPatterns.ts From 6dfc50772a03518f74c510b83887400eb5bdd61d Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 14:21:52 +0900 Subject: [PATCH 05/19] =?UTF-8?q?style:=20=EB=B8=94=EB=A1=9D=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20pandacss=20=EA=B5=AC=EC=A1=B0=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/block/Block.style.ts | 115 +++++++++++++++++++++ client/src/components/block/Block.tsx | 0 2 files changed, 115 insertions(+) create mode 100644 client/src/components/block/Block.style.ts create mode 100644 client/src/components/block/Block.tsx diff --git a/client/src/components/block/Block.style.ts b/client/src/components/block/Block.style.ts new file mode 100644 index 00000000..e3e7f32a --- /dev/null +++ b/client/src/components/block/Block.style.ts @@ -0,0 +1,115 @@ +import { defineRecipe } from "@pandacss/dev"; + +export const editorRecipe = defineRecipe({ + className: 'editor', + base: { + marginLeft: '100px', + color: 'gray.900', + }, + variants: { + type: { + base: { + width: 'full', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'gray.100', + outline: 'none', + textStyle: 'display-medium16', // 기본 텍스트 스타일 적용 + }, + paragraph: { + width: 'full', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'gray.100', + outline: 'none', + textStyle: 'display-medium16', + }, + heading1: { + width: 'full', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'gray.100', + outline: 'none', + textStyle: 'display-medium24', // 큰 제목용 텍스트 스타일 + fontWeight: 'bold', + }, + heading2: { + width: 'full', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'gray.100', + outline: 'none', + textStyle: 'display-medium20', // 중간 제목용 텍스트 스타일 + fontWeight: 'bold', + }, + heading3: { + width: 'full', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'gray.100', + outline: 'none', + textStyle: 'display-medium16', // 작은 제목용 텍스트 스타일 + fontWeight: 'bold', + }, + unorderedList: { + width: 'full', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'gray.100', + outline: 'none', + listStyleType: 'disc', + textStyle: 'display-medium16', + }, + orderedList: { + width: 'full', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'gray.100', + outline: 'none', + listStyleType: 'decimal', + textStyle: 'display-medium16', + }, + listItem: { + margin: '0', + padding: '0', + outline: 'none', + textStyle: 'display-medium16', + }, + input: { + margin: 'spacing.sm 0', + textStyle: 'display-medium16', + }, + blockquote: { + width: '1000px', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'gray.100', + outline: 'none', + borderLeft: '4px solid token(colors.gray.300)', + paddingLeft: 'spacing.md', + fontStyle: 'italic', + color: 'gray.700', + textStyle: 'display-medium16', + }, + } + }, + defaultVariants: { + type: 'base' + } +}) \ No newline at end of file diff --git a/client/src/components/block/Block.tsx b/client/src/components/block/Block.tsx new file mode 100644 index 00000000..e69de29b From 2c363f512d876a26660271b4ed8714b96cc554bf Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 14:33:58 +0900 Subject: [PATCH 06/19] =?UTF-8?q?feat:=20=EB=B8=94=EB=A1=9D=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/block/Block.style.ts | 193 +++++++++------------ client/src/components/block/Block.tsx | 72 ++++++++ 2 files changed, 151 insertions(+), 114 deletions(-) diff --git a/client/src/components/block/Block.style.ts b/client/src/components/block/Block.style.ts index e3e7f32a..c2555ddb 100644 --- a/client/src/components/block/Block.style.ts +++ b/client/src/components/block/Block.style.ts @@ -1,115 +1,80 @@ -import { defineRecipe } from "@pandacss/dev"; +import { css, cx } from '@styled-system/css'; -export const editorRecipe = defineRecipe({ - className: 'editor', - base: { - marginLeft: '100px', - color: 'gray.900', - }, - variants: { - type: { - base: { - width: 'full', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'gray.100', - outline: 'none', - textStyle: 'display-medium16', // 기본 텍스트 스타일 적용 - }, - paragraph: { - width: 'full', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'gray.100', - outline: 'none', - textStyle: 'display-medium16', - }, - heading1: { - width: 'full', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'gray.100', - outline: 'none', - textStyle: 'display-medium24', // 큰 제목용 텍스트 스타일 - fontWeight: 'bold', - }, - heading2: { - width: 'full', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'gray.100', - outline: 'none', - textStyle: 'display-medium20', // 중간 제목용 텍스트 스타일 - fontWeight: 'bold', - }, - heading3: { - width: 'full', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'gray.100', - outline: 'none', - textStyle: 'display-medium16', // 작은 제목용 텍스트 스타일 - fontWeight: 'bold', - }, - unorderedList: { - width: 'full', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'gray.100', - outline: 'none', - listStyleType: 'disc', - textStyle: 'display-medium16', - }, - orderedList: { - width: 'full', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'gray.100', - outline: 'none', - listStyleType: 'decimal', - textStyle: 'display-medium16', - }, - listItem: { - margin: '0', - padding: '0', - outline: 'none', - textStyle: 'display-medium16', - }, - input: { - margin: 'spacing.sm 0', - textStyle: 'display-medium16', - }, - blockquote: { - width: '1000px', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'gray.100', - outline: 'none', - borderLeft: '4px solid token(colors.gray.300)', - paddingLeft: 'spacing.md', - fontStyle: 'italic', - color: 'gray.700', - textStyle: 'display-medium16', - }, - } - }, - defaultVariants: { - type: 'base' - } -}) \ No newline at end of file +// 기본 블록 스타일 정의 +const baseBlockStyle = css({ + width: 'full', + margin: 'spacing.sm 0', + minHeight: 'spacing.lg', + padding: 'spacing.sm', + borderRadius: 'radii.xs', + backgroundColor: 'transparent', + outline: 'none', + textStyle: 'display-medium16', +}); + +// 각 블록 타입별 스타일 정의 +export const blockContainer = { + base: baseBlockStyle, + + paragraph: baseBlockStyle, + + heading1: cx( + baseBlockStyle, + css({ + textStyle: 'display-medium24', + fontWeight: 'bold', + }) + ), + + heading2: cx( + baseBlockStyle, + css({ + textStyle: 'display-medium20', + fontWeight: 'bold', + }) + ), + + heading3: cx( + baseBlockStyle, + css({ + textStyle: 'display-medium16', + fontWeight: 'bold', + }) + ), + + unorderedList: cx( + baseBlockStyle, + css({ + listStyleType: 'disc', + }) + ), + + orderedList: cx( + baseBlockStyle, + css({ + listStyleType: 'decimal', + }) + ), + + listItem: css({ + margin: '0', + padding: '0', + outline: 'none', + textStyle: 'display-medium16', + }), + + input: css({ + margin: 'spacing.sm 0', + textStyle: 'display-medium16', + }), + + blockquote: cx( + baseBlockStyle, + css({ + borderLeft: '4px solid token(colors.gray.300)', + paddingLeft: 'spacing.md', + fontStyle: 'italic', + color: 'gray.700', + }) + ), +}; \ No newline at end of file diff --git a/client/src/components/block/Block.tsx b/client/src/components/block/Block.tsx index e69de29b..84f5e34f 100644 --- a/client/src/components/block/Block.tsx +++ b/client/src/components/block/Block.tsx @@ -0,0 +1,72 @@ +import React, { memo } from "react"; +import { cx } from "@styled-system/css"; +import { EditorNode } from "../../types/markdown"; +import { blockContainer } from "./Block.style"; + +interface BlockProps { + node: EditorNode; + isActive: boolean; + contentRef?: React.RefObject; + onKeyDown: (e: React.KeyboardEvent) => void; + onCompositionStart: () => void; + onCompositionEnd: () => void; + onInput: (e: React.KeyboardEvent) => void; + onClick: (nodeId: string) => void; + currentNodeId: string; +} + +export const Block: React.FC = memo( + ({ + node, + isActive, + contentRef, + onKeyDown, + onCompositionStart, + onCompositionEnd, + onInput, + onClick, + }: BlockProps) => { + const handleClick = (e: React.MouseEvent) => { + e.preventDefault(); + onClick(node.id); + }; + + // node.type에 따른 스타일 선택 + const getBlockStyle = (type: string) => { + switch(type) { + case 'p': return blockContainer.paragraph; + case 'h1': return blockContainer.heading1; + case 'h2': return blockContainer.heading2; + case 'h3': return blockContainer.heading3; + case 'ul': return blockContainer.unorderedList; + case 'ol': return blockContainer.orderedList; + case 'li': return blockContainer.listItem; + case 'blockquote': return blockContainer.blockquote; + case 'input': return blockContainer.input; + default: return blockContainer.base; + } + }; + + const commonProps = { + "data-node-id": node.id, + "data-depth": node.depth, + onKeyDown, + onInput, + onCompositionStart, + onCompositionEnd, + onClick: handleClick, + ref: isActive ? contentRef : undefined, + contentEditable: true, + suppressContentEditableWarning: true, + dangerouslySetInnerHTML: { __html: node.content }, + className: cx( + getBlockStyle(node.type), + ), + }; + + return React.createElement(node.type, commonProps); + }, +); + +// 메모이제이션을 위한 displayName 설정 +Block.displayName = "Block"; \ No newline at end of file From 99443944acda0dd3914a950bf4d80560759566d4 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 14:45:48 +0900 Subject: [PATCH 07/19] =?UTF-8?q?feat:=20=ED=82=A4=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EB=B3=84=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=ED=95=B8=EB=93=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=BB=A4=EC=8A=A4=ED=85=80=20=ED=9B=85=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #009 #010 #011 #012 #016 --- .../useMarkdownGrammer/handlers/arrow.ts | 55 ++++++ .../useMarkdownGrammer/handlers/backSpace.ts | 162 ++++++++++++++++++ .../useMarkdownGrammer/handlers/enter.ts | 155 +++++++++++++++++ .../handlers/handlerProps.ts | 9 + .../useMarkdownGrammer/handlers/space.ts | 57 ++++++ client/src/hooks/useMarkdownGrammer/index.ts | 87 ++++++++++ 6 files changed, 525 insertions(+) create mode 100644 client/src/hooks/useMarkdownGrammer/handlers/arrow.ts create mode 100644 client/src/hooks/useMarkdownGrammer/handlers/backSpace.ts create mode 100644 client/src/hooks/useMarkdownGrammer/handlers/enter.ts create mode 100644 client/src/hooks/useMarkdownGrammer/handlers/handlerProps.ts create mode 100644 client/src/hooks/useMarkdownGrammer/handlers/space.ts create mode 100644 client/src/hooks/useMarkdownGrammer/index.ts diff --git a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts new file mode 100644 index 00000000..d15f3e93 --- /dev/null +++ b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts @@ -0,0 +1,55 @@ +import { useCallback } from "react"; +import { EditorNode } from "../../../types/markdown"; +import { KeyHandlerProps } from "./handlerProps"; + +export const useArrowKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandlerProps) => { + return useCallback( + (e: React.KeyboardEvent) => { + e.preventDefault(); + const { currentNode } = editorState; + if (!currentNode) return; + + let targetNode: EditorNode | null = null; + switch (e.key) { + case "ArrowUp": + if (currentNode.prevNode?.type === "ul" || currentNode.prevNode?.type === "ol") { + targetNode = editorList.getLastChild(currentNode.prevNode!); + } else if (currentNode.type === "li") { + if (currentNode.prevSibling?.id) { + targetNode = currentNode.prevSibling; + } else { + if (currentNode.parentNode?.prevNode) { + targetNode = currentNode.parentNode?.prevNode; + } else return; + } + } else { + targetNode = currentNode.prevNode; + } + break; + case "ArrowDown": + if (currentNode.nextNode?.type === "ul" || currentNode.nextNode?.type === "ol") { + targetNode = currentNode.nextNode!.firstChild; + } else if (currentNode.type === "li") { + if (currentNode.nextSibling?.id) { + targetNode = currentNode.nextSibling; + } else { + if (currentNode.parentNode?.nextNode) { + targetNode = currentNode.parentNode?.nextNode; + } else return; + } + } else { + targetNode = currentNode.nextNode; + } + break; + } + + if (targetNode) { + setEditorState((prev) => ({ + ...prev, + currentNode: targetNode, + })); + } + }, + [editorState, editorList, setEditorState], + ); +}; \ No newline at end of file diff --git a/client/src/hooks/useMarkdownGrammer/handlers/backSpace.ts b/client/src/hooks/useMarkdownGrammer/handlers/backSpace.ts new file mode 100644 index 00000000..3dd55039 --- /dev/null +++ b/client/src/hooks/useMarkdownGrammer/handlers/backSpace.ts @@ -0,0 +1,162 @@ +import { useCallback } from "react"; +import { EditorNode } from "../../../types/markdown"; +import { KeyHandlerProps } from "./handlerProps"; + +export const useBackspaceKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandlerProps) => { + return useCallback( + (e: React.KeyboardEvent) => { + const { currentNode } = editorState; + if (!currentNode || currentNode.content.length > 0) return; + if (currentNode === editorState.rootNode && currentNode.type === "p") return; + + e.preventDefault(); + if (currentNode.type === "li") { + const { parentNode } = currentNode; + if (!parentNode) return; + + const isLastItem = parentNode.firstChild === currentNode; + + if (isLastItem) { + // 리스트를 p 태그로 변환 + const newNode = { + ...currentNode, + type: "p", + content: "", + prevNode: parentNode.prevNode, + nextNode: parentNode.nextNode, + } as EditorNode; + if (parentNode.prevNode) { + editorList.insertAfter(newNode, parentNode.prevNode); + editorList.removeNode(parentNode); + editorList.removeNode(currentNode); + } else { + newNode.prevNode = null; + newNode.nextNode = parentNode.nextNode; + editorList.insertAfter(newNode, parentNode); + editorList.removeNode(parentNode); + editorList.removeNode(currentNode); + } + + // 연결 관계 설정 + if (parentNode.prevNode) { + parentNode.prevNode.nextNode = newNode; + } + + // root 노드 업데이트 + if (parentNode === editorState.rootNode) { + editorList.root = newNode; + } + + setEditorState((prev) => ({ + ...prev, + rootNode: parentNode === prev.rootNode ? newNode : prev.rootNode, + currentNode: newNode, + })); + editorList.current = newNode; + } else { + if (currentNode.nextSibling?.id) { + const newNode = { + ...currentNode, + type: "p", + content: "", + parentNode: null, + prevNode: parentNode.prevNode, + nextNode: parentNode.nextNode, + } as EditorNode; + const newParentList = editorList.createNode( + parentNode.type, + "", + null, + null, + parentNode.depth, + ); + + // 현재 노드의 다음 형제들을 새 리스트로 이동 + let sibling = currentNode.nextSibling; + if (sibling) { + newParentList.firstChild = sibling; + let prevSibling = null; + + while (sibling) { + const nextSibling = sibling.nextSibling as EditorNode | null; + sibling.parentNode = newParentList; + sibling.prevSibling = prevSibling; + if (prevSibling) { + prevSibling.nextSibling = sibling; + } + prevSibling = sibling; + sibling = nextSibling!; + } + } + + // 이전 형제 노드와의 연결 해제 + if (currentNode.prevSibling) { + currentNode.prevSibling.nextSibling = null; + } + + // 원래 부모 리스트의 다음 노드 저장 + const originalNextNode = parentNode.nextNode; + + // 새로운 노드들 간의 연결 설정 + newNode.prevNode = parentNode; + newNode.nextNode = newParentList; + parentNode.nextNode = newNode; + newParentList.prevNode = newNode; + + // 원래 다음 노드가 있었다면 연결 유지 + if (originalNextNode) { + newParentList.nextNode = originalNextNode; + originalNextNode.prevNode = newParentList; + } + + // 현재 노드와 새 리스트의 관계 초기화 + currentNode.nextSibling = null; + currentNode.prevSibling = null; + currentNode.parentNode = null; + + // 현재 노드 제거 + editorList.removeNode(currentNode); + setEditorState((prev) => ({ + ...prev, + currentNode: newNode, + })); + } else { + // 리스트 아이템 제거 + const focusNode = currentNode.prevSibling || currentNode.parentNode; + editorList.removeNode(currentNode); + + setEditorState((prev) => ({ + ...prev, + currentNode: focusNode, + })); + } + } + } else { + if (currentNode.type !== "p") { + // 기본 p 태그로 변환 + currentNode.type = "p"; + setEditorState((prev) => ({ ...prev })); + } else { + let focusNode; + if (currentNode.prevNode?.type === "ul" || currentNode.prevNode?.type === "ol") { + focusNode = editorList.getLastChild(currentNode.prevNode); + } else { + focusNode = currentNode.prevNode || currentNode.parentNode; + } + editorList.removeNode(currentNode); + + if (focusNode === editorState.rootNode) { + editorList.root = focusNode; + } + + setEditorState((prev) => ({ + ...prev, + rootNode: currentNode === prev.rootNode ? focusNode : prev.rootNode, + currentNode: focusNode, + })); + } + } + }, + [editorState, editorList, setEditorState], + ); +}; \ No newline at end of file diff --git a/client/src/hooks/useMarkdownGrammer/handlers/enter.ts b/client/src/hooks/useMarkdownGrammer/handlers/enter.ts new file mode 100644 index 00000000..fca06a28 --- /dev/null +++ b/client/src/hooks/useMarkdownGrammer/handlers/enter.ts @@ -0,0 +1,155 @@ +import { useCallback } from "react"; +import { EditorNode } from "../../../types/markdown"; +import { KeyHandlerProps } from "./handlerProps"; + +export const useEnterKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandlerProps) => { + return useCallback( + (e: React.KeyboardEvent) => { + e.preventDefault(); + const { currentNode } = editorState; + if (!currentNode) return; + + const selection = window.getSelection(); + const caretPosition = selection?.focusOffset || 0; + const { content } = currentNode; + + const beforeText = content.slice(0, caretPosition); + const afterText = content.slice(caretPosition); + + if (currentNode.type === "li") { + const { parentNode } = currentNode; + if (!parentNode) return; + + if (content.length === 0) { + const isLastItem = currentNode.nextSibling === null; + const newNode = editorList.createNode("p", "", null, null, 0); + + if (isLastItem) { + // 마지막 아이템인 경우 + // 이전 형제 노드와의 연결 해제 + if (currentNode.prevSibling) { + currentNode.prevSibling.nextSibling = null; + } else { + parentNode.firstChild = null; + } + + // 새 노드와 부모 리스트 노드 사이의 연결 설정 + newNode.prevNode = parentNode; + + if (parentNode.nextNode) { + newNode.nextNode = parentNode.nextNode; + parentNode.nextNode.prevNode = newNode; + } + + parentNode.nextNode = newNode; + + // 현재 노드 제거 전 연결 관계 정리 + if (currentNode.prevSibling) { + currentNode.prevSibling.nextSibling = null; + } + if (currentNode.nextSibling) { + currentNode.nextSibling.prevSibling = null; + } + + editorList.removeNode(currentNode); + } else { + // 중간 아이템인 경우 + // 새로운 리스트 생성 + const newParentList = editorList.createNode( + parentNode.type, + "", + null, + null, + parentNode.depth, + ); + + // 현재 노드의 다음 형제들을 새 리스트로 이동 + let sibling = currentNode.nextSibling; + if (sibling) { + newParentList.firstChild = sibling; + let prevSibling = null; + + while (sibling) { + const nextSibling = sibling.nextSibling as EditorNode | null; + sibling.parentNode = newParentList; + sibling.prevSibling = prevSibling; + if (prevSibling) { + prevSibling.nextSibling = sibling; + } + prevSibling = sibling; + sibling = nextSibling; + } + } + + // 이전 형제 노드와의 연결 해제 + if (currentNode.prevSibling) { + currentNode.prevSibling.nextSibling = null; + } + + // 원래 부모 리스트의 다음 노드 저장 + const originalNextNode = parentNode.nextNode; + + // 새로운 노드들 간의 연결 설정 + newNode.prevNode = parentNode; + newNode.nextNode = newParentList; + parentNode.nextNode = newNode; + newParentList.prevNode = newNode; + + // 원래 다음 노드가 있었다면 연결 유지 + if (originalNextNode) { + newParentList.nextNode = originalNextNode; + originalNextNode.prevNode = newParentList; + } + + // 현재 노드와 새 리스트의 관계 초기화 + currentNode.nextSibling = null; + currentNode.prevSibling = null; + currentNode.parentNode = null; + + // 현재 노드 제거 + editorList.removeNode(currentNode); + } + + setEditorState((prev) => ({ + ...prev, + currentNode: newNode, + })); + } else { + // 텍스트가 있는 경우 새로운 li 추가 + currentNode.content = beforeText; + const newNode = editorList.createNode("li", afterText, null, null, currentNode.depth); + newNode.parentNode = parentNode; + + // siblings 관계 설정 + newNode.prevSibling = currentNode; + if (currentNode.nextSibling) { + newNode.nextSibling = currentNode.nextSibling; + currentNode.nextSibling.prevSibling = newNode; + } + currentNode.nextSibling = newNode; + + setEditorState((prev) => ({ + ...prev, + currentNode: newNode, + })); + } + } else { + // 일반 블록은 항상 p 태그로 새 블록 생성 + currentNode.content = beforeText; + const newNode = editorList.createNode("p", afterText, currentNode, currentNode.nextNode); + + // 연결 관계 설정 + if (currentNode.nextNode) { + currentNode.nextNode.prevNode = newNode; + } + currentNode.nextNode = newNode; + + setEditorState((prev) => ({ + ...prev, + currentNode: newNode, + })); + } + }, + [editorState, editorList, setEditorState], + ); +}; \ No newline at end of file diff --git a/client/src/hooks/useMarkdownGrammer/handlers/handlerProps.ts b/client/src/hooks/useMarkdownGrammer/handlers/handlerProps.ts new file mode 100644 index 00000000..9bf08c4b --- /dev/null +++ b/client/src/hooks/useMarkdownGrammer/handlers/handlerProps.ts @@ -0,0 +1,9 @@ +import { EditorState, MarkdownElement } from "../../../types/markdown"; +import { LinkedListBlock } from "../../../utils/linkedLIstBlock"; + +export interface KeyHandlerProps { + editorState: EditorState; + editorList: LinkedListBlock; + setEditorState: React.Dispatch>; + checkMarkdownPattern: (text: string) => MarkdownElement | null; +} \ No newline at end of file diff --git a/client/src/hooks/useMarkdownGrammer/handlers/space.ts b/client/src/hooks/useMarkdownGrammer/handlers/space.ts new file mode 100644 index 00000000..ec0cf555 --- /dev/null +++ b/client/src/hooks/useMarkdownGrammer/handlers/space.ts @@ -0,0 +1,57 @@ +import { useCallback } from "react"; +import { KeyHandlerProps } from "./handlerProps"; + +export const useSpaceKeyHandler = ({ + editorState, + editorList, + setEditorState, + checkMarkdownPattern, +}: KeyHandlerProps) => { + return useCallback( + (e: React.KeyboardEvent) => { + if (editorState.currentNode?.type !== "p") return; + const text = (e.target as HTMLElement).textContent || ""; + const newElement = checkMarkdownPattern(text); + + if (newElement) { + e.preventDefault(); + const { currentNode } = editorState; + if (!currentNode) return; + + if (newElement.type === "ul" || newElement.type === "ol") { + // 기존 노드의 위치 관계 저장 + const { prevNode, nextNode } = currentNode; + const wasRoot = currentNode.prevNode === null; + const parentListNode = editorList.createNode(newElement.type, "", prevNode, nextNode); + const listNode = editorList.createNode("li", "", null, null, 1); + parentListNode.firstChild = listNode; + listNode.parentNode = parentListNode; + // root 노드 업데이트 + if (wasRoot) { + editorList.root = parentListNode; + } else { + if (prevNode) { + prevNode.nextNode = parentListNode; + } + if (nextNode) { + nextNode.prevNode = parentListNode; + } + } + + setEditorState((prev) => ({ + ...prev, + rootNode: wasRoot ? parentListNode : prev.rootNode, + currentNode: listNode, + })); + } else { + // 기존 노드의 타입만 변경 + currentNode.type = newElement.type; + currentNode.content = ""; + + setEditorState((prev) => ({ ...prev })); + } + } + }, + [editorState, editorList, checkMarkdownPattern, setEditorState], + ); +}; \ No newline at end of file diff --git a/client/src/hooks/useMarkdownGrammer/index.ts b/client/src/hooks/useMarkdownGrammer/index.ts new file mode 100644 index 00000000..2a225803 --- /dev/null +++ b/client/src/hooks/useMarkdownGrammer/index.ts @@ -0,0 +1,87 @@ +import { useCallback } from "react"; +import { KeyHandlerProps } from "./handlers/handlerProps"; +import { useSpaceKeyHandler } from "./handlers/space"; +import { useBackspaceKeyHandler } from "./handlers/backSpace"; +import { useEnterKeyHandler } from "./handlers/enter"; +import { useArrowKeyHandler } from "./handlers/arrow"; + +export const useKeyboardHandlers = (props: KeyHandlerProps) => { + const handleEnter = useEnterKeyHandler(props); + const handleSpace = useSpaceKeyHandler(props); + const handleBackspace = useBackspaceKeyHandler(props); + const handleArrow = useArrowKeyHandler(props); + // const handleTab = useTabKeyHandler(props); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + switch (e.key) { + case "Enter": + if (!e.shiftKey) handleEnter(e); + break; + case " ": + handleSpace(e); + break; + case "Backspace": + handleBackspace(e); + break; + case "ArrowUp": + case "ArrowDown": + handleArrow(e); + break; + case "Tab": + /* + handleTab(e); + */ + break; + } + }, + [handleEnter, handleSpace, handleBackspace, handleArrow], + ); + + return { handleKeyDown }; +}; + + +/* +const useTabKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandlerProps) => { + return useCallback( + (e: React.KeyboardEvent) => { + e.preventDefault(); + const { currentNode } = editorState; + if (!currentNode) return; + + if (currentNode.type === "li") { + if (e.shiftKey) { + // 들여쓰기 감소 + if (currentNode.depth > 1) { + editorList.decreaseIndent(currentNode); + + // 형제 노드들의 depth도 함께 조정 + let sibling = currentNode.nextSibling; + while (sibling) { + editorList.decreaseIndent(sibling); + sibling = sibling.nextSibling; + } + } + } else { + // 들여쓰기 증가 + if (currentNode.prevSibling) { + // 첫 번째 아이템이 아닌 경우만 + editorList.increaseIndent(currentNode); + + // 형제 노드들의 depth도 함께 조정 + let sibling = currentNode.nextSibling; + while (sibling) { + editorList.increaseIndent(sibling); + sibling = sibling.nextSibling; + } + } + } + } + + setEditorState((prev) => ({ ...prev })); + }, + [editorState, editorList, setEditorState], + ); +}; +*/ \ No newline at end of file From d3affd5aeeecff0301fe39d97dd0c4df9f341365 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 15:16:11 +0900 Subject: [PATCH 08/19] =?UTF-8?q?feat:=20=EC=97=90=EB=94=94=ED=84=B0=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/block/Block.style.ts | 14 +- client/src/features/editor/Editor.style.ts | 15 +++ client/src/features/editor/Editor.tsx | 126 +++++++++++++++++- .../useMarkdownGrammer/handlers/space.ts | 14 ++ 4 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 client/src/features/editor/Editor.style.ts diff --git a/client/src/components/block/Block.style.ts b/client/src/components/block/Block.style.ts index c2555ddb..a87dd547 100644 --- a/client/src/components/block/Block.style.ts +++ b/client/src/components/block/Block.style.ts @@ -8,6 +8,7 @@ const baseBlockStyle = css({ padding: 'spacing.sm', borderRadius: 'radii.xs', backgroundColor: 'transparent', + color: 'gray.700', outline: 'none', textStyle: 'display-medium16', }); @@ -23,6 +24,7 @@ export const blockContainer = { css({ textStyle: 'display-medium24', fontWeight: 'bold', + color: 'gray.900', }) ), @@ -31,6 +33,7 @@ export const blockContainer = { css({ textStyle: 'display-medium20', fontWeight: 'bold', + color: 'gray.900', }) ), @@ -39,6 +42,7 @@ export const blockContainer = { css({ textStyle: 'display-medium16', fontWeight: 'bold', + color: 'gray.900', }) ), @@ -46,6 +50,8 @@ export const blockContainer = { baseBlockStyle, css({ listStyleType: 'disc', + listStylePosition: 'inside', + display: 'block', }) ), @@ -53,14 +59,18 @@ export const blockContainer = { baseBlockStyle, css({ listStyleType: 'decimal', + listStylePosition: 'inside', + display: 'block', }) ), listItem: css({ margin: '0', - padding: '0', + padding: '0 0 0 spacing.md', outline: 'none', textStyle: 'display-medium16', + color: 'gray.700', + display: 'list-item', // 리스트 아이템으로 표시되도록 설정 }), input: css({ @@ -74,7 +84,7 @@ export const blockContainer = { borderLeft: '4px solid token(colors.gray.300)', paddingLeft: 'spacing.md', fontStyle: 'italic', - color: 'gray.700', + color: 'gray.500', }) ), }; \ No newline at end of file diff --git a/client/src/features/editor/Editor.style.ts b/client/src/features/editor/Editor.style.ts new file mode 100644 index 00000000..b8a4b96a --- /dev/null +++ b/client/src/features/editor/Editor.style.ts @@ -0,0 +1,15 @@ +import { css } from "@styled-system/css"; + +export const editorContainer = css({ + width: "full", + height: "full", // 부모 컴포넌트의 header(60px)를 제외한 높이 + margin: "spacing.lg", // 16px margin + padding: "24px", // 24px padding + overflowY: "auto", // 내용이 많을 경우 스크롤 + _focus: { + outline: "none", + }, + display: "flex", + flexDirection: "column", + gap: "spacing.sm", +}); \ No newline at end of file diff --git a/client/src/features/editor/Editor.tsx b/client/src/features/editor/Editor.tsx index ab4d8132..d146e676 100644 --- a/client/src/features/editor/Editor.tsx +++ b/client/src/features/editor/Editor.tsx @@ -1,7 +1,129 @@ +import { useRef, useState, useCallback, useEffect } from "react"; +import { EditorState } from "../../types/markdown"; +import { Block } from "@components/block/Block"; +import { useCaretManager } from "../../hooks/useCaretManager"; +import { LinkedListBlock } from "../../utils/linkedLIstBlock"; +import { checkMarkdownPattern } from "../../utils/markdownPatterns"; +import { useKeyboardHandlers } from "../../hooks/useMarkdownGrammer"; +import { editorContainer } from "./Editor.style"; + export const Editor = () => { + const [editorList] = useState(() => new LinkedListBlock()); + const [editorState, setEditorState] = useState(() => ({ + rootNode: editorList.root, + currentNode: editorList.current, + })); + const [isComposing, setIsComposing] = useState(false); + + const contentRef = useRef(null); + const { setCaretPosition } = useCaretManager(); + + const { handleKeyDown } = useKeyboardHandlers({ + editorState, + editorList, + setEditorState, + checkMarkdownPattern, + }); + + const handleBlockClick = useCallback( + (nodeId: string) => { + const node = editorList.findNodeById(nodeId); + if (node) { + setEditorState((prev) => ({ + ...prev, + currentNode: node, + })); + } + }, + [editorList], + ); + + const handleCompositionStart = useCallback(() => { + setIsComposing(true); + }, []); + + const handleCompositionEnd = useCallback(() => { + setIsComposing(false); + }, []); + + const handleInput = useCallback(() => { + if (isComposing) return; + + if (contentRef.current && editorState.currentNode) { + const newContent = contentRef.current.textContent || ""; + editorState.currentNode.content = newContent; + } + }, [editorState.currentNode, isComposing]); + + useEffect(() => { + if (editorState.currentNode) { + requestAnimationFrame(() => { + const element = document.querySelector( + `[data-node-id="${editorState.currentNode!.id}"]`, + ) as HTMLElement; + if (element) { + contentRef.current = element as HTMLDivElement; + const caretPosition = element.textContent?.length || 0; + setCaretPosition(element, caretPosition); + } + }); + } + }, [editorState.currentNode!.id, editorState.currentNode?.type, setCaretPosition]); + + const renderNodes = () => { + const nodes = editorList.traverseNodes(); + return nodes.map((node) => { + if (node.type === "li") return null; + if (node.type === "ul" || node.type === "ol") { + const children = []; + let child = node.firstChild; + while (child && child.parentNode === node) { + children.push(child); + child = child.nextSibling; + } + + return ( + + {children.map((liNode) => ( + + ))} + + ); + } + + return ( + + ); + }); + }; + return ( -
-

마크다운 에디터

+
+ {renderNodes()}
); }; diff --git a/client/src/hooks/useMarkdownGrammer/handlers/space.ts b/client/src/hooks/useMarkdownGrammer/handlers/space.ts index ec0cf555..5185229c 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/space.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/space.ts @@ -44,10 +44,24 @@ export const useSpaceKeyHandler = ({ currentNode: listNode, })); } else { + const wasRoot = currentNode.prevNode === null; + const { prevNode, nextNode } = currentNode; // 기존 노드의 타입만 변경 currentNode.type = newElement.type; currentNode.content = ""; + if (wasRoot) { + + editorList.root = currentNode; + } else { + if (prevNode) { + prevNode.nextNode = currentNode; + } + if (nextNode) { + nextNode.prevNode = currentNode; + } + } + setEditorState((prev) => ({ ...prev })); } } From 8ec6a01f3feb0154b9b2aaddfadbe6b5b51b9bb4 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 15:35:19 +0900 Subject: [PATCH 09/19] =?UTF-8?q?feat:=20=EC=97=90=EB=94=94=ED=84=B0=20?= =?UTF-8?q?=EB=82=B4=20=EC=A0=9C=EB=AA=A9=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EC=99=80=20=EC=83=81=EB=8B=A8=EB=B0=94=20=EC=A0=9C?= =?UTF-8?q?=EB=AA=A9=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/features/editor/Editor.style.ts | 16 +++++++++++++++- client/src/features/editor/Editor.tsx | 18 ++++++++++++++++-- client/src/features/page/Page.tsx | 13 ++++++++++--- .../PageControlButton.style.ts | 0 .../PageControlButton.tsx | 0 .../components/PageTitle/PageTitle.style.ts | 6 ++++++ .../page/components/PageTitle/PageTitle.tsx | 9 +++++++++ client/src/styles/typography.ts | 12 ++++++++++++ 8 files changed, 68 insertions(+), 6 deletions(-) rename client/src/features/page/components/{ => PageControlButton}/PageControlButton.style.ts (100%) rename client/src/features/page/components/{ => PageControlButton}/PageControlButton.tsx (100%) create mode 100644 client/src/features/page/components/PageTitle/PageTitle.style.ts create mode 100644 client/src/features/page/components/PageTitle/PageTitle.tsx diff --git a/client/src/features/editor/Editor.style.ts b/client/src/features/editor/Editor.style.ts index b8a4b96a..2f0f87df 100644 --- a/client/src/features/editor/Editor.style.ts +++ b/client/src/features/editor/Editor.style.ts @@ -12,4 +12,18 @@ export const editorContainer = css({ display: "flex", flexDirection: "column", gap: "spacing.sm", -}); \ No newline at end of file +}); + +export const editorTitleContainer = css({ + width: 'full', + padding: 'spacing.sm', + marginBottom: 'spacing.md', + border: 'none', + outline: 'none', + textStyle: 'display-medium28', + color: 'gray.700', + backgroundColor: 'transparent', + '&::placeholder': { + color: 'gray.300' + } +}) \ No newline at end of file diff --git a/client/src/features/editor/Editor.tsx b/client/src/features/editor/Editor.tsx index d146e676..31828e9d 100644 --- a/client/src/features/editor/Editor.tsx +++ b/client/src/features/editor/Editor.tsx @@ -5,9 +5,13 @@ import { useCaretManager } from "../../hooks/useCaretManager"; import { LinkedListBlock } from "../../utils/linkedLIstBlock"; import { checkMarkdownPattern } from "../../utils/markdownPatterns"; import { useKeyboardHandlers } from "../../hooks/useMarkdownGrammer"; -import { editorContainer } from "./Editor.style"; +import { editorContainer, editorTitleContainer } from "./Editor.style"; -export const Editor = () => { +interface EditorProps { + onTitleChange: (title: string) => void; +} + +export const Editor = ({ onTitleChange }: EditorProps) => { const [editorList] = useState(() => new LinkedListBlock()); const [editorState, setEditorState] = useState(() => ({ rootNode: editorList.root, @@ -55,6 +59,10 @@ export const Editor = () => { } }, [editorState.currentNode, isComposing]); + const handleTitleChange = (e: React.ChangeEvent) => { + onTitleChange(e.target.value); + }; + useEffect(() => { if (editorState.currentNode) { requestAnimationFrame(() => { @@ -123,6 +131,12 @@ export const Editor = () => { return (
+ {renderNodes()}
); diff --git a/client/src/features/page/Page.tsx b/client/src/features/page/Page.tsx index 64584c47..5e6519e1 100644 --- a/client/src/features/page/Page.tsx +++ b/client/src/features/page/Page.tsx @@ -1,6 +1,8 @@ +import { useState } from "react"; import { Editor } from "@features/editor/Editor"; import { pageContainer, pageHeader, pageTitle } from "./Page.style"; -import { PageControlButton } from "./components/PageControlButton"; +import { PageControlButton } from "./components/PageControlButton/PageControlButton"; +import { PageTitle } from "./components/PageTitle/PageTitle"; interface PageProps { x?: number; @@ -8,6 +10,7 @@ interface PageProps { } export const Page = ({ x = 0, y = 0 }: PageProps) => { + const [title, setTitle] = useState(""); const position = { left: `${x}px`, top: `${y}px`, @@ -17,17 +20,21 @@ export const Page = ({ x = 0, y = 0 }: PageProps) => { const handlePageMaximize = () => {}; const handlePageClose = () => {}; + const handleTitleChange = (newTitle: string) => { + setTitle(newTitle); + }; + return (
-

title

+
- +
); }; diff --git a/client/src/features/page/components/PageControlButton.style.ts b/client/src/features/page/components/PageControlButton/PageControlButton.style.ts similarity index 100% rename from client/src/features/page/components/PageControlButton.style.ts rename to client/src/features/page/components/PageControlButton/PageControlButton.style.ts diff --git a/client/src/features/page/components/PageControlButton.tsx b/client/src/features/page/components/PageControlButton/PageControlButton.tsx similarity index 100% rename from client/src/features/page/components/PageControlButton.tsx rename to client/src/features/page/components/PageControlButton/PageControlButton.tsx diff --git a/client/src/features/page/components/PageTitle/PageTitle.style.ts b/client/src/features/page/components/PageTitle/PageTitle.style.ts new file mode 100644 index 00000000..ea63c326 --- /dev/null +++ b/client/src/features/page/components/PageTitle/PageTitle.style.ts @@ -0,0 +1,6 @@ +import { css } from "@styled-system/css"; + +export const pageTitle = css({ + textStyle: "display-medium24", + color: "gray.500", +}); \ No newline at end of file diff --git a/client/src/features/page/components/PageTitle/PageTitle.tsx b/client/src/features/page/components/PageTitle/PageTitle.tsx new file mode 100644 index 00000000..be557a4b --- /dev/null +++ b/client/src/features/page/components/PageTitle/PageTitle.tsx @@ -0,0 +1,9 @@ +import { pageTitle } from "./PageTitle.style"; + +interface PageTitleProps { + title: string; +} + +export const PageTitle = ({ title }: PageTitleProps) => { + return

{title || "Title"}

; +}; \ No newline at end of file diff --git a/client/src/styles/typography.ts b/client/src/styles/typography.ts index c084aa58..c31d210b 100644 --- a/client/src/styles/typography.ts +++ b/client/src/styles/typography.ts @@ -36,4 +36,16 @@ export const textStyles = defineTextStyles({ textTransform: "None", }, }, + + "display-medium28": { + value: { + fontFamily: "Inter", + fontWeight: "700", + fontSize: "28px", + lineHeight: "36px", + letterSpacing: "-0.2px", + textDecoration: "None", + textTransform: "None", + }, + }, }); From 3c79a83ca311167d8ee0e19a99ad54c2c05ca959 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 15:46:15 +0900 Subject: [PATCH 10/19] =?UTF-8?q?style:=20=EC=A0=9C=EB=AA=A9=EA=B3=BC=20?= =?UTF-8?q?=EB=B3=B8=EB=AC=B8=20=EC=82=AC=EC=9D=B4=20=EB=A7=88=EC=A7=84=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/features/editor/Editor.style.ts | 13 +++++------ client/src/features/editor/Editor.tsx | 25 ++++++++++++---------- client/src/features/page/Page.tsx | 2 +- client/tsconfig.json | 4 +++- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/client/src/features/editor/Editor.style.ts b/client/src/features/editor/Editor.style.ts index 2f0f87df..c3d375bb 100644 --- a/client/src/features/editor/Editor.style.ts +++ b/client/src/features/editor/Editor.style.ts @@ -9,21 +9,22 @@ export const editorContainer = css({ _focus: { outline: "none", }, - display: "flex", - flexDirection: "column", - gap: "spacing.sm", + }); export const editorTitleContainer = css({ width: 'full', padding: 'spacing.sm', - marginBottom: 'spacing.md', + marginBottom: '30px', +}) + +export const editorTitle = css({ + width: 'full', border: 'none', outline: 'none', textStyle: 'display-medium28', color: 'gray.700', - backgroundColor: 'transparent', '&::placeholder': { color: 'gray.300' } -}) \ No newline at end of file +}); \ No newline at end of file diff --git a/client/src/features/editor/Editor.tsx b/client/src/features/editor/Editor.tsx index 31828e9d..c940b65b 100644 --- a/client/src/features/editor/Editor.tsx +++ b/client/src/features/editor/Editor.tsx @@ -1,11 +1,11 @@ import { useRef, useState, useCallback, useEffect } from "react"; import { EditorState } from "../../types/markdown"; import { Block } from "@components/block/Block"; -import { useCaretManager } from "../../hooks/useCaretManager"; -import { LinkedListBlock } from "../../utils/linkedLIstBlock"; -import { checkMarkdownPattern } from "../../utils/markdownPatterns"; -import { useKeyboardHandlers } from "../../hooks/useMarkdownGrammer"; -import { editorContainer, editorTitleContainer } from "./Editor.style"; +import { useCaretManager } from "@hooks/useCaretManager"; +import { useKeyboardHandlers } from "@hooks/useMarkdownGrammer"; +import { LinkedListBlock } from "@utils/linkedLIstBlock"; +import { checkMarkdownPattern } from "@utils/markdownPatterns"; +import { editorContainer, editorTitleContainer, editorTitle } from "./Editor.style"; interface EditorProps { onTitleChange: (title: string) => void; @@ -131,12 +131,15 @@ export const Editor = ({ onTitleChange }: EditorProps) => { return (
- +
+ +
+ {renderNodes()}
); diff --git a/client/src/features/page/Page.tsx b/client/src/features/page/Page.tsx index 5e6519e1..bf1c6ca3 100644 --- a/client/src/features/page/Page.tsx +++ b/client/src/features/page/Page.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { Editor } from "@features/editor/Editor"; -import { pageContainer, pageHeader, pageTitle } from "./Page.style"; +import { pageContainer, pageHeader } from "./Page.style"; import { PageControlButton } from "./components/PageControlButton/PageControlButton"; import { PageTitle } from "./components/PageTitle/PageTitle"; diff --git a/client/tsconfig.json b/client/tsconfig.json index d0a90532..3319e05f 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -23,7 +23,9 @@ "@components/*": ["src/components/*"], "@assets/*": ["src/assets/*"], "@features/*": ["src/features/*"], - "@styles/*": ["src/styles/*"] + "@styles/*": ["src/styles/*"], + "@hooks/*": ["src/hooks/*"], + "@utils/*": ["src/utils/*"], } }, "include": ["src", "*.ts", "*.tsx", "vite.config.ts", "styled-system"], From d35faae0dc91254d1c862a1210742a8b58884137 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 15:52:41 +0900 Subject: [PATCH 11/19] =?UTF-8?q?style:=20lint=20=EC=8B=A4=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/block/Block.style.ts | 106 +++++++++--------- client/src/components/block/Block.tsx | 38 ++++--- client/src/features/editor/Editor.style.ts | 27 +++-- client/src/features/editor/Editor.tsx | 6 +- client/src/features/page/Page.tsx | 2 +- .../components/PageTitle/PageTitle.style.ts | 2 +- .../page/components/PageTitle/PageTitle.tsx | 2 +- client/src/hooks/useCaretManager.ts | 2 +- .../useMarkdownGrammer/handlers/arrow.ts | 8 +- .../useMarkdownGrammer/handlers/backSpace.ts | 8 +- .../useMarkdownGrammer/handlers/enter.ts | 8 +- .../handlers/handlerProps.ts | 2 +- .../useMarkdownGrammer/handlers/space.ts | 3 +- client/src/hooks/useMarkdownGrammer/index.ts | 3 +- client/src/utils/linkedLIstBlock.ts | 1 - 15 files changed, 116 insertions(+), 102 deletions(-) diff --git a/client/src/components/block/Block.style.ts b/client/src/components/block/Block.style.ts index a87dd547..bcc8157b 100644 --- a/client/src/components/block/Block.style.ts +++ b/client/src/components/block/Block.style.ts @@ -1,90 +1,90 @@ -import { css, cx } from '@styled-system/css'; +import { css, cx } from "@styled-system/css"; // 기본 블록 스타일 정의 const baseBlockStyle = css({ - width: 'full', - margin: 'spacing.sm 0', - minHeight: 'spacing.lg', - padding: 'spacing.sm', - borderRadius: 'radii.xs', - backgroundColor: 'transparent', - color: 'gray.700', - outline: 'none', - textStyle: 'display-medium16', + textStyle: "display-medium16", + outline: "none", + borderRadius: "radii.xs", + width: "full", + minHeight: "spacing.lg", + margin: "spacing.sm 0", + padding: "spacing.sm", + color: "gray.700", + backgroundColor: "transparent", }); // 각 블록 타입별 스타일 정의 export const blockContainer = { base: baseBlockStyle, - + paragraph: baseBlockStyle, - + heading1: cx( baseBlockStyle, css({ - textStyle: 'display-medium24', - fontWeight: 'bold', - color: 'gray.900', - }) + textStyle: "display-medium24", + color: "gray.900", + fontWeight: "bold", + }), ), - + heading2: cx( baseBlockStyle, css({ - textStyle: 'display-medium20', - fontWeight: 'bold', - color: 'gray.900', - }) + textStyle: "display-medium20", + color: "gray.900", + fontWeight: "bold", + }), ), - + heading3: cx( baseBlockStyle, css({ - textStyle: 'display-medium16', - fontWeight: 'bold', - color: 'gray.900', - }) + textStyle: "display-medium16", + color: "gray.900", + fontWeight: "bold", + }), ), - + unorderedList: cx( baseBlockStyle, css({ - listStyleType: 'disc', - listStylePosition: 'inside', - display: 'block', - }) + display: "block", + listStyleType: "disc", + listStylePosition: "inside", + }), ), - + orderedList: cx( baseBlockStyle, css({ - listStyleType: 'decimal', - listStylePosition: 'inside', - display: 'block', - }) + display: "block", + listStyleType: "decimal", + listStylePosition: "inside", + }), ), - + listItem: css({ - margin: '0', - padding: '0 0 0 spacing.md', - outline: 'none', - textStyle: 'display-medium16', - color: 'gray.700', - display: 'list-item', // 리스트 아이템으로 표시되도록 설정 + textStyle: "display-medium16", + display: "list-item", // 리스트 아이템으로 표시되도록 설정 + outline: "none", + margin: "0", + padding: "0 0 0 spacing.md", + color: "gray.700", }), - + input: css({ - margin: 'spacing.sm 0', - textStyle: 'display-medium16', + textStyle: "display-medium16", + margin: "spacing.sm 0", }), - + blockquote: cx( baseBlockStyle, css({ - borderLeft: '4px solid token(colors.gray.300)', - paddingLeft: 'spacing.md', - fontStyle: 'italic', - color: 'gray.500', - }) + borderLeft: "4px solid token(colors.gray.300)", + paddingLeft: "spacing.md", + color: "gray.500", + fontStyle: "italic", + }), ), -}; \ No newline at end of file +}; diff --git a/client/src/components/block/Block.tsx b/client/src/components/block/Block.tsx index 84f5e34f..2f718358 100644 --- a/client/src/components/block/Block.tsx +++ b/client/src/components/block/Block.tsx @@ -33,17 +33,27 @@ export const Block: React.FC = memo( // node.type에 따른 스타일 선택 const getBlockStyle = (type: string) => { - switch(type) { - case 'p': return blockContainer.paragraph; - case 'h1': return blockContainer.heading1; - case 'h2': return blockContainer.heading2; - case 'h3': return blockContainer.heading3; - case 'ul': return blockContainer.unorderedList; - case 'ol': return blockContainer.orderedList; - case 'li': return blockContainer.listItem; - case 'blockquote': return blockContainer.blockquote; - case 'input': return blockContainer.input; - default: return blockContainer.base; + switch (type) { + case "p": + return blockContainer.paragraph; + case "h1": + return blockContainer.heading1; + case "h2": + return blockContainer.heading2; + case "h3": + return blockContainer.heading3; + case "ul": + return blockContainer.unorderedList; + case "ol": + return blockContainer.orderedList; + case "li": + return blockContainer.listItem; + case "blockquote": + return blockContainer.blockquote; + case "input": + return blockContainer.input; + default: + return blockContainer.base; } }; @@ -59,9 +69,7 @@ export const Block: React.FC = memo( contentEditable: true, suppressContentEditableWarning: true, dangerouslySetInnerHTML: { __html: node.content }, - className: cx( - getBlockStyle(node.type), - ), + className: cx(getBlockStyle(node.type)), }; return React.createElement(node.type, commonProps); @@ -69,4 +77,4 @@ export const Block: React.FC = memo( ); // 메모이제이션을 위한 displayName 설정 -Block.displayName = "Block"; \ No newline at end of file +Block.displayName = "Block"; diff --git a/client/src/features/editor/Editor.style.ts b/client/src/features/editor/Editor.style.ts index c3d375bb..a2902c36 100644 --- a/client/src/features/editor/Editor.style.ts +++ b/client/src/features/editor/Editor.style.ts @@ -9,22 +9,21 @@ export const editorContainer = css({ _focus: { outline: "none", }, - }); export const editorTitleContainer = css({ - width: 'full', - padding: 'spacing.sm', - marginBottom: '30px', -}) + width: "full", + marginBottom: "30px", + padding: "spacing.sm", +}); export const editorTitle = css({ - width: 'full', - border: 'none', - outline: 'none', - textStyle: 'display-medium28', - color: 'gray.700', - '&::placeholder': { - color: 'gray.300' - } -}); \ No newline at end of file + textStyle: "display-medium28", + outline: "none", + border: "none", + width: "full", + color: "gray.700", + "&::placeholder": { + color: "gray.300", + }, +}); diff --git a/client/src/features/editor/Editor.tsx b/client/src/features/editor/Editor.tsx index c940b65b..bfa287d9 100644 --- a/client/src/features/editor/Editor.tsx +++ b/client/src/features/editor/Editor.tsx @@ -91,9 +91,7 @@ export const Editor = ({ onTitleChange }: EditorProps) => { } return ( - + {children.map((liNode) => ( { className={editorTitle} />
- + {renderNodes()} ); diff --git a/client/src/features/page/Page.tsx b/client/src/features/page/Page.tsx index bf1c6ca3..4842690e 100644 --- a/client/src/features/page/Page.tsx +++ b/client/src/features/page/Page.tsx @@ -34,7 +34,7 @@ export const Page = ({ x = 0, y = 0 }: PageProps) => { onPageMinimize={handlePageMinimize} /> - + ); }; diff --git a/client/src/features/page/components/PageTitle/PageTitle.style.ts b/client/src/features/page/components/PageTitle/PageTitle.style.ts index ea63c326..df1cc901 100644 --- a/client/src/features/page/components/PageTitle/PageTitle.style.ts +++ b/client/src/features/page/components/PageTitle/PageTitle.style.ts @@ -3,4 +3,4 @@ import { css } from "@styled-system/css"; export const pageTitle = css({ textStyle: "display-medium24", color: "gray.500", -}); \ No newline at end of file +}); diff --git a/client/src/features/page/components/PageTitle/PageTitle.tsx b/client/src/features/page/components/PageTitle/PageTitle.tsx index be557a4b..ca24fe41 100644 --- a/client/src/features/page/components/PageTitle/PageTitle.tsx +++ b/client/src/features/page/components/PageTitle/PageTitle.tsx @@ -6,4 +6,4 @@ interface PageTitleProps { export const PageTitle = ({ title }: PageTitleProps) => { return

{title || "Title"}

; -}; \ No newline at end of file +}; diff --git a/client/src/hooks/useCaretManager.ts b/client/src/hooks/useCaretManager.ts index d13470ab..0833e58f 100644 --- a/client/src/hooks/useCaretManager.ts +++ b/client/src/hooks/useCaretManager.ts @@ -49,4 +49,4 @@ export const useCaretManager = () => { }, []); return { saveCaretPosition, restoreCaretPosition, setCaretPosition }; -}; \ No newline at end of file +}; diff --git a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts index d15f3e93..ed97f9f0 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts @@ -2,7 +2,11 @@ import { useCallback } from "react"; import { EditorNode } from "../../../types/markdown"; import { KeyHandlerProps } from "./handlerProps"; -export const useArrowKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandlerProps) => { +export const useArrowKeyHandler = ({ + editorState, + editorList, + setEditorState, +}: KeyHandlerProps) => { return useCallback( (e: React.KeyboardEvent) => { e.preventDefault(); @@ -52,4 +56,4 @@ export const useArrowKeyHandler = ({ editorState, editorList, setEditorState }: }, [editorState, editorList, setEditorState], ); -}; \ No newline at end of file +}; diff --git a/client/src/hooks/useMarkdownGrammer/handlers/backSpace.ts b/client/src/hooks/useMarkdownGrammer/handlers/backSpace.ts index 3dd55039..773cf052 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/backSpace.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/backSpace.ts @@ -2,7 +2,11 @@ import { useCallback } from "react"; import { EditorNode } from "../../../types/markdown"; import { KeyHandlerProps } from "./handlerProps"; -export const useBackspaceKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandlerProps) => { +export const useBackspaceKeyHandler = ({ + editorState, + editorList, + setEditorState, +}: KeyHandlerProps) => { return useCallback( (e: React.KeyboardEvent) => { const { currentNode } = editorState; @@ -159,4 +163,4 @@ export const useBackspaceKeyHandler = ({ editorState, editorList, setEditorState }, [editorState, editorList, setEditorState], ); -}; \ No newline at end of file +}; diff --git a/client/src/hooks/useMarkdownGrammer/handlers/enter.ts b/client/src/hooks/useMarkdownGrammer/handlers/enter.ts index fca06a28..b5d75bc6 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/enter.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/enter.ts @@ -2,7 +2,11 @@ import { useCallback } from "react"; import { EditorNode } from "../../../types/markdown"; import { KeyHandlerProps } from "./handlerProps"; -export const useEnterKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandlerProps) => { +export const useEnterKeyHandler = ({ + editorState, + editorList, + setEditorState, +}: KeyHandlerProps) => { return useCallback( (e: React.KeyboardEvent) => { e.preventDefault(); @@ -152,4 +156,4 @@ export const useEnterKeyHandler = ({ editorState, editorList, setEditorState }: }, [editorState, editorList, setEditorState], ); -}; \ No newline at end of file +}; diff --git a/client/src/hooks/useMarkdownGrammer/handlers/handlerProps.ts b/client/src/hooks/useMarkdownGrammer/handlers/handlerProps.ts index 9bf08c4b..412864a2 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/handlerProps.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/handlerProps.ts @@ -6,4 +6,4 @@ export interface KeyHandlerProps { editorList: LinkedListBlock; setEditorState: React.Dispatch>; checkMarkdownPattern: (text: string) => MarkdownElement | null; -} \ No newline at end of file +} diff --git a/client/src/hooks/useMarkdownGrammer/handlers/space.ts b/client/src/hooks/useMarkdownGrammer/handlers/space.ts index 5185229c..344b6744 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/space.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/space.ts @@ -51,7 +51,6 @@ export const useSpaceKeyHandler = ({ currentNode.content = ""; if (wasRoot) { - editorList.root = currentNode; } else { if (prevNode) { @@ -68,4 +67,4 @@ export const useSpaceKeyHandler = ({ }, [editorState, editorList, checkMarkdownPattern, setEditorState], ); -}; \ No newline at end of file +}; diff --git a/client/src/hooks/useMarkdownGrammer/index.ts b/client/src/hooks/useMarkdownGrammer/index.ts index 2a225803..d5e1fc92 100644 --- a/client/src/hooks/useMarkdownGrammer/index.ts +++ b/client/src/hooks/useMarkdownGrammer/index.ts @@ -41,7 +41,6 @@ export const useKeyboardHandlers = (props: KeyHandlerProps) => { return { handleKeyDown }; }; - /* const useTabKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandlerProps) => { return useCallback( @@ -84,4 +83,4 @@ const useTabKeyHandler = ({ editorState, editorList, setEditorState }: KeyHandle [editorState, editorList, setEditorState], ); }; -*/ \ No newline at end of file +*/ diff --git a/client/src/utils/linkedLIstBlock.ts b/client/src/utils/linkedLIstBlock.ts index 72e32d75..6119d4d6 100644 --- a/client/src/utils/linkedLIstBlock.ts +++ b/client/src/utils/linkedLIstBlock.ts @@ -118,4 +118,3 @@ export class LinkedListBlock { return result; } } - From d75710baeaaa5977f2fe76382da99971c9520802 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 16:48:42 +0900 Subject: [PATCH 12/19] =?UTF-8?q?style:=20=EB=B8=94=EB=A1=9D=EB=B3=84=20?= =?UTF-8?q?=ED=94=8C=EB=A0=88=EC=9D=B4=EC=8A=A4=ED=99=80=EB=8D=94=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/block/Block.style.ts | 157 +++++++++++---------- client/src/components/block/Block.tsx | 32 ++--- 2 files changed, 93 insertions(+), 96 deletions(-) diff --git a/client/src/components/block/Block.style.ts b/client/src/components/block/Block.style.ts index bcc8157b..f4faf998 100644 --- a/client/src/components/block/Block.style.ts +++ b/client/src/components/block/Block.style.ts @@ -1,7 +1,7 @@ -import { css, cx } from "@styled-system/css"; +import { css, cva } from "@styled-system/css"; -// 기본 블록 스타일 정의 -const baseBlockStyle = css({ +// 기본 블록 스타일 +const baseBlockStyle = { textStyle: "display-medium16", outline: "none", borderRadius: "radii.xs", @@ -9,82 +9,83 @@ const baseBlockStyle = css({ minHeight: "spacing.lg", margin: "spacing.sm 0", padding: "spacing.sm", - color: "gray.700", + color: "gray.900", backgroundColor: "transparent", -}); + '&:empty::before': { + content: 'attr(data-placeholder)', // data-placeholder 속성의 값을 표시 + color: 'gray.300', + position: 'absolute', + pointerEvents: 'none' // 텍스트 선택이나 클릭 방지 + } +}; -// 각 블록 타입별 스타일 정의 -export const blockContainer = { +// 블록 타입별 스타일 variants +export const blockContainerStyle = cva({ base: baseBlockStyle, + variants: { + type: { + p: { + textStyle: "display-medium16", + fontWeight: "bold", + }, + h1: { + textStyle: "display-medium24", + fontWeight: "bold", + }, + h2: { + textStyle: "display-medium20", + fontWeight: "bold", + }, + h3: { + textStyle: "display-medium16", + fontWeight: "bold", + }, + ul: { + display: "block", + listStyleType: "disc", + listStylePosition: "inside", + }, + ol: { + display: "block", + listStyleType: "decimal", + listStylePosition: "inside", + }, + li: { + textStyle: "display-medium16", + display: "list-item", + outline: "none", + margin: "0", + padding: "0 0 0 spacing.md", + }, + blockquote: { + borderLeft: "4px solid token(colors.gray.300)", + paddingLeft: "spacing.md", + color: "gray.500", + fontStyle: "italic", + }, + input: {}, + }, + isActive: { + true: { + opacity: 0.9, + }, + false: { + backgroundColor: "transparent", + }, + }, + }, + defaultVariants: { + type: "p", + isActive: false, + }, +}); - paragraph: baseBlockStyle, - - heading1: cx( - baseBlockStyle, - css({ - textStyle: "display-medium24", - color: "gray.900", - fontWeight: "bold", - }), - ), - - heading2: cx( - baseBlockStyle, - css({ - textStyle: "display-medium20", - color: "gray.900", - fontWeight: "bold", - }), - ), - - heading3: cx( - baseBlockStyle, - css({ - textStyle: "display-medium16", - color: "gray.900", - fontWeight: "bold", - }), - ), - - unorderedList: cx( - baseBlockStyle, - css({ - display: "block", - listStyleType: "disc", - listStylePosition: "inside", - }), - ), - - orderedList: cx( - baseBlockStyle, - css({ - display: "block", - listStyleType: "decimal", - listStylePosition: "inside", - }), - ), - - listItem: css({ - textStyle: "display-medium16", - display: "list-item", // 리스트 아이템으로 표시되도록 설정 - outline: "none", - margin: "0", - padding: "0 0 0 spacing.md", - color: "gray.700", - }), - - input: css({ - textStyle: "display-medium16", - margin: "spacing.sm 0", - }), - - blockquote: cx( - baseBlockStyle, - css({ - borderLeft: "4px solid token(colors.gray.300)", - paddingLeft: "spacing.md", - color: "gray.500", - fontStyle: "italic", - }), - ), -}; +// 리스트 아이템은 별도로 정의 (특수한 스타일링 때문) +export const listItemStyle = css({ + textStyle: "display-medium16", + display: "list-item", + outline: "none", + margin: "0", + padding: "0 0 0 spacing.md", + color: "gray.700", +}); \ No newline at end of file diff --git a/client/src/components/block/Block.tsx b/client/src/components/block/Block.tsx index 2f718358..488e1266 100644 --- a/client/src/components/block/Block.tsx +++ b/client/src/components/block/Block.tsx @@ -1,7 +1,6 @@ import React, { memo } from "react"; -import { cx } from "@styled-system/css"; import { EditorNode } from "../../types/markdown"; -import { blockContainer } from "./Block.style"; +import { blockContainerStyle, listItemStyle } from "./Block.style"; interface BlockProps { node: EditorNode; @@ -31,35 +30,29 @@ export const Block: React.FC = memo( onClick(node.id); }; - // node.type에 따른 스타일 선택 - const getBlockStyle = (type: string) => { + const getPlaceholder = (type: string) => { switch (type) { case "p": - return blockContainer.paragraph; + return "텍스트를 입력하세요 ..."; case "h1": - return blockContainer.heading1; + return "제목 1"; case "h2": - return blockContainer.heading2; + return "제목 2"; case "h3": - return blockContainer.heading3; - case "ul": - return blockContainer.unorderedList; - case "ol": - return blockContainer.orderedList; + return "제목 3"; case "li": - return blockContainer.listItem; + return "리스트 항목"; case "blockquote": - return blockContainer.blockquote; - case "input": - return blockContainer.input; + return "인용구를 입력하세요"; default: - return blockContainer.base; + return "텍스트를 입력하세요"; } }; const commonProps = { "data-node-id": node.id, "data-depth": node.depth, + "data-placeholder": getPlaceholder(node.type), onKeyDown, onInput, onCompositionStart, @@ -69,7 +62,10 @@ export const Block: React.FC = memo( contentEditable: true, suppressContentEditableWarning: true, dangerouslySetInnerHTML: { __html: node.content }, - className: cx(getBlockStyle(node.type)), + className: blockContainerStyle({ + type: node.type, + isActive, + }), }; return React.createElement(node.type, commonProps); From 49f78d2b4aa6cb1db3ddc73eb06c1960641c4876 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 16:54:54 +0900 Subject: [PATCH 13/19] =?UTF-8?q?style:=20lint=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/block/Block.style.ts | 24 +++++++--------------- client/src/components/block/Block.tsx | 4 ++-- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/client/src/components/block/Block.style.ts b/client/src/components/block/Block.style.ts index f4faf998..42cf3100 100644 --- a/client/src/components/block/Block.style.ts +++ b/client/src/components/block/Block.style.ts @@ -1,4 +1,4 @@ -import { css, cva } from "@styled-system/css"; +import { cva } from "@styled-system/css"; // 기본 블록 스타일 const baseBlockStyle = { @@ -11,12 +11,12 @@ const baseBlockStyle = { padding: "spacing.sm", color: "gray.900", backgroundColor: "transparent", - '&:empty::before': { - content: 'attr(data-placeholder)', // data-placeholder 속성의 값을 표시 - color: 'gray.300', - position: 'absolute', - pointerEvents: 'none' // 텍스트 선택이나 클릭 방지 - } + "&:empty::before": { + content: "attr(data-placeholder)", // data-placeholder 속성의 값을 표시 + color: "gray.300", + position: "absolute", + pointerEvents: "none", // 텍스트 선택이나 클릭 방지 + }, }; // 블록 타입별 스타일 variants @@ -79,13 +79,3 @@ export const blockContainerStyle = cva({ isActive: false, }, }); - -// 리스트 아이템은 별도로 정의 (특수한 스타일링 때문) -export const listItemStyle = css({ - textStyle: "display-medium16", - display: "list-item", - outline: "none", - margin: "0", - padding: "0 0 0 spacing.md", - color: "gray.700", -}); \ No newline at end of file diff --git a/client/src/components/block/Block.tsx b/client/src/components/block/Block.tsx index 488e1266..8dacd70f 100644 --- a/client/src/components/block/Block.tsx +++ b/client/src/components/block/Block.tsx @@ -1,6 +1,6 @@ import React, { memo } from "react"; import { EditorNode } from "../../types/markdown"; -import { blockContainerStyle, listItemStyle } from "./Block.style"; +import { blockContainerStyle } from "./Block.style"; interface BlockProps { node: EditorNode; @@ -62,7 +62,7 @@ export const Block: React.FC = memo( contentEditable: true, suppressContentEditableWarning: true, dangerouslySetInnerHTML: { __html: node.content }, - className: blockContainerStyle({ + className: blockContainerStyle({ type: node.type, isActive, }), From 6f4ab021cce4b3763a9bf2b84d003a75dcb88f42 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 17:05:32 +0900 Subject: [PATCH 14/19] =?UTF-8?q?fix:=20=ED=85=8D=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EA=B0=80=20=EC=97=86=EA=B3=A0,=20=EA=B8=B0=EB=B3=B8=EB=B8=94?= =?UTF-8?q?=EB=A1=9D=EC=9D=B4=20=EC=95=84=EB=8B=90=EB=95=8C,=20=EC=97=94?= =?UTF-8?q?=ED=84=B0=EB=A5=BC=20=EB=88=84=EB=A5=B4=EB=A9=B4=20=EA=B8=B0?= =?UTF-8?q?=EB=B3=B8=20=EB=B8=94=EB=A1=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EB=90=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../useMarkdownGrammer/handlers/enter.ts | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/client/src/hooks/useMarkdownGrammer/handlers/enter.ts b/client/src/hooks/useMarkdownGrammer/handlers/enter.ts index b5d75bc6..b7feb350 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/enter.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/enter.ts @@ -138,20 +138,30 @@ export const useEnterKeyHandler = ({ })); } } else { - // 일반 블록은 항상 p 태그로 새 블록 생성 - currentNode.content = beforeText; - const newNode = editorList.createNode("p", afterText, currentNode, currentNode.nextNode); + // 현재 텍스트의 길이가 0이면 일반 블록으로 변경 + if (content.length === 0) { + currentNode.type = "p"; + currentNode.content = ""; + setEditorState((prev) => ({ + ...prev, + currentNode, + })); + } else { + // 일반 블록은 항상 p 태그로 새 블록 생성 + currentNode.content = beforeText; + const newNode = editorList.createNode("p", afterText, currentNode, currentNode.nextNode); - // 연결 관계 설정 - if (currentNode.nextNode) { - currentNode.nextNode.prevNode = newNode; - } - currentNode.nextNode = newNode; + // 연결 관계 설정 + if (currentNode.nextNode) { + currentNode.nextNode.prevNode = newNode; + } + currentNode.nextNode = newNode; - setEditorState((prev) => ({ - ...prev, - currentNode: newNode, - })); + setEditorState((prev) => ({ + ...prev, + currentNode: newNode, + })); + } } }, [editorState, editorList, setEditorState], From 6b1fb9b92d003d687d64ea179e23002da1b68eb4 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 21:34:45 +0900 Subject: [PATCH 15/19] =?UTF-8?q?feat:=20=EC=B2=B4=ED=81=AC=EB=B0=95?= =?UTF-8?q?=EC=8A=A4=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #13 --- client/src/components/block/Block.style.ts | 8 +-- client/src/components/block/Block.tsx | 4 +- client/src/features/editor/Editor.style.ts | 21 ++++++ client/src/features/editor/Editor.tsx | 38 +++++++++- .../useMarkdownGrammer/handlers/arrow.ts | 20 +++++- .../useMarkdownGrammer/handlers/backSpace.ts | 69 ++++++++++++++++++- .../useMarkdownGrammer/handlers/enter.ts | 69 ++++++++++++++++++- .../useMarkdownGrammer/handlers/space.ts | 40 ++++++++++- client/src/types/markdown.ts | 2 +- client/src/utils/linkedLIstBlock.ts | 32 +++++++++ client/src/utils/markdownPatterns.ts | 8 ++- 11 files changed, 292 insertions(+), 19 deletions(-) diff --git a/client/src/components/block/Block.style.ts b/client/src/components/block/Block.style.ts index 42cf3100..7261d028 100644 --- a/client/src/components/block/Block.style.ts +++ b/client/src/components/block/Block.style.ts @@ -43,19 +43,19 @@ export const blockContainerStyle = cva({ ul: { display: "block", listStyleType: "disc", - listStylePosition: "inside", + listStylePosition: "outside", }, ol: { display: "block", listStyleType: "decimal", - listStylePosition: "inside", + listStylePosition: "outside", }, li: { textStyle: "display-medium16", display: "list-item", outline: "none", margin: "0", - padding: "0 0 0 spacing.md", + padding: "0 0 0 16px", }, blockquote: { borderLeft: "4px solid token(colors.gray.300)", @@ -63,7 +63,7 @@ export const blockContainerStyle = cva({ color: "gray.500", fontStyle: "italic", }, - input: {}, + checkbox: {}, }, isActive: { true: { diff --git a/client/src/components/block/Block.tsx b/client/src/components/block/Block.tsx index 8dacd70f..c84ff5a9 100644 --- a/client/src/components/block/Block.tsx +++ b/client/src/components/block/Block.tsx @@ -49,6 +49,8 @@ export const Block: React.FC = memo( } }; + const nodeType = node.type === "checkbox" ? "p" : node.type; + const commonProps = { "data-node-id": node.id, "data-depth": node.depth, @@ -68,7 +70,7 @@ export const Block: React.FC = memo( }), }; - return React.createElement(node.type, commonProps); + return React.createElement(nodeType, commonProps); }, ); diff --git a/client/src/features/editor/Editor.style.ts b/client/src/features/editor/Editor.style.ts index a2902c36..c6145d80 100644 --- a/client/src/features/editor/Editor.style.ts +++ b/client/src/features/editor/Editor.style.ts @@ -27,3 +27,24 @@ export const editorTitle = css({ color: "gray.300", }, }); + +export const checkboxContainer = css({ + display: "flex", + gap: "spacing.sm", + flexDirection: "row", + alignItems: "center", +}); + +export const checkbox = css({ + border: "1px solid", + borderColor: "gray.300", + borderRadius: "4px", + width: "16px", + height: "16px", + margin: "0 8px 0 0", + cursor: "pointer", + "&:checked": { + borderColor: "blue.500", + backgroundColor: "blue.500", + }, +}); diff --git a/client/src/features/editor/Editor.tsx b/client/src/features/editor/Editor.tsx index bfa287d9..80430873 100644 --- a/client/src/features/editor/Editor.tsx +++ b/client/src/features/editor/Editor.tsx @@ -5,7 +5,13 @@ import { useCaretManager } from "@hooks/useCaretManager"; import { useKeyboardHandlers } from "@hooks/useMarkdownGrammer"; import { LinkedListBlock } from "@utils/linkedLIstBlock"; import { checkMarkdownPattern } from "@utils/markdownPatterns"; -import { editorContainer, editorTitleContainer, editorTitle } from "./Editor.style"; +import { + editorContainer, + editorTitleContainer, + editorTitle, + checkboxContainer, + checkbox, +} from "./Editor.style"; interface EditorProps { onTitleChange: (title: string) => void; @@ -81,7 +87,7 @@ export const Editor = ({ onTitleChange }: EditorProps) => { const renderNodes = () => { const nodes = editorList.traverseNodes(); return nodes.map((node) => { - if (node.type === "li") return null; + if (node.type === "li") return; if (node.type === "ul" || node.type === "ol") { const children = []; let child = node.firstChild; @@ -110,6 +116,34 @@ export const Editor = ({ onTitleChange }: EditorProps) => { ); } + if (node.type === "checkbox") { + return ( +
+ {}} + onClick={(e) => e.stopPropagation()} + className={checkbox} + /> + {node.firstChild && ( + + )} +
+ ); + } + return ( 0) return; if (currentNode === editorState.rootNode && currentNode.type === "p") return; - e.preventDefault(); - if (currentNode.type === "li") { + if (currentNode.parentNode?.type === "checkbox") { + const { parentNode } = currentNode; + const wasRoot = parentNode === editorState.rootNode; + + let focusNode; + if (parentNode.prevNode?.type === "checkbox") { + // undefined가 될 수 있는 상황 체크 + const prevFirstChild = parentNode.prevNode.firstChild; + if (!prevFirstChild) return; + focusNode = prevFirstChild; + } else { + focusNode = editorList.createNode("p", "", parentNode.prevNode, parentNode.nextNode); + + // 포인터 관계 설정 + if (parentNode.prevNode) { + parentNode.prevNode.nextNode = focusNode; + } + if (parentNode.nextNode) { + parentNode.nextNode.prevNode = focusNode; + } + + if (wasRoot) { + editorList.root = focusNode; + } + } + + // 관계 정리 순서 변경 + // 1. 기존 연결 관계 정리 + if (parentNode.nextNode) { + parentNode.nextNode.prevNode = parentNode.prevNode; + } + if (parentNode.prevNode) { + parentNode.prevNode.nextNode = parentNode.nextNode; + } + + // 2. 부모-자식 관계 정리 + currentNode.parentNode = null; + parentNode.firstChild = null; + + // 3. 마지막으로 현재 노드의 관계 정리 + parentNode.prevNode = null; + parentNode.nextNode = null; + + // 노드 제거 + editorList.removeNode(currentNode); + editorList.removeNode(parentNode); + + setEditorState((prev) => ({ + ...prev, + rootNode: wasRoot ? focusNode : prev.rootNode, + currentNode: focusNode, + })); + } else if (currentNode.type === "li") { const { parentNode } = currentNode; if (!parentNode) return; @@ -142,11 +193,23 @@ export const useBackspaceKeyHandler = ({ setEditorState((prev) => ({ ...prev })); } else { let focusNode; - if (currentNode.prevNode?.type === "ul" || currentNode.prevNode?.type === "ol") { + if (currentNode.prevNode?.type === "checkbox") { + // 이전 노드가 체크박스면 그 체크박스의 content 노드로 포커스 + focusNode = currentNode.prevNode.firstChild; + } else if (currentNode.prevNode?.type === "ul" || currentNode.prevNode?.type === "ol") { focusNode = editorList.getLastChild(currentNode.prevNode); } else { focusNode = currentNode.prevNode || currentNode.parentNode; } + + // 현재 노드 제거 전에 연결 관계 정리 + if (currentNode.prevNode) { + currentNode.prevNode.nextNode = currentNode.nextNode; + } + if (currentNode.nextNode) { + currentNode.nextNode.prevNode = currentNode.prevNode; + } + editorList.removeNode(currentNode); if (focusNode === editorState.rootNode) { diff --git a/client/src/hooks/useMarkdownGrammer/handlers/enter.ts b/client/src/hooks/useMarkdownGrammer/handlers/enter.ts index b7feb350..632d0680 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/enter.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/enter.ts @@ -20,7 +20,65 @@ export const useEnterKeyHandler = ({ const beforeText = content.slice(0, caretPosition); const afterText = content.slice(caretPosition); - if (currentNode.type === "li") { + if (currentNode.parentNode?.type === "checkbox") { + const { parentNode } = currentNode; + if (content.length === 0) { + // 빈 체크박스에서 엔터 -> 일반 블록으로 전환 + const newNode = editorList.createNode("p", "", parentNode.prevNode, parentNode.nextNode); + + if (parentNode.prevNode) { + parentNode.prevNode.nextNode = newNode; + } + if (parentNode.nextNode) { + parentNode.nextNode.prevNode = newNode; + } + + // root 노드 업데이트 + if (parentNode === editorState.rootNode) { + editorList.root = newNode; + } + + editorList.removeNode(currentNode); + + setEditorState((prev) => ({ + ...prev, + rootNode: parentNode === prev.rootNode ? newNode : prev.rootNode, + currentNode: newNode, + })); + } else { + // 텍스트가 있는 체크박스에서 엔터 -> 새로운 체크박스 블록 생성 + currentNode.content = beforeText; + + // 새로운 체크박스 컨테이너와 컨텐츠 생성 + const newContainer = editorList.createNode( + "checkbox", + "", + parentNode, + parentNode.nextNode, + ); + const newContent = editorList.createNode("p", afterText, null, null, currentNode.depth); + + // 새 체크박스의 관계 설정 + newContainer.firstChild = newContent; + newContent.parentNode = newContainer; + + // 기존 노드들과의 연결 설정 + if (parentNode.nextNode) { + parentNode.nextNode.prevNode = newContainer; + } + parentNode.nextNode = newContainer; + + // 기본 체크박스 속성 설정 + newContainer.attributes = { + checked: false, + }; + + setEditorState((prev) => ({ + ...prev, + currentNode: newContent, + })); + } + } else if (currentNode.type === "li") { const { parentNode } = currentNode; if (!parentNode) return; @@ -140,11 +198,18 @@ export const useEnterKeyHandler = ({ } else { // 현재 텍스트의 길이가 0이면 일반 블록으로 변경 if (content.length === 0) { + /* currentNode.type = "p"; currentNode.content = ""; + */ + const newNode = editorList.createNode("p", "", currentNode, currentNode.nextNode); + if (currentNode.nextNode) { + currentNode.nextNode.prevNode = newNode; + } + currentNode.nextNode = newNode; setEditorState((prev) => ({ ...prev, - currentNode, + currentNode: newNode, })); } else { // 일반 블록은 항상 p 태그로 새 블록 생성 diff --git a/client/src/hooks/useMarkdownGrammer/handlers/space.ts b/client/src/hooks/useMarkdownGrammer/handlers/space.ts index 344b6744..290b08da 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/space.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/space.ts @@ -17,8 +17,46 @@ export const useSpaceKeyHandler = ({ e.preventDefault(); const { currentNode } = editorState; if (!currentNode) return; + if (newElement.type === "checkbox") { + const { prevNode, nextNode } = currentNode; + const wasRoot = currentNode.prevNode === null; + + // checkbox-container 노드 생성 + const containerNode = editorList.createNode( + "checkbox", + "", + prevNode, + nextNode, + currentNode.depth, + ); + + // content 노드 생성 + const contentNode = editorList.createNode("p", "", null, null, currentNode.depth + 1); + + // 노드 간 관계 설정 + containerNode.firstChild = contentNode; + contentNode.parentNode = containerNode; + + // checkbox 속성 설정 + containerNode.attributes = { + checked: false, + ...newElement.attributes, + }; + + // root 노드 업데이트 + if (wasRoot) { + editorList.root = containerNode; + } else { + if (prevNode) prevNode.nextNode = containerNode; + if (nextNode) nextNode.prevNode = containerNode; + } - if (newElement.type === "ul" || newElement.type === "ol") { + setEditorState((prev) => ({ + ...prev, + rootNode: wasRoot ? containerNode : prev.rootNode, + currentNode: contentNode, + })); + } else if (newElement.type === "ul" || newElement.type === "ol") { // 기존 노드의 위치 관계 저장 const { prevNode, nextNode } = currentNode; const wasRoot = currentNode.prevNode === null; diff --git a/client/src/types/markdown.ts b/client/src/types/markdown.ts index 738219a9..5a1f8174 100644 --- a/client/src/types/markdown.ts +++ b/client/src/types/markdown.ts @@ -1,4 +1,4 @@ -export type ElementType = "p" | "h1" | "h2" | "h3" | "ul" | "ol" | "li" | "input" | "blockquote"; +export type ElementType = "p" | "h1" | "h2" | "h3" | "ul" | "ol" | "li" | "checkbox" | "blockquote"; export interface ListProperties { index?: number; diff --git a/client/src/utils/linkedLIstBlock.ts b/client/src/utils/linkedLIstBlock.ts index 6119d4d6..47e7adf9 100644 --- a/client/src/utils/linkedLIstBlock.ts +++ b/client/src/utils/linkedLIstBlock.ts @@ -49,6 +49,23 @@ export class LinkedListBlock { // 노드 삭제 removeNode(node: EditorNode): void { + // 부모-자식 관계 정리 + if (node.parentNode) { + if (node.parentNode.firstChild === node) { + node.parentNode.firstChild = node.nextSibling; + } + node.parentNode = null; + } + + // 형제 관계 정리 + if (node.prevSibling) { + node.prevSibling.nextSibling = node.nextSibling; + } + if (node.nextSibling) { + node.nextSibling.prevSibling = node.prevSibling; + } + + // 수평 관계 정리 if (node.prevNode) { node.prevNode.nextNode = node.nextNode; } @@ -56,11 +73,23 @@ export class LinkedListBlock { node.nextNode.prevNode = node.prevNode; } + // firstChild가 있는 경우 관계 정리 + if (node.firstChild) { + node.firstChild.parentNode = null; + node.firstChild = null; + } + // root 노드인 경우 업데이트 if (node === this.root) { this.root = node.nextNode; } + // 현재 노드인 경우 업데이트 + if (node === this.current) { + this.current = node.prevNode || node.nextNode; + } + + // 노드의 모든 참조 제거 Object.keys(node).forEach((key) => { delete (node as any)[key]; }); @@ -78,6 +107,9 @@ export class LinkedListBlock { child = child.nextSibling; } } + if (node.type === "checkbox") { + return node.firstChild; + } return find(node.nextNode); }; diff --git a/client/src/utils/markdownPatterns.ts b/client/src/utils/markdownPatterns.ts index 1a7deafd..a7bbc41e 100644 --- a/client/src/utils/markdownPatterns.ts +++ b/client/src/utils/markdownPatterns.ts @@ -32,9 +32,11 @@ const MARKDOWN_PATTERNS: Record = { createElement: () => ({ type: "blockquote" }), }, checkbox: { - regex: /^>$/, - length: 1, - createElement: () => ({ type: "input" }), + regex: /^\[ ?\]$/, // "[ ]" 또는 "[]" 패턴 매칭 + length: 3, + createElement: () => ({ + type: "checkbox", + }), }, }; From 6c8fa35a620f1c44b548c7434926fb1c816df090 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 22:32:20 +0900 Subject: [PATCH 16/19] =?UTF-8?q?fix:=20=ED=99=94=EC=82=B4=ED=91=9C=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- @noctaCrdt/dist/Crdt.d.ts | 1 + @noctaCrdt/dist/Crdt.d.ts.map | 1 + @noctaCrdt/dist/Crdt.js | 2 + @noctaCrdt/dist/Crdt.js.map | 1 + @noctaCrdt/dist/Interfaces.d.ts | 1 + @noctaCrdt/dist/Interfaces.d.ts.map | 1 + @noctaCrdt/dist/Interfaces.js | 2 + @noctaCrdt/dist/Interfaces.js.map | 1 + @noctaCrdt/dist/LinkedList.d.ts | 1 + @noctaCrdt/dist/LinkedList.d.ts.map | 1 + @noctaCrdt/dist/LinkedList.js | 2 + @noctaCrdt/dist/LinkedList.js.map | 1 + @noctaCrdt/dist/Node.d.ts | 1 + @noctaCrdt/dist/Node.d.ts.map | 1 + @noctaCrdt/dist/Node.js | 2 + @noctaCrdt/dist/Node.js.map | 1 + @noctaCrdt/dist/tsconfig.tsbuildinfo | 1 + .../useMarkdownGrammer/handlers/arrow.ts | 69 ++++++++++++++++++- client/tsconfig.tsbuildinfo | 2 +- 19 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 @noctaCrdt/dist/Crdt.d.ts create mode 100644 @noctaCrdt/dist/Crdt.d.ts.map create mode 100644 @noctaCrdt/dist/Crdt.js create mode 100644 @noctaCrdt/dist/Crdt.js.map create mode 100644 @noctaCrdt/dist/Interfaces.d.ts create mode 100644 @noctaCrdt/dist/Interfaces.d.ts.map create mode 100644 @noctaCrdt/dist/Interfaces.js create mode 100644 @noctaCrdt/dist/Interfaces.js.map create mode 100644 @noctaCrdt/dist/LinkedList.d.ts create mode 100644 @noctaCrdt/dist/LinkedList.d.ts.map create mode 100644 @noctaCrdt/dist/LinkedList.js create mode 100644 @noctaCrdt/dist/LinkedList.js.map create mode 100644 @noctaCrdt/dist/Node.d.ts create mode 100644 @noctaCrdt/dist/Node.d.ts.map create mode 100644 @noctaCrdt/dist/Node.js create mode 100644 @noctaCrdt/dist/Node.js.map create mode 100644 @noctaCrdt/dist/tsconfig.tsbuildinfo diff --git a/@noctaCrdt/dist/Crdt.d.ts b/@noctaCrdt/dist/Crdt.d.ts new file mode 100644 index 00000000..c18fa772 --- /dev/null +++ b/@noctaCrdt/dist/Crdt.d.ts @@ -0,0 +1 @@ +//# sourceMappingURL=Crdt.d.ts.map \ No newline at end of file diff --git a/@noctaCrdt/dist/Crdt.d.ts.map b/@noctaCrdt/dist/Crdt.d.ts.map new file mode 100644 index 00000000..296f43c5 --- /dev/null +++ b/@noctaCrdt/dist/Crdt.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Crdt.d.ts","sourceRoot":"","sources":["../Crdt.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/@noctaCrdt/dist/Crdt.js b/@noctaCrdt/dist/Crdt.js new file mode 100644 index 00000000..dde9413f --- /dev/null +++ b/@noctaCrdt/dist/Crdt.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=Crdt.js.map \ No newline at end of file diff --git a/@noctaCrdt/dist/Crdt.js.map b/@noctaCrdt/dist/Crdt.js.map new file mode 100644 index 00000000..dea3b8d8 --- /dev/null +++ b/@noctaCrdt/dist/Crdt.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Crdt.js","sourceRoot":"","sources":["../Crdt.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/@noctaCrdt/dist/Interfaces.d.ts b/@noctaCrdt/dist/Interfaces.d.ts new file mode 100644 index 00000000..00f43a55 --- /dev/null +++ b/@noctaCrdt/dist/Interfaces.d.ts @@ -0,0 +1 @@ +//# sourceMappingURL=Interfaces.d.ts.map \ No newline at end of file diff --git a/@noctaCrdt/dist/Interfaces.d.ts.map b/@noctaCrdt/dist/Interfaces.d.ts.map new file mode 100644 index 00000000..2c99ef16 --- /dev/null +++ b/@noctaCrdt/dist/Interfaces.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Interfaces.d.ts","sourceRoot":"","sources":["../Interfaces.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/@noctaCrdt/dist/Interfaces.js b/@noctaCrdt/dist/Interfaces.js new file mode 100644 index 00000000..04b8a87d --- /dev/null +++ b/@noctaCrdt/dist/Interfaces.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=Interfaces.js.map \ No newline at end of file diff --git a/@noctaCrdt/dist/Interfaces.js.map b/@noctaCrdt/dist/Interfaces.js.map new file mode 100644 index 00000000..f5f7494b --- /dev/null +++ b/@noctaCrdt/dist/Interfaces.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Interfaces.js","sourceRoot":"","sources":["../Interfaces.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/@noctaCrdt/dist/LinkedList.d.ts b/@noctaCrdt/dist/LinkedList.d.ts new file mode 100644 index 00000000..5e7fec9e --- /dev/null +++ b/@noctaCrdt/dist/LinkedList.d.ts @@ -0,0 +1 @@ +//# sourceMappingURL=LinkedList.d.ts.map \ No newline at end of file diff --git a/@noctaCrdt/dist/LinkedList.d.ts.map b/@noctaCrdt/dist/LinkedList.d.ts.map new file mode 100644 index 00000000..22f7d5a6 --- /dev/null +++ b/@noctaCrdt/dist/LinkedList.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"LinkedList.d.ts","sourceRoot":"","sources":["../LinkedList.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/@noctaCrdt/dist/LinkedList.js b/@noctaCrdt/dist/LinkedList.js new file mode 100644 index 00000000..bca2e8bd --- /dev/null +++ b/@noctaCrdt/dist/LinkedList.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=LinkedList.js.map \ No newline at end of file diff --git a/@noctaCrdt/dist/LinkedList.js.map b/@noctaCrdt/dist/LinkedList.js.map new file mode 100644 index 00000000..e9833e5c --- /dev/null +++ b/@noctaCrdt/dist/LinkedList.js.map @@ -0,0 +1 @@ +{"version":3,"file":"LinkedList.js","sourceRoot":"","sources":["../LinkedList.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/@noctaCrdt/dist/Node.d.ts b/@noctaCrdt/dist/Node.d.ts new file mode 100644 index 00000000..5dc1fc3c --- /dev/null +++ b/@noctaCrdt/dist/Node.d.ts @@ -0,0 +1 @@ +//# sourceMappingURL=Node.d.ts.map \ No newline at end of file diff --git a/@noctaCrdt/dist/Node.d.ts.map b/@noctaCrdt/dist/Node.d.ts.map new file mode 100644 index 00000000..97d301b8 --- /dev/null +++ b/@noctaCrdt/dist/Node.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Node.d.ts","sourceRoot":"","sources":["../Node.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/@noctaCrdt/dist/Node.js b/@noctaCrdt/dist/Node.js new file mode 100644 index 00000000..27b1e7e8 --- /dev/null +++ b/@noctaCrdt/dist/Node.js @@ -0,0 +1,2 @@ +"use strict"; +//# sourceMappingURL=Node.js.map \ No newline at end of file diff --git a/@noctaCrdt/dist/Node.js.map b/@noctaCrdt/dist/Node.js.map new file mode 100644 index 00000000..22bd2e45 --- /dev/null +++ b/@noctaCrdt/dist/Node.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Node.js","sourceRoot":"","sources":["../Node.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/@noctaCrdt/dist/tsconfig.tsbuildinfo b/@noctaCrdt/dist/tsconfig.tsbuildinfo new file mode 100644 index 00000000..9b9c312d --- /dev/null +++ b/@noctaCrdt/dist/tsconfig.tsbuildinfo @@ -0,0 +1 @@ +{"program":{"fileNames":["../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es5.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2021.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.scripthost.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2021.promise.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2021.string.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2021.intl.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2021.full.d.ts","../crdt.ts","../interfaces.ts","../linkedlist.ts","../node.ts"],"fileInfos":[{"version":"f33e5332b24c3773e930e212cbb8b6867c8ba3ec4492064ea78e55a524d57450","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","26f2f787e82c4222710f3b676b4d83eb5ad0a72fa7b746f03449e7a026ce5073","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569",{"version":"21e41a76098aa7a191028256e52a726baafd45a925ea5cf0222eb430c96c1d83","affectsGlobalScope":true},{"version":"35299ae4a62086698444a5aaee27fc7aa377c68cbb90b441c9ace246ffd05c97","affectsGlobalScope":true},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true},{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"e0275cd0e42990dc3a16f0b7c8bca3efe87f1c8ad404f80c6db1c7c0b828c59f","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"ec0104fee478075cb5171e5f4e3f23add8e02d845ae0165bfa3f1099241fa2aa","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"acae90d417bee324b1372813b5a00829d31c7eb670d299cd7f8f9a648ac05688","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true},{"version":"51e547984877a62227042850456de71a5c45e7fe86b7c975c6e68896c86fa23b","affectsGlobalScope":true},{"version":"62a4966981264d1f04c44eb0f4b5bdc3d81c1a54725608861e44755aa24ad6a5","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},"c1e8d979afc15d66e2bd5a58c732d5a2ba3ccaae41ac7d5a2c539e6de66a8e51","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"],"root":[[54,57]],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"emitDecoratorMetadata":true,"experimentalDecorators":true,"module":99,"outDir":"./","removeComments":true,"rootDir":"..","skipLibCheck":true,"sourceMap":true,"strict":true,"target":8},"referencedMap":[],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[54,55,56,57,51,52,9,10,14,13,2,15,16,17,18,19,20,21,22,3,4,23,27,24,25,26,28,29,30,5,31,32,33,34,6,38,35,36,37,39,7,40,45,46,41,42,43,44,8,53,50,47,48,49,1,12,11],"latestChangedDtsFile":"./Node.d.ts"},"version":"5.3.3"} \ No newline at end of file diff --git a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts index d798b991..06e943df 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts @@ -14,6 +14,72 @@ export const useArrowKeyHandler = ({ if (!currentNode) return; let targetNode: EditorNode | null = null; + + switch (e.key) { + case "ArrowUp": + if (currentNode.parentNode?.type === "checkbox") { + if (currentNode.parentNode.prevNode) { + if (currentNode.parentNode.prevNode.type === "checkbox") { + targetNode = currentNode.parentNode.prevNode.firstChild; + } else { + targetNode = currentNode.parentNode.prevNode; + } + } + } else if (currentNode.prevNode?.type === "ul" || currentNode.prevNode?.type === "ol") { + targetNode = editorList.getLastChild(currentNode.prevNode); + } else if (currentNode.type === "li") { + if (currentNode.prevSibling?.id) { + targetNode = currentNode.prevSibling; + } else { + if (currentNode.parentNode?.prevNode) { + if (currentNode.parentNode.prevNode.type === "checkbox") { + // 이전 블록이 체크박스인 경우 처리 + targetNode = currentNode.parentNode.prevNode.firstChild; + } else { + targetNode = currentNode.parentNode.prevNode; + } + } else { + return; + } + } + } else { + targetNode = currentNode.prevNode; + } + break; + + case "ArrowDown": + if (currentNode.parentNode?.type === "checkbox") { + if (currentNode.parentNode.nextNode) { + if (currentNode.parentNode.nextNode.type === "checkbox") { + targetNode = currentNode.parentNode.nextNode.firstChild; + } else { + targetNode = currentNode.parentNode.nextNode; + } + } + } else if (currentNode.nextNode?.type === "ul" || currentNode.nextNode?.type === "ol") { + targetNode = currentNode.nextNode.firstChild; + } else if (currentNode.type === "li") { + if (currentNode.nextSibling?.id) { + targetNode = currentNode.nextSibling; + } else { + if (currentNode.parentNode?.nextNode) { + if (currentNode.parentNode.nextNode.type === "checkbox") { + // 다음 블록이 체크박스인 경우 처리 + targetNode = currentNode.parentNode.nextNode.firstChild; + } else { + targetNode = currentNode.parentNode.nextNode; + } + } else { + return; + } + } + } else { + targetNode = currentNode.nextNode; + } + break; + } + + /* switch (e.key) { case "ArrowUp": if (currentNode.parentNode?.type === "checkbox") { @@ -47,6 +113,7 @@ export const useArrowKeyHandler = ({ targetNode = currentNode.parentNode.nextNode; } } + } else if (currentNode.nextNode?.type === "ul" || currentNode.nextNode?.type === "ol") { targetNode = currentNode.nextNode!.firstChild; } else if (currentNode.type === "li") { @@ -62,7 +129,7 @@ export const useArrowKeyHandler = ({ } break; } - + */ if (targetNode) { setEditorState((prev) => ({ ...prev, diff --git a/client/tsconfig.tsbuildinfo b/client/tsconfig.tsbuildinfo index d4f4053e..6dafd3ba 100644 --- a/client/tsconfig.tsbuildinfo +++ b/client/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"program":{"fileNames":["../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es5.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/global.d.ts","../node_modules/.pnpm/csstype@3.1.3/node_modules/csstype/index.d.ts","../node_modules/.pnpm/@types+prop-types@15.7.13/node_modules/@types/prop-types/index.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/index.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/jsx-runtime.d.ts","./src/app.tsx","../node_modules/.pnpm/@types+react-dom@18.3.1/node_modules/@types/react-dom/client.d.ts","./src/main.tsx","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/types/hmrpayload.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/types/customevent.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/types/hot.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/types/importglob.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/types/importmeta.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/client.d.ts","./src/vite-env.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/disposable.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/indexable.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/iterators.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/index.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/globals.typedarray.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/buffer.buffer.d.ts","../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/header.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/readable.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/file.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/fetch.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/formdata.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/connector.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/client.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/errors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-origin.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool-stats.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/handlers.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/balanced-pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-interceptor.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-client.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-errors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/env-http-proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-handler.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/api.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/interceptors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/util.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cookies.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/patch.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/websocket.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/eventsource.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/filereader.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/content-type.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cache.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/index.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/globals.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/assert.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/assert/strict.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/async_hooks.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/buffer.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/child_process.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/cluster.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/console.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/constants.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/crypto.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dgram.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dns.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dns/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/domain.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dom-events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/fs.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/fs/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/http.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/http2.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/https.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/inspector.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/module.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/net.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/os.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/path.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/perf_hooks.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/process.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/punycode.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/querystring.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/readline.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/readline/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/repl.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/sea.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/consumers.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/web.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/string_decoder.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/test.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/timers.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/timers/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/tls.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/trace_events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/tty.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/url.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/util.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/v8.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/vm.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/wasi.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/worker_threads.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/zlib.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/index.d.ts","../node_modules/.pnpm/@types+estree@1.0.6/node_modules/@types/estree/index.d.ts","../node_modules/.pnpm/rollup@4.24.3/node_modules/rollup/dist/rollup.d.ts","../node_modules/.pnpm/rollup@4.24.3/node_modules/rollup/dist/parseast.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/dist/node/types.d-agj9qkwt.d.ts","../node_modules/.pnpm/esbuild@0.21.5/node_modules/esbuild/lib/main.d.ts","../node_modules/.pnpm/source-map-js@1.2.1/node_modules/source-map-js/source-map.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/previous-map.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/input.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/css-syntax-error.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/declaration.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/root.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/warning.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/lazy-result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/no-work-result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/processor.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/document.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/rule.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/node.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/comment.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/container.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/at-rule.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/list.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/postcss.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/postcss.d.mts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/dist/node/runtime.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/types/metadata.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/dist/node/index.d.ts","../node_modules/.pnpm/@babel+types@7.26.0/node_modules/@babel/types/lib/index.d.ts","../node_modules/.pnpm/@types+babel__generator@7.6.8/node_modules/@types/babel__generator/index.d.ts","../node_modules/.pnpm/@babel+parser@7.26.2/node_modules/@babel/parser/typings/babel-parser.d.ts","../node_modules/.pnpm/@types+babel__template@7.4.4/node_modules/@types/babel__template/index.d.ts","../node_modules/.pnpm/@types+babel__traverse@7.20.6/node_modules/@types/babel__traverse/index.d.ts","../node_modules/.pnpm/@types+babel__core@7.20.5/node_modules/@types/babel__core/index.d.ts","../node_modules/.pnpm/@vitejs+plugin-react@4.3.3_vite@5.4.10_@types+node@20.17.6_terser@5.36.0_/node_modules/@vitejs/plugin-react/dist/index.d.mts","./vite.config.ts","../node_modules/.pnpm/@types+react-dom@18.3.1/node_modules/@types/react-dom/index.d.ts"],"fileInfos":[{"version":"f33e5332b24c3773e930e212cbb8b6867c8ba3ec4492064ea78e55a524d57450","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","26f2f787e82c4222710f3b676b4d83eb5ad0a72fa7b746f03449e7a026ce5073","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4",{"version":"21e41a76098aa7a191028256e52a726baafd45a925ea5cf0222eb430c96c1d83","affectsGlobalScope":true},{"version":"35299ae4a62086698444a5aaee27fc7aa377c68cbb90b441c9ace246ffd05c97","affectsGlobalScope":true},{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"e0275cd0e42990dc3a16f0b7c8bca3efe87f1c8ad404f80c6db1c7c0b828c59f","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"ec0104fee478075cb5171e5f4e3f23add8e02d845ae0165bfa3f1099241fa2aa","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"acae90d417bee324b1372813b5a00829d31c7eb670d299cd7f8f9a648ac05688","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},{"version":"36a2e4c9a67439aca5f91bb304611d5ae6e20d420503e96c230cf8fcdc948d94","affectsGlobalScope":true},"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","ed6b820c54de95b2510bb673490d61c7f2187f532a339d8d04981645a918961f",{"version":"aa17748c522bd586f8712b1a308ea23af59c309b2fd278f6d4f406647c72e659","affectsGlobalScope":true},"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","721b5420d3b29825c1e43096e0a04081ad237a453732232097c23efdf4491b87","05321b823dd3781d0b6aac8700bfdc0c9181d56479fe52ba6a40c9196fd661a8","c0209b13d11b5529d8f1e7eb15ce5c26367b4fb538ff69c785b075f3484c5a29","282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea",{"version":"4025a454b1ca489b179ee8c684bdd70ff8c1967e382076ade53e7e4653e1daec","affectsGlobalScope":true},{"version":"984c09345059b76fc4221c2c54e53511f4c27a0794dfd6e9f81dc60f0b564e05","affectsGlobalScope":true},"424faf9241dd699dda995b367ed36665732da1e6ec1f33b2fd40394488ecac92",{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true},"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a",{"version":"613b21ccdf3be6329d56e6caa13b258c842edf8377be7bc9f014ed14cdcfc308","affectsGlobalScope":true},{"version":"2d1319e6b5d0efd8c5eae07eb864a00102151e8b9afddd2d45db52e9aae002c4","affectsGlobalScope":true},"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","24bd580b5743dc56402c440dc7f9a4f5d592ad7a419f25414d37a7bfe11e342b","25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","6bdc71028db658243775263e93a7db2fd2abfce3ca569c3cca5aee6ed5eb186d","cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","4d2b0eb911816f66abe4970898f97a2cfc902bcd743cbfa5017fad79f7ef90d8","bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","24b8685c62562f5d98615c5a0c1d05f297cf5065f15246edfe99e81ec4c0e011","93507c745e8f29090efb99399c3f77bec07db17acd75634249dc92f961573387","339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107",{"version":"ca6d304b929748ea15c33f28c1f159df18a94470b424ab78c52d68d40a41e1e9","affectsGlobalScope":true},"a72ffc815104fb5c075106ebca459b2d55d07862a773768fce89efc621b3964b","7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","3d77c73be94570813f8cadd1f05ebc3dc5e2e4fdefe4d340ca20cd018724ee36",{"version":"d674383111e06b6741c4ad2db962131b5b0fa4d0294b998566c635e86195a453","affectsGlobalScope":true},"f3e58c4c18a031cbb17abec7a4ad0bd5ae9fc70c1f4ba1e7fb921ad87c504aca","a3e8bafb2af8e850c644f4be7f5156cf7d23b7bfdc3b786bd4d10ed40329649c",{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true},"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb",{"version":"f77d9188e41291acf14f476e931972460a303e1952538f9546e7b370cb8d0d20","affectsGlobalScope":true},"b0c0d1d13be149f790a75b381b413490f98558649428bb916fd2d71a3f47a134","3c884d9d9ec454bdf0d5a0b8465bf8297d2caa4d853851d92cc417ac6f30b969","5a369483ac4cfbdf0331c248deeb36140e6907db5e1daed241546b4a2055f82c","e8f5b5cc36615c17d330eaf8eebbc0d6bdd942c25991f96ef122f246f4ff722f","f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45",{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true},{"version":"4d7da7075068195f8f127f41c61e304cdca5aafb1be2d0f4fb67c6b4c3e98d50","affectsGlobalScope":true},"a4bdde4e601e9554a844e1e0d0ccfa05e183ef9d82ab3ac25f17c1709033d360","ad23fd126ff06e72728dd7bfc84326a8ca8cec2b9d2dac0193d42a777df0e7d8","9dd9f50652a176469e85fb65aa081d2e7eb807e2c476f378233de4f1f6604962","93bd413918fa921c8729cef45302b24d8b6c7855d72d5bf82d3972595ae8dcbf","4ff41188773cbf465807dd2f7059c7494cbee5115608efc297383832a1150c43","dccdf1677e531e33f8ac961a68bc537418c9a414797c1ea7e91307501cdc3f5e",{"version":"7edec695cdb707c7146ac34c44ca364469c7ea504344b3206c686e79f61b61a2","affectsGlobalScope":true},"d206b4baf4ddcc15d9d69a9a2f4999a72a2c6adeaa8af20fa7a9960816287555","93f437e1398a4f06a984f441f7fa7a9f0535c04399619b5c22e0b87bdee182cb","afbe24ab0d74694372baa632ecb28bb375be53f3be53f9b07ecd7fc994907de5",{"version":"70731d10d5311bd4cf710ef7f6539b62660f4b0bfdbb3f9fbe1d25fe6366a7fa","affectsGlobalScope":true},{"version":"a20f1e119615bf7632729fd89b6c0b5ffdc2df3b512d6304146294528e3ebe19","affectsGlobalScope":true},"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","137c2894e8f3e9672d401cc0a305dc7b1db7c69511cf6d3970fb53302f9eae09","3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","8145e07aad6da5f23f2fcd8c8e4c5c13fb26ee986a79d03b0829b8fce152d8b2","f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","235bfb54b4869c26f7e98e3d1f68dbfc85acf4cf5c38a4444a006fbf74a8a43d","37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633",{"version":"bb715efb4857eb94539eafb420352105a0cff40746837c5140bf6b035dd220ba","affectsGlobalScope":true},"1851a3b4db78664f83901bb9cac9e45e03a37bb5933cc5bf37e10bb7e91ab4eb",{"version":"fdedf82878e4c744bc2a1c1e802ae407d63474da51f14a54babe039018e53d8f","affectsGlobalScope":true},{"version":"08353b04a3501d84fc8d7b49de99f6c1cc26026e6d9d697a18315f3bfe92ed03","affectsGlobalScope":true},"578d8bb6dcb2a1c03c4c3f8eb71abc9677e1a5c788b7f24848e3138ce17f3400","4f029899f9bae07e225c43aef893590541b2b43267383bf5e32e3a884d219ed5","ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9",{"version":"5b566927cad2ed2139655d55d690ffa87df378b956e7fe1c96024c4d9f75c4cf","affectsGlobalScope":true},{"version":"bce947017cb7a2deebcc4f5ba04cead891ce6ad1602a4438ae45ed9aa1f39104","affectsGlobalScope":true},"efeedd8bbc5c0d53e760d8b120a010470722982e6ae14de8d1bcff66ebc2ae71","e2c72c065a36bc9ab2a00ac6a6f51e71501619a72c0609defd304d46610487a4","d91a7d8b5655c42986f1bdfe2105c4408f472831c8f20cf11a8c3345b6b56c8c",{"version":"616075a6ac578cf5a013ee12964188b4412823796ce0b202c6f1d2e4ca8480d7","affectsGlobalScope":true},"e8a979b8af001c9fc2e774e7809d233c8ca955a28756f52ee5dee88ccb0611d2","9091e564b81e7b4c382a33c62de704a699e10508190547d4f7c1c3e039d2db2b","785b9d575b49124ce01b46f5b9402157c7611e6532effa562ac6aebec0074dfc",{"version":"e58a3ce75105c1557e34fab7408942d77374e047c16383e80880ed1220166dfa","affectsGlobalScope":true},"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87",{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","affectsGlobalScope":true},"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","4d979e3c12ffb6497d2b1dc5613130196d986fff764c4526360c0716a162e7e7","e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","80781460eca408fe8d2937d9fdbbb780d6aac35f549621e6200c9bee1da5b8fe","4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","b9261ac3e9944d3d72c5ee4cf888ad35d9743a5563405c6963c4e43ee3708ca4","c84fd54e8400def0d1ef1569cafd02e9f39a622df9fa69b57ccc82128856b916","a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","2ed6489ef46eb61442d067c08e87e3db501c0bfb2837eee4041a27bf3e792bb0","644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","d60fe6d59d4e19ecc65359490b8535e359ca4b760d2cdb56897ca75d09d41ba3","f45a2a8b1777ecb50ed65e1a04bb899d4b676529b7921bd5d69b08573a00c832","774b783046ba3d473948132d28a69f52a295b2f378f2939304118ba571b1355e","b5734e05c787a40e4f9efe71f16683c5f7dc3bdb0de7c04440c855bd000f8fa7","14ba97f0907144771331e1349fdccb5a13526eba0647e6b447e572376d811b6f","2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","7165050eddaed878c2d2cd3cafcaf171072ac39e586a048c0603712b5555f536","26e629be9bbd94ea1d465af83ce5a3306890520695f07be6eb016f8d734d02be","82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","9ae0ca65717af0d3b554a26fd333ad9c78ad3910ad4b22140ff02acb63076927","03f1d83d61696326ea29c8a1c15cbaccf61e92598d53f2ccae06078531f42448","2c8e55457aaf4902941dfdba4061935922e8ee6e120539c9801cd7b400fae050","3a9313fe5ace558b8b18e85f931da10b259e738775f411c061e5f15787b138eb","670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","9e0cf651e8e2c5b9bebbabdff2f7c6f8cedd91b1d9afcc0a854cdff053a88f1b","069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","f5e8546cfe500116aba8a6cb7ee171774b14a6db30d4bcd6e0aa5073e919e739","f2673caf4db0c1ddeacfe42c839eaec96a8a741c40a6dd49ff966a3883e63af1","17ed71200119e86ccef2d96b73b02ce8854b76ad6bd21b5021d4269bec527b5f"],"root":[51,53,60,194],"options":{"allowImportingTsExtensions":true,"composite":true,"jsx":4,"module":99,"noFallthroughCasesInSwitch":true,"noUnusedLocals":true,"noUnusedParameters":true,"skipLibCheck":true,"strict":true,"target":7,"useDefineForClassFields":true},"fileIdsList":[[49,50,59,66,109],[49,50,51,52,59,66,109],[59,66,109],[50,66,109,186,193],[66,109,187],[66,109],[66,109,187,188,189,190,191],[66,109,187,189],[66,106,109],[66,108,109],[66,109,114,143],[66,109,110,115,121,122,129,140,151],[66,109,110,111,121,129],[61,62,63,66,109],[66,109,112,152],[66,109,113,114,122,130],[66,109,114,140,148],[66,109,115,117,121,129],[66,108,109,116],[66,109,117,118],[66,109,121],[66,109,119,121],[66,108,109,121],[66,109,121,122,123,140,151],[66,109,121,122,123,136,140,143],[66,104,109,156],[66,109,117,121,124,129,140,151],[66,109,121,122,124,125,129,140,148,151],[66,109,124,126,140,148,151],[66,109,121,127],[66,109,128,151,156],[66,109,117,121,129,140],[66,109,130],[66,109,131],[66,108,109,132],[66,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157],[66,109,134],[66,109,135],[66,109,121,136,137],[66,109,136,138,152,154],[66,109,121,140,141,142,143],[66,109,140,142],[66,109,140,141],[66,109,143],[66,109,144],[66,106,109,140],[66,109,121,146,147],[66,109,146,147],[66,109,114,129,140,148],[66,109,149],[109],[64,65,66,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157],[66,109,129,150],[66,109,124,135,151],[66,109,114,152],[66,109,140,153],[66,109,128,154],[66,109,155],[66,109,114,121,123,132,140,151,154,156],[66,109,140,157],[49,66,109],[46,47,48,66,109],[66,109,186,192],[66,109,179],[66,109,177,179],[66,109,168,176,177,178,180],[66,109,166],[66,109,169,174,179,182],[66,109,165,182],[66,109,169,170,173,174,175,182],[66,109,169,170,171,173,174,182],[66,109,166,167,168,169,170,174,175,176,178,179,180,182],[66,109,182],[66,109,164,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181],[66,109,164,182],[66,109,169,171,172,174,175,182],[66,109,173,182],[66,109,174,175,179,182],[66,109,167,177],[66,109,160,185],[66,109,159,160],[66,76,80,109,151],[66,76,109,140,151],[66,71,109],[66,73,76,109,148,151],[66,109,129,148],[66,109,158],[66,71,109,158],[66,73,76,109,129,151],[66,68,69,72,75,109,121,140,151],[66,76,83,109],[66,68,74,109],[66,76,97,98,109],[66,72,76,109,143,151,158],[66,97,109,158],[66,70,71,109,158],[66,76,109],[66,70,71,72,73,74,75,76,77,78,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,98,99,100,101,102,103,109],[66,76,91,109],[66,76,83,84,109],[66,74,76,84,85,109],[66,75,109],[66,68,71,76,109],[66,76,80,84,85,109],[66,80,109],[66,74,76,79,109,151],[66,68,73,76,83,109],[66,109,140],[66,71,76,97,109,156,158],[58,66,109],[54,55,56,57,66,109,121,122,124,125,126,129,140,148,151,157,158,160,161,162,163,183,184,185],[54,55,56,66,109,162],[54,55,56,66,109],[54,66,109],[55,66,109],[56,57,66,109],[66,109,160]],"referencedMap":[[51,1],[53,2],[60,3],[194,4],[189,5],[187,6],[192,7],[188,5],[190,8],[191,5],[159,6],[106,9],[107,9],[108,10],[109,11],[110,12],[111,13],[61,6],[64,14],[62,6],[63,6],[112,15],[113,16],[114,17],[115,18],[116,19],[117,20],[118,20],[120,21],[119,22],[121,23],[122,24],[123,25],[105,26],[124,27],[125,28],[126,29],[127,30],[128,31],[129,32],[130,33],[131,34],[132,35],[133,36],[134,37],[135,38],[136,39],[137,39],[138,40],[139,6],[140,41],[142,42],[141,43],[143,44],[144,45],[145,46],[146,47],[147,48],[148,49],[149,50],[66,51],[65,6],[158,52],[150,53],[151,54],[152,55],[153,56],[154,57],[155,58],[156,59],[157,60],[48,6],[52,61],[195,61],[46,6],[49,62],[50,61],[193,63],[67,6],[47,6],[163,6],[180,64],[178,65],[179,66],[167,67],[168,65],[175,68],[166,69],[171,70],[181,6],[172,71],[177,72],[183,73],[182,74],[165,75],[173,76],[174,77],[169,78],[176,64],[170,79],[161,80],[160,81],[164,6],[44,6],[45,6],[8,6],[9,6],[11,6],[10,6],[2,6],[12,6],[13,6],[14,6],[15,6],[16,6],[17,6],[18,6],[19,6],[3,6],[4,6],[20,6],[24,6],[21,6],[22,6],[23,6],[25,6],[26,6],[27,6],[5,6],[28,6],[29,6],[30,6],[31,6],[6,6],[35,6],[32,6],[33,6],[34,6],[36,6],[7,6],[37,6],[42,6],[43,6],[38,6],[39,6],[40,6],[41,6],[1,6],[83,82],[93,83],[82,82],[103,84],[74,85],[73,86],[102,87],[96,88],[101,89],[76,90],[90,91],[75,92],[99,93],[71,94],[70,87],[100,95],[72,96],[77,97],[78,6],[81,97],[68,6],[104,98],[94,99],[85,100],[86,101],[88,102],[84,103],[87,104],[97,87],[79,105],[80,106],[89,107],[69,108],[92,99],[91,97],[95,6],[98,109],[59,110],[186,111],[184,112],[162,113],[55,114],[54,6],[56,115],[57,6],[58,116],[185,117]],"exportedModulesMap":[[51,1],[53,2],[60,3],[194,4],[189,5],[187,6],[192,7],[188,5],[190,8],[191,5],[159,6],[106,9],[107,9],[108,10],[109,11],[110,12],[111,13],[61,6],[64,14],[62,6],[63,6],[112,15],[113,16],[114,17],[115,18],[116,19],[117,20],[118,20],[120,21],[119,22],[121,23],[122,24],[123,25],[105,26],[124,27],[125,28],[126,29],[127,30],[128,31],[129,32],[130,33],[131,34],[132,35],[133,36],[134,37],[135,38],[136,39],[137,39],[138,40],[139,6],[140,41],[142,42],[141,43],[143,44],[144,45],[145,46],[146,47],[147,48],[148,49],[149,50],[66,51],[65,6],[158,52],[150,53],[151,54],[152,55],[153,56],[154,57],[155,58],[156,59],[157,60],[48,6],[52,61],[195,61],[46,6],[49,62],[50,61],[193,63],[67,6],[47,6],[163,6],[180,64],[178,65],[179,66],[167,67],[168,65],[175,68],[166,69],[171,70],[181,6],[172,71],[177,72],[183,73],[182,74],[165,75],[173,76],[174,77],[169,78],[176,64],[170,79],[161,80],[160,81],[164,6],[44,6],[45,6],[8,6],[9,6],[11,6],[10,6],[2,6],[12,6],[13,6],[14,6],[15,6],[16,6],[17,6],[18,6],[19,6],[3,6],[4,6],[20,6],[24,6],[21,6],[22,6],[23,6],[25,6],[26,6],[27,6],[5,6],[28,6],[29,6],[30,6],[31,6],[6,6],[35,6],[32,6],[33,6],[34,6],[36,6],[7,6],[37,6],[42,6],[43,6],[38,6],[39,6],[40,6],[41,6],[1,6],[83,82],[93,83],[82,82],[103,84],[74,85],[73,86],[102,87],[96,88],[101,89],[76,90],[90,91],[75,92],[99,93],[71,94],[70,87],[100,95],[72,96],[77,97],[78,6],[81,97],[68,6],[104,98],[94,99],[85,100],[86,101],[88,102],[84,103],[87,104],[97,87],[79,105],[80,106],[89,107],[69,108],[92,99],[91,97],[95,6],[98,109],[59,110],[186,111],[184,112],[162,113],[55,114],[54,6],[56,115],[57,6],[58,116],[185,117]],"semanticDiagnosticsPerFile":[51,53,60,194,189,187,192,188,190,191,159,106,107,108,109,110,111,61,64,62,63,112,113,114,115,116,117,118,120,119,121,122,123,105,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,142,141,143,144,145,146,147,148,149,66,65,158,150,151,152,153,154,155,156,157,48,52,195,46,49,50,193,67,47,163,180,178,179,167,168,175,166,171,181,172,177,183,182,165,173,174,169,176,170,161,160,164,44,45,8,9,11,10,2,12,13,14,15,16,17,18,19,3,4,20,24,21,22,23,25,26,27,5,28,29,30,31,6,35,32,33,34,36,7,37,42,43,38,39,40,41,1,83,93,82,103,74,73,102,96,101,76,90,75,99,71,70,100,72,77,78,81,68,104,94,85,86,88,84,87,97,79,80,89,69,92,91,95,98,59,186,184,162,55,54,56,57,58,185],"affectedFilesPendingEmit":[51,53,194],"emitSignatures":[51,53,194]},"version":"5.3.3"} \ No newline at end of file +{"program":{"fileNames":["../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es5.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.dom.iterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/global.d.ts","../node_modules/.pnpm/csstype@3.1.3/node_modules/csstype/index.d.ts","../node_modules/.pnpm/@types+prop-types@15.7.13/node_modules/@types/prop-types/index.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/index.d.ts","../node_modules/.pnpm/@types+react@18.3.12/node_modules/@types/react/jsx-runtime.d.ts","../node_modules/.pnpm/mlly@1.7.2/node_modules/mlly/dist/index.d.ts","../node_modules/.pnpm/typescript@5.3.3/node_modules/typescript/lib/typescript.d.ts","../node_modules/.pnpm/pkg-types@1.0.3/node_modules/pkg-types/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/csstype.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/selectors.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/conditions.d.ts","../node_modules/.pnpm/microdiff@1.3.2/node_modules/microdiff/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/artifact.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/static-css.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/prop-type.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/style-props.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/system-types.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/recipe.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/style-rules.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/hooks-api.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/logger.d.ts","../node_modules/.pnpm/@ts-morph+common@0.22.0/node_modules/@ts-morph/common/lib/typescript.d.ts","../node_modules/.pnpm/@ts-morph+common@0.22.0/node_modules/@ts-morph/common/lib/ts-morph-common.d.ts","../node_modules/.pnpm/ts-morph@21.0.1/node_modules/ts-morph/lib/ts-morph.d.ts","../node_modules/.pnpm/ts-evaluator@1.2.0_typescript@5.3.3/node_modules/ts-evaluator/dist/esm/index.d.ts","../node_modules/.pnpm/@pandacss+extractor@0.40.1_typescript@5.3.3/node_modules/@pandacss/extractor/dist/index.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/parser.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/hooks.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/shared.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/tokens.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/pattern.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/composition.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/theme.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/utility.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/config.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/analyze-report.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/parts.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/runtime.d.ts","../node_modules/.pnpm/@pandacss+types@0.47.1/node_modules/@pandacss/types/dist/index.d.ts","../node_modules/.pnpm/@pandacss+dev@0.47.1_typescript@5.3.3/node_modules/@pandacss/dev/dist/index.d.ts","./styled-system/types/static-css.d.ts","./styled-system/types/csstype.d.ts","./styled-system/types/selectors.d.ts","./styled-system/types/conditions.d.ts","./styled-system/tokens/tokens.d.ts","./styled-system/tokens/index.d.ts","./styled-system/types/prop-type.d.ts","./styled-system/types/style-props.d.ts","./styled-system/types/system-types.d.ts","./styled-system/types/recipe.d.ts","./styled-system/types/parts.d.ts","./styled-system/types/pattern.d.ts","./styled-system/types/composition.d.ts","./styled-system/types/global.d.ts","./styled-system/types/index.d.ts","./styled-system/css/css.d.ts","./styled-system/css/cx.d.ts","./styled-system/css/cva.d.ts","./styled-system/css/sva.d.ts","./styled-system/css/index.d.ts","./src/components/button/iconbutton.style.ts","./src/components/button/iconbutton.tsx","./styled-system/recipes/glass-container.d.ts","./styled-system/recipes/index.d.ts","./src/components/bottomnavigator/bottomnavigator.style.ts","./src/components/bottomnavigator/bottomnavigator.tsx","./src/components/sidebar/menubutton.style.ts","./src/components/sidebar/menubutton.tsx","./src/components/sidebar/pageitem.style.ts","./src/components/sidebar/pageitem.tsx","./src/components/sidebar/sidebar.style.ts","./src/components/sidebar/sidebar.tsx","./src/features/editor/editor.tsx","./src/features/page/page.style.ts","./src/features/page/components/pagecontrolbutton.style.ts","./src/features/page/components/pagecontrolbutton.tsx","./src/features/page/page.tsx","./src/features/workspace/workspace.style.ts","./src/features/workspace/workspace.tsx","./src/app.tsx","../node_modules/.pnpm/@types+react-dom@18.3.1/node_modules/@types/react-dom/client.d.ts","./src/main.tsx","./src/vite-env.d.ts","./src/styles/global.ts","./src/styles/typography.ts","./src/styles/recipes/glasscontainerrecipe.ts","./src/styles/tokens/color.ts","./src/styles/tokens/radii.ts","./src/styles/tokens/shadow.ts","./src/styles/tokens/spacing.ts","./panda.config.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/disposable.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/indexable.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/iterators.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/compatibility/index.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/globals.typedarray.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/buffer.buffer.d.ts","../node_modules/.pnpm/buffer@5.7.1/node_modules/buffer/index.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/header.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/readable.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/file.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/fetch.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/formdata.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/connector.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/client.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/errors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-dispatcher.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-origin.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool-stats.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/handlers.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/balanced-pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-interceptor.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-client.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-pool.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-errors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/env-http-proxy-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-handler.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-agent.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/api.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/interceptors.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/util.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cookies.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/patch.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/websocket.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/eventsource.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/filereader.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/content-type.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cache.d.ts","../node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/index.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/globals.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/assert.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/assert/strict.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/async_hooks.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/buffer.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/child_process.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/cluster.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/console.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/constants.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/crypto.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dgram.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dns.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dns/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/domain.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/dom-events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/fs.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/fs/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/http.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/http2.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/https.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/inspector.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/module.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/net.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/os.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/path.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/perf_hooks.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/process.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/punycode.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/querystring.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/readline.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/readline/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/repl.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/sea.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/consumers.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/stream/web.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/string_decoder.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/test.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/timers.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/timers/promises.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/tls.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/trace_events.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/tty.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/url.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/util.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/v8.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/vm.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/wasi.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/worker_threads.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/zlib.d.ts","../node_modules/.pnpm/@types+node@20.17.6/node_modules/@types/node/ts5.6/index.d.ts","../node_modules/.pnpm/@types+estree@1.0.6/node_modules/@types/estree/index.d.ts","../node_modules/.pnpm/rollup@4.24.3/node_modules/rollup/dist/rollup.d.ts","../node_modules/.pnpm/rollup@4.24.3/node_modules/rollup/dist/parseast.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/hmrpayload.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/customevent.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/hot.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/types.d-agj9qkwt.d.ts","../node_modules/.pnpm/esbuild@0.21.5/node_modules/esbuild/lib/main.d.ts","../node_modules/.pnpm/source-map-js@1.2.1/node_modules/source-map-js/source-map.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/previous-map.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/input.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/css-syntax-error.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/declaration.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/root.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/warning.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/lazy-result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/no-work-result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/processor.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/result.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/document.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/rule.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/node.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/comment.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/container.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/at-rule.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/list.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/postcss.d.ts","../node_modules/.pnpm/postcss@8.4.47/node_modules/postcss/lib/postcss.d.mts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/runtime.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/importglob.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/metadata.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/dist/node/index.d.ts","../node_modules/.pnpm/@babel+types@7.26.0/node_modules/@babel/types/lib/index.d.ts","../node_modules/.pnpm/@types+babel__generator@7.6.8/node_modules/@types/babel__generator/index.d.ts","../node_modules/.pnpm/@babel+parser@7.26.2/node_modules/@babel/parser/typings/babel-parser.d.ts","../node_modules/.pnpm/@types+babel__template@7.4.4/node_modules/@types/babel__template/index.d.ts","../node_modules/.pnpm/@types+babel__traverse@7.20.6/node_modules/@types/babel__traverse/index.d.ts","../node_modules/.pnpm/@types+babel__core@7.20.5/node_modules/@types/babel__core/index.d.ts","../node_modules/.pnpm/@vitejs+plugin-react@4.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/@vitejs/plugin-react/dist/index.d.mts","../node_modules/.pnpm/vite-tsconfig-paths@5.1.0_typescript@5.3.3_vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0_/node_modules/vite-tsconfig-paths/dist/index.d.ts","./vite.config.ts","./styled-system/patterns/aspect-ratio.d.ts","./styled-system/patterns/bleed.d.ts","./styled-system/patterns/box.d.ts","./styled-system/patterns/center.d.ts","./styled-system/patterns/circle.d.ts","./styled-system/patterns/container.d.ts","./styled-system/patterns/cq.d.ts","./styled-system/patterns/divider.d.ts","./styled-system/patterns/flex.d.ts","./styled-system/patterns/float.d.ts","./styled-system/patterns/grid-item.d.ts","./styled-system/patterns/grid.d.ts","./styled-system/patterns/hstack.d.ts","./styled-system/patterns/stack.d.ts","./styled-system/patterns/vstack.d.ts","./styled-system/patterns/spacer.d.ts","./styled-system/patterns/square.d.ts","./styled-system/patterns/link-overlay.d.ts","./styled-system/patterns/wrap.d.ts","./styled-system/patterns/visually-hidden.d.ts","./styled-system/patterns/index.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/types/importmeta.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_lightningcss@1.25.1_terser@5.36.0/node_modules/vite/client.d.ts","../node_modules/.pnpm/vite@5.4.10_@types+node@20.17.6_terser@5.36.0/node_modules/vite/types/metadata.d.ts"],"fileInfos":[{"version":"f33e5332b24c3773e930e212cbb8b6867c8ba3ec4492064ea78e55a524d57450","affectsGlobalScope":true},"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","26f2f787e82c4222710f3b676b4d83eb5ad0a72fa7b746f03449e7a026ce5073","9a68c0c07ae2fa71b44384a839b7b8d81662a236d4b9ac30916718f7510b1b2d","5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4",{"version":"21e41a76098aa7a191028256e52a726baafd45a925ea5cf0222eb430c96c1d83","affectsGlobalScope":true},{"version":"35299ae4a62086698444a5aaee27fc7aa377c68cbb90b441c9ace246ffd05c97","affectsGlobalScope":true},{"version":"138fb588d26538783b78d1e3b2c2cc12d55840b97bf5e08bca7f7a174fbe2f17","affectsGlobalScope":true},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true},{"version":"4443e68b35f3332f753eacc66a04ac1d2053b8b035a0e0ac1d455392b5e243b3","affectsGlobalScope":true},{"version":"bc47685641087c015972a3f072480889f0d6c65515f12bd85222f49a98952ed7","affectsGlobalScope":true},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true},{"version":"93495ff27b8746f55d19fcbcdbaccc99fd95f19d057aed1bd2c0cafe1335fbf0","affectsGlobalScope":true},{"version":"6fc23bb8c3965964be8c597310a2878b53a0306edb71d4b5a4dfe760186bcc01","affectsGlobalScope":true},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true},{"version":"bb42a7797d996412ecdc5b2787720de477103a0b2e53058569069a0e2bae6c7e","affectsGlobalScope":true},{"version":"4738f2420687fd85629c9efb470793bb753709c2379e5f85bc1815d875ceadcd","affectsGlobalScope":true},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true},{"version":"9fc46429fbe091ac5ad2608c657201eb68b6f1b8341bd6d670047d32ed0a88fa","affectsGlobalScope":true},{"version":"61c37c1de663cf4171e1192466e52c7a382afa58da01b1dc75058f032ddf0839","affectsGlobalScope":true},{"version":"b541a838a13f9234aba650a825393ffc2292dc0fc87681a5d81ef0c96d281e7a","affectsGlobalScope":true},{"version":"e0275cd0e42990dc3a16f0b7c8bca3efe87f1c8ad404f80c6db1c7c0b828c59f","affectsGlobalScope":true},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true},{"version":"49ed889be54031e1044af0ad2c603d627b8bda8b50c1a68435fe85583901d072","affectsGlobalScope":true},{"version":"e93d098658ce4f0c8a0779e6cab91d0259efb88a318137f686ad76f8410ca270","affectsGlobalScope":true},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true},{"version":"bf14a426dbbf1022d11bd08d6b8e709a2e9d246f0c6c1032f3b2edb9a902adbe","affectsGlobalScope":true},{"version":"ec0104fee478075cb5171e5f4e3f23add8e02d845ae0165bfa3f1099241fa2aa","affectsGlobalScope":true},{"version":"2b72d528b2e2fe3c57889ca7baef5e13a56c957b946906d03767c642f386bbc3","affectsGlobalScope":true},{"version":"acae90d417bee324b1372813b5a00829d31c7eb670d299cd7f8f9a648ac05688","affectsGlobalScope":true},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true},{"version":"33358442698bb565130f52ba79bfd3d4d484ac85fe33f3cb1759c54d18201393","affectsGlobalScope":true},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true},{"version":"36a2e4c9a67439aca5f91bb304611d5ae6e20d420503e96c230cf8fcdc948d94","affectsGlobalScope":true},"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","ed6b820c54de95b2510bb673490d61c7f2187f532a339d8d04981645a918961f",{"version":"aa17748c522bd586f8712b1a308ea23af59c309b2fd278f6d4f406647c72e659","affectsGlobalScope":true},"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","8697faa527dd799c5bbe64723aa2593fdd47c609864aa4c49689997cd06cebac","b426147fec725961d1305b25b26dbf99e5c419de98b5728974a8a44fc5959181","1235f6acae8da14ce25d9f75df290c4e4f7d53d024b4e91c6121ff44ea13c801","8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","77d596561ec05cddc53701988ff8d891047978036c603de4b405b31e11f8575b","15bd07838cd4506b93e6835f78c5dedacc0bcae7202b2086444637df4a8f4d45","348c57c67c092eb3c28873d630c320e392e947a07946aaced323e8e6eafb915d","83fcaf1f41dd04269322cfdd47aa2546ec0393c83c2f3a1a2ad321765a3e3aa2","98240aef8bd41abfdef295d1dbe712d51a8cf1dea125c40f270bafc816cbf6c5","4baa8b99f90861f5e8ba1efb2deef2195be4037ea47b83180b6770d76bfe845c","03c0c949e86c44a98165752c31d9edea61b853a237254806b5a452c16b6f709f","7c8cffc734f0860b5eb694a3cf43a347cbcc531877a06a8a0b0748113487c4df","d3a88ebd39ffd613ac064bbe2d813e47d262219d4581dd437caf80d4cfd3e437","db56a1b0b070b2a9b68561c3542b3928492793e32c632171caa6c53fb8ecb402","a92ea8cdc292bee86d7bf00ade4d4c2b84ef07b6a772650c4a3f503e83c43f95","9cc2ce851dce49e8e831ffefd5ac85b62319e97df4821683dcc80fb17e08197e","f2a60f3d9dac64110308154059537cd87ab6f4c607395a89e3cc703f837b8d22","b2f74a813678952f4906641449101cb04e6b94a3055a60c194d28f93fcb58a25","e5b2239e66924ad249294b617d85dc561a04fa1491f3b9aa45e067456682ada7","3ae8dd5663704463b336ce8e43dab2a53fc7f085841602f90f07d3edf675ce65","c6c583d215c29a8420c52a01f041a3ebfa5ad9eecd4049b57acda599e3e30ed0","10ccdcf171b365e3fc0b9540f9941ad3915ba3672eda63099156d64f5b9616e8","9e6ae4de60321c9c875ce5871dfcc9426dbb006b76ec6593363f012d434cf704","85329c72103a5d46c60b93f130a8cc941d029dfc52caf8ba01f208b3b006083e","56fb55555c935a1ef9f70369252c25f96397171443b3fa829eab2e27aab7f43b","1cc1dd565274a0c1f7a13a2f1d581c51b3b770b4c502a7ddf2b623d8e57671a8","e83447f88a6a9a5e5426131b165337b4dff7ff249d3899c7cacc6e7c47267412","baac36a022cf0ccddaf1648e242068e358e2b78483efb816c8d05384217928fc","e1dfeb7fe1815dae68e2513ac1cf5130d6977688a5090eeef9f3dde05791532f","4e4c1412ce497716a61b7bbca1302826c4eb6cf68fce4bb76f190c31e544568c","86075b555f88780f45c665374f1678b0010ed92c1da6defb8978aef63ad9823f","729d731c01903375efde3fbee81d8bdb2f189bd42f5af97de33c8dde4a948011","f6059a11ad8f08358eec11f1167e9b6ecd4adcba611c266dad5a6476381b6a79","faacee8a12d1ac0edfc1393404f3629e1264f955680a89cbfecc58dabc85e24a","f86cbc47cd362a2095e6841a9f636ed41f196c06d800c9d031a4e5a9fa3609d6","532a61e1bc826812ddf5b670c3e832ea9fe875c95a9d3be33e4c2a176b5f71f0","1e852a81f8ab8017a2ec279e822641c9a6d856717696da38d7e01b78c7725775","2f462d47bcf3b80e045843dc3aae0bd1c0ea673a9cbc46ed6a367e59790e99f1","620a5aae820e9ba53965b4af9c87e5bdd7d30c6aa549687af36bd557b18992d4","786d3aa183718767586a27b94ddb7b836757c5a4c24e53ded623d05e6a86d6c4","695932cb32b555db096ee4072a818b774aeec9cd0c6864d4af5180c0e58f83dd","5d9359d943f675879e1dcb5d7dbd77edae1503769fd9036f4372ce6e54f358a8","f27e2c4fbb11766959ba9bb27882efebe8cc3346c4f3dfe78200eb23681ca1ce","da459d6c84246bbf0a8befd1df34a1120374d9570e8ca73800862ccb47cc7e1b","ea9f8137a900e961ab0d0afe2493a3be050a9e5e3aa3bd4d2b7cb62751bdf7a8","f6b0d3cfad6acbe42c53a53ec86cd8e8c65881668a1fc627940376eca9beb1fa","2edd7faf1bc8a0fca9ee6060a1935c3cd43487ebdc71f34df7f8c59f65b39480","0725189193a07a4fb3cc82c856c70b913f51bd850e86a3586a2457e8c008affd","951ea5f4424d919bf78c95291e66d0c0f36b26d01b70db627e5f19dca3fe1778","5027a140fc57c7750853cacec34363c091dda7c4ca97dad0e2c4f5c8ad0bc87f","ea6dd5ffdf73eb07480bd7e6358845b2cf5237041851e477c9cb72d02d4d86fa","a803b31b8a4ecf5f782da5c6254b1a327a9f55fc90c0d09e4a8770db53d70e30","76702c38ff90508cad63a94e66d752858bd4456dadc501c7dd919b441215df35","4e979330517c1527ed78e19bb70619e5b276b80a89103f8fed7f63b2f27d52cb","044aae1e62523280d3679eed49ffa288bb793d87b98ab4aaa37a7024838929f3",{"version":"7b312001a7cc821594bf346b364bc76604ec14db06292bdb3f8037dbe82d28f1","signature":"f7ce3c14b40fd0fa1f38a4922e4f65f0dc296cd0798ddcb569b5681e682ba2ff"},{"version":"9d859490d085e26024ff254e37b8d01c050fa09bc24c77002e04016102c69741","signature":"241670462fddff5bd4688b4e030bf860c9f0e8a63aced869cf515d123f1e4de3"},"d3c03ffa8da44ac52d6f610275a3bf57957846e8cf417bf5ca9610722b319857","ec61b7543855ffd13ec368dfad5a492669d78cb5060ccbffd294c5141e3c3606",{"version":"2d617b5b26592ea5529011d707b76290d323dd85b065f98e1e7e568faf9cc526","signature":"4f105da204a6ec7666bb6f560534b19d83d294e7227dfceccc7127e472245287"},{"version":"c10329719ba28c1ede3361522df4aeaa5d0bc699fd3883dbd87445719efaf7da","signature":"b2e54a0ad500b4cfceb8a721ac7c920fb95202fd76e3c8b8ffe3f568a4988b12"},{"version":"9fd356c5bc995eaa8e143fadd96fd68e98d5c6cf845abc7c78db78169c908e96","signature":"d839925736d555cb6822e9ebcac9b2be23fc0e77b5ca070079f8ea154240df3e"},{"version":"39b181b80b791712b781b1eef242bf7e7472ab45fe9c34fd789374bdded6af54","signature":"d79fd618eba486f4b25279d184f9dc9db1f930b0590c868c8881bb9d97df3c5f"},{"version":"f856532160b20e581e50063aa30cf43829eb6501d196865087dcb9691e5bf37a","signature":"f6f25d3f349c387e05a3733c53e04b90e26a8ee6f7b8d785a6fa51bb1b9fd4a1"},{"version":"bb06fe1c093862e107e7ec0dbc3d391d5ce120166b9842f702654ae9ba99a300","signature":"dc8b47c261dfa3ed5d3d97572c8c8548f0a8e4fcd91054dbe281f9633767a900"},{"version":"0f7feecc46662338245b7886ef5ea4b72590f1993f027acf35c00676cf9a9535","signature":"9017e09dfb4877c8fdad50c5d454c30ce87b31ee41039345cb8da60c265e6d4b"},{"version":"9a1a50db04b39c469a27b4a4a31aa072ced57ee9c2718f65648d98eefededed5","signature":"bfc4ca2b4e87103961ef1d70f04980c21a27262a66a6551491b0ced2fcfa9102"},{"version":"695340b7eea7617219bdd4a5517d6b88bba692885439e7891b2fbee11d5a691a","signature":"520b1c79cff87d3187ee406fde2a72577f989300a7a1fb45db1c5239efb67917"},{"version":"eccd2add5a048109eec8bb15162f1b666a7c2de2efccb229df77be2f86807ebc","signature":"b367fd518f6ae9d010da0fe9f5a26d0b3fbc56d0954ce0b6d9f5704c9a993899"},{"version":"f6bb11818d6d7f08403b9b3117ea3ee858fbee57326c8d60a76da54f9b455dd0","signature":"08e35ec6e9d870d137605d1d386f8a1fdd7c0132b9ff25dc935f16e4056da155"},{"version":"af223f20d2c38d42f0e91eb44d0546220a1e94322907e6552448419d63405606","signature":"cff912230eac799da5f80f17b67b686a2f97d37166514252ec5e7e5a26ba3f3b"},{"version":"6b71869dc6e59a969575f1d03ce8357d80a0f9a4ed356e8a9758e316bb6f0389","signature":"328d0ad2a92efba2c3dcdc5c0264c9b8357858e49d9a75afe5a620fbf7e5f543"},{"version":"79d673af430de474244eb7f3811d1bed659d75dbeedc890b6d48d0d55797fbb8","signature":"d1ee79509a15b7071cae5ae12ae9e9251ef981595591f33e99140497b5930a36"},{"version":"10775308af7d02db9a8994daf1ada5ecddd965da259223aa5572e51e62cfb176","signature":"914eab2f592d2ba92a43000d133d72a0cddc4a3f165d1eb54c44167c0f2a8fac"},{"version":"b35374fd1a543743ce348681b44f3682d36c8c424b2bc8e010549eb2204fdf17","signature":"341b573d3667f20d60339a9be793c7fdbe61b67428ca1b11ced2c5ddb8321882"},"05321b823dd3781d0b6aac8700bfdc0c9181d56479fe52ba6a40c9196fd661a8",{"version":"c6713f68e9761117b8e6ec9be2992af70f395b01b4d058d8baac0b6108ecc763","signature":"2590965bf9ef1f0d1be0cf046845c563138258f8180f56986d62d04066b4155a"},"d071c1fa889272a3c73a1fb993916fbd6fb5c70d90a7a19a9beb7d83b3d6060b",{"version":"4a734a7287b85d3af862acf994a9350c667fcecec5ccd44aeb05517e9730ff1b","signature":"65de77c56894d87baa5d0f33964a2b9bd5aafc9159726e6fd33d3c6a36377be9"},{"version":"76bd507995c3526c540630dd7b0261e05c72818e683c56673d8770d998d35441","signature":"1f921a0effb5a2af82bd16d6818d315c2720f209f3ae907e8b2522b007c0e349"},{"version":"46872cbcf7f1dc60e570fa9a97a9dad480bdca6de92386ec61031b7b0388b2f9","signature":"51b8df2285c4af64db9b02bbeaa82ea7334832584cd50a79fce929e4fd083b67"},{"version":"2fedcdcb14fafa8715a065ffcb28bd5c797f236c71d2c92d6269b0e73a1887c6","signature":"2fd088628cba7e13eed0a1b5fd162b32c327a0d29bbe63dec1c16e9ecca10649"},{"version":"7e9569b2e39f27fabfcf3644816654d71fb01a107b2baf343cc9aaa730e78821","signature":"e52b62f8975a33bd32a4a17f9bb7448ff17f5e28d8a5912b0901c8c4475da6e3"},{"version":"8ea21d92ccfc4932ac22be7c557915328a8383d4b67a3add27e817a50cb8f617","signature":"525b64c6dcd7ebf552f06d89bed16bc275bc456037860bdedf2dff6db9a0fa57"},{"version":"1cd7a0be40ec779afd2c18884dd2566f15b67d29a4bd2410b642472097994b15","signature":"56524c89f40203a5bc531f76df1b2c2d077231fc75994487d4f1a227e7d8ab27"},{"version":"9ec0ac5e68f574b2e5bf86dd1a3b222886b51a5d7f52747791f2b9df106e2245","signature":"fb629e920ad81007307732f89afa5c310a5ab5ac946009cd2b0d5604c7926e03"},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true},"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a",{"version":"613b21ccdf3be6329d56e6caa13b258c842edf8377be7bc9f014ed14cdcfc308","affectsGlobalScope":true},{"version":"2d1319e6b5d0efd8c5eae07eb864a00102151e8b9afddd2d45db52e9aae002c4","affectsGlobalScope":true},"8e9c23ba78aabc2e0a27033f18737a6df754067731e69dc5f52823957d60a4b6","5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","24bd580b5743dc56402c440dc7f9a4f5d592ad7a419f25414d37a7bfe11e342b","25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","6bdc71028db658243775263e93a7db2fd2abfce3ca569c3cca5aee6ed5eb186d","cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","4d2b0eb911816f66abe4970898f97a2cfc902bcd743cbfa5017fad79f7ef90d8","bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","e53a3c2a9f624d90f24bf4588aacd223e7bec1b9d0d479b68d2f4a9e6011147f","24b8685c62562f5d98615c5a0c1d05f297cf5065f15246edfe99e81ec4c0e011","93507c745e8f29090efb99399c3f77bec07db17acd75634249dc92f961573387","339dc5265ee5ed92e536a93a04c4ebbc2128f45eeec6ed29f379e0085283542c","4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107",{"version":"ca6d304b929748ea15c33f28c1f159df18a94470b424ab78c52d68d40a41e1e9","affectsGlobalScope":true},"a72ffc815104fb5c075106ebca459b2d55d07862a773768fce89efc621b3964b","7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","3d77c73be94570813f8cadd1f05ebc3dc5e2e4fdefe4d340ca20cd018724ee36",{"version":"d674383111e06b6741c4ad2db962131b5b0fa4d0294b998566c635e86195a453","affectsGlobalScope":true},"f3e58c4c18a031cbb17abec7a4ad0bd5ae9fc70c1f4ba1e7fb921ad87c504aca","a3e8bafb2af8e850c644f4be7f5156cf7d23b7bfdc3b786bd4d10ed40329649c",{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true},"a40826e8476694e90da94aa008283a7de50d1dafd37beada623863f1901cb7fb",{"version":"f77d9188e41291acf14f476e931972460a303e1952538f9546e7b370cb8d0d20","affectsGlobalScope":true},"b0c0d1d13be149f790a75b381b413490f98558649428bb916fd2d71a3f47a134","3c884d9d9ec454bdf0d5a0b8465bf8297d2caa4d853851d92cc417ac6f30b969","5a369483ac4cfbdf0331c248deeb36140e6907db5e1daed241546b4a2055f82c","e8f5b5cc36615c17d330eaf8eebbc0d6bdd942c25991f96ef122f246f4ff722f","f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45",{"version":"ee1ee365d88c4c6c0c0a5a5701d66ebc27ccd0bcfcfaa482c6e2e7fe7b98edf7","affectsGlobalScope":true},{"version":"4d7da7075068195f8f127f41c61e304cdca5aafb1be2d0f4fb67c6b4c3e98d50","affectsGlobalScope":true},"a4bdde4e601e9554a844e1e0d0ccfa05e183ef9d82ab3ac25f17c1709033d360","ad23fd126ff06e72728dd7bfc84326a8ca8cec2b9d2dac0193d42a777df0e7d8","9dd9f50652a176469e85fb65aa081d2e7eb807e2c476f378233de4f1f6604962","93bd413918fa921c8729cef45302b24d8b6c7855d72d5bf82d3972595ae8dcbf","4ff41188773cbf465807dd2f7059c7494cbee5115608efc297383832a1150c43","dccdf1677e531e33f8ac961a68bc537418c9a414797c1ea7e91307501cdc3f5e",{"version":"7edec695cdb707c7146ac34c44ca364469c7ea504344b3206c686e79f61b61a2","affectsGlobalScope":true},"d206b4baf4ddcc15d9d69a9a2f4999a72a2c6adeaa8af20fa7a9960816287555","93f437e1398a4f06a984f441f7fa7a9f0535c04399619b5c22e0b87bdee182cb","afbe24ab0d74694372baa632ecb28bb375be53f3be53f9b07ecd7fc994907de5",{"version":"70731d10d5311bd4cf710ef7f6539b62660f4b0bfdbb3f9fbe1d25fe6366a7fa","affectsGlobalScope":true},{"version":"a20f1e119615bf7632729fd89b6c0b5ffdc2df3b512d6304146294528e3ebe19","affectsGlobalScope":true},"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","137c2894e8f3e9672d401cc0a305dc7b1db7c69511cf6d3970fb53302f9eae09","3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","8145e07aad6da5f23f2fcd8c8e4c5c13fb26ee986a79d03b0829b8fce152d8b2","f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","235bfb54b4869c26f7e98e3d1f68dbfc85acf4cf5c38a4444a006fbf74a8a43d","37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","93452d394fdd1dc551ec62f5042366f011a00d342d36d50793b3529bfc9bd633",{"version":"bb715efb4857eb94539eafb420352105a0cff40746837c5140bf6b035dd220ba","affectsGlobalScope":true},"1851a3b4db78664f83901bb9cac9e45e03a37bb5933cc5bf37e10bb7e91ab4eb",{"version":"fdedf82878e4c744bc2a1c1e802ae407d63474da51f14a54babe039018e53d8f","affectsGlobalScope":true},{"version":"08353b04a3501d84fc8d7b49de99f6c1cc26026e6d9d697a18315f3bfe92ed03","affectsGlobalScope":true},"578d8bb6dcb2a1c03c4c3f8eb71abc9677e1a5c788b7f24848e3138ce17f3400","4f029899f9bae07e225c43aef893590541b2b43267383bf5e32e3a884d219ed5","ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9",{"version":"5b566927cad2ed2139655d55d690ffa87df378b956e7fe1c96024c4d9f75c4cf","affectsGlobalScope":true},{"version":"bce947017cb7a2deebcc4f5ba04cead891ce6ad1602a4438ae45ed9aa1f39104","affectsGlobalScope":true},"efeedd8bbc5c0d53e760d8b120a010470722982e6ae14de8d1bcff66ebc2ae71","e2c72c065a36bc9ab2a00ac6a6f51e71501619a72c0609defd304d46610487a4","d91a7d8b5655c42986f1bdfe2105c4408f472831c8f20cf11a8c3345b6b56c8c",{"version":"616075a6ac578cf5a013ee12964188b4412823796ce0b202c6f1d2e4ca8480d7","affectsGlobalScope":true},"e8a979b8af001c9fc2e774e7809d233c8ca955a28756f52ee5dee88ccb0611d2","9091e564b81e7b4c382a33c62de704a699e10508190547d4f7c1c3e039d2db2b","785b9d575b49124ce01b46f5b9402157c7611e6532effa562ac6aebec0074dfc",{"version":"e58a3ce75105c1557e34fab7408942d77374e047c16383e80880ed1220166dfa","affectsGlobalScope":true},"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","282f98006ed7fa9bb2cd9bdbe2524595cfc4bcd58a0bb3232e4519f2138df811","6222e987b58abfe92597e1273ad7233626285bc2d78409d4a7b113d81a83496b","cbe726263ae9a7bf32352380f7e8ab66ee25b3457137e316929269c19e18a2be","8b96046bf5fb0a815cba6b0880d9f97b7f3a93cf187e8dcfe8e2792e97f38f87",{"version":"bacf2c84cf448b2cd02c717ad46c3d7fd530e0c91282888c923ad64810a4d511","affectsGlobalScope":true},"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","8885cf05f3e2abf117590bbb951dcf6359e3e5ac462af1c901cfd24c6a6472e2","4d979e3c12ffb6497d2b1dc5613130196d986fff764c4526360c0716a162e7e7","e61df3640a38d535fd4bc9f4a53aef17c296b58dc4b6394fd576b808dd2fe5e6","80781460eca408fe8d2937d9fdbbb780d6aac35f549621e6200c9bee1da5b8fe","4719c209b9c00b579553859407a7e5dcfaa1c472994bd62aa5dd3cc0757eb077","7ec359bbc29b69d4063fe7dad0baaf35f1856f914db16b3f4f6e3e1bca4099fa","b9261ac3e9944d3d72c5ee4cf888ad35d9743a5563405c6963c4e43ee3708ca4","c84fd54e8400def0d1ef1569cafd02e9f39a622df9fa69b57ccc82128856b916","a022503e75d6953d0e82c2c564508a5c7f8556fad5d7f971372d2d40479e4034","2ed6489ef46eb61442d067c08e87e3db501c0bfb2837eee4041a27bf3e792bb0","644491cde678bd462bb922c1d0cfab8f17d626b195ccb7f008612dc31f445d2d","d60fe6d59d4e19ecc65359490b8535e359ca4b760d2cdb56897ca75d09d41ba3","f45a2a8b1777ecb50ed65e1a04bb899d4b676529b7921bd5d69b08573a00c832","774b783046ba3d473948132d28a69f52a295b2f378f2939304118ba571b1355e","b5734e05c787a40e4f9efe71f16683c5f7dc3bdb0de7c04440c855bd000f8fa7","14ba97f0907144771331e1349fdccb5a13526eba0647e6b447e572376d811b6f","2a771d907aebf9391ac1f50e4ad37952943515eeea0dcc7e78aa08f508294668","7165050eddaed878c2d2cd3cafcaf171072ac39e586a048c0603712b5555f536","26e629be9bbd94ea1d465af83ce5a3306890520695f07be6eb016f8d734d02be","82e687ebd99518bc63ea04b0c3810fb6e50aa6942decd0ca6f7a56d9b9a212a6","7f698624bbbb060ece7c0e51b7236520ebada74b747d7523c7df376453ed6fea","8f07f2b6514744ac96e51d7cb8518c0f4de319471237ea10cf688b8d0e9d0225","9ae0ca65717af0d3b554a26fd333ad9c78ad3910ad4b22140ff02acb63076927","03f1d83d61696326ea29c8a1c15cbaccf61e92598d53f2ccae06078531f42448","2c8e55457aaf4902941dfdba4061935922e8ee6e120539c9801cd7b400fae050","3a9313fe5ace558b8b18e85f931da10b259e738775f411c061e5f15787b138eb","670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","9e0cf651e8e2c5b9bebbabdff2f7c6f8cedd91b1d9afcc0a854cdff053a88f1b","069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","f5e8546cfe500116aba8a6cb7ee171774b14a6db30d4bcd6e0aa5073e919e739","cadf7a128bda2a4937411ad8fc659c08142ae7b53a7559eada72e8c34a5ea273",{"version":"5325aed271103cf0c9732fa24eecf95155af7d7c2e6ce8bd9d09795986ead6ee","signature":"4b96dd19fd2949d28ce80e913412b0026dc421e5bf6c31d87c7b5eb11b5753b4"},"40afb567fb15f802cc373d3f968cb12f06ef91105997ac6cd1b7476f9f1400a7","b4f7765a7e4378d5553d62243e1294f9e84e6b155b786ff3a2d70dd90a0b7269","767b2fc647298d1e885ab9b5e80a3bfc955b7c3a56fdc67e09697ac66662617f","58d97a898371adf4648416a194695cac091094a93aec40d4bf80d178c655e322","33ab53254b48915b80729554b64dc520ddf52fa2fbb9d158f548e04184ebcf8c","0c85d40d15a7dccddc3f1687c956b44e884da668c4709ebe46443ba01f8e8842","bb9e974b872fc5efe3fbeb234afa1b167466822c521adec28f312b629f5dda56","c8263035d5bb170e586fef2a84cb43b6ae0a40e0febe619b3870733587629ab4","854d32966f04256f250530f7c03b4f7e11379c73b88d45cf8eb867ee3f790866","7372dded088ca5020b7bdc36c767207b5be95bac93db7d4da8939b4e5183d504","f141146eac82ec13c16311bc7d5088251c6c36e177946f804532b9457a5b4858","4af9e9cd8b6f583bbd4f5a25603385d0d32082b437334b70c90b5ea56a197301","68c96a0456890bd49e2871dd88c53ff7f9fd87eb32f2cd419e4a83f79a8d5ef1","73a58b4dd96dd47dab5b4029726b9bb923543ca24ddd04c6069577945ba46a88","b3554a8f9ac018e333c208a4eaac5744c6739430fd58a9442b904949a4850cdc","fd893a255c9b5fbcf730166bfc8cb13cbdfbd151212fe6d14bbc2850b1577dfb","288fa23f9ecb8231712fda606a90e8fcb8e5badc7d26b6aa55f41c935406654d","469a48cc4e8c79de08be72d4b91aba0c1ff0ff590ddaf4d63430cb8195d5d3b1","1a4c70b6a02db30f1f4cf606763ef4811f7f1ce845c6513e75ac92e8d066fb46","71a56feb625489eec845132b255df1429e3e0e7c76a4e3eef4731f82748076cb","a11f50b21d60f03639225314e0b81e1ffb73469f6500648c303b2a6b26f94d1d",{"version":"4025a454b1ca489b179ee8c684bdd70ff8c1967e382076ade53e7e4653e1daec","affectsGlobalScope":true},{"version":"984c09345059b76fc4221c2c54e53511f4c27a0794dfd6e9f81dc60f0b564e05","affectsGlobalScope":true}],"root":[[86,125],[127,136],[275,296]],"options":{"allowImportingTsExtensions":true,"composite":true,"jsx":4,"module":99,"noFallthroughCasesInSwitch":true,"noUnusedLocals":true,"noUnusedParameters":true,"skipLibCheck":true,"strict":true,"target":7,"useDefineForClassFields":true},"fileIdsList":[[50,85,99,129,130,131,132,133,134,135,142,185],[50,124,142,185],[50,105,109,142,185],[50,107,110,142,185],[50,105,142,185],[50,106,142,185],[50,112,142,185],[50,114,142,185],[50,113,115,116,142,185],[50,142,185],[50,120,142,185],[50,118,119,121,142,185],[50,111,117,122,123,142,185],[49,50,125,126,142,185,298],[50,85,99,142,185],[50,132,142,185],[142,185],[100,142,185],[95,142,185],[101,102,103,104,142,185],[87,91,93,94,100,142,185],[142,185,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295],[94,100,142,185],[108,142,185],[90,142,185],[94,142,185],[88,142,185],[85,94,95,96,97,98,99,142,185],[89,93,94,95,97,99,142,185],[91,94,142,185],[89,91,94,142,185],[86,94,142,185],[87,142,185],[89,91,92,94,142,185],[87,89,93,142,185],[50,142,185,207,266,273,274],[142,185,267],[84,142,185],[69,70,142,185],[80,142,185],[57,142,185],[62,142,185],[55,142,185],[53,56,59,62,73,74,76,78,79,142,185],[62,63,64,80,142,185],[58,65,66,72,80,142,185],[56,58,59,62,63,64,65,66,72,73,74,75,76,77,78,79,80,81,82,83,142,185],[71,142,185],[62,75,142,185],[56,62,142,185],[59,62,142,185],[54,142,185],[54,56,60,142,185],[56,142,185],[54,56,61,142,185],[62,63,75,77,142,185],[74,142,185],[62,74,75,142,185],[67,142,185],[142,185,267,268,269,270,271],[142,185,267,269],[142,182,185],[142,184,185],[142,185,190,219],[142,185,186,191,197,198,205,216,227],[142,185,186,187,197,205],[137,138,139,142,185],[142,185,188,228],[142,185,189,190,198,206],[142,185,190,216,224],[142,185,191,193,197,205],[142,184,185,192],[142,185,193,194],[142,185,197],[142,185,195,197],[142,184,185,197],[142,185,197,198,199,216,227],[142,185,197,198,199,212,216,219],[142,180,185,232],[142,185,193,197,200,205,216,227],[142,185,197,198,200,201,205,216,224,227],[142,185,200,202,216,224,227],[142,185,197,203],[142,185,204,227,232],[142,185,193,197,205,216],[142,185,206],[142,185,207],[142,184,185,208],[142,182,183,184,185,186,187,188,189,190,191,192,193,194,195,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233],[142,185,210],[142,185,211],[142,185,197,212,213],[142,185,212,214,228,230],[142,185,197,216,217,218,219],[142,185,216,218],[142,185,216,217],[142,185,219],[142,185,220],[142,182,185,216],[142,185,197,222,223],[142,185,222,223],[142,185,190,205,216,224],[142,185,225],[185],[140,141,142,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233],[142,185,205,226],[142,185,200,211,227],[142,185,190,228],[142,185,216,229],[142,185,204,230],[142,185,231],[142,185,190,197,199,208,216,227,230,232],[142,185,216,233],[49,142,185],[46,47,48,142,185],[142,185,266,272],[51,52,142,185],[142,185,258],[142,185,256,258],[142,185,247,255,256,257,259],[142,185,245],[142,185,248,253,258,261],[142,185,244,261],[142,185,248,249,252,253,254,261],[142,185,248,249,250,252,253,261],[142,185,245,246,247,248,249,253,254,255,257,258,259,261],[142,185,261],[142,185,243,245,246,247,248,249,250,252,253,254,255,256,257,258,259,260],[142,185,243,261],[142,185,248,250,251,253,254,261],[142,185,252,261],[142,185,253,254,258,261],[142,185,246,256],[142,185,236,265],[142,185,235,236],[52,142,185],[68,142,185],[142,152,156,185,227],[142,152,185,216,227],[142,147,185],[142,149,152,185,224,227],[142,185,205,224],[142,185,234],[142,147,185,234],[142,149,152,185,205,227],[142,144,145,148,151,185,197,216,227],[142,152,159,185],[142,144,150,185],[142,152,173,174,185],[142,148,152,185,219,227,234],[142,173,185,234],[142,146,147,185,234],[142,152,185],[142,146,147,148,149,150,151,152,153,154,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,174,175,176,177,178,179,185],[142,152,167,185],[142,152,159,160,185],[142,150,152,160,161,185],[142,151,185],[142,144,147,152,185],[142,152,156,160,161,185],[142,156,185],[142,150,152,155,185,227],[142,144,149,152,159,185],[142,185,216],[142,147,152,173,185,232,234],[142,185,266],[142,185,297],[142,185,197,198,200,201,202,205,216,224,227,233,234,236,237,238,239,240,241,242,262,263,264,265],[142,185,238,239,240,241],[142,185,238,239,240],[142,185,238],[142,185,239],[142,185,240,264],[142,185,236],[85,99],[50],[100],[298],[266],[142,185,236,299]],"referencedMap":[[136,1],[125,2],[110,3],[111,4],[106,5],[107,6],[112,5],[113,7],[114,5],[115,8],[116,3],[117,9],[118,10],[120,5],[121,11],[119,3],[122,12],[123,5],[124,13],[127,14],[129,15],[131,15],[132,10],[133,10],[134,16],[135,10],[130,15],[128,17],[101,18],[103,19],[102,17],[105,20],[104,19],[276,21],[277,21],[278,21],[279,21],[280,21],[281,21],[282,21],[283,21],[284,21],[285,21],[286,21],[287,21],[288,21],[296,22],[293,21],[291,21],[292,21],[289,21],[295,21],[290,21],[294,21],[108,23],[109,24],[91,25],[90,17],[98,26],[89,27],[87,17],[99,28],[100,29],[96,17],[97,30],[92,31],[95,32],[88,33],[86,17],[93,34],[94,35],[275,36],[269,37],[267,17],[85,38],[71,39],[81,40],[58,41],[77,42],[56,43],[80,44],[54,17],[65,45],[73,46],[84,47],[66,17],[72,48],[82,17],[76,49],[60,50],[63,51],[83,17],[55,52],[74,17],[59,17],[61,53],[64,54],[62,55],[78,56],[75,57],[79,58],[68,59],[67,17],[272,60],[268,37],[270,61],[271,37],[235,17],[182,62],[183,62],[184,63],[185,64],[186,65],[187,66],[137,17],[140,67],[138,17],[139,17],[188,68],[189,69],[190,70],[191,71],[192,72],[193,73],[194,73],[196,74],[195,75],[197,76],[198,77],[199,78],[181,79],[200,80],[201,81],[202,82],[203,83],[204,84],[205,85],[206,86],[207,87],[208,88],[209,89],[210,90],[211,91],[212,92],[213,92],[214,93],[215,17],[216,94],[218,95],[217,96],[219,97],[220,98],[221,99],[222,100],[223,101],[224,102],[225,103],[142,104],[141,17],[234,105],[226,106],[227,107],[228,108],[229,109],[230,110],[231,111],[232,112],[233,113],[48,17],[126,114],[46,17],[49,115],[50,114],[273,116],[143,17],[47,17],[242,17],[57,17],[51,17],[53,117],[259,118],[257,119],[258,120],[246,121],[247,119],[254,122],[245,123],[250,124],[260,17],[251,125],[256,126],[262,127],[261,128],[244,129],[252,130],[253,131],[248,132],[255,118],[249,133],[237,134],[236,135],[243,17],[70,136],[69,137],[44,17],[45,17],[8,17],[9,17],[11,17],[10,17],[2,17],[12,17],[13,17],[14,17],[15,17],[16,17],[17,17],[18,17],[19,17],[3,17],[4,17],[20,17],[24,17],[21,17],[22,17],[23,17],[25,17],[26,17],[27,17],[5,17],[28,17],[29,17],[30,17],[31,17],[6,17],[35,17],[32,17],[33,17],[34,17],[36,17],[7,17],[37,17],[42,17],[43,17],[38,17],[39,17],[40,17],[41,17],[1,17],[52,17],[159,138],[169,139],[158,138],[179,140],[150,141],[149,142],[178,143],[172,144],[177,145],[152,146],[166,147],[151,148],[175,149],[147,150],[146,143],[176,151],[148,152],[153,153],[154,17],[157,153],[144,17],[180,154],[170,155],[161,156],[162,157],[164,158],[160,159],[163,160],[173,143],[155,161],[156,162],[165,163],[145,164],[168,155],[167,153],[171,17],[174,165],[274,166],[298,167],[266,168],[263,169],[241,170],[239,171],[238,17],[240,172],[264,17],[297,173],[265,174]],"exportedModulesMap":[[136,175],[125,176],[111,176],[106,177],[107,176],[113,176],[115,176],[117,176],[118,176],[120,177],[121,176],[122,176],[124,176],[127,178],[129,175],[131,175],[130,175],[128,17],[101,18],[103,19],[102,17],[105,20],[104,19],[276,21],[277,21],[278,21],[279,21],[280,21],[281,21],[282,21],[283,21],[284,21],[285,21],[286,21],[287,21],[288,21],[296,22],[293,21],[291,21],[292,21],[289,21],[295,21],[290,21],[294,21],[108,23],[109,24],[91,25],[90,17],[98,26],[89,27],[87,17],[99,28],[100,29],[96,17],[97,30],[92,31],[95,32],[88,33],[86,17],[93,34],[94,35],[275,179],[269,37],[267,17],[85,38],[71,39],[81,40],[58,41],[77,42],[56,43],[80,44],[54,17],[65,45],[73,46],[84,47],[66,17],[72,48],[82,17],[76,49],[60,50],[63,51],[83,17],[55,52],[74,17],[59,17],[61,53],[64,54],[62,55],[78,56],[75,57],[79,58],[68,59],[67,17],[272,60],[268,37],[270,61],[271,37],[235,17],[182,62],[183,62],[184,63],[185,64],[186,65],[187,66],[137,17],[140,67],[138,17],[139,17],[188,68],[189,69],[190,70],[191,71],[192,72],[193,73],[194,73],[196,74],[195,75],[197,76],[198,77],[199,78],[181,79],[200,80],[201,81],[202,82],[203,83],[204,84],[205,85],[206,86],[207,87],[208,88],[209,89],[210,90],[211,91],[212,92],[213,92],[214,93],[215,17],[216,94],[218,95],[217,96],[219,97],[220,98],[221,99],[222,100],[223,101],[224,102],[225,103],[142,104],[141,17],[234,105],[226,106],[227,107],[228,108],[229,109],[230,110],[231,111],[232,112],[233,113],[48,17],[126,114],[46,17],[49,115],[50,114],[273,116],[143,17],[47,17],[242,17],[57,17],[51,17],[53,117],[259,118],[257,119],[258,120],[246,121],[247,119],[254,122],[245,123],[250,124],[260,17],[251,125],[256,126],[262,127],[261,128],[244,129],[252,130],[253,131],[248,132],[255,118],[249,133],[237,180],[236,135],[243,17],[70,136],[69,137],[44,17],[45,17],[8,17],[9,17],[11,17],[10,17],[2,17],[12,17],[13,17],[14,17],[15,17],[16,17],[17,17],[18,17],[19,17],[3,17],[4,17],[20,17],[24,17],[21,17],[22,17],[23,17],[25,17],[26,17],[27,17],[5,17],[28,17],[29,17],[30,17],[31,17],[6,17],[35,17],[32,17],[33,17],[34,17],[36,17],[7,17],[37,17],[42,17],[43,17],[38,17],[39,17],[40,17],[41,17],[1,17],[52,17],[159,138],[169,139],[158,138],[179,140],[150,141],[149,142],[178,143],[172,144],[177,145],[152,146],[166,147],[151,148],[175,149],[147,150],[146,143],[176,151],[148,152],[153,153],[154,17],[157,153],[144,17],[180,154],[170,155],[161,156],[162,157],[164,158],[160,159],[163,160],[173,143],[155,161],[156,162],[165,163],[145,164],[168,155],[167,153],[171,17],[174,165],[274,166],[298,167],[266,168],[263,169],[241,170],[239,171],[238,17],[240,172],[264,17],[297,173],[265,174]],"semanticDiagnosticsPerFile":[136,125,110,111,106,107,112,113,114,115,116,117,118,120,121,119,122,123,124,127,129,131,132,133,134,135,130,128,101,103,102,105,104,276,277,278,279,280,281,282,283,284,285,286,287,288,296,293,291,292,289,295,290,294,108,109,91,90,98,89,87,99,100,96,97,92,95,88,86,93,94,275,269,267,85,71,81,58,77,56,80,54,65,73,84,66,72,82,76,60,63,83,55,74,59,61,64,62,78,75,79,68,67,272,268,270,271,235,182,183,184,185,186,187,137,140,138,139,188,189,190,191,192,193,194,196,195,197,198,199,181,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,218,217,219,220,221,222,223,224,225,142,141,234,226,227,228,229,230,231,232,233,48,126,46,49,50,273,143,47,242,57,51,53,259,257,258,246,247,254,245,250,260,251,256,262,261,244,252,253,248,255,249,237,236,243,70,69,44,45,8,9,11,10,2,12,13,14,15,16,17,18,19,3,4,20,24,21,22,23,25,26,27,5,28,29,30,31,6,35,32,33,34,36,7,37,42,43,38,39,40,41,1,52,159,169,158,179,150,149,178,172,177,152,166,151,175,147,146,176,148,153,154,157,144,180,170,161,162,164,160,163,173,155,156,165,145,168,167,171,174,274,298,266,263,241,239,238,240,264,297,265],"affectedFilesPendingEmit":[136,125,110,111,106,107,112,113,114,115,116,117,118,120,121,119,122,123,124,127,129,131,132,133,134,135,130,275],"emitSignatures":[106,107,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,127,129,130,131,132,133,134,135,136,275]},"version":"5.3.3"} \ No newline at end of file From 70086dd99dee185025ad56faa09be49be6db0df7 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Tue, 12 Nov 2024 22:33:05 +0900 Subject: [PATCH 17/19] =?UTF-8?q?style:=20lint=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/hooks/useMarkdownGrammer/handlers/arrow.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts index 06e943df..9f92e7a9 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts @@ -14,7 +14,7 @@ export const useArrowKeyHandler = ({ if (!currentNode) return; let targetNode: EditorNode | null = null; - + switch (e.key) { case "ArrowUp": if (currentNode.parentNode?.type === "checkbox") { @@ -46,7 +46,7 @@ export const useArrowKeyHandler = ({ targetNode = currentNode.prevNode; } break; - + case "ArrowDown": if (currentNode.parentNode?.type === "checkbox") { if (currentNode.parentNode.nextNode) { @@ -78,7 +78,7 @@ export const useArrowKeyHandler = ({ } break; } - + /* switch (e.key) { case "ArrowUp": From 7b75bb17fea915e6dc264fddec6d1034384bdf64 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Wed, 13 Nov 2024 00:31:14 +0900 Subject: [PATCH 18/19] =?UTF-8?q?refactor:=20=ED=99=94=EC=82=B4=ED=91=9C?= =?UTF-8?q?=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=A1=9C=EC=A7=81=20=EC=9C=A0?= =?UTF-8?q?=ED=8B=B8=EB=A6=AC=ED=8B=B0=20=ED=95=A8=EC=88=98=EB=A1=9C=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../useMarkdownGrammer/handlers/arrow.ts | 120 ++---------------- client/src/utils/blockNavigationUtils.ts | 110 ++++++++++++++++ 2 files changed, 118 insertions(+), 112 deletions(-) create mode 100644 client/src/utils/blockNavigationUtils.ts diff --git a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts index 9f92e7a9..dd20dab2 100644 --- a/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts +++ b/client/src/hooks/useMarkdownGrammer/handlers/arrow.ts @@ -1,6 +1,7 @@ import { useCallback } from "react"; import { EditorNode } from "../../../types/markdown"; import { KeyHandlerProps } from "./handlerProps"; +import { handleKeyNavigation } from "@utils/blockNavigationUtils"; export const useArrowKeyHandler = ({ editorState, @@ -14,122 +15,17 @@ export const useArrowKeyHandler = ({ if (!currentNode) return; let targetNode: EditorNode | null = null; - switch (e.key) { case "ArrowUp": - if (currentNode.parentNode?.type === "checkbox") { - if (currentNode.parentNode.prevNode) { - if (currentNode.parentNode.prevNode.type === "checkbox") { - targetNode = currentNode.parentNode.prevNode.firstChild; - } else { - targetNode = currentNode.parentNode.prevNode; - } - } - } else if (currentNode.prevNode?.type === "ul" || currentNode.prevNode?.type === "ol") { - targetNode = editorList.getLastChild(currentNode.prevNode); - } else if (currentNode.type === "li") { - if (currentNode.prevSibling?.id) { - targetNode = currentNode.prevSibling; - } else { - if (currentNode.parentNode?.prevNode) { - if (currentNode.parentNode.prevNode.type === "checkbox") { - // 이전 블록이 체크박스인 경우 처리 - targetNode = currentNode.parentNode.prevNode.firstChild; - } else { - targetNode = currentNode.parentNode.prevNode; - } - } else { - return; - } - } - } else { - targetNode = currentNode.prevNode; - } - break; - - case "ArrowDown": - if (currentNode.parentNode?.type === "checkbox") { - if (currentNode.parentNode.nextNode) { - if (currentNode.parentNode.nextNode.type === "checkbox") { - targetNode = currentNode.parentNode.nextNode.firstChild; - } else { - targetNode = currentNode.parentNode.nextNode; - } - } - } else if (currentNode.nextNode?.type === "ul" || currentNode.nextNode?.type === "ol") { - targetNode = currentNode.nextNode.firstChild; - } else if (currentNode.type === "li") { - if (currentNode.nextSibling?.id) { - targetNode = currentNode.nextSibling; - } else { - if (currentNode.parentNode?.nextNode) { - if (currentNode.parentNode.nextNode.type === "checkbox") { - // 다음 블록이 체크박스인 경우 처리 - targetNode = currentNode.parentNode.nextNode.firstChild; - } else { - targetNode = currentNode.parentNode.nextNode; - } - } else { - return; - } - } - } else { - targetNode = currentNode.nextNode; - } - break; - } - - /* - switch (e.key) { - case "ArrowUp": - if (currentNode.parentNode?.type === "checkbox") { - if (currentNode.parentNode.prevNode) { - if (currentNode.parentNode.prevNode.type === "checkbox") { - targetNode = currentNode.parentNode.prevNode.firstChild; - } else { - targetNode = currentNode.parentNode.prevNode; - } - } - } else if (currentNode.prevNode?.type === "ul" || currentNode.prevNode?.type === "ol") { - targetNode = editorList.getLastChild(currentNode.prevNode!); - } else if (currentNode.type === "li") { - if (currentNode.prevSibling?.id) { - targetNode = currentNode.prevSibling; - } else { - if (currentNode.parentNode?.prevNode) { - targetNode = currentNode.parentNode?.prevNode; - } else return; - } - } else { - targetNode = currentNode.prevNode; - } - break; - case "ArrowDown": - if (currentNode.parentNode?.type === "checkbox") { - if (currentNode.parentNode.nextNode) { - if (currentNode.parentNode.nextNode.type === "checkbox") { - targetNode = currentNode.parentNode.nextNode.firstChild; - } else { - targetNode = currentNode.parentNode.nextNode; - } - } - - } else if (currentNode.nextNode?.type === "ul" || currentNode.nextNode?.type === "ol") { - targetNode = currentNode.nextNode!.firstChild; - } else if (currentNode.type === "li") { - if (currentNode.nextSibling?.id) { - targetNode = currentNode.nextSibling; - } else { - if (currentNode.parentNode?.nextNode) { - targetNode = currentNode.parentNode?.nextNode; - } else return; - } - } else { - targetNode = currentNode.nextNode; - } + case "ArrowDown": { + e.preventDefault(); + + const direction = e.key === "ArrowUp" ? "prev" : "next"; + targetNode = handleKeyNavigation(currentNode, direction); + break; + } } - */ if (targetNode) { setEditorState((prev) => ({ ...prev, diff --git a/client/src/utils/blockNavigationUtils.ts b/client/src/utils/blockNavigationUtils.ts new file mode 100644 index 00000000..49a5c3e4 --- /dev/null +++ b/client/src/utils/blockNavigationUtils.ts @@ -0,0 +1,110 @@ +import { EditorNode } from "../types/markdown"; + +type NavigationDirection = 'prev' | 'next'; + + // 에디터 노드 타입 체크를 위한 유틸리티 함수들 +export const nodeTypeCheckers = { + isCheckbox: (node?: EditorNode | null): boolean => node?.type === 'checkbox', + isList: (node?: EditorNode | null): boolean => node?.type === 'ul' || node?.type === 'ol', + isListItem: (node?: EditorNode | null): boolean => node?.type === 'li', + isCheckboxChild: (node: EditorNode): boolean => nodeTypeCheckers.isCheckbox(node.parentNode), +}; + + // 리스트 관련 유틸리티 함수들 +export const listUtils = { + getFirstListItem: (node: EditorNode) => node.firstChild, + getLastListItem: (node: EditorNode) => { + if (!node.firstChild) return null; + + let lastItem: EditorNode = node.firstChild; + while (lastItem.nextSibling?.id) { + lastItem = lastItem.nextSibling; + } + return lastItem; + }, +}; + + // 체크박스 자식 노드의 이동 처리 +const handleCheckboxChildNavigation = ( + currentNode: EditorNode, + direction: NavigationDirection +): EditorNode | null => { + const parentCheckbox = currentNode.parentNode; + const targetNode = direction === 'prev' ? parentCheckbox?.prevNode : parentCheckbox?.nextNode; + + if (!targetNode) return null; + + if (nodeTypeCheckers.isCheckbox(targetNode)) { + return targetNode.firstChild ?? null; + } + + if (nodeTypeCheckers.isList(targetNode)) { + return direction === 'prev' + ? listUtils.getLastListItem(targetNode) + : listUtils.getFirstListItem(targetNode); + } + + return targetNode; +}; + + // 리스트 아이템 노드의 이동 처리 +const handleListItemNavigation = ( + currentNode: EditorNode, + direction: NavigationDirection +): EditorNode | null => { + const sibling = direction === 'prev' ? currentNode.prevSibling : currentNode.nextSibling; + + if (sibling?.id) { + return sibling; + } + + const parentSibling = direction === 'prev' + ? currentNode.parentNode?.prevNode + : currentNode.parentNode?.nextNode; + + if (!parentSibling) return null; + + if (nodeTypeCheckers.isCheckbox(parentSibling)) { + return parentSibling.firstChild ?? null; + } + + return parentSibling; +}; + + // 기본 블록 노드의 이동 처리 +const handleBasicBlockNavigation = ( + currentNode: EditorNode, + direction: NavigationDirection +): EditorNode | null => { + const targetNode = direction === 'prev' ? currentNode.prevNode : currentNode.nextNode; + + if (!targetNode) return null; + + if (nodeTypeCheckers.isCheckbox(targetNode)) { + return targetNode.firstChild ?? null; + } + + if (nodeTypeCheckers.isList(targetNode)) { + return direction === 'prev' + ? listUtils.getLastListItem(targetNode) + : listUtils.getFirstListItem(targetNode); + } + + return targetNode; +}; + + // 키보드 네비게이션 핸들러 -> 현재 노드와 이동 방향을 받아 다음 타겟 노드를 반환 +export const handleKeyNavigation = ( + currentNode: EditorNode, + direction: NavigationDirection +): EditorNode | null => { + if (nodeTypeCheckers.isCheckboxChild(currentNode)) { + return handleCheckboxChildNavigation(currentNode, direction); + } + + if (nodeTypeCheckers.isListItem(currentNode)) { + return handleListItemNavigation(currentNode, direction); + } + + return handleBasicBlockNavigation(currentNode, direction); +}; \ No newline at end of file From 5b81345a2d8e60c4813d64213d6e47756841c407 Mon Sep 17 00:00:00 2001 From: Yeonkyu Min Date: Wed, 13 Nov 2024 00:35:55 +0900 Subject: [PATCH 19/19] =?UTF-8?q?fix:=20conflict=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/tsconfig.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/tsconfig.json b/client/tsconfig.json index 3319e05f..3492c3da 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -26,6 +26,8 @@ "@styles/*": ["src/styles/*"], "@hooks/*": ["src/hooks/*"], "@utils/*": ["src/utils/*"], + "@noctaCrdt": ["../@noctaCrdt/dist"], + "@noctaCrdt/*": ["../@noctaCrdt/dist/*"] } }, "include": ["src", "*.ts", "*.tsx", "vite.config.ts", "styled-system"],