@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.
Files changed (42) hide show
  1. package/dist/{ast-BhbOxomw.js → ast-CAhr9WXv.js} +78 -20
  2. package/dist/ast-CAhr9WXv.js.map +1 -0
  3. package/dist/{boundary-DOBK2HnX.js → boundary-DQiKrXhI.js} +2 -2
  4. package/dist/{boundary-DOBK2HnX.js.map → boundary-DQiKrXhI.js.map} +1 -1
  5. package/dist/{context-DOMX_RsU.js → context-CJ0_ptf4.js} +3 -3
  6. package/dist/{context-DOMX_RsU.js.map → context-CJ0_ptf4.js.map} +1 -1
  7. package/dist/core-D5Hn-6ow.js +123 -0
  8. package/dist/core-D5Hn-6ow.js.map +1 -0
  9. package/dist/dnd/index.d.ts +1 -1
  10. package/dist/dnd/index.js +1 -1
  11. package/dist/{dnd-E8LbmRfE.js → dnd-C1YGcp4k.js} +138 -86
  12. package/dist/dnd-C1YGcp4k.js.map +1 -0
  13. package/dist/{document-Ddw-tfnt.js → document-CgUTKVQo.js} +11 -9
  14. package/dist/document-CgUTKVQo.js.map +1 -0
  15. package/dist/editor/index.js +2 -2
  16. package/dist/{editor-ka05eWyz.js → editor-Ds-mUYs_.js} +3 -3
  17. package/dist/{editor-ka05eWyz.js.map → editor-Ds-mUYs_.js.map} +1 -1
  18. package/dist/error/index.js +2 -2
  19. package/dist/{error-fzPGTaFe.js → error-B5MciRP7.js} +2 -2
  20. package/dist/{error-fzPGTaFe.js.map → error-B5MciRP7.js.map} +1 -1
  21. package/dist/{index-2CUWhF-T.d.ts → index-9bvWkK07.d.ts} +2 -2
  22. package/dist/{index-FKgYmeNR.d.ts → index-GuEiafMN.d.ts} +29 -2
  23. package/dist/index.d.ts +1 -1
  24. package/dist/index.js +5 -5
  25. package/dist/preview/index.js +1 -1
  26. package/dist/{preview-EsfzEjis.js → preview-DtBbnlwy.js} +4 -4
  27. package/dist/{preview-EsfzEjis.js.map → preview-DtBbnlwy.js.map} +1 -1
  28. package/dist/provider/index.js +1 -1
  29. package/dist/style.css +448 -60
  30. package/dist/{use-dynamic-tailwind-CRMGuKnH.js → use-dynamic-tailwind-cdaivJXJ.js} +2 -2
  31. package/dist/{use-dynamic-tailwind-CRMGuKnH.js.map → use-dynamic-tailwind-cdaivJXJ.js.map} +1 -1
  32. package/dist/utils/ast/index.d.ts +2 -2
  33. package/dist/utils/ast/index.js +2 -2
  34. package/dist/utils/index.js +2 -2
  35. package/dist/{utils-B6zpA7mT.js → utils-DbfbS1yV.js} +2 -2
  36. package/dist/{utils-B6zpA7mT.js.map → utils-DbfbS1yV.js.map} +1 -1
  37. package/package.json +26 -10
  38. package/dist/ast-BhbOxomw.js.map +0 -1
  39. package/dist/core-D-ZvVhdn.js +0 -11195
  40. package/dist/core-D-ZvVhdn.js.map +0 -1
  41. package/dist/dnd-E8LbmRfE.js.map +0 -1
  42. 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"}
@@ -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-2CUWhF-T.js";
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-E8LbmRfE.js";
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-Ddw-tfnt.js";
2
- import { d as replaceSections, o as extractSections, r as cn, s as generateSection, u as preloadScripts } from "./utils-B6zpA7mT.js";
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-BhbOxomw.js";
5
- import { n as useCompiledModule, r as Frame, t as useDynamicTailwind } from "./use-dynamic-tailwind-CRMGuKnH.js";
6
- import { n as Error, t as ErrorBoundary } from "./boundary-DOBK2HnX.js";
7
- import { t as Core } from "./core-D-ZvVhdn.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-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 p-2",
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)) : /* @__PURE__ */ jsx("div", {
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(Tiptap, {
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
- Toast.error("Failed to update this field", { description: "Check the console for details." });
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__ */ jsx("div", {
1491
- className: "hidden w-1/5 overflow-y-auto md:block",
1492
- children: /* @__PURE__ */ jsx("div", {
1493
- className: "h-full bg-gray-50 p-4",
1494
- children: renderPaletteItems(addItem)
1495
- })
1496
- }),
1497
- /* @__PURE__ */ jsx("div", {
1498
- className: cn("relative", "h-full w-full md:w-3/5", "overflow-y-auto"),
1499
- "data-frame-container": true,
1500
- style: {
1501
- isolation: "isolate",
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
- }) : /* @__PURE__ */ jsx(SortableContext, {
1515
- items: sections.map((s) => s.id),
1516
- strategy: verticalListSortingStrategy,
1517
- children: sections.map((section, index) => /* @__PURE__ */ jsx(Sortable, {
1518
- id: section.id,
1519
- name: section.name,
1520
- selected: selectedId === section.id,
1521
- onClick: () => onSelect(section.id),
1522
- onDelete,
1523
- onCopy,
1524
- children: /* @__PURE__ */ jsx(renderer_default, {
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-E8LbmRfE.js.map
1640
+ //# sourceMappingURL=dnd-C1YGcp4k.js.map