@jbpark/live-editor 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ast-BhbOxomw.js → ast-CAhr9WXv.js} +78 -20
- package/dist/ast-CAhr9WXv.js.map +1 -0
- package/dist/{boundary-DOBK2HnX.js → boundary-DQiKrXhI.js} +2 -2
- package/dist/{boundary-DOBK2HnX.js.map → boundary-DQiKrXhI.js.map} +1 -1
- package/dist/{context-DOMX_RsU.js → context-CJ0_ptf4.js} +3 -3
- package/dist/{context-DOMX_RsU.js.map → context-CJ0_ptf4.js.map} +1 -1
- package/dist/core-D5Hn-6ow.js +123 -0
- package/dist/core-D5Hn-6ow.js.map +1 -0
- package/dist/dnd/index.d.ts +1 -1
- package/dist/dnd/index.js +1 -1
- package/dist/{dnd-E8LbmRfE.js → dnd-C1YGcp4k.js} +138 -86
- package/dist/dnd-C1YGcp4k.js.map +1 -0
- package/dist/{document-Ddw-tfnt.js → document-CgUTKVQo.js} +11 -9
- package/dist/document-CgUTKVQo.js.map +1 -0
- package/dist/editor/index.js +2 -2
- package/dist/{editor-ka05eWyz.js → editor-Ds-mUYs_.js} +3 -3
- package/dist/{editor-ka05eWyz.js.map → editor-Ds-mUYs_.js.map} +1 -1
- package/dist/error/index.js +2 -2
- package/dist/{error-fzPGTaFe.js → error-B5MciRP7.js} +2 -2
- package/dist/{error-fzPGTaFe.js.map → error-B5MciRP7.js.map} +1 -1
- package/dist/{index-2CUWhF-T.d.ts → index-9bvWkK07.d.ts} +2 -2
- package/dist/{index-FKgYmeNR.d.ts → index-GuEiafMN.d.ts} +29 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/preview/index.js +1 -1
- package/dist/{preview-EsfzEjis.js → preview-DtBbnlwy.js} +4 -4
- package/dist/{preview-EsfzEjis.js.map → preview-DtBbnlwy.js.map} +1 -1
- package/dist/provider/index.js +1 -1
- package/dist/style.css +448 -60
- package/dist/{use-dynamic-tailwind-CRMGuKnH.js → use-dynamic-tailwind-cdaivJXJ.js} +2 -2
- package/dist/{use-dynamic-tailwind-CRMGuKnH.js.map → use-dynamic-tailwind-cdaivJXJ.js.map} +1 -1
- package/dist/utils/ast/index.d.ts +2 -2
- package/dist/utils/ast/index.js +2 -2
- package/dist/utils/index.js +2 -2
- package/dist/{utils-B6zpA7mT.js → utils-DbfbS1yV.js} +2 -2
- package/dist/{utils-B6zpA7mT.js.map → utils-DbfbS1yV.js.map} +1 -1
- package/package.json +26 -10
- package/dist/ast-BhbOxomw.js.map +0 -1
- package/dist/core-D-ZvVhdn.js +0 -11195
- package/dist/core-D-ZvVhdn.js.map +0 -1
- package/dist/dnd-E8LbmRfE.js.map +0 -1
- package/dist/document-Ddw-tfnt.js.map +0 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { a as detectTypeScript, r as cn } from "./utils-DbfbS1yV.js";
|
|
2
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
import { javascript } from "@codemirror/lang-javascript";
|
|
5
|
+
import { vscodeLight } from "@uiw/codemirror-theme-vscode";
|
|
6
|
+
import CodeMirror from "@uiw/react-codemirror";
|
|
7
|
+
import { EditorView } from "codemirror";
|
|
8
|
+
//#region src/components/editor/use-format-code.ts
|
|
9
|
+
const loadPrettier = async () => {
|
|
10
|
+
const [prettier, babel, estree, typescript] = await Promise.all([
|
|
11
|
+
import("prettier"),
|
|
12
|
+
import("prettier/plugins/babel"),
|
|
13
|
+
import("prettier/plugins/estree"),
|
|
14
|
+
import("prettier/plugins/typescript")
|
|
15
|
+
]);
|
|
16
|
+
return {
|
|
17
|
+
format: prettier.format,
|
|
18
|
+
plugins: [
|
|
19
|
+
babel.default,
|
|
20
|
+
estree.default,
|
|
21
|
+
typescript.default
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
const DEFAULT_PRETTIER_OPTIONS = {
|
|
26
|
+
tabWidth: 2,
|
|
27
|
+
singleQuote: true,
|
|
28
|
+
trailingComma: "all",
|
|
29
|
+
htmlWhitespaceSensitivity: "ignore",
|
|
30
|
+
arrowParens: "avoid",
|
|
31
|
+
printWidth: 60
|
|
32
|
+
};
|
|
33
|
+
const useFormatCode = ({ fragment, prettierOptions } = {}) => {
|
|
34
|
+
const prettierConfig = useMemo(() => ({
|
|
35
|
+
...DEFAULT_PRETTIER_OPTIONS,
|
|
36
|
+
...prettierOptions
|
|
37
|
+
}), [prettierOptions]);
|
|
38
|
+
return useCallback(async (code) => {
|
|
39
|
+
const isTypeScript = detectTypeScript(code);
|
|
40
|
+
const source = fragment ? `<>${code}</>` : code;
|
|
41
|
+
let prettier;
|
|
42
|
+
try {
|
|
43
|
+
prettier = await loadPrettier();
|
|
44
|
+
} catch {
|
|
45
|
+
return code;
|
|
46
|
+
}
|
|
47
|
+
const formatted = await prettier.format(source, {
|
|
48
|
+
parser: isTypeScript ? "typescript" : "babel",
|
|
49
|
+
plugins: prettier.plugins,
|
|
50
|
+
...prettierConfig
|
|
51
|
+
});
|
|
52
|
+
if (fragment) return formatted.replace(/^<>\n?/, "").replace(/\n?<\/>;?\s*$/, "").replace(/^ {2}/gm, "").trim();
|
|
53
|
+
return formatted;
|
|
54
|
+
}, [prettierConfig, fragment]);
|
|
55
|
+
};
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/components/editor/core.tsx
|
|
58
|
+
const Core = ({ value, theme, height, className, prettierOptions, fragment, raw, onChange, onSave: _onSave, onError, ...props }) => {
|
|
59
|
+
const editorRef = useRef(null);
|
|
60
|
+
const formatCode = useFormatCode({
|
|
61
|
+
fragment,
|
|
62
|
+
prettierOptions
|
|
63
|
+
});
|
|
64
|
+
const onSave = useCallback(async (val) => {
|
|
65
|
+
try {
|
|
66
|
+
const currentView = editorRef.current?.view;
|
|
67
|
+
if (!currentView) return;
|
|
68
|
+
const currentLength = currentView.state.doc.length;
|
|
69
|
+
const cursorPos = currentView.state.selection.main.head;
|
|
70
|
+
const formattedCode = raw ? val : await formatCode(val);
|
|
71
|
+
if (currentLength === currentView.state.doc.length) {
|
|
72
|
+
const newCursorPos = Math.min(cursorPos, formattedCode.length);
|
|
73
|
+
const transaction = currentView.state.update({
|
|
74
|
+
changes: {
|
|
75
|
+
from: 0,
|
|
76
|
+
to: currentLength,
|
|
77
|
+
insert: formattedCode
|
|
78
|
+
},
|
|
79
|
+
selection: { anchor: newCursorPos }
|
|
80
|
+
});
|
|
81
|
+
currentView.dispatch(transaction);
|
|
82
|
+
onChange?.(formattedCode);
|
|
83
|
+
_onSave?.(formattedCode);
|
|
84
|
+
}
|
|
85
|
+
onError?.(null);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
onError?.(e instanceof Error ? e.message : String(e));
|
|
88
|
+
}
|
|
89
|
+
}, [
|
|
90
|
+
raw,
|
|
91
|
+
formatCode,
|
|
92
|
+
onChange,
|
|
93
|
+
_onSave,
|
|
94
|
+
onError
|
|
95
|
+
]);
|
|
96
|
+
const onKeyDown = useCallback((e) => {
|
|
97
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "s") {
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
const currentValue = editorRef.current?.view?.state.doc.toString() || value;
|
|
100
|
+
onSave(currentValue);
|
|
101
|
+
}
|
|
102
|
+
}, [onSave, value]);
|
|
103
|
+
return /* @__PURE__ */ jsx("div", {
|
|
104
|
+
className: cn(className),
|
|
105
|
+
onKeyDown,
|
|
106
|
+
children: /* @__PURE__ */ jsx(CodeMirror, {
|
|
107
|
+
ref: editorRef,
|
|
108
|
+
theme: theme || vscodeLight,
|
|
109
|
+
height: height || "100%",
|
|
110
|
+
value,
|
|
111
|
+
extensions: [javascript({
|
|
112
|
+
jsx: true,
|
|
113
|
+
typescript: true
|
|
114
|
+
}), EditorView.lineWrapping],
|
|
115
|
+
onChange,
|
|
116
|
+
...props
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
//#endregion
|
|
121
|
+
export { useFormatCode as n, Core as t };
|
|
122
|
+
|
|
123
|
+
//# sourceMappingURL=core-D5Hn-6ow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core-D5Hn-6ow.js","names":[],"sources":["../src/components/editor/use-format-code.ts","../src/components/editor/core.tsx"],"sourcesContent":["import { useCallback, useMemo } from 'react';\n\nimport { detectTypeScript } from '~/utils';\n\n// prettier is an optional peer dependency (#282): the editor subpath is the\n// only thing that needs it, so consumers who don't use format-on-save\n// shouldn't have to install ~9.6 MB. It's loaded lazily below and its absence\n// degrades gracefully (the code is returned unformatted) instead of throwing.\nconst loadPrettier = async () => {\n const [prettier, babel, estree, typescript] = await Promise.all([\n import('prettier'),\n import('prettier/plugins/babel'),\n import('prettier/plugins/estree'),\n import('prettier/plugins/typescript'),\n ]);\n\n return {\n format: prettier.format,\n plugins: [babel.default, estree.default, typescript.default],\n };\n};\n\nconst DEFAULT_PRETTIER_OPTIONS: Record<string, unknown> = {\n tabWidth: 2,\n singleQuote: true,\n trailingComma: 'all',\n htmlWhitespaceSensitivity: 'ignore',\n arrowParens: 'avoid',\n printWidth: 60,\n};\n\nexport interface UseFormatCodeOptions {\n fragment?: boolean;\n prettierOptions?: Record<string, unknown>;\n}\n\n// Extracted out of Core so a custom renderEditor (see editor.tsx's\n// renderEditor prop) can reuse the exact same formatting behavior instead\n// of reimplementing prettier wiring from scratch.\nexport const useFormatCode = ({\n fragment,\n prettierOptions,\n}: UseFormatCodeOptions = {}) => {\n const prettierConfig = useMemo(\n () => ({\n ...DEFAULT_PRETTIER_OPTIONS,\n ...prettierOptions,\n }),\n [prettierOptions],\n );\n\n return useCallback(\n async (code: string) => {\n const isTypeScript = detectTypeScript(code);\n const source = fragment ? `<>${code}</>` : code;\n\n // Only a missing prettier is swallowed here; a genuine format error\n // (prettier present, but the code is unparseable) still propagates so\n // the editor's Cmd+S path can surface it via onError.\n let prettier: Awaited<ReturnType<typeof loadPrettier>>;\n try {\n prettier = await loadPrettier();\n } catch {\n return code;\n }\n\n const formatted = await prettier.format(source, {\n parser: isTypeScript ? 'typescript' : 'babel',\n plugins: prettier.plugins,\n ...prettierConfig,\n });\n\n if (fragment) {\n return formatted\n .replace(/^<>\\n?/, '')\n .replace(/\\n?<\\/>;?\\s*$/, '')\n .replace(/^ {2}/gm, '')\n .trim();\n }\n\n return formatted;\n },\n [prettierConfig, fragment],\n );\n};\n","import { useCallback, useRef } from 'react';\n\nimport { javascript } from '@codemirror/lang-javascript';\nimport { vscodeLight } from '@uiw/codemirror-theme-vscode';\nimport CodeMirror, {\n type Extension,\n type ReactCodeMirrorRef,\n} from '@uiw/react-codemirror';\nimport { EditorView } from 'codemirror';\n\nimport { cn } from '~/utils';\n\nimport { useFormatCode } from './use-format-code';\n\nexport interface Props {\n value: string;\n height?: string;\n theme?: Extension | 'light' | 'dark' | 'none';\n prettierOptions?: Record<string, unknown>;\n fragment?: boolean;\n raw?: boolean;\n className?: string;\n onChange?: (value: string) => void;\n onSave?: (value: string) => void;\n onError?: (error: string | null) => void;\n}\n\nconst Core = ({\n value,\n theme,\n height,\n className,\n prettierOptions,\n fragment,\n raw,\n onChange,\n onSave: _onSave,\n onError,\n ...props\n}: Props) => {\n const editorRef = useRef<ReactCodeMirrorRef>(null);\n\n const formatCode = useFormatCode({ fragment, prettierOptions });\n\n const onSave = useCallback(\n async (val: string) => {\n try {\n const currentView = editorRef.current?.view;\n if (!currentView) {\n return;\n }\n\n const currentLength = currentView.state.doc.length;\n const cursorPos = currentView.state.selection.main.head;\n const formattedCode = raw ? val : await formatCode(val);\n\n if (currentLength === currentView.state.doc.length) {\n const newCursorPos = Math.min(cursorPos, formattedCode.length);\n const transaction = currentView.state.update({\n changes: { from: 0, to: currentLength, insert: formattedCode },\n selection: { anchor: newCursorPos },\n });\n currentView.dispatch(transaction);\n\n onChange?.(formattedCode);\n _onSave?.(formattedCode);\n }\n\n onError?.(null);\n } catch (e) {\n onError?.(e instanceof Error ? e.message : String(e));\n }\n },\n [raw, formatCode, onChange, _onSave, onError],\n );\n\n const onKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n if ((e.metaKey || e.ctrlKey) && e.key === 's') {\n e.preventDefault();\n const currentValue =\n editorRef.current?.view?.state.doc.toString() || value;\n onSave(currentValue);\n }\n },\n [onSave, value],\n );\n\n return (\n <div className={cn(className)} onKeyDown={onKeyDown}>\n <CodeMirror\n ref={editorRef}\n theme={theme || vscodeLight}\n height={height || '100%'}\n value={value}\n extensions={[\n javascript({ jsx: true, typescript: true }),\n EditorView.lineWrapping,\n ]}\n onChange={onChange}\n {...props}\n />\n </div>\n );\n};\n\nexport default Core;\n"],"mappings":";;;;;;;;AAQA,MAAM,eAAe,YAAY;CAC/B,MAAM,CAAC,UAAU,OAAO,QAAQ,cAAc,MAAM,QAAQ,IAAI;EAC9D,OAAO;EACP,OAAO;EACP,OAAO;EACP,OAAO;CACT,CAAC;CAED,OAAO;EACL,QAAQ,SAAS;EACjB,SAAS;GAAC,MAAM;GAAS,OAAO;GAAS,WAAW;EAAO;CAC7D;AACF;AAEA,MAAM,2BAAoD;CACxD,UAAU;CACV,aAAa;CACb,eAAe;CACf,2BAA2B;CAC3B,aAAa;CACb,YAAY;AACd;AAUA,MAAa,iBAAiB,EAC5B,UACA,oBACwB,CAAC,MAAM;CAC/B,MAAM,iBAAiB,eACd;EACL,GAAG;EACH,GAAG;CACL,IACA,CAAC,eAAe,CAClB;CAEA,OAAO,YACL,OAAO,SAAiB;EACtB,MAAM,eAAe,iBAAiB,IAAI;EAC1C,MAAM,SAAS,WAAW,KAAK,KAAK,OAAO;EAK3C,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,aAAa;EAChC,QAAQ;GACN,OAAO;EACT;EAEA,MAAM,YAAY,MAAM,SAAS,OAAO,QAAQ;GAC9C,QAAQ,eAAe,eAAe;GACtC,SAAS,SAAS;GAClB,GAAG;EACL,CAAC;EAED,IAAI,UACF,OAAO,UACJ,QAAQ,UAAU,EAAE,CAAC,CACrB,QAAQ,iBAAiB,EAAE,CAAC,CAC5B,QAAQ,WAAW,EAAE,CAAC,CACtB,KAAK;EAGV,OAAO;CACT,GACA,CAAC,gBAAgB,QAAQ,CAC3B;AACF;;;ACzDA,MAAM,QAAQ,EACZ,OACA,OACA,QACA,WACA,iBACA,UACA,KACA,UACA,QAAQ,SACR,SACA,GAAG,YACQ;CACX,MAAM,YAAY,OAA2B,IAAI;CAEjD,MAAM,aAAa,cAAc;EAAE;EAAU;CAAgB,CAAC;CAE9D,MAAM,SAAS,YACb,OAAO,QAAgB;EACrB,IAAI;GACF,MAAM,cAAc,UAAU,SAAS;GACvC,IAAI,CAAC,aACH;GAGF,MAAM,gBAAgB,YAAY,MAAM,IAAI;GAC5C,MAAM,YAAY,YAAY,MAAM,UAAU,KAAK;GACnD,MAAM,gBAAgB,MAAM,MAAM,MAAM,WAAW,GAAG;GAEtD,IAAI,kBAAkB,YAAY,MAAM,IAAI,QAAQ;IAClD,MAAM,eAAe,KAAK,IAAI,WAAW,cAAc,MAAM;IAC7D,MAAM,cAAc,YAAY,MAAM,OAAO;KAC3C,SAAS;MAAE,MAAM;MAAG,IAAI;MAAe,QAAQ;KAAc;KAC7D,WAAW,EAAE,QAAQ,aAAa;IACpC,CAAC;IACD,YAAY,SAAS,WAAW;IAEhC,WAAW,aAAa;IACxB,UAAU,aAAa;GACzB;GAEA,UAAU,IAAI;EAChB,SAAS,GAAG;GACV,UAAU,aAAa,QAAQ,EAAE,UAAU,OAAO,CAAC,CAAC;EACtD;CACF,GACA;EAAC;EAAK;EAAY;EAAU;EAAS;CAAO,CAC9C;CAEA,MAAM,YAAY,aACf,MAA2C;EAC1C,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,KAAK;GAC7C,EAAE,eAAe;GACjB,MAAM,eACJ,UAAU,SAAS,MAAM,MAAM,IAAI,SAAS,KAAK;GACnD,OAAO,YAAY;EACrB;CACF,GACA,CAAC,QAAQ,KAAK,CAChB;CAEA,OACE,oBAAC,OAAD;EAAK,WAAW,GAAG,SAAS;EAAc;EACxC,UAAA,oBAAC,YAAD;GACE,KAAK;GACL,OAAO,SAAS;GAChB,QAAQ,UAAU;GACX;GACP,YAAY,CACV,WAAW;IAAE,KAAK;IAAM,YAAY;GAAK,CAAC,GAC1C,WAAW,YACb;GACU;GACV,GAAI;EACL,CAAA;CACE,CAAA;AAET"}
|
package/dist/dnd/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ICON_OPTIONS, c as PanelRenderData, d as DraggableItemDragState, f as DraggableItemProps, i as ICON_MAP, l as Props, n as Panel, o as PaletteRenderData, r as PanelProps, s as PanelBinding, t as Dnd, u as DraggableItem } from "../index-
|
|
1
|
+
import { a as ICON_OPTIONS, c as PanelRenderData, d as DraggableItemDragState, f as DraggableItemProps, i as ICON_MAP, l as Props, n as Panel, o as PaletteRenderData, r as PanelProps, s as PanelBinding, t as Dnd, u as DraggableItem } from "../index-9bvWkK07.js";
|
|
2
2
|
export { Panel as DefaultPanel, DraggableItem, type DraggableItemDragState, type DraggableItemProps, ICON_MAP, ICON_OPTIONS, type PaletteRenderData, type PanelBinding, type PanelProps, type PanelRenderData, type Props, Dnd as default };
|
package/dist/dnd/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as DraggableItem, i as ICON_OPTIONS, n as Panel, r as ICON_MAP, t as Dnd } from "../dnd-
|
|
1
|
+
import { a as DraggableItem, i as ICON_OPTIONS, n as Panel, r as ICON_MAP, t as Dnd } from "../dnd-C1YGcp4k.js";
|
|
2
2
|
export { Panel as DefaultPanel, DraggableItem, ICON_MAP, ICON_OPTIONS, Dnd as default };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { C as __toESM, b as DRAGGABLE_ITEMS, f as nanoid, g as BINDING_PROP, m as require_lib, n as createSectionPreviewCache, r as fillSectionIds, y as DEFAULT_TEMPLATE } from "./document-
|
|
2
|
-
import { d as replaceSections, o as extractSections, r as cn, s as generateSection, u as preloadScripts } from "./utils-
|
|
1
|
+
import { C as __toESM, b as DRAGGABLE_ITEMS, f as nanoid, g as BINDING_PROP, m as require_lib, n as createSectionPreviewCache, r as fillSectionIds, y as DEFAULT_TEMPLATE } from "./document-CgUTKVQo.js";
|
|
2
|
+
import { d as replaceSections, o as extractSections, r as cn, s as generateSection, u as preloadScripts } from "./utils-DbfbS1yV.js";
|
|
3
3
|
import { i as usePreview } from "./states-Ci1AvoQ9.js";
|
|
4
|
-
import { A as parseValue, D as extractObjectProperties, E as extractNodeValue, M as generateCode, S as parseBinding, _ as moveSelectedIndices, a as extract, b as getCurrentValue, c as moveArrayItem, d as removeArrayItems, f as updateArrayItemProperty, g as replaceIds, h as fillIds, k as parseArrayExpression, l as moveArrayItems, o as appendArrayItem, p as updateArrayItemValue, r as update, s as duplicateArrayItems, t as validateBindingValue, v as removeIndices, x as getStructuredValue, y as findEditableChildren } from "./ast-
|
|
5
|
-
import { n as useCompiledModule, r as Frame, t as useDynamicTailwind } from "./use-dynamic-tailwind-
|
|
6
|
-
import { n as Error, t as ErrorBoundary } from "./boundary-
|
|
7
|
-
import { t as Core } from "./core-
|
|
4
|
+
import { A as parseValue, D as extractObjectProperties, E as extractNodeValue, M as generateCode, S as parseBinding, _ as moveSelectedIndices, a as extract, b as getCurrentValue, c as moveArrayItem, d as removeArrayItems, f as updateArrayItemProperty, g as replaceIds, h as fillIds, k as parseArrayExpression, l as moveArrayItems, o as appendArrayItem, p as updateArrayItemValue, r as update, s as duplicateArrayItems, t as validateBindingValue, v as removeIndices, x as getStructuredValue, y as findEditableChildren } from "./ast-CAhr9WXv.js";
|
|
5
|
+
import { n as useCompiledModule, r as Frame, t as useDynamicTailwind } from "./use-dynamic-tailwind-cdaivJXJ.js";
|
|
6
|
+
import { n as Error, t as ErrorBoundary } from "./boundary-DQiKrXhI.js";
|
|
7
|
+
import { t as Core } from "./core-D5Hn-6ow.js";
|
|
8
8
|
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
9
|
-
import { Button, Card, Checkbox, ColorPicker, DatePicker, Drawer, Input, Select, Space, Toast, Typography, Upload } from "@jbpark/ui-kit";
|
|
9
|
+
import { Button, Card, Checkbox, ColorPicker, DatePicker, Drawer, Input, RichTextEditor, Select, Space, Splitter, Toast, Typography, Upload } from "@jbpark/ui-kit";
|
|
10
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
import { DndContext, DragOverlay, PointerSensor, closestCenter, useDndContext, useDraggable, useDroppable, useSensor, useSensors } from "@dnd-kit/core";
|
|
12
12
|
import { restrictToVerticalAxis } from "@dnd-kit/modifiers";
|
|
@@ -14,9 +14,6 @@ import { SortableContext, arrayMove, useSortable, verticalListSortingStrategy }
|
|
|
14
14
|
import { useDebounce, useMultiSelect, useResponsiveSize } from "@jbpark/use-hooks";
|
|
15
15
|
import { AlertCircle, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, Bell, Bookmark, Calendar, Camera, Check, ChevronDown, ChevronRight, ChevronUp, Clock, Copy, Download, Edit, Eye, Filter, Heart, Home, Image, Info, LayoutGrid, Link, Mail, Map as Map$1, Menu, MessageCircle, Phone, Plus, Search, Settings, Share, ShoppingCart, Star, Trash, Upload as Upload$1, User, X } from "lucide-react";
|
|
16
16
|
import { CSS } from "@dnd-kit/utilities";
|
|
17
|
-
import Placeholder from "@tiptap/extension-placeholder";
|
|
18
|
-
import { EditorContent, useEditor } from "@tiptap/react";
|
|
19
|
-
import StarterKit from "@tiptap/starter-kit";
|
|
20
17
|
//#region src/components/dnd/draggable.tsx
|
|
21
18
|
const DraggableItem = ({ item, children }) => {
|
|
22
19
|
const { attributes, listeners, setNodeRef, isDragging } = useDraggable({
|
|
@@ -169,26 +166,6 @@ const Overlay = ({ sections, renderProps }) => {
|
|
|
169
166
|
return null;
|
|
170
167
|
};
|
|
171
168
|
//#endregion
|
|
172
|
-
//#region src/components/editor/tiptap.tsx
|
|
173
|
-
const Tiptap = ({ value = "", placeholder = "Enter text...", className, onChange }) => {
|
|
174
|
-
const editor = useEditor({
|
|
175
|
-
extensions: [StarterKit, Placeholder.configure({ placeholder })],
|
|
176
|
-
content: value,
|
|
177
|
-
onBlur: ({ editor: e }) => {
|
|
178
|
-
onChange?.(e.getHTML());
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
useEffect(() => {
|
|
182
|
-
if (!editor) return;
|
|
183
|
-
if (editor.getHTML() !== value) editor.commands.setContent(value, { emitUpdate: false });
|
|
184
|
-
}, [value, editor]);
|
|
185
|
-
return /* @__PURE__ */ jsx(EditorContent, {
|
|
186
|
-
editor,
|
|
187
|
-
className: cn(`tiptap-editor min-h-20 rounded border border-gray-200 bg-white px-3
|
|
188
|
-
py-2`, "prose prose-sm max-w-none text-sm text-gray-800", "[&_.tiptap]:outline-none", "[&_.tiptap_p.is-editor-empty:first-child::before]:pointer-events-none", "[&_.tiptap_p.is-editor-empty:first-child::before]:float-left", "[&_.tiptap_p.is-editor-empty:first-child::before]:h-0", "[&_.tiptap_p.is-editor-empty:first-child::before]:text-gray-400", "[&_.tiptap_p.is-editor-empty:first-child::before]:content-[attr(data-placeholder)]", className)
|
|
189
|
-
});
|
|
190
|
-
};
|
|
191
|
-
//#endregion
|
|
192
169
|
//#region src/components/dnd/panel/node.tsx
|
|
193
170
|
var import_lib = /* @__PURE__ */ __toESM(require_lib(), 1);
|
|
194
171
|
const Node = ({ data, onChange }) => {
|
|
@@ -316,8 +293,9 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
316
293
|
return;
|
|
317
294
|
}
|
|
318
295
|
const jsxBindings = {};
|
|
296
|
+
const jsxFallbacks = {};
|
|
319
297
|
element.properties.forEach((prop) => {
|
|
320
|
-
if (!import_lib.isObjectProperty(prop) || !import_lib.isIdentifier(prop.key) || !import_lib.isJSXElement(prop.value)) return;
|
|
298
|
+
if (!import_lib.isObjectProperty(prop) || !import_lib.isIdentifier(prop.key) || !(import_lib.isJSXElement(prop.value) || import_lib.isJSXFragment(prop.value))) return;
|
|
321
299
|
const propertyName = prop.key.name;
|
|
322
300
|
try {
|
|
323
301
|
const jsxCode = generateCode(prop.value);
|
|
@@ -331,6 +309,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
331
309
|
bindings.push(...editableChildren);
|
|
332
310
|
});
|
|
333
311
|
if (bindings.length > 0) jsxBindings[propertyName] = bindings;
|
|
312
|
+
else jsxFallbacks[propertyName] = jsxCode;
|
|
334
313
|
} catch (error) {
|
|
335
314
|
console.error(`Failed to parse JSX in property '${propertyName}':`, error);
|
|
336
315
|
}
|
|
@@ -340,7 +319,8 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
340
319
|
index: objectItems.length,
|
|
341
320
|
elementIndex,
|
|
342
321
|
editableProperties: extractObjectProperties(element),
|
|
343
|
-
jsxBindings
|
|
322
|
+
jsxBindings,
|
|
323
|
+
jsxFallbacks
|
|
344
324
|
});
|
|
345
325
|
});
|
|
346
326
|
return {
|
|
@@ -614,7 +594,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
614
594
|
}),
|
|
615
595
|
/* @__PURE__ */ jsx("div", {
|
|
616
596
|
className: "space-y-3 border-t pt-2",
|
|
617
|
-
children: Object.entries(item.jsxBindings).length > 0 ? Object.entries(item.jsxBindings).map(([propertyName, bindings]) => /* @__PURE__ */ jsxs("div", {
|
|
597
|
+
children: Object.entries(item.jsxBindings).length > 0 || Object.entries(item.jsxFallbacks).length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [Object.entries(item.jsxBindings).map(([propertyName, bindings]) => /* @__PURE__ */ jsxs("div", {
|
|
618
598
|
className: "space-y-2",
|
|
619
599
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
620
600
|
className: "text-xs font-medium text-blue-700",
|
|
@@ -627,7 +607,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
627
607
|
}), bindings.map((bindingNode, idx) => {
|
|
628
608
|
const nodeId = bindingNode.dataAttributes.find((a) => a.name === "data-id")?.value;
|
|
629
609
|
return /* @__PURE__ */ jsxs("div", {
|
|
630
|
-
className: "rounded border border-blue-100 bg-blue-50\n
|
|
610
|
+
className: "rounded border border-blue-100 bg-blue-50\n p-2",
|
|
631
611
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
632
612
|
className: "mb-1 text-xs text-blue-600",
|
|
633
613
|
children: [
|
|
@@ -641,7 +621,24 @@ const Items = ({ value, render, onChange, onChildChange }) => {
|
|
|
641
621
|
})]
|
|
642
622
|
}, `binding-${item.id}-${propertyName}-${nodeId || idx}`);
|
|
643
623
|
})]
|
|
644
|
-
}, propertyName))
|
|
624
|
+
}, propertyName)), Object.entries(item.jsxFallbacks).map(([propertyName, code]) => /* @__PURE__ */ jsxs("div", {
|
|
625
|
+
className: "space-y-2",
|
|
626
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
627
|
+
className: "text-xs font-medium text-blue-700",
|
|
628
|
+
children: propertyName
|
|
629
|
+
}), /* @__PURE__ */ jsx(Field, {
|
|
630
|
+
binding: {
|
|
631
|
+
id: `item-${item.id}-${propertyName}-jsx`,
|
|
632
|
+
label: propertyName,
|
|
633
|
+
property: propertyName,
|
|
634
|
+
type: "jsx",
|
|
635
|
+
value: code,
|
|
636
|
+
rawValue: code,
|
|
637
|
+
onChange: (next) => updateProperty(item.elementIndex, propertyName, next)
|
|
638
|
+
},
|
|
639
|
+
onNodeChange: onChildChange
|
|
640
|
+
})]
|
|
641
|
+
}, propertyName))] }) : /* @__PURE__ */ jsx("div", {
|
|
645
642
|
className: "text-xs text-gray-500",
|
|
646
643
|
children: "✓ No JSX bindings found"
|
|
647
644
|
})
|
|
@@ -913,6 +910,14 @@ const formatDateValue = (date) => {
|
|
|
913
910
|
return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
914
911
|
};
|
|
915
912
|
const COLOR_COMMIT_DELAY = 75;
|
|
913
|
+
const RICHTEXT_TOOLBAR = [
|
|
914
|
+
"bold",
|
|
915
|
+
"italic",
|
|
916
|
+
"underline",
|
|
917
|
+
"bulletList",
|
|
918
|
+
"orderedList",
|
|
919
|
+
"link"
|
|
920
|
+
];
|
|
916
921
|
const ColorPickerField = ({ value, onChange }) => {
|
|
917
922
|
const [liveValue, setLiveValue] = useState(value);
|
|
918
923
|
const [prevValue, setPrevValue] = useState(value);
|
|
@@ -960,8 +965,9 @@ const Field = ({ binding, onNodeChange }) => {
|
|
|
960
965
|
onChange,
|
|
961
966
|
onChildChange: onNodeChange
|
|
962
967
|
});
|
|
963
|
-
if (binding.type === "richtext") return /* @__PURE__ */ jsx(
|
|
968
|
+
if (binding.type === "richtext") return /* @__PURE__ */ jsx(RichTextEditor, {
|
|
964
969
|
value: rawValue,
|
|
970
|
+
toolbar: RICHTEXT_TOOLBAR,
|
|
965
971
|
onChange: (next) => {
|
|
966
972
|
if (next !== rawValue) onChange(next);
|
|
967
973
|
}
|
|
@@ -1334,6 +1340,35 @@ const useSectionDocument = (value, onChange) => {
|
|
|
1334
1340
|
};
|
|
1335
1341
|
//#endregion
|
|
1336
1342
|
//#region src/components/dnd/dnd.tsx
|
|
1343
|
+
const describeUpdateFailure = (failure, label) => {
|
|
1344
|
+
switch (failure?.reason) {
|
|
1345
|
+
case "attribute-not-found": return {
|
|
1346
|
+
title: `Failed to update "${label}"`,
|
|
1347
|
+
description: `This element has no "${failure.property}" attribute — check the property in its data-binding.`
|
|
1348
|
+
};
|
|
1349
|
+
case "binding-not-declared": return {
|
|
1350
|
+
title: `Failed to update "${label}"`,
|
|
1351
|
+
description: `No binding for ${failure.property ? `property "${failure.property}"` : `label "${label}"`} is declared on this element's data-binding.`
|
|
1352
|
+
};
|
|
1353
|
+
case "duplicate-binding": return {
|
|
1354
|
+
title: `Failed to update "${label}"`,
|
|
1355
|
+
description: `${failure.count} bindings share ${failure.property ? `property "${failure.property}"` : `label "${label}"`} on this element — remove the duplicate in its data-binding.`
|
|
1356
|
+
};
|
|
1357
|
+
case "no-binding": return {
|
|
1358
|
+
title: `Failed to update "${label}"`,
|
|
1359
|
+
description: "This element has no data-binding declaration."
|
|
1360
|
+
};
|
|
1361
|
+
case "element-not-found": return {
|
|
1362
|
+
title: `Failed to update "${label}"`,
|
|
1363
|
+
description: "The target element could not be found in this section."
|
|
1364
|
+
};
|
|
1365
|
+
case "parse-error": return {
|
|
1366
|
+
title: `Failed to update "${label}"`,
|
|
1367
|
+
description: "Check the console for details."
|
|
1368
|
+
};
|
|
1369
|
+
default: return { title: `Failed to update "${label}"` };
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1337
1372
|
const conditionalModifiers = (args) => {
|
|
1338
1373
|
const { active } = args;
|
|
1339
1374
|
if (active?.data.current?.type === "new-item") return args.transform;
|
|
@@ -1394,7 +1429,8 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1394
1429
|
const onFieldChange = ({ id, label, property, value: fieldValue }) => {
|
|
1395
1430
|
const result = update(updatedCode, id, label, fieldValue, property);
|
|
1396
1431
|
if (!result.success) {
|
|
1397
|
-
|
|
1432
|
+
const { title, description } = describeUpdateFailure(result.failure, label);
|
|
1433
|
+
Toast.error(title, description ? { description } : void 0);
|
|
1398
1434
|
return;
|
|
1399
1435
|
}
|
|
1400
1436
|
if (selectedItem) onChange({
|
|
@@ -1476,6 +1512,45 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1476
1512
|
onNodeChange: onFieldChange
|
|
1477
1513
|
});
|
|
1478
1514
|
};
|
|
1515
|
+
const canvas = /* @__PURE__ */ jsx("div", {
|
|
1516
|
+
className: "relative h-full w-full overflow-y-auto",
|
|
1517
|
+
"data-frame-container": true,
|
|
1518
|
+
style: {
|
|
1519
|
+
isolation: "isolate",
|
|
1520
|
+
contain: "layout style",
|
|
1521
|
+
transform: "translateZ(0)"
|
|
1522
|
+
},
|
|
1523
|
+
children: /* @__PURE__ */ jsx(Droppable, {
|
|
1524
|
+
className: cn(!sections.length && "h-full"),
|
|
1525
|
+
children: !sections.length ? /* @__PURE__ */ jsx("div", {
|
|
1526
|
+
className: cn("flex items-center justify-center", "h-full", "text-gray-500"),
|
|
1527
|
+
children: /* @__PURE__ */ jsxs(Space, {
|
|
1528
|
+
orientation: "vertical",
|
|
1529
|
+
align: "center",
|
|
1530
|
+
children: [/* @__PURE__ */ jsx(Typography.Paragraph, { children: "No sections available" }), /* @__PURE__ */ jsx(Typography.Text, { children: isMobile ? "Tap a component to add it" : "Drag a component from the left to add it" })]
|
|
1531
|
+
})
|
|
1532
|
+
}) : /* @__PURE__ */ jsx(SortableContext, {
|
|
1533
|
+
items: sections.map((s) => s.id),
|
|
1534
|
+
strategy: verticalListSortingStrategy,
|
|
1535
|
+
children: sections.map((section, index) => /* @__PURE__ */ jsx(Sortable, {
|
|
1536
|
+
id: section.id,
|
|
1537
|
+
name: section.name,
|
|
1538
|
+
selected: selectedId === section.id,
|
|
1539
|
+
onClick: () => onSelect(section.id),
|
|
1540
|
+
onDelete,
|
|
1541
|
+
onCopy,
|
|
1542
|
+
children: /* @__PURE__ */ jsx(renderer_default, {
|
|
1543
|
+
preview: previews[index],
|
|
1544
|
+
modules,
|
|
1545
|
+
frame,
|
|
1546
|
+
dynamicTailwind,
|
|
1547
|
+
provider,
|
|
1548
|
+
...props
|
|
1549
|
+
})
|
|
1550
|
+
}, section.id))
|
|
1551
|
+
})
|
|
1552
|
+
})
|
|
1553
|
+
});
|
|
1479
1554
|
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(DndContext, {
|
|
1480
1555
|
sensors,
|
|
1481
1556
|
collisionDetection: closestCenter,
|
|
@@ -1484,58 +1559,35 @@ const Dnd$1 = ({ value: _value, props, modules = {}, onChange: _onChange, classN
|
|
|
1484
1559
|
onDragOver,
|
|
1485
1560
|
onDragEnd,
|
|
1486
1561
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
1487
|
-
className: cn("relative flex w-full", className),
|
|
1562
|
+
className: cn("relative flex h-full w-full", className),
|
|
1488
1563
|
...restProps,
|
|
1489
1564
|
children: [
|
|
1490
|
-
/* @__PURE__ */
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
contain: "layout style",
|
|
1503
|
-
transform: "translateZ(0)"
|
|
1504
|
-
},
|
|
1505
|
-
children: /* @__PURE__ */ jsx(Droppable, {
|
|
1506
|
-
className: cn(!sections.length && "h-full"),
|
|
1507
|
-
children: !sections.length ? /* @__PURE__ */ jsx("div", {
|
|
1508
|
-
className: cn("flex items-center justify-center", "h-full", "text-gray-500"),
|
|
1509
|
-
children: /* @__PURE__ */ jsxs(Space, {
|
|
1510
|
-
orientation: "vertical",
|
|
1511
|
-
align: "center",
|
|
1512
|
-
children: [/* @__PURE__ */ jsx(Typography.Paragraph, { children: "No sections available" }), /* @__PURE__ */ jsx(Typography.Text, { children: isMobile ? "Tap a component to add it" : "Drag a component from the left to add it" })]
|
|
1565
|
+
isMobile ? canvas : /* @__PURE__ */ jsxs(Splitter, {
|
|
1566
|
+
withHandle: true,
|
|
1567
|
+
orientation: "horizontal",
|
|
1568
|
+
children: [
|
|
1569
|
+
/* @__PURE__ */ jsx(Splitter.Panel, {
|
|
1570
|
+
defaultSize: "20%",
|
|
1571
|
+
minSize: "15%",
|
|
1572
|
+
maxSize: "35%",
|
|
1573
|
+
collapsible: true,
|
|
1574
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1575
|
+
className: "h-full overflow-y-auto bg-gray-50 p-4",
|
|
1576
|
+
children: renderPaletteItems(addItem)
|
|
1513
1577
|
})
|
|
1514
|
-
})
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
children:
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
preview: previews[index],
|
|
1526
|
-
modules,
|
|
1527
|
-
frame,
|
|
1528
|
-
dynamicTailwind,
|
|
1529
|
-
provider,
|
|
1530
|
-
...props
|
|
1531
|
-
})
|
|
1532
|
-
}, section.id))
|
|
1578
|
+
}),
|
|
1579
|
+
/* @__PURE__ */ jsx(Splitter.Panel, {
|
|
1580
|
+
defaultSize: "60%",
|
|
1581
|
+
children: canvas
|
|
1582
|
+
}),
|
|
1583
|
+
/* @__PURE__ */ jsx(Splitter.Panel, {
|
|
1584
|
+
defaultSize: "20%",
|
|
1585
|
+
minSize: "15%",
|
|
1586
|
+
maxSize: "35%",
|
|
1587
|
+
collapsible: true,
|
|
1588
|
+
children: renderPanelContent()
|
|
1533
1589
|
})
|
|
1534
|
-
|
|
1535
|
-
}),
|
|
1536
|
-
/* @__PURE__ */ jsx("div", {
|
|
1537
|
-
className: "hidden w-1/5 md:block",
|
|
1538
|
-
children: renderPanelContent()
|
|
1590
|
+
]
|
|
1539
1591
|
}),
|
|
1540
1592
|
/* @__PURE__ */ jsx(Button, {
|
|
1541
1593
|
type: "primary",
|
|
@@ -1585,4 +1637,4 @@ Dnd.DefaultPanel = Panel;
|
|
|
1585
1637
|
//#endregion
|
|
1586
1638
|
export { DraggableItem as a, ICON_OPTIONS as i, Panel as n, ICON_MAP as r, Dnd as t };
|
|
1587
1639
|
|
|
1588
|
-
//# sourceMappingURL=dnd-
|
|
1640
|
+
//# sourceMappingURL=dnd-C1YGcp4k.js.map
|