diff --git a/package-lock.json b/package-lock.json
index 95d4c984..90c9a02e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,12 +11,11 @@
"@aws-sdk/client-s3": "^3.540.0",
"@blocknote/core": "^0.12.1",
"@blocknote/react": "^0.12.2",
+ "@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-sql": "^6.5.5",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@justmiracle/result": "^1.2.0",
- "@lexical/markdown": "^0.16.1",
- "@lexical/react": "^0.16.1",
"@lezer/common": "^1.2.1",
"@lezer/lr": "^1.4.0",
"@libsql/client": "^0.5.3",
@@ -44,6 +43,7 @@
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-toggle-group": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.7",
+ "@replit/codemirror-indentation-markers": "^6.5.3",
"@silevis/reactgrid": "^4.1.3",
"@t3-oss/env-nextjs": "^0.9.2",
"@tiptap/core": "^2.3.0",
@@ -64,7 +64,6 @@
"drizzle-orm": "^0.30.1",
"eslint-plugin-jest": "^27.6.3",
"file-saver": "^2.0.5",
- "lexical": "^0.16.1",
"libsql-stateless-easy": "^1.6.11",
"lucia": "^3.2.0",
"lucide-react": "^0.309.0",
@@ -3805,239 +3804,6 @@
"resolved": "https://registry.npmjs.org/@justmiracle/result/-/result-1.2.0.tgz",
"integrity": "sha512-MyyfTSloRNvdB1EnzSDiOeyPtdXeK+gp1d2zxqcjq/XHoagsIzo7ImEJCKIUkOTlmuEInPfYZrcAU7sdeCWqkg=="
},
- "node_modules/@lexical/clipboard": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/clipboard/-/clipboard-0.16.1.tgz",
- "integrity": "sha512-0dWs/SwKS5KPpuf6fUVVt9vSCl6HAqcDGhSITw/okv0rrIlXTUT6WhVsMJtXfFxTyVvwMeOecJHvQH3i/jRQtA==",
- "dependencies": {
- "@lexical/html": "0.16.1",
- "@lexical/list": "0.16.1",
- "@lexical/selection": "0.16.1",
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/code": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/code/-/code-0.16.1.tgz",
- "integrity": "sha512-pOC28rRZ2XkmI2nIJm50DbKaCJtk5D0o7r6nORYp4i0z+lxt5Sf2m82DL9ksUHJRqKy87pwJDpoWvJ2SAI0ohw==",
- "dependencies": {
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1",
- "prismjs": "^1.27.0"
- }
- },
- "node_modules/@lexical/devtools-core": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/devtools-core/-/devtools-core-0.16.1.tgz",
- "integrity": "sha512-8CvGERGL7ySDVGLU+YPeq+JupIXsOFlXa3EuJ88koLKqXxYenwMleZgGqayFp6lCP78xqPKnATVeoOZUt/NabQ==",
- "dependencies": {
- "@lexical/html": "0.16.1",
- "@lexical/link": "0.16.1",
- "@lexical/mark": "0.16.1",
- "@lexical/table": "0.16.1",
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- },
- "peerDependencies": {
- "react": ">=17.x",
- "react-dom": ">=17.x"
- }
- },
- "node_modules/@lexical/dragon": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/dragon/-/dragon-0.16.1.tgz",
- "integrity": "sha512-Rvd60GIYN5kpjjBumS34EnNbBaNsoseI0AlzOdtIV302jiHPCLH0noe9kxzu9nZy+MZmjZy8Dx2zTbQT2mueRw==",
- "dependencies": {
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/hashtag": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/hashtag/-/hashtag-0.16.1.tgz",
- "integrity": "sha512-G+YOxStAKs3q1utqm9KR4D4lCkwIH52Rctm4RgaVTI+4lvTaybeDRGFV75P/pI/qlF7/FvAYHTYEzCjtC3GNMQ==",
- "dependencies": {
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/history": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/history/-/history-0.16.1.tgz",
- "integrity": "sha512-WQhScx0TJeKSQAnEkRpIaWdUXqirrNrom2MxbBUc/32zEUMm9FzV7nRGknvUabEFUo7vZq6xTZpOExQJqHInQA==",
- "dependencies": {
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/html": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/html/-/html-0.16.1.tgz",
- "integrity": "sha512-vbtAdCvQ3PaAqa5mFmtmrvbiAvjCu1iXBAJ0bsHqFXCF2Sba5LwHVe8dUAOTpfEZEMbiHfjul6b5fj4vNPGF2A==",
- "dependencies": {
- "@lexical/selection": "0.16.1",
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/link": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/link/-/link-0.16.1.tgz",
- "integrity": "sha512-zG36gEnEqbIe6tK/MhXi7wn/XMY/zdivnPcOY5WyC3derkEezeLSSIFsC1u5UNeK5pbpNMSy4LDpLhi1Ww4Y5w==",
- "dependencies": {
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/list": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/list/-/list-0.16.1.tgz",
- "integrity": "sha512-i9YhLAh5N6YO9dP+R1SIL9WEdCKeTiQQYVUzj84vDvX5DIBxMPUjTmMn3LXu9T+QO3h1s2L/vJusZASrl45eAw==",
- "dependencies": {
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/mark": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/mark/-/mark-0.16.1.tgz",
- "integrity": "sha512-CZRGMLcxn5D+jzf1XnH+Z+uUugmpg1mBwTbGybCPm8UWpBrKDHkrscfMgWz62iRWz0cdVjM5+0zWpNElxFTRjQ==",
- "dependencies": {
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/markdown": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/markdown/-/markdown-0.16.1.tgz",
- "integrity": "sha512-0sBLttMvfQO/hVaIqpHdvDowpgV2CoRuWo2CNwvRLZPPWvPVjL4Nkb73wmi8zAZsAOTbX2aw+g4m/+k5oJqNig==",
- "dependencies": {
- "@lexical/code": "0.16.1",
- "@lexical/link": "0.16.1",
- "@lexical/list": "0.16.1",
- "@lexical/rich-text": "0.16.1",
- "@lexical/text": "0.16.1",
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/offset": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/offset/-/offset-0.16.1.tgz",
- "integrity": "sha512-/i2J04lQmFeydUZIF8tKXLQTXiJDTQ6GRnkfv1OpxU4amc0rwGa7+qAz/PuF1n58rP6InpLmSHxgY5JztXa2jw==",
- "dependencies": {
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/overflow": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/overflow/-/overflow-0.16.1.tgz",
- "integrity": "sha512-xh5YpoxwA7K4wgMQF/Sjl8sdjaxqesLCtH5ZrcMsaPlmucDIEEs+i8xxk+kDUTEY7y+3FvRxs4lGNgX8RVWkvQ==",
- "dependencies": {
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/plain-text": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/plain-text/-/plain-text-0.16.1.tgz",
- "integrity": "sha512-GjY4ylrBZIaAVIF8IFnmW0XGyHAuRmWA6gKB8iTTlsjgFrCHFIYC74EeJSp309O0Hflg9rRBnKoX1TYruFHVwA==",
- "dependencies": {
- "@lexical/clipboard": "0.16.1",
- "@lexical/selection": "0.16.1",
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/react": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/react/-/react-0.16.1.tgz",
- "integrity": "sha512-SsGgLt9iKfrrMRy9lFb6ROVPUYOgv6b+mCn9Al+TLqs/gBReDBi3msA7m526nrtBUKYUnjHdQ1QXIJzuKgOxcg==",
- "dependencies": {
- "@lexical/clipboard": "0.16.1",
- "@lexical/code": "0.16.1",
- "@lexical/devtools-core": "0.16.1",
- "@lexical/dragon": "0.16.1",
- "@lexical/hashtag": "0.16.1",
- "@lexical/history": "0.16.1",
- "@lexical/link": "0.16.1",
- "@lexical/list": "0.16.1",
- "@lexical/mark": "0.16.1",
- "@lexical/markdown": "0.16.1",
- "@lexical/overflow": "0.16.1",
- "@lexical/plain-text": "0.16.1",
- "@lexical/rich-text": "0.16.1",
- "@lexical/selection": "0.16.1",
- "@lexical/table": "0.16.1",
- "@lexical/text": "0.16.1",
- "@lexical/utils": "0.16.1",
- "@lexical/yjs": "0.16.1",
- "lexical": "0.16.1",
- "react-error-boundary": "^3.1.4"
- },
- "peerDependencies": {
- "react": ">=17.x",
- "react-dom": ">=17.x"
- }
- },
- "node_modules/@lexical/rich-text": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/rich-text/-/rich-text-0.16.1.tgz",
- "integrity": "sha512-4uEVXJur7tdSbqbmsToCW4YVm0AMh4y9LK077Yq2O9hSuA5dqpI8UbTDnxZN2D7RfahNvwlqp8eZKFB1yeiJGQ==",
- "dependencies": {
- "@lexical/clipboard": "0.16.1",
- "@lexical/selection": "0.16.1",
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/selection": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/selection/-/selection-0.16.1.tgz",
- "integrity": "sha512-+nK3RvXtyQvQDq7AZ46JpphmM33pwuulwiRfeXR5T9iFQTtgWOEjsAi/KKX7vGm70BxACfiSxy5QCOgBWFwVJg==",
- "dependencies": {
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/table": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/table/-/table-0.16.1.tgz",
- "integrity": "sha512-GWb0/MM1sVXpi1p2HWWOBldZXASMQ4c6WRNYnRmq7J/aB5N66HqQgJGKp3m66Kz4k1JjhmZfPs7F018qIBhnFQ==",
- "dependencies": {
- "@lexical/utils": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/text": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/text/-/text-0.16.1.tgz",
- "integrity": "sha512-Os/nKQegORTrKKN6vL3/FMVszyzyqaotlisPynvTaHTUC+yY4uyjM2hlF93i5a2ixxyiPLF9bDroxUP96TMPXg==",
- "dependencies": {
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/utils": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/utils/-/utils-0.16.1.tgz",
- "integrity": "sha512-BVyJxDQi/rIxFTDjf2zE7rMDKSuEaeJ4dybHRa/hRERt85gavGByQawSLeQlTjLaYLVsy+x7wCcqh2fNhlLf0g==",
- "dependencies": {
- "@lexical/list": "0.16.1",
- "@lexical/selection": "0.16.1",
- "@lexical/table": "0.16.1",
- "lexical": "0.16.1"
- }
- },
- "node_modules/@lexical/yjs": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/@lexical/yjs/-/yjs-0.16.1.tgz",
- "integrity": "sha512-QHw1bmzB/IypIV1tRWMH4hhwE1xX7wV+HxbzBS8oJAkoU5AYXM/kyp/sQicgqiwVfpai1Px7zatOoUDFgbyzHQ==",
- "dependencies": {
- "@lexical/offset": "0.16.1",
- "lexical": "0.16.1"
- },
- "peerDependencies": {
- "yjs": ">=13.5.22"
- }
- },
"node_modules/@lezer/common": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz",
@@ -7037,6 +6803,16 @@
"resolved": "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-2.0.2.tgz",
"integrity": "sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ=="
},
+ "node_modules/@replit/codemirror-indentation-markers": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/@replit/codemirror-indentation-markers/-/codemirror-indentation-markers-6.5.3.tgz",
+ "integrity": "sha512-hL5Sfvw3C1vgg7GolLe/uxX5T3tmgOA3ZzqlMv47zjU1ON51pzNWiVbS22oh6crYhtVhv8b3gdXwoYp++2ilHw==",
+ "peerDependencies": {
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/state": "^6.0.0",
+ "@codemirror/view": "^6.0.0"
+ }
+ },
"node_modules/@replit/codemirror-lang-csharp": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@replit/codemirror-lang-csharp/-/codemirror-lang-csharp-6.2.0.tgz",
@@ -15740,11 +15516,6 @@
"node": ">= 0.8.0"
}
},
- "node_modules/lexical": {
- "version": "0.16.1",
- "resolved": "https://registry.npmjs.org/lexical/-/lexical-0.16.1.tgz",
- "integrity": "sha512-+R05d3+N945OY8pTUjTqQrWoApjC+ctzvjnmNETtx9WmVAaiW0tQVG+AYLt5pDGY8dQXtd4RPorvnxBTECt9SA=="
- },
"node_modules/lib0": {
"version": "0.2.94",
"resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.94.tgz",
@@ -20886,14 +20657,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/prismjs": {
- "version": "1.29.0",
- "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
- "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/prompts": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -21202,21 +20965,6 @@
"react": "^18.3.1"
}
},
- "node_modules/react-error-boundary": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.4.tgz",
- "integrity": "sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==",
- "dependencies": {
- "@babel/runtime": "^7.12.5"
- },
- "engines": {
- "node": ">=10",
- "npm": ">=6"
- },
- "peerDependencies": {
- "react": ">=16.13.1"
- }
- },
"node_modules/react-icons": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
diff --git a/package.json b/package.json
index 6f22eca6..3300f563 100644
--- a/package.json
+++ b/package.json
@@ -30,12 +30,11 @@
"@aws-sdk/client-s3": "^3.540.0",
"@blocknote/core": "^0.12.1",
"@blocknote/react": "^0.12.2",
+ "@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-sql": "^6.5.5",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@justmiracle/result": "^1.2.0",
- "@lexical/markdown": "^0.16.1",
- "@lexical/react": "^0.16.1",
"@lezer/common": "^1.2.1",
"@lezer/lr": "^1.4.0",
"@libsql/client": "^0.5.3",
@@ -63,6 +62,7 @@
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-toggle-group": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.7",
+ "@replit/codemirror-indentation-markers": "^6.5.3",
"@silevis/reactgrid": "^4.1.3",
"@t3-oss/env-nextjs": "^0.9.2",
"@tiptap/core": "^2.3.0",
@@ -83,7 +83,6 @@
"drizzle-orm": "^0.30.1",
"eslint-plugin-jest": "^27.6.3",
"file-saver": "^2.0.5",
- "lexical": "^0.16.1",
"libsql-stateless-easy": "^1.6.11",
"lucia": "^3.2.0",
"lucide-react": "^0.309.0",
diff --git a/src/app/testing/page.tsx b/src/app/testing/page.tsx
index d8172b17..6a2973a1 100644
--- a/src/app/testing/page.tsx
+++ b/src/app/testing/page.tsx
@@ -1,9 +1,27 @@
-import MarkdownEditor from "@/components/markdown-editor";
+"use client";
+import JsonEditor from "@/components/gui/json-editor";
+import ThemeProvider from "@/context/theme-provider";
+import { useState } from "react";
export default function TestingPage() {
+ const [code, setCode] = useState(
+ JSON.stringify(
+ {
+ name: "Visal",
+ country: {
+ id: 1,
+ verified: true,
+ name: "Cambodia",
+ },
+ },
+ undefined,
+ 2
+ )
+ );
+
return (
-
-
-
+
+
+
);
}
diff --git a/src/components/gui/json-editor/index.tsx b/src/components/gui/json-editor/index.tsx
new file mode 100644
index 00000000..60d87391
--- /dev/null
+++ b/src/components/gui/json-editor/index.tsx
@@ -0,0 +1,102 @@
+import CodeMirror, { ReactCodeMirrorRef } from "@uiw/react-codemirror";
+import { json } from "@codemirror/lang-json";
+import { forwardRef, useMemo } from "react";
+import { tags as t } from "@lezer/highlight";
+import createTheme from "@uiw/codemirror-themes";
+import { useTheme } from "@/context/theme-provider";
+import { indentationMarkers } from "@replit/codemirror-indentation-markers";
+
+interface JsonEditorProps {
+ value: string;
+ readOnly?: boolean;
+ onChange?: (value: string) => void;
+}
+
+function useJsonTheme() {
+ const { theme } = useTheme();
+
+ return useMemo(() => {
+ if (theme === "light") {
+ return createTheme({
+ theme: "light",
+ settings: {
+ background: "#FFFFFF",
+ foreground: "#000000",
+ caret: "#FBAC52",
+ selection: "#FFD420",
+ selectionMatch: "#FFD420",
+ gutterBackground: "#fff",
+ gutterForeground: "#4D4D4C",
+ gutterBorder: "transparent",
+ lineHighlight: "#00000012",
+ fontFamily:
+ 'Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace',
+ },
+ styles: [
+ { tag: [t.propertyName], color: "#4078F2" },
+ { tag: [t.bool, t.null], color: "#696C77" },
+ { tag: [t.number], color: "#FF0080" },
+ { tag: [t.string], color: "#50A14F" },
+ { tag: [t.separator], color: "#383A42" },
+ { tag: [t.squareBracket], color: "#383A42" },
+ { tag: [t.brace], color: "#A626A4" },
+ ],
+ });
+ } else {
+ return createTheme({
+ theme: "dark",
+ settings: {
+ background: "var(--background)",
+ foreground: "#9cdcfe",
+ caret: "#c6c6c6",
+ selection: "#6199ff2f",
+ selectionMatch: "#72a1ff59",
+ lineHighlight: "#ffffff0f",
+ gutterBackground: "var(--background)",
+ gutterForeground: "#838383",
+ gutterActiveForeground: "#fff",
+ fontFamily:
+ 'Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace',
+ },
+ styles: [
+ { tag: [t.propertyName], color: "#4078F2" },
+ { tag: [t.bool, t.null], color: "#696C77" },
+ { tag: [t.number], color: "#f39c12" },
+ { tag: [t.string], color: "#50A14F" },
+ { tag: [t.separator], color: "#383A42" },
+ { tag: [t.squareBracket], color: "#383A42" },
+ { tag: [t.brace], color: "#A626A4" },
+ ],
+ });
+ }
+ }, [theme]);
+}
+
+const JsonEditor = forwardRef(
+ function SqlEditor({ value, onChange, readOnly }: JsonEditorProps, ref) {
+ const theme = useJsonTheme();
+
+ return (
+
+ );
+ }
+);
+
+export default JsonEditor;
diff --git a/src/components/gui/providers/full-editor-provider.tsx b/src/components/gui/providers/full-editor-provider.tsx
index 27777678..4b331724 100644
--- a/src/components/gui/providers/full-editor-provider.tsx
+++ b/src/components/gui/providers/full-editor-provider.tsx
@@ -17,6 +17,7 @@ import {
useMemo,
useState,
} from "react";
+import JsonEditor from "../json-editor";
interface FullEditorContextValue {
openEditor: (option: FullEditorOption) => void;
@@ -25,6 +26,8 @@ interface FullEditorContextValue {
interface FullEditorOption {
initialValue: string;
+ format: string;
+ readOnly?: boolean;
onSave: (value: string) => void;
onCancel: () => void;
}
@@ -35,47 +38,67 @@ const FullEditorContext = createContext({
});
function FullEditorSheet({ option }: { option: FullEditorOption }) {
- const [value, setValue] = useState(option.initialValue);
+ const [value, setValue] = useState(() => {
+ if (option.format === "json") {
+ try {
+ return JSON.stringify(JSON.parse(option.initialValue), undefined, 2);
+ } catch {
+ return option.initialValue;
+ }
+ }
+
+ return option.initialValue;
+ });
return (
-
+
-
-
-
-
@@ -92,8 +115,11 @@ export function FullEditorProvider({ children }: PropsWithChildren) {
const props = useMemo(() => {
return {
openEditor: (opt: FullEditorOption) => {
+ console.log(opt);
setOption({
initialValue: opt.initialValue,
+ format: opt.format,
+ readOnly: opt.readOnly,
onCancel: () => {
if (opt.onCancel) opt.onCancel();
setOption(null);
diff --git a/src/components/gui/query-result-table.tsx b/src/components/gui/query-result-table.tsx
index 839ab99a..55e83d49 100644
--- a/src/components/gui/query-result-table.tsx
+++ b/src/components/gui/query-result-table.tsx
@@ -1,6 +1,6 @@
-import GenericCell from "@/components/gui/table-cell/GenericCell";
-import NumberCell from "@/components/gui/table-cell/NumberCell";
-import TextCell from "@/components/gui/table-cell/TextCell";
+import GenericCell from "@/components/gui/table-cell/generic-cell";
+import NumberCell from "@/components/gui/table-cell/number-cell";
+import TextCell from "@/components/gui/table-cell/text-cell";
import OptimizeTable, {
OptimizeTableCellRenderProps,
OptimizeTableHeaderWithIndexProps,
@@ -37,7 +37,7 @@ import {
DropdownMenuItem,
DropdownMenuSeparator,
} from "../ui/dropdown-menu";
-import BigNumberCell from "./table-cell/BigNumberCell";
+import BigNumberCell from "./table-cell/big-number-cell";
import { useDatabaseDriver } from "@/context/driver-provider";
import { useConfig } from "@/context/config-provider";
import { useFullEditor } from "./providers/full-editor-provider";
@@ -60,6 +60,29 @@ function isBlockNoteString(value: DatabaseValue
): boolean {
return parsedJson?.format === "BLOCK_NOTE";
}
+function detectTextEditorType(
+ value: DatabaseValue
+): "input" | "json" | "text" {
+ if (typeof value !== "string") return "input";
+
+ // Check if it is JSON format
+ const trimmedText = value.trim();
+ if (
+ trimmedText.substring(0, 1) === "{" &&
+ trimmedText.substring(trimmedText.length - 1) === "}"
+ ) {
+ if (parseSafeJson(trimmedText, undefined) !== undefined) return "json";
+ }
+
+ // Check if it is long string
+ if (value.length > 200) return "text";
+
+ // If it is multiple line
+ if (value.search(/[\n\r]/) >= 0) return "text";
+
+ return "input";
+}
+
function Header({
children,
header,
@@ -179,11 +202,7 @@ export default function ResultTable({
if (header.dataType === TableColumnDataType.TEXT) {
const value = state.getValue(y, x) as DatabaseValue;
- let editor: "input" | "blocknote" = "input"; // this is default editor
-
- if (isBlockNoteString(value)) {
- editor = "blocknote";
- }
+ let editor = detectTextEditorType(value);
return (
{},
+ onSave: (newValue) => {
+ state.setFocusValue(newValue);
+ },
+ });
+ }
+ },
+ },
+ {
+ title: "JSON Editor",
+ onClick: () => {
+ const focusValue = state.getFocusValue();
+ if (typeof focusValue === "string") {
+ openEditor({
+ initialValue: focusValue,
+ format: "json",
+ readOnly: state.getReadOnlyMode(),
onCancel: () => {},
onSave: (newValue) => {
state.setFocusValue(newValue);
@@ -362,8 +400,6 @@ export default function ResultTable({
}
},
},
- { title: "Markdown Editor" },
- { title: "JSON Editor" },
],
},
...((extensionMenu ?? []).length > 0
diff --git a/src/components/gui/table-cell/BigNumberCell.tsx b/src/components/gui/table-cell/big-number-cell.tsx
similarity index 88%
rename from src/components/gui/table-cell/BigNumberCell.tsx
rename to src/components/gui/table-cell/big-number-cell.tsx
index 8dc407d5..1acb2931 100644
--- a/src/components/gui/table-cell/BigNumberCell.tsx
+++ b/src/components/gui/table-cell/big-number-cell.tsx
@@ -1,4 +1,4 @@
-import createEditableCell from "./createEditableCell";
+import createEditableCell from "./create-editable-cell";
const BigNumberCell = createEditableCell({
align: "right",
diff --git a/src/components/gui/table-cell/createEditableCell.tsx b/src/components/gui/table-cell/create-editable-cell.tsx
similarity index 84%
rename from src/components/gui/table-cell/createEditableCell.tsx
rename to src/components/gui/table-cell/create-editable-cell.tsx
index ec25918e..acd68841 100644
--- a/src/components/gui/table-cell/createEditableCell.tsx
+++ b/src/components/gui/table-cell/create-editable-cell.tsx
@@ -1,7 +1,8 @@
import { useState, useEffect, useCallback, useRef } from "react";
-import GenericCell from "./GenericCell";
+import GenericCell from "./generic-cell";
import { DatabaseValue } from "@/drivers/base-driver";
import OptimizeTableState from "../table-optimized/OptimizeTableState";
+import { useFullEditor } from "../providers/full-editor-provider";
export interface TableEditableCell {
value: DatabaseValue;
@@ -10,7 +11,7 @@ export interface TableEditableCell {
editMode?: boolean;
state: OptimizeTableState;
onChange?: (newValue: DatabaseValue) => void;
- editor?: "input" | "blocknote";
+ editor?: "input" | "json" | "text";
}
interface TabeEditableCellProps {
@@ -23,6 +24,7 @@ function InputCellEditor({
value,
align,
discardChange,
+ readOnly,
applyChange,
onChange,
state,
@@ -33,6 +35,7 @@ function InputCellEditor({
value: DatabaseValue;
onChange: (v: string) => void;
state: OptimizeTableState;
+ readOnly?: boolean;
}>) {
const inputRef = useRef(null);
const shouldExit = useRef(true);
@@ -48,6 +51,7 @@ function InputCellEditor({
{
applyChange(value, shouldExit.current);
}}
@@ -102,11 +106,13 @@ export default function createEditableCell({
focus,
onChange,
state,
+ editor,
editMode,
}: TableEditableCell) {
const [editValue, setEditValue] = useState>(
toString(value)
);
+ const { openEditor } = useFullEditor();
useEffect(() => {
setEditValue(toString(value));
@@ -135,11 +141,12 @@ export default function createEditableCell({
.filter(Boolean)
.join(" ");
- if (editMode) {
+ if (editMode && (editor === undefined || editor === "input")) {
return (
({
isChanged={isChanged}
align={align}
onDoubleClick={() => {
+ if (
+ typeof editValue === "string" &&
+ (editor === "json" || editor === "text")
+ ) {
+ openEditor({
+ format: editor,
+ initialValue: editValue,
+ readOnly: state.getReadOnlyMode(),
+ onCancel: () => state.exitEditMode(),
+ onSave: applyChange,
+ });
+ }
state.enterEditMode();
}}
/>
diff --git a/src/components/gui/table-cell/GenericCell.tsx b/src/components/gui/table-cell/generic-cell.tsx
similarity index 100%
rename from src/components/gui/table-cell/GenericCell.tsx
rename to src/components/gui/table-cell/generic-cell.tsx
diff --git a/src/components/gui/table-cell/NumberCell.tsx b/src/components/gui/table-cell/number-cell.tsx
similarity index 89%
rename from src/components/gui/table-cell/NumberCell.tsx
rename to src/components/gui/table-cell/number-cell.tsx
index 2c35a9e3..c5c86a31 100644
--- a/src/components/gui/table-cell/NumberCell.tsx
+++ b/src/components/gui/table-cell/number-cell.tsx
@@ -1,4 +1,4 @@
-import createEditableCell from "./createEditableCell";
+import createEditableCell from "./create-editable-cell";
const NumberCell = createEditableCell({
align: "right",
diff --git a/src/components/gui/table-cell/TextCell.tsx b/src/components/gui/table-cell/text-cell.tsx
similarity index 67%
rename from src/components/gui/table-cell/TextCell.tsx
rename to src/components/gui/table-cell/text-cell.tsx
index 22ce3313..d51bca3c 100644
--- a/src/components/gui/table-cell/TextCell.tsx
+++ b/src/components/gui/table-cell/text-cell.tsx
@@ -1,4 +1,4 @@
-import createEditableCell from "./createEditableCell";
+import createEditableCell from "./create-editable-cell";
const TextCell = createEditableCell({
toString: (v) => v,
diff --git a/src/components/gui/table-optimized/OptimizeTableState.tsx b/src/components/gui/table-optimized/OptimizeTableState.tsx
index 68b609fe..c66e6046 100644
--- a/src/components/gui/table-optimized/OptimizeTableState.tsx
+++ b/src/components/gui/table-optimized/OptimizeTableState.tsx
@@ -123,6 +123,10 @@ export default class OptimizeTableState {
this.readOnlyMode = readOnly;
}
+ getReadOnlyMode() {
+ return this.readOnlyMode;
+ }
+
setContainer(div: HTMLDivElement | null) {
this.container = div;
}
@@ -187,6 +191,8 @@ export default class OptimizeTableState {
}
changeValue(y: number, x: number, newValue: unknown) {
+ if (this.readOnlyMode) return;
+
const oldValue = this.getOriginalValue(y, x);
const row = this.data[y];
@@ -382,7 +388,6 @@ export default class OptimizeTableState {
}
enterEditMode() {
- if (this.readOnlyMode) return;
this.editMode = true;
this.broadcastChange();
}
diff --git a/src/components/markdown-editor/index.tsx b/src/components/markdown-editor/index.tsx
deleted file mode 100644
index 902f9c45..00000000
--- a/src/components/markdown-editor/index.tsx
+++ /dev/null
@@ -1,107 +0,0 @@
-"use client";
-import { Suspense, useEffect, useRef } from "react";
-import {
- $getRoot,
- $getSelection,
- LexicalEditor,
- $setSelection,
- $addUpdateTag,
-} from "lexical";
-import { LexicalComposer } from "@lexical/react/LexicalComposer";
-import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
-import { ContentEditable } from "@lexical/react/LexicalContentEditable";
-import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
-import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
-import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
-import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
-import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
-import { ListPlugin } from "@lexical/react/LexicalListPlugin";
-
-import { ListItemNode, ListNode } from "@lexical/list";
-
-import {
- $convertFromMarkdownString,
- $convertToMarkdownString,
- TRANSFORMERS,
-} from "@lexical/markdown";
-import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
-
-const initialMarkdown = "This is **markdown**";
-
-function MarkdownPreview() {
- const mdRef = useRef(null);
- const [editor] = useLexicalComposerContext();
-
- useEffect(() => {
- return editor.registerUpdateListener(({ editorState, tags }) => {
- if (!tags.has("from-markdown-preview")) {
- editorState.read(() => {
- if (mdRef.current) {
- mdRef.current.value = $convertToMarkdownString(TRANSFORMERS);
- }
- });
- }
- });
- }, [editor]);
-
- return (
-