@wipco/sdui-editor 0.17.0 → 0.18.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/index.js +30 -11
- package/dist/styles.css +8 -2
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { lazy, Suspense, useState, useCallback, useEffect, useMemo, useRef, useLayoutEffect, useDeferredValue, useReducer, useId } from 'react';
|
|
2
|
-
import { defaultRegistry, createRegistry, Tooltip, SidebarNav, SegmentedControl, Radio, Breadcrumb, Avatar, Alert, Icon, IconButton, Spinner, Button, Card, Tabs, Input, Badge, EmptyState, Table, SduiDialog, Field, Select, validateSpec, SduiRenderer, Checkbox, Switch, Dialog, Textarea } from '@wipco/sdui';
|
|
2
|
+
import { defaultRegistry, createRegistry, Tooltip, SidebarNav, SegmentedControl, Radio, Breadcrumb, Avatar, Alert, Icon, IconButton, Spinner, Button, Card, Tabs, Input, Badge, EmptyState, Table, SduiDialog, Field, Select, validateSpec, SduiRenderer, Checkbox, Switch, OverlayContainerContext, Dialog, Textarea } from '@wipco/sdui';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { EditorView, basicSetup } from 'codemirror';
|
|
5
5
|
import { EditorState } from '@codemirror/state';
|
|
@@ -10091,6 +10091,11 @@ function EditorView2({
|
|
|
10091
10091
|
const [corrupt, setCorrupt] = useState(false);
|
|
10092
10092
|
const [draftRestored, setDraftRestored] = useState(false);
|
|
10093
10093
|
const [helpOpen, setHelpOpen] = useState(false);
|
|
10094
|
+
const previewBodyRef = useRef(null);
|
|
10095
|
+
const [previewBody, setPreviewBody] = useState(null);
|
|
10096
|
+
useEffect(() => {
|
|
10097
|
+
setPreviewBody(previewBodyRef.current);
|
|
10098
|
+
}, []);
|
|
10094
10099
|
const [previewKey, setPreviewKey] = useState(0);
|
|
10095
10100
|
const [previewNotice, setPreviewNotice] = useState(null);
|
|
10096
10101
|
const noticeTimer = useRef(null);
|
|
@@ -10118,8 +10123,10 @@ function EditorView2({
|
|
|
10118
10123
|
alive = false;
|
|
10119
10124
|
};
|
|
10120
10125
|
}, [store]);
|
|
10126
|
+
const docIdRef = useRef(null);
|
|
10121
10127
|
useEffect(() => {
|
|
10122
10128
|
if (!id) return;
|
|
10129
|
+
docIdRef.current = null;
|
|
10123
10130
|
setLoaded(null);
|
|
10124
10131
|
setLoadError(null);
|
|
10125
10132
|
setConflict(false);
|
|
@@ -10147,6 +10154,7 @@ function EditorView2({
|
|
|
10147
10154
|
setDraftRestored(false);
|
|
10148
10155
|
setBaseVersion(record.version);
|
|
10149
10156
|
}
|
|
10157
|
+
docIdRef.current = id;
|
|
10150
10158
|
let openedSpec;
|
|
10151
10159
|
try {
|
|
10152
10160
|
openedSpec = JSON.parse(opened);
|
|
@@ -10373,7 +10381,9 @@ function EditorView2({
|
|
|
10373
10381
|
const parsedRef = useRef(parsed);
|
|
10374
10382
|
parsedRef.current = parsed;
|
|
10375
10383
|
const overrideSpec = useCallback(
|
|
10376
|
-
|
|
10384
|
+
// docIdRef 가드 — 문서 전환 1프레임의 "새 id + 이전 파싱본"을 조각으로 내보내지
|
|
10385
|
+
// 않는다(위 docIdRef 주석). 그동안은 스토어 read가 맡는다.
|
|
10386
|
+
(specId) => specId === id && docIdRef.current === id ? parsedRef.current.spec ?? void 0 : void 0,
|
|
10377
10387
|
[id]
|
|
10378
10388
|
);
|
|
10379
10389
|
const useSpec = useMemo(() => createEditorUseSpec(store, overrideSpec), [store, overrideSpec]);
|
|
@@ -10572,7 +10582,7 @@ function EditorView2({
|
|
|
10572
10582
|
onClose: () => setSeedPanelOpen(false)
|
|
10573
10583
|
}
|
|
10574
10584
|
) : null,
|
|
10575
|
-
/* @__PURE__ */ jsx("div", { className: "sdui-editor-preview__body", children: previewPage ? /* @__PURE__ */ jsx(
|
|
10585
|
+
/* @__PURE__ */ jsx("div", { className: "sdui-editor-preview__body", ref: previewBodyRef, children: /* @__PURE__ */ jsx(OverlayContainerContext.Provider, { value: previewBody, children: previewPage ? /* @__PURE__ */ jsx(
|
|
10576
10586
|
PreviewBoundary,
|
|
10577
10587
|
{
|
|
10578
10588
|
resetKey: previewKey,
|
|
@@ -10589,7 +10599,7 @@ function EditorView2({
|
|
|
10589
10599
|
`${previewKey}:${seedSignature(seeds)}`
|
|
10590
10600
|
)
|
|
10591
10601
|
}
|
|
10592
|
-
) : /* @__PURE__ */ jsx(Alert, { tone: parsed.error ? "warning" : "neutral", children: parsed.error ? "JSON\uC744 \uACE0\uCE58\uBA74 \uBBF8\uB9AC\uBCF4\uAE30\uAC00 \uB2E4\uC2DC \uADF8\uB824\uC9D1\uB2C8\uB2E4." : "\uC2A4\uD399\uC744 \uC785\uB825\uD558\uC138\uC694." }) })
|
|
10602
|
+
) : /* @__PURE__ */ jsx(Alert, { tone: parsed.error ? "warning" : "neutral", children: parsed.error ? "JSON\uC744 \uACE0\uCE58\uBA74 \uBBF8\uB9AC\uBCF4\uAE30\uAC00 \uB2E4\uC2DC \uADF8\uB824\uC9D1\uB2C8\uB2E4." : "\uC2A4\uD399\uC744 \uC785\uB825\uD558\uC138\uC694." }) }) })
|
|
10593
10603
|
] }),
|
|
10594
10604
|
helpOpen ? /* @__PURE__ */ jsx(HelpPanel, { onClose: () => setHelpOpen(false) }) : null
|
|
10595
10605
|
] })
|
|
@@ -10627,12 +10637,14 @@ function ViewerView({
|
|
|
10627
10637
|
error: null,
|
|
10628
10638
|
seq: 0
|
|
10629
10639
|
});
|
|
10640
|
+
const loadedForRef = useRef(null);
|
|
10630
10641
|
const load = useCallback(() => {
|
|
10631
|
-
store.read(id).then(
|
|
10632
|
-
|
|
10642
|
+
store.read(id).then((record) => {
|
|
10643
|
+
loadedForRef.current = record ? id : null;
|
|
10644
|
+
setState(
|
|
10633
10645
|
(prev) => record ? { spec: record.spec, error: null, seq: prev.seq + 1 } : { spec: null, error: "\uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4", seq: prev.seq + 1 }
|
|
10634
|
-
)
|
|
10635
|
-
).catch(
|
|
10646
|
+
);
|
|
10647
|
+
}).catch(
|
|
10636
10648
|
(err) => setState((prev) => ({ spec: null, error: messageOf(err, "\uD398\uC774\uC9C0\uB97C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4"), seq: prev.seq + 1 }))
|
|
10637
10649
|
);
|
|
10638
10650
|
}, [store, id]);
|
|
@@ -10641,10 +10653,16 @@ function ViewerView({
|
|
|
10641
10653
|
setState((prev) => ({ spec: null, error: "\uD398\uC774\uC9C0 id\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", seq: prev.seq + 1 }));
|
|
10642
10654
|
return;
|
|
10643
10655
|
}
|
|
10656
|
+
loadedForRef.current = null;
|
|
10644
10657
|
setState((prev) => ({ spec: null, error: null, seq: prev.seq + 1 }));
|
|
10645
10658
|
load();
|
|
10646
10659
|
}, [id, load]);
|
|
10647
10660
|
const [blocked, setBlocked] = useState(null);
|
|
10661
|
+
const viewerBodyRef = useRef(null);
|
|
10662
|
+
const [viewerBody, setViewerBody] = useState(null);
|
|
10663
|
+
useEffect(() => {
|
|
10664
|
+
setViewerBody(viewerBodyRef.current);
|
|
10665
|
+
}, []);
|
|
10648
10666
|
const blockedTimer = useRef(null);
|
|
10649
10667
|
const notifyBlocked = useCallback((what) => {
|
|
10650
10668
|
setBlocked(`${what} \u2014 \uBCF4\uAE30\uC5D0\uC11C\uB294 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`);
|
|
@@ -10678,7 +10696,8 @@ function ViewerView({
|
|
|
10678
10696
|
const specRef = useRef(state.spec);
|
|
10679
10697
|
specRef.current = state.spec;
|
|
10680
10698
|
const overrideSpec = useCallback(
|
|
10681
|
-
|
|
10699
|
+
// loadedForRef 가드 — id 전환 1프레임의 "새 id + 이전 스펙"을 조각으로 내보내지 않는다.
|
|
10700
|
+
(specId) => specId === id && loadedForRef.current === id ? specRef.current ?? void 0 : void 0,
|
|
10682
10701
|
[id]
|
|
10683
10702
|
);
|
|
10684
10703
|
const useSpec = useMemo(() => createEditorUseSpec(store, overrideSpec), [store, overrideSpec]);
|
|
@@ -10732,7 +10751,7 @@ function ViewerView({
|
|
|
10732
10751
|
onClose: () => setSeedPanelOpen(false)
|
|
10733
10752
|
}
|
|
10734
10753
|
) : null,
|
|
10735
|
-
/* @__PURE__ */ jsx("div", { className: "sdui-editor-viewer__body", children: state.error ? /* @__PURE__ */ jsx(Alert, { tone: "danger", title: "\uD398\uC774\uC9C0\uB97C \uD45C\uC2DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4", children: state.error }) : !state.spec ? /* @__PURE__ */ jsx("div", { className: "sdui-editor-center", style: { padding: 64 }, children: /* @__PURE__ */ jsx(Spinner, { size: "lg", label: "\uBD88\uB7EC\uC624\uB294 \uC911" }) }) : /* @__PURE__ */ jsx(
|
|
10754
|
+
/* @__PURE__ */ jsx("div", { className: "sdui-editor-viewer__body", ref: viewerBodyRef, children: /* @__PURE__ */ jsx(OverlayContainerContext.Provider, { value: viewerBody, children: state.error ? /* @__PURE__ */ jsx(Alert, { tone: "danger", title: "\uD398\uC774\uC9C0\uB97C \uD45C\uC2DC\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4", children: state.error }) : !state.spec ? /* @__PURE__ */ jsx("div", { className: "sdui-editor-center", style: { padding: 64 }, children: /* @__PURE__ */ jsx(Spinner, { size: "lg", label: "\uBD88\uB7EC\uC624\uB294 \uC911" }) }) : /* @__PURE__ */ jsx(
|
|
10736
10755
|
ViewerBoundary,
|
|
10737
10756
|
{
|
|
10738
10757
|
resetKey: `${id}#${state.seq}`,
|
|
@@ -10765,7 +10784,7 @@ function ViewerView({
|
|
|
10765
10784
|
`${id}#${state.seq}:${seedSignature(seeds)}`
|
|
10766
10785
|
)
|
|
10767
10786
|
}
|
|
10768
|
-
) })
|
|
10787
|
+
) }) })
|
|
10769
10788
|
] });
|
|
10770
10789
|
}
|
|
10771
10790
|
function SduiEditor({
|
package/dist/styles.css
CHANGED
|
@@ -122,7 +122,11 @@
|
|
|
122
122
|
background: var(--wp-slate-25);
|
|
123
123
|
}
|
|
124
124
|
.sdui-editor-preview__notice { font-size: 12px; color: var(--wp-text-info); }
|
|
125
|
-
|
|
125
|
+
/* contain: paint — 미리본 다이얼로그의 오버레이(SduiDialog 래퍼가 position:fixed로
|
|
126
|
+
뷰포트에 고정)를 이 상자의 컨테이닝 블록에 가둔다. 없으면 오버레이가 편집기
|
|
127
|
+
전체를 덮어 시딩 버튼·패널이 마우스로 조작 불가였다(0.17.1 검수 실측:
|
|
128
|
+
elementFromPoint=wp-overlay, 클릭 타임아웃). */
|
|
129
|
+
.sdui-editor-preview__body { flex: 1; overflow-y: auto; padding: 24px; position: relative; contain: paint; }
|
|
126
130
|
.sdui-editor-preview__body .sdui-root { display: flex; flex-direction: column; gap: var(--wp-space-4); }
|
|
127
131
|
|
|
128
132
|
/* ---------- 도움말 패널 ---------- */
|
|
@@ -164,7 +168,9 @@
|
|
|
164
168
|
border-bottom: 1px solid var(--wp-border-subtle);
|
|
165
169
|
}
|
|
166
170
|
.sdui-editor-viewer__id { color: var(--wp-text-subtle); }
|
|
167
|
-
|
|
171
|
+
/* contain: paint — 위 .sdui-editor-preview__body와 같은 이유. 뷰어도 다이얼로그
|
|
172
|
+
스펙을 열린 채 그리므로 오버레이가 상단 바·시딩 패널을 덮으면 안 된다. */
|
|
173
|
+
.sdui-editor-viewer__body { flex: 1; width: 100%; max-width: 1080px; margin: 0 auto; padding: 28px 24px 48px; contain: paint; }
|
|
168
174
|
.sdui-editor-viewer__body .sdui-root { display: flex; flex-direction: column; gap: var(--wp-space-4); }
|
|
169
175
|
|
|
170
176
|
@media (max-width: 900px) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wipco/sdui-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "SDUI 페이지 스펙 편집기 — 소비 프로젝트가 자기 라우트에 마운트하는 React 컴포넌트",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sdui",
|
|
@@ -58,14 +58,14 @@
|
|
|
58
58
|
"codemirror": "^6.0.1"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@wipco/sdui": "^0.
|
|
61
|
+
"@wipco/sdui": "^0.18.0",
|
|
62
62
|
"react": ">=18",
|
|
63
63
|
"react-dom": ">=18"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@types/react": "^19.0.0",
|
|
67
67
|
"@types/react-dom": "^19.0.0",
|
|
68
|
-
"@wipco/sdui": "^0.
|
|
68
|
+
"@wipco/sdui": "^0.18.0",
|
|
69
69
|
"tsup": "^8.5.0",
|
|
70
70
|
"tsx": "^4.20.0",
|
|
71
71
|
"typescript": "^5.7.0"
|