@wipco/sdui-editor 0.15.0 → 0.17.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.d.ts +346 -8
- package/dist/index.js +1371 -710
- package/dist/styles.css +30 -0
- 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, Input, Badge, EmptyState, Table, SduiDialog, Field, Select, validateSpec, SduiRenderer, Checkbox, Dialog, Textarea
|
|
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';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import { EditorView, basicSetup } from 'codemirror';
|
|
5
5
|
import { EditorState } from '@codemirror/state';
|
|
@@ -7,6 +7,7 @@ import { keymap } from '@codemirror/view';
|
|
|
7
7
|
import { indentWithTab } from '@codemirror/commands';
|
|
8
8
|
import { json } from '@codemirror/lang-json';
|
|
9
9
|
import { getComponentMeta, slotNamesOf, paletteGroups } from '@wipco/sdui/meta';
|
|
10
|
+
import { AutocompleteField } from '@wipco/sdui/widgets/AutocompleteField';
|
|
10
11
|
|
|
11
12
|
// src/SduiEditor.tsx
|
|
12
13
|
|
|
@@ -77,6 +78,10 @@ var PAGE_ID_PATTERN = /^([A-Za-z0-9_-]+|\{[A-Za-z0-9_]+\})(\/([A-Za-z0-9_-]+|\{[
|
|
|
77
78
|
function isValidPageId(id) {
|
|
78
79
|
return PAGE_ID_PATTERN.test(id) && id.length <= 200;
|
|
79
80
|
}
|
|
81
|
+
var DIALOG_PREFIX = "dialogs/";
|
|
82
|
+
function isDialogSpecId(id) {
|
|
83
|
+
return id.startsWith(DIALOG_PREFIX);
|
|
84
|
+
}
|
|
80
85
|
function titleOf(spec) {
|
|
81
86
|
if (spec && typeof spec === "object" && typeof spec.title === "string") {
|
|
82
87
|
return spec.title;
|
|
@@ -384,11 +389,47 @@ var LIST = {
|
|
|
384
389
|
}
|
|
385
390
|
]
|
|
386
391
|
};
|
|
392
|
+
var DIALOG = {
|
|
393
|
+
version: 1,
|
|
394
|
+
title: "\uB2E4\uC774\uC5BC\uB85C\uADF8",
|
|
395
|
+
body: [
|
|
396
|
+
{
|
|
397
|
+
component: "Show",
|
|
398
|
+
props: { when: { $state: "open" } },
|
|
399
|
+
children: [
|
|
400
|
+
{
|
|
401
|
+
component: "Dialog",
|
|
402
|
+
props: {
|
|
403
|
+
title: "\uB2E4\uC774\uC5BC\uB85C\uADF8 \uC81C\uBAA9",
|
|
404
|
+
size: "md",
|
|
405
|
+
onClose: { action: "close", key: "open" }
|
|
406
|
+
},
|
|
407
|
+
slots: {
|
|
408
|
+
footer: [
|
|
409
|
+
{
|
|
410
|
+
component: "Button",
|
|
411
|
+
props: { onClick: { action: "close", key: "open" } },
|
|
412
|
+
children: ["\uCDE8\uC18C"]
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
component: "Button",
|
|
416
|
+
props: { variant: "primary", onClick: { action: "close", key: "open" } },
|
|
417
|
+
children: ["\uD655\uC778"]
|
|
418
|
+
}
|
|
419
|
+
]
|
|
420
|
+
},
|
|
421
|
+
children: [{ component: "Text", props: { preset: "body", value: "\uB0B4\uC6A9\uC744 \uAD6C\uC131\uD558\uC138\uC694." } }]
|
|
422
|
+
}
|
|
423
|
+
]
|
|
424
|
+
}
|
|
425
|
+
]
|
|
426
|
+
};
|
|
387
427
|
var TEMPLATES = [
|
|
388
428
|
{ key: "blank", label: "\uBE48 \uD398\uC774\uC9C0", description: "\uCE74\uB4DC \uD558\uB098\uB85C \uC2DC\uC791", spec: BLANK },
|
|
389
429
|
{ key: "dashboard", label: "\uB300\uC2DC\uBCF4\uB4DC", description: "StatCard 4\uAC1C + \uCE74\uB4DC", spec: DASHBOARD },
|
|
390
430
|
{ key: "form", label: "\uC785\uB825 \uD3FC", description: "\uAC80\uC99D + \uC81C\uCD9C \uACE8\uACA9", spec: FORM },
|
|
391
|
-
{ key: "list", label: "\uBAA9\uB85D", description: "\uD14C\uC774\uBE14 + \uC0C1\uD0DC \uBC30\uC9C0", spec: LIST }
|
|
431
|
+
{ key: "list", label: "\uBAA9\uB85D", description: "\uD14C\uC774\uBE14 + \uC0C1\uD0DC \uBC30\uC9C0", spec: LIST },
|
|
432
|
+
{ key: "dialog", label: "\uB2E4\uC774\uC5BC\uB85C\uADF8 \uC870\uAC01", description: "Show(open) + Dialog \uACE8\uACA9 \u2014 dialogs/ \uC2A4\uD399\uC6A9", spec: DIALOG }
|
|
392
433
|
];
|
|
393
434
|
|
|
394
435
|
// src/util.ts
|
|
@@ -409,11 +450,18 @@ function PageListView({ store, onEdit, onPreview }) {
|
|
|
409
450
|
const [listFailed, setListFailed] = useState(false);
|
|
410
451
|
const [error, setError] = useState(null);
|
|
411
452
|
const [query, setQuery] = useState("");
|
|
453
|
+
const [tab, setTab] = useState("pages");
|
|
412
454
|
const [createOpen, setCreateOpen] = useState(false);
|
|
413
455
|
const [newId, setNewId] = useState("");
|
|
414
456
|
const [template, setTemplate] = useState("blank");
|
|
415
457
|
const [createError, setCreateError] = useState(null);
|
|
416
458
|
const [creating, setCreating] = useState(false);
|
|
459
|
+
const openCreate = () => {
|
|
460
|
+
setCreateOpen(true);
|
|
461
|
+
setCreateError(null);
|
|
462
|
+
setNewId(tab === "dialogs" ? DIALOG_PREFIX : "");
|
|
463
|
+
setTemplate(tab === "dialogs" ? "dialog" : "blank");
|
|
464
|
+
};
|
|
417
465
|
const load = useCallback(() => {
|
|
418
466
|
setListFailed(false);
|
|
419
467
|
store.list().then(setPages).catch((err) => {
|
|
@@ -422,12 +470,17 @@ function PageListView({ store, onEdit, onPreview }) {
|
|
|
422
470
|
});
|
|
423
471
|
}, [store]);
|
|
424
472
|
useEffect(load, [load]);
|
|
473
|
+
const counts = useMemo(() => {
|
|
474
|
+
const dialogs = pages?.filter((p) => isDialogSpecId(p.id)).length ?? 0;
|
|
475
|
+
return { dialogs, pages: (pages?.length ?? 0) - dialogs };
|
|
476
|
+
}, [pages]);
|
|
425
477
|
const filtered = useMemo(() => {
|
|
426
478
|
if (!pages) return null;
|
|
479
|
+
const scoped = pages.filter((p) => isDialogSpecId(p.id) === (tab === "dialogs"));
|
|
427
480
|
const q = query.trim().toLowerCase();
|
|
428
|
-
if (!q) return
|
|
429
|
-
return
|
|
430
|
-
}, [pages, query]);
|
|
481
|
+
if (!q) return scoped;
|
|
482
|
+
return scoped.filter((p) => p.id.toLowerCase().includes(q) || (p.title ?? "").toLowerCase().includes(q));
|
|
483
|
+
}, [pages, query, tab]);
|
|
431
484
|
const createPage = async () => {
|
|
432
485
|
if (pages === null) {
|
|
433
486
|
setCreateError("\uD398\uC774\uC9C0 \uBAA9\uB85D\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD574 \uC911\uBCF5 \uC5EC\uBD80\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBAA9\uB85D\uC744 \uB2E4\uC2DC \uBD88\uB7EC\uC628 \uB4A4 \uC2DC\uB3C4\uD558\uC138\uC694.");
|
|
@@ -498,10 +551,7 @@ function PageListView({ store, onEdit, onPreview }) {
|
|
|
498
551
|
/* @__PURE__ */ jsx("h1", { className: "wp-page-head__title", children: "\uD398\uC774\uC9C0" }),
|
|
499
552
|
/* @__PURE__ */ jsx("div", { className: "wp-page-head__sub", children: "SDUI \uD398\uC774\uC9C0 \uC2A4\uD399\uC744 \uCD94\uAC00\xB7\uC218\uC815\uD569\uB2C8\uB2E4" })
|
|
500
553
|
] }),
|
|
501
|
-
/* @__PURE__ */ jsx("div", { className: "wp-page-head__actions", children: /* @__PURE__ */ jsx(Button, { variant: "primary", icon: "plus", onClick:
|
|
502
|
-
setCreateOpen(true);
|
|
503
|
-
setCreateError(null);
|
|
504
|
-
}, children: "\uC0C8 \uD398\uC774\uC9C0" }) })
|
|
554
|
+
/* @__PURE__ */ jsx("div", { className: "wp-page-head__actions", children: /* @__PURE__ */ jsx(Button, { variant: "primary", icon: "plus", onClick: openCreate, children: tab === "dialogs" ? "\uC0C8 \uB2E4\uC774\uC5BC\uB85C\uADF8" : "\uC0C8 \uD398\uC774\uC9C0" }) })
|
|
505
555
|
] }),
|
|
506
556
|
error ? /* @__PURE__ */ jsx(
|
|
507
557
|
Alert,
|
|
@@ -515,6 +565,17 @@ function PageListView({ store, onEdit, onPreview }) {
|
|
|
515
565
|
caps.limitations.length > 0 ? /* @__PURE__ */ jsx(Alert, { tone: "info", title: `${caps.label} \uC800\uC7A5\uC18C\uB97C \uD3B8\uC9D1 \uC911\uC785\uB2C8\uB2E4`, children: /* @__PURE__ */ jsx("ul", { className: "sdui-editor-limitations", children: caps.limitations.map((limitation) => /* @__PURE__ */ jsx("li", { children: limitation }, limitation)) }) }) : null,
|
|
516
566
|
/* @__PURE__ */ jsxs(Card, { padding: "none", children: [
|
|
517
567
|
/* @__PURE__ */ jsxs("div", { className: "sdui-editor-list-toolbar", children: [
|
|
568
|
+
/* @__PURE__ */ jsx(
|
|
569
|
+
Tabs,
|
|
570
|
+
{
|
|
571
|
+
items: [
|
|
572
|
+
{ value: "pages", icon: "layout-dashboard", label: "\uD654\uBA74", count: counts.pages },
|
|
573
|
+
{ value: "dialogs", icon: "external-link", label: "\uB2E4\uC774\uC5BC\uB85C\uADF8", count: counts.dialogs }
|
|
574
|
+
],
|
|
575
|
+
value: tab,
|
|
576
|
+
onChange: (next) => setTab(next)
|
|
577
|
+
}
|
|
578
|
+
),
|
|
518
579
|
/* @__PURE__ */ jsx(Input, { icon: "search", placeholder: "id \uB610\uB294 \uC81C\uBAA9 \uAC80\uC0C9", value: query, onChange: (e) => setQuery(e.target.value) }),
|
|
519
580
|
/* @__PURE__ */ jsxs(Badge, { tone: "brand", children: [
|
|
520
581
|
filtered?.length ?? 0,
|
|
@@ -554,9 +615,9 @@ function PageListView({ store, onEdit, onPreview }) {
|
|
|
554
615
|
empty: /* @__PURE__ */ jsx(
|
|
555
616
|
EmptyState,
|
|
556
617
|
{
|
|
557
|
-
title: query ? "\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" : "\uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
558
|
-
actions: query ? void 0 : /* @__PURE__ */ jsx(Button, { variant: "primary", icon: "plus", onClick:
|
|
559
|
-
children: query ? "\uB2E4\uB978 \uAC80\uC0C9\uC5B4\uB85C \uC2DC\uB3C4\uD574 \uBCF4\uC138\uC694." : "\uC0C8 \uD398\uC774\uC9C0\uB97C \uB9CC\uB4E4\uC5B4 \uC2DC\uC791\uD558\uC138\uC694."
|
|
618
|
+
title: query ? "\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4" : tab === "dialogs" ? "\uB2E4\uC774\uC5BC\uB85C\uADF8 \uC870\uAC01\uC774 \uC5C6\uC2B5\uB2C8\uB2E4" : "\uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4",
|
|
619
|
+
actions: query ? void 0 : /* @__PURE__ */ jsx(Button, { variant: "primary", icon: "plus", onClick: openCreate, children: tab === "dialogs" ? "\uCCAB \uB2E4\uC774\uC5BC\uB85C\uADF8 \uB9CC\uB4E4\uAE30" : "\uCCAB \uD398\uC774\uC9C0 \uB9CC\uB4E4\uAE30" }),
|
|
620
|
+
children: query ? "\uB2E4\uB978 \uAC80\uC0C9\uC5B4\uB85C \uC2DC\uB3C4\uD574 \uBCF4\uC138\uC694." : tab === "dialogs" ? `${DIALOG_PREFIX} \uC811\uB450 id\uB85C \uB9CC\uB4E0 \uC2A4\uD399\uC774 \uC774 \uD0ED\uC5D0 \uBAA8\uC785\uB2C8\uB2E4 \u2014 Fragment\uAC00 \uB07C\uC6CC \uC4F0\uB294 \uACF5\uC6A9 \uC870\uAC01\uC785\uB2C8\uB2E4.` : "\uC0C8 \uD398\uC774\uC9C0\uB97C \uB9CC\uB4E4\uC5B4 \uC2DC\uC791\uD558\uC138\uC694."
|
|
560
621
|
}
|
|
561
622
|
)
|
|
562
623
|
}
|
|
@@ -565,8 +626,8 @@ function PageListView({ store, onEdit, onPreview }) {
|
|
|
565
626
|
createOpen ? /* @__PURE__ */ jsxs(
|
|
566
627
|
SduiDialog,
|
|
567
628
|
{
|
|
568
|
-
title: "\uC0C8 \uD398\uC774\uC9C0",
|
|
569
|
-
subtitle: "id\uB294 URL \uACBD\uB85C\uAC00 \uB429\uB2C8\uB2E4",
|
|
629
|
+
title: tab === "dialogs" ? "\uC0C8 \uB2E4\uC774\uC5BC\uB85C\uADF8 \uC870\uAC01" : "\uC0C8 \uD398\uC774\uC9C0",
|
|
630
|
+
subtitle: tab === "dialogs" ? `${DIALOG_PREFIX} \uC811\uB450\uAC00 \uB2E4\uC774\uC5BC\uB85C\uADF8 \uD0ED\uC758 \uAE30\uC900\uC785\uB2C8\uB2E4` : "id\uB294 URL \uACBD\uB85C\uAC00 \uB429\uB2C8\uB2E4",
|
|
570
631
|
icon: "plus",
|
|
571
632
|
onClose: () => setCreateOpen(false),
|
|
572
633
|
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -576,23 +637,31 @@ function PageListView({ store, onEdit, onPreview }) {
|
|
|
576
637
|
children: [
|
|
577
638
|
pages === null ? /* @__PURE__ */ jsx(Alert, { tone: "warning", title: "\uC9C0\uAE08\uC740 \uC0C8 \uD398\uC774\uC9C0\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4", children: "\uD398\uC774\uC9C0 \uBAA9\uB85D\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD574 \uC5B4\uB5A4 id\uAC00 \uC774\uBBF8 \uC4F0\uC774\uB294\uC9C0 \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBAA9\uB85D\uC744 \uBA3C\uC800 \uB2E4\uC2DC \uBD88\uB7EC\uC624\uC138\uC694." }) : null,
|
|
578
639
|
createError ? /* @__PURE__ */ jsx(Alert, { tone: "danger", children: createError }) : null,
|
|
579
|
-
/* @__PURE__ */ jsx(
|
|
580
|
-
|
|
640
|
+
/* @__PURE__ */ jsx(
|
|
641
|
+
Field,
|
|
581
642
|
{
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
643
|
+
label: "\uD398\uC774\uC9C0 id",
|
|
644
|
+
required: true,
|
|
645
|
+
hint: tab === "dialogs" ? `\uC608: ${DIALOG_PREFIX}asset-edit` : "\uC608: home, sales/orders",
|
|
646
|
+
children: /* @__PURE__ */ jsx(
|
|
647
|
+
Input,
|
|
648
|
+
{
|
|
649
|
+
mono: true,
|
|
650
|
+
value: newId,
|
|
651
|
+
autoFocus: true,
|
|
652
|
+
disabled: pages === null,
|
|
653
|
+
placeholder: tab === "dialogs" ? `${DIALOG_PREFIX}asset-edit` : "sales/orders",
|
|
654
|
+
onChange: (e) => setNewId(e.target.value),
|
|
655
|
+
onKeyDown: (e) => {
|
|
656
|
+
if (e.key === "Enter") {
|
|
657
|
+
e.preventDefault();
|
|
658
|
+
if (pages !== null) void createPage();
|
|
659
|
+
}
|
|
660
|
+
}
|
|
592
661
|
}
|
|
593
|
-
|
|
662
|
+
)
|
|
594
663
|
}
|
|
595
|
-
)
|
|
664
|
+
),
|
|
596
665
|
/* @__PURE__ */ jsx(Field, { label: "\uD15C\uD50C\uB9BF", children: /* @__PURE__ */ jsx(
|
|
597
666
|
Select,
|
|
598
667
|
{
|
|
@@ -848,10 +917,122 @@ var editorRegistry = createRegistry({
|
|
|
848
917
|
() => import('@wipco/sdui/widgets/TreeView').then((m) => ({ default: m.TreeView }))
|
|
849
918
|
)
|
|
850
919
|
});
|
|
920
|
+
|
|
921
|
+
// src/preview/seed.ts
|
|
922
|
+
function isPlainObject(value) {
|
|
923
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
924
|
+
}
|
|
925
|
+
function hasDialogInside(node) {
|
|
926
|
+
if (!isPlainObject(node)) return false;
|
|
927
|
+
if (node.component === "Dialog") return true;
|
|
928
|
+
const children = Array.isArray(node.children) ? node.children : [];
|
|
929
|
+
for (const child of children) if (hasDialogInside(child)) return true;
|
|
930
|
+
if (isPlainObject(node.slots)) {
|
|
931
|
+
for (const list of Object.values(node.slots)) {
|
|
932
|
+
if (!Array.isArray(list)) continue;
|
|
933
|
+
for (const child of list) if (hasDialogInside(child)) return true;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return false;
|
|
937
|
+
}
|
|
938
|
+
function dialogOpenSeeds(spec) {
|
|
939
|
+
const seeds = {};
|
|
940
|
+
if (!isPlainObject(spec) || !Array.isArray(spec.body)) return seeds;
|
|
941
|
+
for (const node of spec.body) {
|
|
942
|
+
if (!isPlainObject(node) || node.component !== "Show") continue;
|
|
943
|
+
const when = isPlainObject(node.props) ? node.props.when : void 0;
|
|
944
|
+
if (!isPlainObject(when) || typeof when.$state !== "string" || when.$state === "") continue;
|
|
945
|
+
if (Object.keys(when).some((key) => key !== "$state" && key !== "default")) continue;
|
|
946
|
+
if (!hasDialogInside(node)) continue;
|
|
947
|
+
seeds[when.$state] = true;
|
|
948
|
+
}
|
|
949
|
+
return seeds;
|
|
950
|
+
}
|
|
951
|
+
function seedSignature(seeds) {
|
|
952
|
+
return JSON.stringify(
|
|
953
|
+
Object.keys(seeds).sort().map((key) => [key, seeds[key]])
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
var INITIAL_PREVIEW_SETUP = {
|
|
957
|
+
autoOpen: true,
|
|
958
|
+
manual: [],
|
|
959
|
+
argsOn: false,
|
|
960
|
+
argsText: "{\n}",
|
|
961
|
+
dataArmed: false,
|
|
962
|
+
entityLabels: {}
|
|
963
|
+
};
|
|
964
|
+
function parseSeedValue(text) {
|
|
965
|
+
try {
|
|
966
|
+
return JSON.parse(text);
|
|
967
|
+
} catch {
|
|
968
|
+
return text;
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
function seedsOf(setup, autoSeeds) {
|
|
972
|
+
const seeds = setup.autoOpen ? { ...autoSeeds } : {};
|
|
973
|
+
for (const row of setup.manual) {
|
|
974
|
+
const key = row.key.trim();
|
|
975
|
+
if (!key) continue;
|
|
976
|
+
seeds[key] = parseSeedValue(row.text);
|
|
977
|
+
}
|
|
978
|
+
return seeds;
|
|
979
|
+
}
|
|
980
|
+
function argsWrapperPage(specId, argsText) {
|
|
981
|
+
let parsed;
|
|
982
|
+
try {
|
|
983
|
+
parsed = JSON.parse(argsText);
|
|
984
|
+
} catch {
|
|
985
|
+
return null;
|
|
986
|
+
}
|
|
987
|
+
if (!isPlainObject(parsed)) return null;
|
|
988
|
+
const page = {
|
|
989
|
+
version: 1,
|
|
990
|
+
body: [{ component: "Fragment", props: { id: specId, args: parsed } }]
|
|
991
|
+
};
|
|
992
|
+
return { page, args: parsed };
|
|
993
|
+
}
|
|
994
|
+
var STATE_WRITING_ACTIONS = /* @__PURE__ */ new Set([
|
|
995
|
+
"setState",
|
|
996
|
+
"open",
|
|
997
|
+
"close",
|
|
998
|
+
"arrayAppend",
|
|
999
|
+
"arrayRemove",
|
|
1000
|
+
"arrayMove",
|
|
1001
|
+
"arrayUpdate"
|
|
1002
|
+
]);
|
|
1003
|
+
function collectStateKeys(spec, limit = 200) {
|
|
1004
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1005
|
+
const touch = (key) => counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
1006
|
+
const walk = (value) => {
|
|
1007
|
+
if (Array.isArray(value)) {
|
|
1008
|
+
for (const item of value) walk(item);
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
if (!isPlainObject(value)) return;
|
|
1012
|
+
if (typeof value.$state === "string" && value.$state) touch(value.$state);
|
|
1013
|
+
if (typeof value.action === "string" && STATE_WRITING_ACTIONS.has(value.action) && typeof value.key === "string" && value.key) {
|
|
1014
|
+
touch(value.key);
|
|
1015
|
+
}
|
|
1016
|
+
for (const [name, sub] of Object.entries(value)) {
|
|
1017
|
+
if (name === "$state") continue;
|
|
1018
|
+
walk(sub);
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
walk(spec);
|
|
1022
|
+
return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, limit).map(([key]) => key);
|
|
1023
|
+
}
|
|
1024
|
+
function patternParams(specId) {
|
|
1025
|
+
const params = [];
|
|
1026
|
+
for (const segment of specId.split("/")) {
|
|
1027
|
+
const match = /^\{([A-Za-z0-9_]+)\}$/.exec(segment);
|
|
1028
|
+
if (match) params.push(match[1]);
|
|
1029
|
+
}
|
|
1030
|
+
return params;
|
|
1031
|
+
}
|
|
851
1032
|
var ROOT_ID = "$root";
|
|
852
1033
|
var DEFAULT_SLOT = "$children";
|
|
853
1034
|
var TEXT_CHILD = "#text";
|
|
854
|
-
function
|
|
1035
|
+
function isPlainObject2(v) {
|
|
855
1036
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
856
1037
|
}
|
|
857
1038
|
function mint(seq) {
|
|
@@ -861,11 +1042,11 @@ function childFromSpec(spec, seq) {
|
|
|
861
1042
|
if (typeof spec === "string") {
|
|
862
1043
|
return { kind: "text", id: mint(seq), text: spec };
|
|
863
1044
|
}
|
|
864
|
-
if (!
|
|
1045
|
+
if (!isPlainObject2(spec) || typeof spec.component !== "string") {
|
|
865
1046
|
return { kind: "text", id: mint(seq), text: JSON.stringify(spec) ?? "" };
|
|
866
1047
|
}
|
|
867
1048
|
const slots = {};
|
|
868
|
-
if (
|
|
1049
|
+
if (isPlainObject2(spec.slots)) {
|
|
869
1050
|
for (const [name, list] of Object.entries(spec.slots)) {
|
|
870
1051
|
if (!Array.isArray(list) || list.length === 0) continue;
|
|
871
1052
|
slots[name] = list.map((c) => childFromSpec(c, seq));
|
|
@@ -878,14 +1059,14 @@ function childFromSpec(spec, seq) {
|
|
|
878
1059
|
kind: "node",
|
|
879
1060
|
id: mint(seq),
|
|
880
1061
|
component: spec.component,
|
|
881
|
-
props:
|
|
1062
|
+
props: isPlainObject2(spec.props) ? { ...spec.props } : {},
|
|
882
1063
|
slots
|
|
883
1064
|
};
|
|
884
1065
|
return typeof spec.key === "string" ? { ...node, key: spec.key } : node;
|
|
885
1066
|
}
|
|
886
1067
|
function fromPage(page) {
|
|
887
1068
|
const seq = { next: 1 };
|
|
888
|
-
if (!
|
|
1069
|
+
if (!isPlainObject2(page)) {
|
|
889
1070
|
return { meta: { version: 1 }, body: [], nextId: seq.next };
|
|
890
1071
|
}
|
|
891
1072
|
const { body, ...rest } = page;
|
|
@@ -1841,125 +2022,381 @@ var SPEC_PAIR_FREQ = {
|
|
|
1841
2022
|
"Show>LiveClock": 1,
|
|
1842
2023
|
"Strip>Row": 1
|
|
1843
2024
|
};
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
2025
|
+
|
|
2026
|
+
// src/builder/canvas/project.ts
|
|
2027
|
+
var EDIT_MARK = "$EditMark";
|
|
2028
|
+
var EDIT_FOREACH = "$EditForEach";
|
|
2029
|
+
var MARK_ATTR = "data-sdui-id";
|
|
2030
|
+
var LOGICAL = /* @__PURE__ */ new Set(["Show", "Can", "ForEach"]);
|
|
2031
|
+
function bindingLabel(value) {
|
|
2032
|
+
if (value === void 0 || value === null) return void 0;
|
|
2033
|
+
if (typeof value === "string") return value || void 0;
|
|
1850
2034
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1851
|
-
if (
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
2035
|
+
if (Array.isArray(value)) return void 0;
|
|
2036
|
+
const bag = value;
|
|
2037
|
+
if (typeof bag.$state === "string") return `{${bag.$state}}`;
|
|
2038
|
+
if (bag.$item === true) return "{\uD589}";
|
|
2039
|
+
if (typeof bag.$item === "string") return `{\uD589.${bag.$item}}`;
|
|
2040
|
+
if (bag.$index === true) return "{\uBC88\uD638}";
|
|
2041
|
+
const calc = bag.$calc;
|
|
2042
|
+
if (calc !== null && typeof calc === "object" && !Array.isArray(calc)) {
|
|
2043
|
+
const op = calc.op;
|
|
2044
|
+
if (typeof op === "string") return `{\uACC4\uC0B0:${op}}`;
|
|
1857
2045
|
}
|
|
1858
2046
|
return void 0;
|
|
1859
2047
|
}
|
|
1860
|
-
function
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
const first = child.slots[DEFAULT_SLOT]?.[0];
|
|
1874
|
-
if (first?.kind === "text") hint = first.text.trim() || void 0;
|
|
2048
|
+
function chromeHintOf(node) {
|
|
2049
|
+
switch (node.component) {
|
|
2050
|
+
case "Show":
|
|
2051
|
+
return bindingLabel(node.props.when);
|
|
2052
|
+
case "Can": {
|
|
2053
|
+
const entity = typeof node.props.entity === "string" ? node.props.entity : "?";
|
|
2054
|
+
const action = typeof node.props.action === "string" ? node.props.action : "read";
|
|
2055
|
+
return `${entity} \xB7 ${action}`;
|
|
2056
|
+
}
|
|
2057
|
+
case "ForEach":
|
|
2058
|
+
return bindingLabel(node.props.source);
|
|
2059
|
+
default:
|
|
2060
|
+
return void 0;
|
|
1875
2061
|
}
|
|
1876
|
-
return {
|
|
1877
|
-
label: meta?.label ?? child.component,
|
|
1878
|
-
...hint ? { hint } : {},
|
|
1879
|
-
...meta ? { icon: meta.icon } : {},
|
|
1880
|
-
known: meta !== void 0
|
|
1881
|
-
};
|
|
1882
2062
|
}
|
|
1883
|
-
function
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
const child = getChild(doc, step);
|
|
1888
|
-
if (child) out.push({ id: step, label: describeChild(child, catalog).label });
|
|
1889
|
-
}
|
|
1890
|
-
return out;
|
|
2063
|
+
function chromeOf(node) {
|
|
2064
|
+
if (LOGICAL.has(node.component)) return "logic";
|
|
2065
|
+
if (node.component === "Dialog") return "modal";
|
|
2066
|
+
return void 0;
|
|
1891
2067
|
}
|
|
1892
|
-
function
|
|
1893
|
-
const
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
seenNames.add(slot);
|
|
1899
|
-
out.push({
|
|
1900
|
-
slot,
|
|
1901
|
-
count: node.slots[slot]?.length ?? 0,
|
|
1902
|
-
seen: slotUsage(node.component, slot),
|
|
1903
|
-
...d
|
|
1904
|
-
});
|
|
2068
|
+
function mark(child, parent, slot, index) {
|
|
2069
|
+
const props = {
|
|
2070
|
+
nid: child.id,
|
|
2071
|
+
parent,
|
|
2072
|
+
slot,
|
|
2073
|
+
index
|
|
1905
2074
|
};
|
|
1906
|
-
|
|
1907
|
-
if (
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
const asProp = meta.props.find((p) => p.name === name && p.slot === true);
|
|
1918
|
-
push(name, {
|
|
1919
|
-
label: declared?.label ?? asProp?.label ?? name,
|
|
1920
|
-
...declared?.description ?? asProp?.description ? { description: declared?.description ?? asProp?.description } : {},
|
|
1921
|
-
known: true,
|
|
1922
|
-
accepts: true
|
|
1923
|
-
});
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
for (const name of Object.keys(node.slots)) {
|
|
1927
|
-
push(name, { label: name, known: false, accepts: true });
|
|
2075
|
+
let inner;
|
|
2076
|
+
if (child.kind === "text") {
|
|
2077
|
+
props.text = true;
|
|
2078
|
+
inner = child.text;
|
|
2079
|
+
} else {
|
|
2080
|
+
props.name = child.component;
|
|
2081
|
+
const chrome = chromeOf(child);
|
|
2082
|
+
if (chrome) props.chrome = chrome;
|
|
2083
|
+
const hint = chromeHintOf(child);
|
|
2084
|
+
if (hint) props.hint = hint;
|
|
2085
|
+
inner = toCanvasNode(child);
|
|
1928
2086
|
}
|
|
1929
|
-
return
|
|
1930
|
-
if (a.slot === DEFAULT_SLOT) return -1;
|
|
1931
|
-
if (b.slot === DEFAULT_SLOT) return 1;
|
|
1932
|
-
return b.seen - a.seen || a.slot.localeCompare(b.slot);
|
|
1933
|
-
});
|
|
2087
|
+
return { component: EDIT_MARK, key: child.id, props, children: [inner] };
|
|
1934
2088
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
2089
|
+
function markList(list, parent, slot) {
|
|
2090
|
+
if (!list || list.length === 0) return void 0;
|
|
2091
|
+
return list.map((child, index) => mark(child, parent, slot, index));
|
|
2092
|
+
}
|
|
2093
|
+
function toCanvasNode(node) {
|
|
2094
|
+
const out = {
|
|
2095
|
+
// ForEach만 편집용 구현으로 돌린다(위 주석 참고). 나머지는 이름 그대로 —
|
|
2096
|
+
// 레지스트리 쪽에서 갈아끼우므로 여기서 손댈 일이 없다.
|
|
2097
|
+
component: node.component === "ForEach" ? EDIT_FOREACH : node.component
|
|
2098
|
+
};
|
|
2099
|
+
if (Object.keys(node.props).length > 0) out.props = { ...node.props };
|
|
2100
|
+
let slots;
|
|
2101
|
+
for (const [name, list] of Object.entries(node.slots)) {
|
|
2102
|
+
if (name === DEFAULT_SLOT) continue;
|
|
2103
|
+
const marked = markList(list, node.id, name);
|
|
2104
|
+
if (marked) (slots ??= {})[name] = marked;
|
|
1943
2105
|
}
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
return SLOT_USAGE.get(`${component}#${slot}`) ?? 0;
|
|
2106
|
+
if (slots) out.slots = slots;
|
|
2107
|
+
const own = markList(node.slots[DEFAULT_SLOT], node.id, DEFAULT_SLOT);
|
|
2108
|
+
if (own) out.children = own;
|
|
2109
|
+
return out;
|
|
1949
2110
|
}
|
|
1950
|
-
function
|
|
1951
|
-
const {
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
2111
|
+
function toCanvasPage(doc) {
|
|
2112
|
+
const { urlState: _urlState, subscribe: _subscribe, ...meta } = doc.meta;
|
|
2113
|
+
return {
|
|
2114
|
+
...meta,
|
|
2115
|
+
body: doc.body.map((child, index) => mark(child, ROOT_ID, DEFAULT_SLOT, index))
|
|
2116
|
+
};
|
|
2117
|
+
}
|
|
2118
|
+
var CHROME_LABEL = {
|
|
2119
|
+
Show: "\uC870\uAC74\uBD80",
|
|
2120
|
+
Can: "\uAD8C\uD55C",
|
|
2121
|
+
ForEach: "\uBC18\uBCF5",
|
|
2122
|
+
Dialog: "\uBAA8\uB2EC"
|
|
2123
|
+
};
|
|
2124
|
+
function EditMark({ nid, parent, slot, index, name, text, chrome, hint, children }) {
|
|
2125
|
+
const common = {
|
|
2126
|
+
"data-sdui-id": nid,
|
|
2127
|
+
"data-sdui-parent": parent,
|
|
2128
|
+
"data-sdui-slot": slot,
|
|
2129
|
+
"data-sdui-index": index,
|
|
2130
|
+
...name ? { "data-sdui-name": name } : {},
|
|
2131
|
+
...text ? { "data-sdui-text": "true" } : {}
|
|
2132
|
+
};
|
|
2133
|
+
if (chrome && name) {
|
|
2134
|
+
return /* @__PURE__ */ jsxs("div", { className: `sdui-editor-cv-chrome sdui-editor-cv-chrome--${chrome}`, ...common, children: [
|
|
2135
|
+
/* @__PURE__ */ jsxs("span", { className: "sdui-editor-cv-chrome__tag", children: [
|
|
2136
|
+
CHROME_LABEL[name] ?? name,
|
|
2137
|
+
hint ? /* @__PURE__ */ jsx("em", { className: "sdui-editor-cv-chrome__hint", children: hint }) : null
|
|
2138
|
+
] }),
|
|
2139
|
+
children
|
|
2140
|
+
] });
|
|
2141
|
+
}
|
|
2142
|
+
return /* @__PURE__ */ jsx("span", { className: "sdui-editor-cv-mark", ...common, children });
|
|
2143
|
+
}
|
|
2144
|
+
function EditShow({ children }) {
|
|
2145
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
2146
|
+
}
|
|
2147
|
+
function EditCan({
|
|
2148
|
+
fallback,
|
|
2149
|
+
children
|
|
2150
|
+
}) {
|
|
2151
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2152
|
+
children,
|
|
2153
|
+
fallback ? /* @__PURE__ */ jsxs("div", { className: "sdui-editor-cv-branch", children: [
|
|
2154
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-editor-cv-branch__tag", children: "\uCC28\uB2E8 \uC2DC" }),
|
|
2155
|
+
fallback
|
|
2156
|
+
] }) : null
|
|
2157
|
+
] });
|
|
2158
|
+
}
|
|
2159
|
+
function EditForEach({
|
|
2160
|
+
source,
|
|
2161
|
+
empty,
|
|
2162
|
+
children
|
|
2163
|
+
}) {
|
|
2164
|
+
const rows = Array.isArray(source) ? source.length : null;
|
|
2165
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2166
|
+
/* @__PURE__ */ jsxs("div", { className: "sdui-editor-cv-branch", children: [
|
|
2167
|
+
/* @__PURE__ */ jsxs("span", { className: "sdui-editor-cv-branch__tag", children: [
|
|
2168
|
+
"\uD589 1\uAC1C \uBBF8\uB9AC\uBCF4\uAE30",
|
|
2169
|
+
rows === null ? "" : ` \xB7 \uC9C0\uAE08 ${rows}\uAC74`
|
|
2170
|
+
] }),
|
|
2171
|
+
children
|
|
2172
|
+
] }),
|
|
2173
|
+
empty ? /* @__PURE__ */ jsxs("div", { className: "sdui-editor-cv-branch", children: [
|
|
2174
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-editor-cv-branch__tag", children: "\uBE44\uC5C8\uC744 \uB54C" }),
|
|
2175
|
+
empty
|
|
2176
|
+
] }) : null
|
|
2177
|
+
] });
|
|
2178
|
+
}
|
|
2179
|
+
function createEditRegistry(base = defaultRegistry) {
|
|
2180
|
+
return {
|
|
2181
|
+
...base,
|
|
2182
|
+
Show: EditShow,
|
|
2183
|
+
Can: EditCan,
|
|
2184
|
+
Dialog,
|
|
2185
|
+
[EDIT_MARK]: EditMark,
|
|
2186
|
+
[EDIT_FOREACH]: EditForEach
|
|
2187
|
+
};
|
|
2188
|
+
}
|
|
2189
|
+
var PLACEHOLDER_SVG = [
|
|
2190
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">',
|
|
2191
|
+
'<rect width="64" height="64" fill="#e2e8f0"/>',
|
|
2192
|
+
'<path d="M0 0h16v16H0zM32 0h16v16H32zM16 16h16v16H16zM48 16h16v16H48z',
|
|
2193
|
+
'M0 32h16v16H0zM32 32h16v16H32zM16 48h16v16H16zM48 48h16v16H48z" fill="#cbd5e1"/>',
|
|
2194
|
+
'<circle cx="24" cy="24" r="6" fill="#94a3b8"/>',
|
|
2195
|
+
'<path d="M8 52l16-18 10 11 8-8 14 15z" fill="#94a3b8"/>',
|
|
2196
|
+
"</svg>"
|
|
2197
|
+
].join("");
|
|
2198
|
+
var CANVAS_ASSET_PLACEHOLDER = `data:image/svg+xml,${encodeURIComponent(PLACEHOLDER_SVG)}`;
|
|
2199
|
+
function isInertUrl(url) {
|
|
2200
|
+
const value = url.trim().toLowerCase();
|
|
2201
|
+
return value.startsWith("#") || value.startsWith("data:") || value.startsWith("blob:");
|
|
2202
|
+
}
|
|
2203
|
+
function resolveCanvasAsset(url, ctx) {
|
|
2204
|
+
if (isInertUrl(url)) return url;
|
|
2205
|
+
return ctx.kind === "attribute" ? CANVAS_ASSET_PLACEHOLDER : null;
|
|
2206
|
+
}
|
|
2207
|
+
function createCanvasAdapter(onBlocked) {
|
|
2208
|
+
return {
|
|
2209
|
+
navigate: (to) => onBlocked(`navigate \u2192 ${to}`),
|
|
2210
|
+
// 요청은 보내지 않되 성공(null)으로 응답한다 — onSuccess 체인이 어떻게 흐르는지는
|
|
2211
|
+
// 보여 주면서 서버는 건드리지 않는다.
|
|
2212
|
+
fetch: async (path, init) => {
|
|
2213
|
+
onBlocked(`${init.method} ${path}`);
|
|
2214
|
+
return null;
|
|
2215
|
+
},
|
|
2216
|
+
// download는 응답을 파일로 저장한다. 실패로 끊어 빈 파일이 내려가는 것까지 막는다.
|
|
2217
|
+
rawFetch: async (path) => {
|
|
2218
|
+
onBlocked(`download ${path}`);
|
|
2219
|
+
throw new Error("\uCE94\uBC84\uC2A4\uC5D0\uC11C\uB294 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
2220
|
+
},
|
|
2221
|
+
invalidate: (prefix) => onBlocked(`invalidate ${prefix}`),
|
|
2222
|
+
refresh: () => onBlocked("refresh"),
|
|
2223
|
+
// 편집 중 상태가 호스트 앱의 URL을 덮어쓰지 않게 한다(syncUrlState={false}와 이중 방어).
|
|
2224
|
+
replaceQuery: () => {
|
|
2225
|
+
},
|
|
2226
|
+
// 스펙 최상위 `subscribe`가 여는 실시간 채널. **지금 이걸 비워 두면 안전한 것은 우연이다** —
|
|
2227
|
+
// `defaultAdapter`에 아직 구현이 없어서일 뿐이고, 구현이 생기는 순간 캔버스가 조용히
|
|
2228
|
+
// EventSource를 연다. 실제로 vehicle/logs 스펙이 최상위 subscribe를 갖고 있다.
|
|
2229
|
+
// 해제 함수를 돌려주는 계약이라 no-op도 함수를 반환해야 한다.
|
|
2230
|
+
subscribe: (channels) => {
|
|
2231
|
+
onBlocked(`subscribe ${channels.join(", ")}`);
|
|
2232
|
+
return () => {
|
|
2233
|
+
};
|
|
2234
|
+
},
|
|
2235
|
+
// 위의 다섯과 성질이 다르다. 저 다섯은 어댑터가 **호출을 소유**하므로 비워 두면
|
|
2236
|
+
// 아무 일도 안 일어나지만, `<img src>`와 `background-image: url(…)`은 요청을 내는
|
|
2237
|
+
// 주체가 브라우저라 어댑터가 그 자리에 없다. 실제로 캔버스 클릭 차단과 위 다섯 개를
|
|
2238
|
+
// 다 두고도 아바타·라이트박스·style 프롭으로 요청 5건이 세션 쿠키를 달고 나갔다.
|
|
2239
|
+
resolveAsset: resolveCanvasAsset,
|
|
2240
|
+
// 위의 여섯과 또 성질이 다르다. 저것들은 **이 어댑터를 거쳐 나가는** 경로라 여기서
|
|
2241
|
+
// 끊을 수 있지만, 소비 앱의 목록 위젯처럼 **자기 데이터 클라이언트로 직접** 조회하는
|
|
2242
|
+
// 컴포넌트는 어댑터를 아예 지나가지 않는다(ERP의 RemoteSearchResults가 그렇다 —
|
|
2243
|
+
// TanStack Query 모듈 싱글턴이라 끼어들 자리가 없다). 그런 컴포넌트가 스스로
|
|
2244
|
+
// 물러설 수 있게 "여기는 진짜 화면이 아니다"만 알려 준다.
|
|
2245
|
+
//
|
|
2246
|
+
// 값 교체가 아니라 **선언**이라는 점이 중요하다. `fetch`처럼 빈 응답을 돌려주는 것으로
|
|
2247
|
+
// 대신하려 했다가 버렸다 — 그 빈 응답이 소비 앱의 공유 캐시에 실려, 편집기를 닫고
|
|
2248
|
+
// 진짜 페이지를 열면 오염된 목록이 나온다. 요청은 **시작되기 전에** 막혀야 한다.
|
|
2249
|
+
sandbox: true
|
|
2250
|
+
};
|
|
2251
|
+
}
|
|
2252
|
+
|
|
2253
|
+
// src/preview/preview-adapter.ts
|
|
2254
|
+
function createDataPreviewAdapter(previewFetch, onBlocked) {
|
|
2255
|
+
const sealed = createCanvasAdapter(onBlocked);
|
|
2256
|
+
return {
|
|
2257
|
+
...sealed,
|
|
2258
|
+
fetch: async (path, init) => {
|
|
2259
|
+
if (init.method !== "GET") {
|
|
2260
|
+
onBlocked(`${init.method} ${path}`);
|
|
2261
|
+
return null;
|
|
2262
|
+
}
|
|
2263
|
+
return previewFetch(path, { method: "GET", signal: init.signal });
|
|
2264
|
+
},
|
|
2265
|
+
resolveAsset: (url, ctx) => {
|
|
2266
|
+
const value = url.trim();
|
|
2267
|
+
if (value.startsWith("/") && !value.startsWith("//")) return url;
|
|
2268
|
+
return sealed.resolveAsset ? sealed.resolveAsset(url, ctx) : null;
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
}
|
|
2272
|
+
function resolvePreviewAdapter({
|
|
2273
|
+
armed,
|
|
2274
|
+
previewFetch,
|
|
2275
|
+
onBlocked,
|
|
2276
|
+
useSpec
|
|
2277
|
+
}) {
|
|
2278
|
+
const base = armed && previewFetch ? createDataPreviewAdapter(previewFetch, onBlocked) : createCanvasAdapter(onBlocked);
|
|
2279
|
+
return useSpec ? { ...base, useSpec } : base;
|
|
2280
|
+
}
|
|
2281
|
+
var HINT_PROPS = ["title", "label", "header", "text", "value", "placeholder", "name"];
|
|
2282
|
+
function isPlainObject3(v) {
|
|
2283
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2284
|
+
}
|
|
2285
|
+
function summarize(value) {
|
|
2286
|
+
if (typeof value === "string") return value.trim() || void 0;
|
|
2287
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2288
|
+
if (isPlainObject3(value)) {
|
|
2289
|
+
if (typeof value.$state === "string") return `{${value.$state}}`;
|
|
2290
|
+
if (value.$item === true) return "{\uD589}";
|
|
2291
|
+
if (typeof value.$item === "string") return `{\uD589.${value.$item}}`;
|
|
2292
|
+
if (value.$index === true) return "{\uBC88\uD638}";
|
|
2293
|
+
if (isPlainObject3(value.$calc) && typeof value.$calc.op === "string") return `{\uACC4\uC0B0:${value.$calc.op}}`;
|
|
2294
|
+
}
|
|
2295
|
+
return void 0;
|
|
2296
|
+
}
|
|
2297
|
+
function describeChild(child, catalog) {
|
|
2298
|
+
if (child.kind === "text") {
|
|
2299
|
+
const text = child.text.trim();
|
|
2300
|
+
return { label: "\uD14D\uC2A4\uD2B8", hint: text || "(\uBE48 \uBB38\uC790\uC5F4)", known: true };
|
|
2301
|
+
}
|
|
2302
|
+
const meta = getComponentMeta(child.component, catalog);
|
|
2303
|
+
let hint;
|
|
2304
|
+
for (const name of HINT_PROPS) {
|
|
2305
|
+
if (!(name in child.props)) continue;
|
|
2306
|
+
hint = summarize(child.props[name]);
|
|
2307
|
+
if (hint) break;
|
|
2308
|
+
}
|
|
2309
|
+
if (!hint) {
|
|
2310
|
+
const first = child.slots[DEFAULT_SLOT]?.[0];
|
|
2311
|
+
if (first?.kind === "text") hint = first.text.trim() || void 0;
|
|
2312
|
+
}
|
|
2313
|
+
return {
|
|
2314
|
+
label: meta?.label ?? child.component,
|
|
2315
|
+
...hint ? { hint } : {},
|
|
2316
|
+
...meta ? { icon: meta.icon } : {},
|
|
2317
|
+
known: meta !== void 0
|
|
2318
|
+
};
|
|
2319
|
+
}
|
|
2320
|
+
function breadcrumbOf(doc, id, catalog) {
|
|
2321
|
+
const trail = [...ancestorIdsOf(doc, id), id];
|
|
2322
|
+
const out = [];
|
|
2323
|
+
for (const step of trail) {
|
|
2324
|
+
const child = getChild(doc, step);
|
|
2325
|
+
if (child) out.push({ id: step, label: describeChild(child, catalog).label });
|
|
2326
|
+
}
|
|
2327
|
+
return out;
|
|
2328
|
+
}
|
|
2329
|
+
function slotsOf(node, catalog) {
|
|
2330
|
+
const meta = getComponentMeta(node.component, catalog);
|
|
2331
|
+
const out = [];
|
|
2332
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
2333
|
+
const push = (slot, d) => {
|
|
2334
|
+
if (seenNames.has(slot)) return;
|
|
2335
|
+
seenNames.add(slot);
|
|
2336
|
+
out.push({
|
|
2337
|
+
slot,
|
|
2338
|
+
count: node.slots[slot]?.length ?? 0,
|
|
2339
|
+
seen: slotUsage(node.component, slot),
|
|
2340
|
+
...d
|
|
2341
|
+
});
|
|
2342
|
+
};
|
|
2343
|
+
const acceptsDefault = meta ? meta.children.accepts : true;
|
|
2344
|
+
if (acceptsDefault || (node.slots[DEFAULT_SLOT]?.length ?? 0) > 0) {
|
|
2345
|
+
push(DEFAULT_SLOT, {
|
|
2346
|
+
label: meta?.children.label ?? "\uC790\uC2DD",
|
|
2347
|
+
known: meta !== void 0,
|
|
2348
|
+
accepts: acceptsDefault
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
if (meta) {
|
|
2352
|
+
for (const name of slotNamesOf(meta)) {
|
|
2353
|
+
const declared = (meta.slots ?? []).find((s) => s.name === name);
|
|
2354
|
+
const asProp = meta.props.find((p) => p.name === name && p.slot === true);
|
|
2355
|
+
push(name, {
|
|
2356
|
+
label: declared?.label ?? asProp?.label ?? name,
|
|
2357
|
+
...declared?.description ?? asProp?.description ? { description: declared?.description ?? asProp?.description } : {},
|
|
2358
|
+
known: true,
|
|
2359
|
+
accepts: true
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
for (const name of Object.keys(node.slots)) {
|
|
2364
|
+
push(name, { label: name, known: false, accepts: true });
|
|
2365
|
+
}
|
|
2366
|
+
return out.sort((a, b) => {
|
|
2367
|
+
if (a.slot === DEFAULT_SLOT) return -1;
|
|
2368
|
+
if (b.slot === DEFAULT_SLOT) return 1;
|
|
2369
|
+
return b.seen - a.seen || a.slot.localeCompare(b.slot);
|
|
2370
|
+
});
|
|
2371
|
+
}
|
|
2372
|
+
var SLOT_USAGE = (() => {
|
|
2373
|
+
const totals = /* @__PURE__ */ new Map();
|
|
2374
|
+
for (const [key, count] of Object.entries(SPEC_PAIR_FREQ)) {
|
|
2375
|
+
const arrow = key.indexOf(">");
|
|
2376
|
+
const hash = key.indexOf("#");
|
|
2377
|
+
if (hash < 0 || hash > arrow) continue;
|
|
2378
|
+
const head = key.slice(0, arrow);
|
|
2379
|
+
totals.set(head, (totals.get(head) ?? 0) + count);
|
|
2380
|
+
}
|
|
2381
|
+
return totals;
|
|
2382
|
+
})();
|
|
2383
|
+
function slotUsage(component, slot) {
|
|
2384
|
+
if (slot === DEFAULT_SLOT) return 0;
|
|
2385
|
+
return SLOT_USAGE.get(`${component}#${slot}`) ?? 0;
|
|
2386
|
+
}
|
|
2387
|
+
function flattenTree(doc, options = {}) {
|
|
2388
|
+
const { expanded, showSlots = true, catalog } = options;
|
|
2389
|
+
const isOpen = (key) => expanded === void 0 || expanded.has(key);
|
|
2390
|
+
const rows = [];
|
|
2391
|
+
const emitList = (list, parent, slot, depth) => {
|
|
2392
|
+
list.forEach((child, index) => {
|
|
2393
|
+
if (child.kind === "text") {
|
|
2394
|
+
const d2 = describeChild(child, catalog);
|
|
2395
|
+
rows.push({
|
|
2396
|
+
kind: "text",
|
|
2397
|
+
key: child.id,
|
|
2398
|
+
id: child.id,
|
|
2399
|
+
depth,
|
|
1963
2400
|
parent,
|
|
1964
2401
|
slot,
|
|
1965
2402
|
index,
|
|
@@ -2058,7 +2495,7 @@ function dropTargetsAround(doc, hoveredId, child, catalog) {
|
|
|
2058
2495
|
}
|
|
2059
2496
|
return out;
|
|
2060
2497
|
}
|
|
2061
|
-
var
|
|
2498
|
+
var STATE_WRITING_ACTIONS2 = /* @__PURE__ */ new Set([
|
|
2062
2499
|
"setState",
|
|
2063
2500
|
"open",
|
|
2064
2501
|
"close",
|
|
@@ -2091,12 +2528,12 @@ function buildStateKeyIndex(doc) {
|
|
|
2091
2528
|
for (const item of value) walkValue(item, node);
|
|
2092
2529
|
return;
|
|
2093
2530
|
}
|
|
2094
|
-
if (!
|
|
2531
|
+
if (!isPlainObject3(value)) return;
|
|
2095
2532
|
if (typeof value.$state === "string" && value.$state) {
|
|
2096
2533
|
const draft = touch(value.$state, "default" in value ? "default" : "read", node);
|
|
2097
2534
|
draft.reads++;
|
|
2098
2535
|
}
|
|
2099
|
-
if (typeof value.action === "string" &&
|
|
2536
|
+
if (typeof value.action === "string" && STATE_WRITING_ACTIONS2.has(value.action)) {
|
|
2100
2537
|
if (typeof value.key === "string" && value.key) {
|
|
2101
2538
|
const draft = touch(value.key, "setState", node);
|
|
2102
2539
|
draft.writes++;
|
|
@@ -2114,7 +2551,7 @@ function buildStateKeyIndex(doc) {
|
|
|
2114
2551
|
const fields = /* @__PURE__ */ new Set();
|
|
2115
2552
|
for (const source of ["initial", "rules", "labels", "initialFromUrl"]) {
|
|
2116
2553
|
const bag = child.props[source];
|
|
2117
|
-
if (!
|
|
2554
|
+
if (!isPlainObject3(bag)) continue;
|
|
2118
2555
|
for (const field of Object.keys(bag)) fields.add(field);
|
|
2119
2556
|
}
|
|
2120
2557
|
for (const field of fields) touch(`${id}.${field}`, "form", child.id);
|
|
@@ -2157,297 +2594,70 @@ function buildKeyTree(entries) {
|
|
|
2157
2594
|
}
|
|
2158
2595
|
}
|
|
2159
2596
|
const finish = (bucket, declaredAbove) => {
|
|
2160
|
-
const entry = entries.get(bucket.key);
|
|
2161
|
-
const declaredHere = declaredAbove || (entry?.declared ?? false);
|
|
2162
|
-
return {
|
|
2163
|
-
segment: bucket.segment,
|
|
2164
|
-
key: bucket.key,
|
|
2165
|
-
...entry ? { entry } : {},
|
|
2166
|
-
derived: declaredAbove,
|
|
2167
|
-
children: [...bucket.children.values()].map((child) => finish(child, declaredHere)).sort((a, b) => a.segment.localeCompare(b.segment, "ko"))
|
|
2168
|
-
};
|
|
2169
|
-
};
|
|
2170
|
-
return [...roots.values()].map((bucket) => finish(bucket, false)).sort((a, b) => a.segment.localeCompare(b.segment, "ko"));
|
|
2171
|
-
}
|
|
2172
|
-
function stateKeyStatus(index, key) {
|
|
2173
|
-
const entry = index.entries.get(key);
|
|
2174
|
-
if (entry?.declared) return "declared";
|
|
2175
|
-
const segments = key.split(".");
|
|
2176
|
-
for (let cut = segments.length - 1; cut >= 1; cut--) {
|
|
2177
|
-
const head = segments.slice(0, cut).join(".");
|
|
2178
|
-
if (index.entries.get(head)?.declared) return "derived";
|
|
2179
|
-
}
|
|
2180
|
-
return entry ? "read" : "unknown";
|
|
2181
|
-
}
|
|
2182
|
-
function suggestStateKeys(index, query = "", limit = 20) {
|
|
2183
|
-
const needle = query.trim().toLowerCase();
|
|
2184
|
-
const matched = [...index.entries.values()].filter(
|
|
2185
|
-
(entry) => needle === "" || entry.key.toLowerCase().includes(needle)
|
|
2186
|
-
);
|
|
2187
|
-
return matched.sort((a, b) => {
|
|
2188
|
-
if (a.declared !== b.declared) return a.declared ? -1 : 1;
|
|
2189
|
-
if (needle) {
|
|
2190
|
-
const ap = a.key.toLowerCase().startsWith(needle);
|
|
2191
|
-
const bp = b.key.toLowerCase().startsWith(needle);
|
|
2192
|
-
if (ap !== bp) return ap ? -1 : 1;
|
|
2193
|
-
}
|
|
2194
|
-
return b.reads + b.writes - (a.reads + a.writes) || a.key.localeCompare(b.key);
|
|
2195
|
-
}).slice(0, limit);
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
|
-
// src/builder/canvas/dnd.ts
|
|
2199
|
-
var DRAG_MIME = "application/x-wipco-sdui-builder";
|
|
2200
|
-
var payload = null;
|
|
2201
|
-
function beginDrag(transfer, next) {
|
|
2202
|
-
payload = next;
|
|
2203
|
-
if (!transfer) return;
|
|
2204
|
-
transfer.setData(DRAG_MIME, next.component);
|
|
2205
|
-
transfer.setData("text/plain", next.label);
|
|
2206
|
-
transfer.effectAllowed = next.kind === "insert" ? "copy" : "move";
|
|
2207
|
-
}
|
|
2208
|
-
function currentDrag() {
|
|
2209
|
-
return payload;
|
|
2210
|
-
}
|
|
2211
|
-
function endDrag() {
|
|
2212
|
-
payload = null;
|
|
2213
|
-
}
|
|
2214
|
-
function isBuilderDrag(transfer) {
|
|
2215
|
-
if (payload !== null) return true;
|
|
2216
|
-
return transfer ? Array.from(transfer.types).includes(DRAG_MIME) : false;
|
|
2217
|
-
}
|
|
2218
|
-
function insertDragOf(spec, label) {
|
|
2219
|
-
return {
|
|
2220
|
-
kind: "insert",
|
|
2221
|
-
component: typeof spec === "string" ? TEXT_CHILD : spec.component,
|
|
2222
|
-
spec,
|
|
2223
|
-
label
|
|
2224
|
-
};
|
|
2225
|
-
}
|
|
2226
|
-
|
|
2227
|
-
// src/builder/canvas/project.ts
|
|
2228
|
-
var EDIT_MARK = "$EditMark";
|
|
2229
|
-
var EDIT_FOREACH = "$EditForEach";
|
|
2230
|
-
var MARK_ATTR = "data-sdui-id";
|
|
2231
|
-
var LOGICAL = /* @__PURE__ */ new Set(["Show", "Can", "ForEach"]);
|
|
2232
|
-
function bindingLabel(value) {
|
|
2233
|
-
if (value === void 0 || value === null) return void 0;
|
|
2234
|
-
if (typeof value === "string") return value || void 0;
|
|
2235
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
2236
|
-
if (Array.isArray(value)) return void 0;
|
|
2237
|
-
const bag = value;
|
|
2238
|
-
if (typeof bag.$state === "string") return `{${bag.$state}}`;
|
|
2239
|
-
if (bag.$item === true) return "{\uD589}";
|
|
2240
|
-
if (typeof bag.$item === "string") return `{\uD589.${bag.$item}}`;
|
|
2241
|
-
if (bag.$index === true) return "{\uBC88\uD638}";
|
|
2242
|
-
const calc = bag.$calc;
|
|
2243
|
-
if (calc !== null && typeof calc === "object" && !Array.isArray(calc)) {
|
|
2244
|
-
const op = calc.op;
|
|
2245
|
-
if (typeof op === "string") return `{\uACC4\uC0B0:${op}}`;
|
|
2246
|
-
}
|
|
2247
|
-
return void 0;
|
|
2248
|
-
}
|
|
2249
|
-
function chromeHintOf(node) {
|
|
2250
|
-
switch (node.component) {
|
|
2251
|
-
case "Show":
|
|
2252
|
-
return bindingLabel(node.props.when);
|
|
2253
|
-
case "Can": {
|
|
2254
|
-
const entity = typeof node.props.entity === "string" ? node.props.entity : "?";
|
|
2255
|
-
const action = typeof node.props.action === "string" ? node.props.action : "read";
|
|
2256
|
-
return `${entity} \xB7 ${action}`;
|
|
2257
|
-
}
|
|
2258
|
-
case "ForEach":
|
|
2259
|
-
return bindingLabel(node.props.source);
|
|
2260
|
-
default:
|
|
2261
|
-
return void 0;
|
|
2262
|
-
}
|
|
2263
|
-
}
|
|
2264
|
-
function chromeOf(node) {
|
|
2265
|
-
if (LOGICAL.has(node.component)) return "logic";
|
|
2266
|
-
if (node.component === "Dialog") return "modal";
|
|
2267
|
-
return void 0;
|
|
2268
|
-
}
|
|
2269
|
-
function mark(child, parent, slot, index) {
|
|
2270
|
-
const props = {
|
|
2271
|
-
nid: child.id,
|
|
2272
|
-
parent,
|
|
2273
|
-
slot,
|
|
2274
|
-
index
|
|
2275
|
-
};
|
|
2276
|
-
let inner;
|
|
2277
|
-
if (child.kind === "text") {
|
|
2278
|
-
props.text = true;
|
|
2279
|
-
inner = child.text;
|
|
2280
|
-
} else {
|
|
2281
|
-
props.name = child.component;
|
|
2282
|
-
const chrome = chromeOf(child);
|
|
2283
|
-
if (chrome) props.chrome = chrome;
|
|
2284
|
-
const hint = chromeHintOf(child);
|
|
2285
|
-
if (hint) props.hint = hint;
|
|
2286
|
-
inner = toCanvasNode(child);
|
|
2287
|
-
}
|
|
2288
|
-
return { component: EDIT_MARK, key: child.id, props, children: [inner] };
|
|
2289
|
-
}
|
|
2290
|
-
function markList(list, parent, slot) {
|
|
2291
|
-
if (!list || list.length === 0) return void 0;
|
|
2292
|
-
return list.map((child, index) => mark(child, parent, slot, index));
|
|
2293
|
-
}
|
|
2294
|
-
function toCanvasNode(node) {
|
|
2295
|
-
const out = {
|
|
2296
|
-
// ForEach만 편집용 구현으로 돌린다(위 주석 참고). 나머지는 이름 그대로 —
|
|
2297
|
-
// 레지스트리 쪽에서 갈아끼우므로 여기서 손댈 일이 없다.
|
|
2298
|
-
component: node.component === "ForEach" ? EDIT_FOREACH : node.component
|
|
2299
|
-
};
|
|
2300
|
-
if (Object.keys(node.props).length > 0) out.props = { ...node.props };
|
|
2301
|
-
let slots;
|
|
2302
|
-
for (const [name, list] of Object.entries(node.slots)) {
|
|
2303
|
-
if (name === DEFAULT_SLOT) continue;
|
|
2304
|
-
const marked = markList(list, node.id, name);
|
|
2305
|
-
if (marked) (slots ??= {})[name] = marked;
|
|
2306
|
-
}
|
|
2307
|
-
if (slots) out.slots = slots;
|
|
2308
|
-
const own = markList(node.slots[DEFAULT_SLOT], node.id, DEFAULT_SLOT);
|
|
2309
|
-
if (own) out.children = own;
|
|
2310
|
-
return out;
|
|
2311
|
-
}
|
|
2312
|
-
function toCanvasPage(doc) {
|
|
2313
|
-
const { urlState: _urlState, subscribe: _subscribe, ...meta } = doc.meta;
|
|
2314
|
-
return {
|
|
2315
|
-
...meta,
|
|
2316
|
-
body: doc.body.map((child, index) => mark(child, ROOT_ID, DEFAULT_SLOT, index))
|
|
2597
|
+
const entry = entries.get(bucket.key);
|
|
2598
|
+
const declaredHere = declaredAbove || (entry?.declared ?? false);
|
|
2599
|
+
return {
|
|
2600
|
+
segment: bucket.segment,
|
|
2601
|
+
key: bucket.key,
|
|
2602
|
+
...entry ? { entry } : {},
|
|
2603
|
+
derived: declaredAbove,
|
|
2604
|
+
children: [...bucket.children.values()].map((child) => finish(child, declaredHere)).sort((a, b) => a.segment.localeCompare(b.segment, "ko"))
|
|
2605
|
+
};
|
|
2317
2606
|
};
|
|
2607
|
+
return [...roots.values()].map((bucket) => finish(bucket, false)).sort((a, b) => a.segment.localeCompare(b.segment, "ko"));
|
|
2318
2608
|
}
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
const common = {
|
|
2327
|
-
"data-sdui-id": nid,
|
|
2328
|
-
"data-sdui-parent": parent,
|
|
2329
|
-
"data-sdui-slot": slot,
|
|
2330
|
-
"data-sdui-index": index,
|
|
2331
|
-
...name ? { "data-sdui-name": name } : {},
|
|
2332
|
-
...text ? { "data-sdui-text": "true" } : {}
|
|
2333
|
-
};
|
|
2334
|
-
if (chrome && name) {
|
|
2335
|
-
return /* @__PURE__ */ jsxs("div", { className: `sdui-editor-cv-chrome sdui-editor-cv-chrome--${chrome}`, ...common, children: [
|
|
2336
|
-
/* @__PURE__ */ jsxs("span", { className: "sdui-editor-cv-chrome__tag", children: [
|
|
2337
|
-
CHROME_LABEL[name] ?? name,
|
|
2338
|
-
hint ? /* @__PURE__ */ jsx("em", { className: "sdui-editor-cv-chrome__hint", children: hint }) : null
|
|
2339
|
-
] }),
|
|
2340
|
-
children
|
|
2341
|
-
] });
|
|
2609
|
+
function stateKeyStatus(index, key) {
|
|
2610
|
+
const entry = index.entries.get(key);
|
|
2611
|
+
if (entry?.declared) return "declared";
|
|
2612
|
+
const segments = key.split(".");
|
|
2613
|
+
for (let cut = segments.length - 1; cut >= 1; cut--) {
|
|
2614
|
+
const head = segments.slice(0, cut).join(".");
|
|
2615
|
+
if (index.entries.get(head)?.declared) return "derived";
|
|
2342
2616
|
}
|
|
2343
|
-
return
|
|
2344
|
-
}
|
|
2345
|
-
function EditShow({ children }) {
|
|
2346
|
-
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
2617
|
+
return entry ? "read" : "unknown";
|
|
2347
2618
|
}
|
|
2348
|
-
function
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2619
|
+
function suggestStateKeys(index, query = "", limit = 20) {
|
|
2620
|
+
const needle = query.trim().toLowerCase();
|
|
2621
|
+
const matched = [...index.entries.values()].filter(
|
|
2622
|
+
(entry) => needle === "" || entry.key.toLowerCase().includes(needle)
|
|
2623
|
+
);
|
|
2624
|
+
return matched.sort((a, b) => {
|
|
2625
|
+
if (a.declared !== b.declared) return a.declared ? -1 : 1;
|
|
2626
|
+
if (needle) {
|
|
2627
|
+
const ap = a.key.toLowerCase().startsWith(needle);
|
|
2628
|
+
const bp = b.key.toLowerCase().startsWith(needle);
|
|
2629
|
+
if (ap !== bp) return ap ? -1 : 1;
|
|
2630
|
+
}
|
|
2631
|
+
return b.reads + b.writes - (a.reads + a.writes) || a.key.localeCompare(b.key);
|
|
2632
|
+
}).slice(0, limit);
|
|
2359
2633
|
}
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
rows === null ? "" : ` \xB7 \uC9C0\uAE08 ${rows}\uAC74`
|
|
2371
|
-
] }),
|
|
2372
|
-
children
|
|
2373
|
-
] }),
|
|
2374
|
-
empty ? /* @__PURE__ */ jsxs("div", { className: "sdui-editor-cv-branch", children: [
|
|
2375
|
-
/* @__PURE__ */ jsx("span", { className: "sdui-editor-cv-branch__tag", children: "\uBE44\uC5C8\uC744 \uB54C" }),
|
|
2376
|
-
empty
|
|
2377
|
-
] }) : null
|
|
2378
|
-
] });
|
|
2634
|
+
|
|
2635
|
+
// src/builder/canvas/dnd.ts
|
|
2636
|
+
var DRAG_MIME = "application/x-wipco-sdui-builder";
|
|
2637
|
+
var payload = null;
|
|
2638
|
+
function beginDrag(transfer, next) {
|
|
2639
|
+
payload = next;
|
|
2640
|
+
if (!transfer) return;
|
|
2641
|
+
transfer.setData(DRAG_MIME, next.component);
|
|
2642
|
+
transfer.setData("text/plain", next.label);
|
|
2643
|
+
transfer.effectAllowed = next.kind === "insert" ? "copy" : "move";
|
|
2379
2644
|
}
|
|
2380
|
-
function
|
|
2381
|
-
return
|
|
2382
|
-
...base,
|
|
2383
|
-
Show: EditShow,
|
|
2384
|
-
Can: EditCan,
|
|
2385
|
-
Dialog,
|
|
2386
|
-
[EDIT_MARK]: EditMark,
|
|
2387
|
-
[EDIT_FOREACH]: EditForEach
|
|
2388
|
-
};
|
|
2645
|
+
function currentDrag() {
|
|
2646
|
+
return payload;
|
|
2389
2647
|
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
'<rect width="64" height="64" fill="#e2e8f0"/>',
|
|
2393
|
-
'<path d="M0 0h16v16H0zM32 0h16v16H32zM16 16h16v16H16zM48 16h16v16H48z',
|
|
2394
|
-
'M0 32h16v16H0zM32 32h16v16H32zM16 48h16v16H16zM48 48h16v16H48z" fill="#cbd5e1"/>',
|
|
2395
|
-
'<circle cx="24" cy="24" r="6" fill="#94a3b8"/>',
|
|
2396
|
-
'<path d="M8 52l16-18 10 11 8-8 14 15z" fill="#94a3b8"/>',
|
|
2397
|
-
"</svg>"
|
|
2398
|
-
].join("");
|
|
2399
|
-
var CANVAS_ASSET_PLACEHOLDER = `data:image/svg+xml,${encodeURIComponent(PLACEHOLDER_SVG)}`;
|
|
2400
|
-
function isInertUrl(url) {
|
|
2401
|
-
const value = url.trim().toLowerCase();
|
|
2402
|
-
return value.startsWith("#") || value.startsWith("data:") || value.startsWith("blob:");
|
|
2648
|
+
function endDrag() {
|
|
2649
|
+
payload = null;
|
|
2403
2650
|
}
|
|
2404
|
-
function
|
|
2405
|
-
if (
|
|
2406
|
-
return
|
|
2651
|
+
function isBuilderDrag(transfer) {
|
|
2652
|
+
if (payload !== null) return true;
|
|
2653
|
+
return transfer ? Array.from(transfer.types).includes(DRAG_MIME) : false;
|
|
2407
2654
|
}
|
|
2408
|
-
function
|
|
2655
|
+
function insertDragOf(spec, label) {
|
|
2409
2656
|
return {
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
onBlocked(`${init.method} ${path}`);
|
|
2415
|
-
return null;
|
|
2416
|
-
},
|
|
2417
|
-
// download는 응답을 파일로 저장한다. 실패로 끊어 빈 파일이 내려가는 것까지 막는다.
|
|
2418
|
-
rawFetch: async (path) => {
|
|
2419
|
-
onBlocked(`download ${path}`);
|
|
2420
|
-
throw new Error("\uCE94\uBC84\uC2A4\uC5D0\uC11C\uB294 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4");
|
|
2421
|
-
},
|
|
2422
|
-
invalidate: (prefix) => onBlocked(`invalidate ${prefix}`),
|
|
2423
|
-
refresh: () => onBlocked("refresh"),
|
|
2424
|
-
// 편집 중 상태가 호스트 앱의 URL을 덮어쓰지 않게 한다(syncUrlState={false}와 이중 방어).
|
|
2425
|
-
replaceQuery: () => {
|
|
2426
|
-
},
|
|
2427
|
-
// 스펙 최상위 `subscribe`가 여는 실시간 채널. **지금 이걸 비워 두면 안전한 것은 우연이다** —
|
|
2428
|
-
// `defaultAdapter`에 아직 구현이 없어서일 뿐이고, 구현이 생기는 순간 캔버스가 조용히
|
|
2429
|
-
// EventSource를 연다. 실제로 vehicle/logs 스펙이 최상위 subscribe를 갖고 있다.
|
|
2430
|
-
// 해제 함수를 돌려주는 계약이라 no-op도 함수를 반환해야 한다.
|
|
2431
|
-
subscribe: (channels) => {
|
|
2432
|
-
onBlocked(`subscribe ${channels.join(", ")}`);
|
|
2433
|
-
return () => {
|
|
2434
|
-
};
|
|
2435
|
-
},
|
|
2436
|
-
// 위의 다섯과 성질이 다르다. 저 다섯은 어댑터가 **호출을 소유**하므로 비워 두면
|
|
2437
|
-
// 아무 일도 안 일어나지만, `<img src>`와 `background-image: url(…)`은 요청을 내는
|
|
2438
|
-
// 주체가 브라우저라 어댑터가 그 자리에 없다. 실제로 캔버스 클릭 차단과 위 다섯 개를
|
|
2439
|
-
// 다 두고도 아바타·라이트박스·style 프롭으로 요청 5건이 세션 쿠키를 달고 나갔다.
|
|
2440
|
-
resolveAsset: resolveCanvasAsset,
|
|
2441
|
-
// 위의 여섯과 또 성질이 다르다. 저것들은 **이 어댑터를 거쳐 나가는** 경로라 여기서
|
|
2442
|
-
// 끊을 수 있지만, 소비 앱의 목록 위젯처럼 **자기 데이터 클라이언트로 직접** 조회하는
|
|
2443
|
-
// 컴포넌트는 어댑터를 아예 지나가지 않는다(ERP의 RemoteSearchResults가 그렇다 —
|
|
2444
|
-
// TanStack Query 모듈 싱글턴이라 끼어들 자리가 없다). 그런 컴포넌트가 스스로
|
|
2445
|
-
// 물러설 수 있게 "여기는 진짜 화면이 아니다"만 알려 준다.
|
|
2446
|
-
//
|
|
2447
|
-
// 값 교체가 아니라 **선언**이라는 점이 중요하다. `fetch`처럼 빈 응답을 돌려주는 것으로
|
|
2448
|
-
// 대신하려 했다가 버렸다 — 그 빈 응답이 소비 앱의 공유 캐시에 실려, 편집기를 닫고
|
|
2449
|
-
// 진짜 페이지를 열면 오염된 목록이 나온다. 요청은 **시작되기 전에** 막혀야 한다.
|
|
2450
|
-
sandbox: true
|
|
2657
|
+
kind: "insert",
|
|
2658
|
+
component: typeof spec === "string" ? TEXT_CHILD : spec.component,
|
|
2659
|
+
spec,
|
|
2660
|
+
label
|
|
2451
2661
|
};
|
|
2452
2662
|
}
|
|
2453
2663
|
|
|
@@ -3155,6 +3365,10 @@ function Canvas({
|
|
|
3155
3365
|
*/
|
|
3156
3366
|
registry = editorRegistry,
|
|
3157
3367
|
can,
|
|
3368
|
+
useSpec,
|
|
3369
|
+
previewFetch,
|
|
3370
|
+
dataArmed,
|
|
3371
|
+
initialState,
|
|
3158
3372
|
className
|
|
3159
3373
|
}) {
|
|
3160
3374
|
ensureBuilderStyles();
|
|
@@ -3184,8 +3398,13 @@ function Canvas({
|
|
|
3184
3398
|
const page = useMemo(() => toCanvasPage(doc), [doc]);
|
|
3185
3399
|
const editRegistry = useMemo(() => createEditRegistry(registry), [registry]);
|
|
3186
3400
|
const adapter = useMemo(
|
|
3187
|
-
() =>
|
|
3188
|
-
|
|
3401
|
+
() => resolvePreviewAdapter({
|
|
3402
|
+
armed: dataArmed === true,
|
|
3403
|
+
previewFetch,
|
|
3404
|
+
onBlocked: (what) => announce(`${what} \u2014 \uCE94\uBC84\uC2A4\uC5D0\uC11C\uB294 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4`),
|
|
3405
|
+
useSpec
|
|
3406
|
+
}),
|
|
3407
|
+
[announce, dataArmed, previewFetch, useSpec]
|
|
3189
3408
|
);
|
|
3190
3409
|
useLayoutEffect(() => {
|
|
3191
3410
|
setVersion((v) => v + 1);
|
|
@@ -3455,9 +3674,11 @@ function Canvas({
|
|
|
3455
3674
|
page,
|
|
3456
3675
|
registry: editRegistry,
|
|
3457
3676
|
adapter,
|
|
3677
|
+
initialState,
|
|
3458
3678
|
syncUrlState: false,
|
|
3459
3679
|
can: can ?? "allow-all"
|
|
3460
|
-
}
|
|
3680
|
+
},
|
|
3681
|
+
initialState ? seedSignature(initialState) : void 0
|
|
3461
3682
|
),
|
|
3462
3683
|
notice ? /* @__PURE__ */ jsx("div", { className: "sdui-editor-cv-notice", children: notice }) : null
|
|
3463
3684
|
] }),
|
|
@@ -3700,16 +3921,16 @@ function Palette({ doc, selection, dispatch, catalog, registry, className }) {
|
|
|
3700
3921
|
] })
|
|
3701
3922
|
] });
|
|
3702
3923
|
}
|
|
3703
|
-
function
|
|
3924
|
+
function isPlainObject4(v) {
|
|
3704
3925
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3705
3926
|
}
|
|
3706
3927
|
function bindingOf(value) {
|
|
3707
|
-
if (!
|
|
3928
|
+
if (!isPlainObject4(value)) return null;
|
|
3708
3929
|
if (typeof value.$state === "string") return { kind: "state", label: "\uC0C1\uD0DC", detail: value.$state };
|
|
3709
3930
|
if (value.$item === true) return { kind: "item", label: "\uD589", detail: "\uC804\uCCB4" };
|
|
3710
3931
|
if (typeof value.$item === "string") return { kind: "item", label: "\uD589", detail: value.$item };
|
|
3711
3932
|
if (value.$index === true) return { kind: "index", label: "\uBC88\uD638" };
|
|
3712
|
-
if (
|
|
3933
|
+
if (isPlainObject4(value.$calc) && typeof value.$calc.op === "string") {
|
|
3713
3934
|
return { kind: "calc", label: "\uACC4\uC0B0", detail: String(value.$calc.op) };
|
|
3714
3935
|
}
|
|
3715
3936
|
return null;
|
|
@@ -3889,7 +4110,7 @@ function asArray(value) {
|
|
|
3889
4110
|
return Array.isArray(value) ? value : null;
|
|
3890
4111
|
}
|
|
3891
4112
|
function asObject(value) {
|
|
3892
|
-
return
|
|
4113
|
+
return isPlainObject4(value) ? value : null;
|
|
3893
4114
|
}
|
|
3894
4115
|
function patchObject(base, name, value) {
|
|
3895
4116
|
const next = { ...base ?? {} };
|
|
@@ -4065,30 +4286,246 @@ function toSteps(value) {
|
|
|
4065
4286
|
if (value === void 0) return [];
|
|
4066
4287
|
return [value];
|
|
4067
4288
|
}
|
|
4068
|
-
function fromSteps(steps, wasArray) {
|
|
4069
|
-
if (steps.length === 0) return void 0;
|
|
4070
|
-
if (steps.length === 1 && !wasArray) return steps[0];
|
|
4071
|
-
return steps;
|
|
4289
|
+
function fromSteps(steps, wasArray) {
|
|
4290
|
+
if (steps.length === 0) return void 0;
|
|
4291
|
+
if (steps.length === 1 && !wasArray) return steps[0];
|
|
4292
|
+
return steps;
|
|
4293
|
+
}
|
|
4294
|
+
function summarizeStep(step) {
|
|
4295
|
+
const obj = asObject(step);
|
|
4296
|
+
if (!obj) return toJsonText(step).slice(0, 60);
|
|
4297
|
+
const verb = typeof obj.action === "string" ? VERB_BY_NAME.get(obj.action) : void 0;
|
|
4298
|
+
const label = verb?.label ?? (typeof obj.action === "string" ? obj.action : "\uC54C \uC218 \uC5C6\uB294 \uB3D9\uC791");
|
|
4299
|
+
const detail = verb?.summaryField ? obj[verb.summaryField] : void 0;
|
|
4300
|
+
return typeof detail === "string" || typeof detail === "number" ? `${label} \xB7 ${detail}` : label;
|
|
4301
|
+
}
|
|
4302
|
+
function switchVerb(step, next) {
|
|
4303
|
+
const out = { action: next.action };
|
|
4304
|
+
for (const field of next.fields) {
|
|
4305
|
+
const carried = step?.[field.name];
|
|
4306
|
+
if (carried !== void 0) out[field.name] = carried;
|
|
4307
|
+
}
|
|
4308
|
+
return out;
|
|
4309
|
+
}
|
|
4310
|
+
function isActionShaped(value) {
|
|
4311
|
+
if (Array.isArray(value)) return value.every((v) => isPlainObject4(v) && typeof v.action === "string");
|
|
4312
|
+
return isPlainObject4(value) && typeof value.action === "string";
|
|
4313
|
+
}
|
|
4314
|
+
function ToolButton({
|
|
4315
|
+
icon,
|
|
4316
|
+
label,
|
|
4317
|
+
onClick,
|
|
4318
|
+
disabled,
|
|
4319
|
+
active: active2,
|
|
4320
|
+
text
|
|
4321
|
+
}) {
|
|
4322
|
+
return /* @__PURE__ */ jsxs(
|
|
4323
|
+
"button",
|
|
4324
|
+
{
|
|
4325
|
+
type: "button",
|
|
4326
|
+
className: `sdui-insp-tool${active2 ? " sdui-insp-tool--on" : ""}`,
|
|
4327
|
+
onClick,
|
|
4328
|
+
disabled,
|
|
4329
|
+
title: label,
|
|
4330
|
+
"aria-label": label,
|
|
4331
|
+
children: [
|
|
4332
|
+
/* @__PURE__ */ jsx(Icon, { name: icon, size: 14 }),
|
|
4333
|
+
text ? /* @__PURE__ */ jsx("span", { children: text }) : null
|
|
4334
|
+
]
|
|
4335
|
+
}
|
|
4336
|
+
);
|
|
4337
|
+
}
|
|
4338
|
+
function textCommitValue(raw, meta) {
|
|
4339
|
+
return raw === "" && !meta?.required ? void 0 : raw;
|
|
4340
|
+
}
|
|
4341
|
+
function TextWidget({ value, onChange, meta, stateKeys }) {
|
|
4342
|
+
const listId = useId();
|
|
4343
|
+
const suggest = stateKeys && stateKeys.length > 0;
|
|
4344
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4345
|
+
/* @__PURE__ */ jsx(
|
|
4346
|
+
Input,
|
|
4347
|
+
{
|
|
4348
|
+
size: "sm",
|
|
4349
|
+
value: typeof value === "string" ? value : formatScalar(value),
|
|
4350
|
+
placeholder: meta?.default !== void 0 ? `\uAE30\uBCF8\uAC12: ${formatScalar(meta.default)}` : void 0,
|
|
4351
|
+
list: suggest ? listId : void 0,
|
|
4352
|
+
onChange: (e) => onChange(textCommitValue(e.target.value, meta))
|
|
4353
|
+
}
|
|
4354
|
+
),
|
|
4355
|
+
suggest ? /* @__PURE__ */ jsx("datalist", { id: listId, children: stateKeys.slice(0, 200).map((key) => /* @__PURE__ */ jsx("option", { value: key }, key)) }) : null
|
|
4356
|
+
] });
|
|
4357
|
+
}
|
|
4358
|
+
function NumberWidget({ value, onChange, meta }) {
|
|
4359
|
+
const external = formatScalar(value);
|
|
4360
|
+
const [text, setText2] = useState(external);
|
|
4361
|
+
const mine = useRef(external);
|
|
4362
|
+
useEffect(() => {
|
|
4363
|
+
if (external !== mine.current) {
|
|
4364
|
+
mine.current = external;
|
|
4365
|
+
setText2(external);
|
|
4366
|
+
}
|
|
4367
|
+
}, [external]);
|
|
4368
|
+
return /* @__PURE__ */ jsx(
|
|
4369
|
+
Input,
|
|
4370
|
+
{
|
|
4371
|
+
size: "sm",
|
|
4372
|
+
inputMode: "decimal",
|
|
4373
|
+
value: text,
|
|
4374
|
+
placeholder: meta?.default !== void 0 ? `\uAE30\uBCF8\uAC12: ${formatScalar(meta.default)}` : void 0,
|
|
4375
|
+
onChange: (e) => {
|
|
4376
|
+
const next = e.target.value;
|
|
4377
|
+
setText2(next);
|
|
4378
|
+
const parsed = parseNumber(next);
|
|
4379
|
+
if (parsed === null) return;
|
|
4380
|
+
mine.current = formatScalar(parsed);
|
|
4381
|
+
onChange(parsed);
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
);
|
|
4385
|
+
}
|
|
4386
|
+
function BoolWidget({ value, onChange, meta }) {
|
|
4387
|
+
const on = value === true;
|
|
4388
|
+
return /* @__PURE__ */ jsx(
|
|
4389
|
+
Switch,
|
|
4390
|
+
{
|
|
4391
|
+
size: "sm",
|
|
4392
|
+
checked: on,
|
|
4393
|
+
label: on ? "\uCF2C" : "\uB054",
|
|
4394
|
+
onChange: (e) => {
|
|
4395
|
+
if (e.target.checked) onChange(true);
|
|
4396
|
+
else onChange(meta?.default === true ? false : void 0);
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
);
|
|
4072
4400
|
}
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
const
|
|
4077
|
-
const
|
|
4078
|
-
const
|
|
4079
|
-
|
|
4401
|
+
var CURRENT = "__current__";
|
|
4402
|
+
function EnumWidget({ value, onChange, meta }) {
|
|
4403
|
+
const options = meta?.options ?? [];
|
|
4404
|
+
const known = options.findIndex((o) => o.value === value);
|
|
4405
|
+
const outsider = value !== void 0 && known < 0;
|
|
4406
|
+
const choices = options.map((option, index) => ({
|
|
4407
|
+
value: String(index),
|
|
4408
|
+
label: option.legacy ? `${option.label} (\uC61B \uAC12)` : option.label
|
|
4409
|
+
}));
|
|
4410
|
+
if (outsider) choices.push({ value: CURRENT, label: `${formatScalar(value)} (\uD6C4\uBCF4 \uBC16)` });
|
|
4411
|
+
return /* @__PURE__ */ jsx(
|
|
4412
|
+
Select,
|
|
4413
|
+
{
|
|
4414
|
+
size: "sm",
|
|
4415
|
+
options: choices,
|
|
4416
|
+
placeholder: meta?.default !== void 0 ? `\uAE30\uBCF8\uAC12: ${labelOf(options, meta.default)}` : "(\uC5C6\uC74C)",
|
|
4417
|
+
value: outsider ? CURRENT : known >= 0 ? String(known) : "",
|
|
4418
|
+
onChange: (e) => {
|
|
4419
|
+
const raw = e.target.value;
|
|
4420
|
+
if (raw === "") onChange(void 0);
|
|
4421
|
+
else if (raw === CURRENT) onChange(value);
|
|
4422
|
+
else onChange(options[Number(raw)]?.value);
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
);
|
|
4080
4426
|
}
|
|
4081
|
-
function
|
|
4082
|
-
|
|
4083
|
-
for (const field of next.fields) {
|
|
4084
|
-
const carried = step?.[field.name];
|
|
4085
|
-
if (carried !== void 0) out[field.name] = carried;
|
|
4086
|
-
}
|
|
4087
|
-
return out;
|
|
4427
|
+
function labelOf(options, value) {
|
|
4428
|
+
return options.find((o) => o.value === value)?.label ?? formatScalar(value);
|
|
4088
4429
|
}
|
|
4089
|
-
function
|
|
4090
|
-
|
|
4091
|
-
|
|
4430
|
+
function JsonWidget({ value, onChange, rows = 4 }) {
|
|
4431
|
+
const external = toJsonText(value);
|
|
4432
|
+
const [text, setText2] = useState(external);
|
|
4433
|
+
const [error, setError] = useState(null);
|
|
4434
|
+
const mine = useRef(external);
|
|
4435
|
+
useEffect(() => {
|
|
4436
|
+
if (external !== mine.current) {
|
|
4437
|
+
mine.current = external;
|
|
4438
|
+
setText2(external);
|
|
4439
|
+
setError(null);
|
|
4440
|
+
}
|
|
4441
|
+
}, [external]);
|
|
4442
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4443
|
+
/* @__PURE__ */ jsx(
|
|
4444
|
+
"textarea",
|
|
4445
|
+
{
|
|
4446
|
+
className: `sdui-insp-json${error ? " sdui-insp-json--bad" : ""}`,
|
|
4447
|
+
rows,
|
|
4448
|
+
spellCheck: false,
|
|
4449
|
+
value: text,
|
|
4450
|
+
onChange: (e) => {
|
|
4451
|
+
const next = e.target.value;
|
|
4452
|
+
setText2(next);
|
|
4453
|
+
const parsed = parseJson(next);
|
|
4454
|
+
if (!parsed.ok) {
|
|
4455
|
+
setError(parsed.error ?? "JSON\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
4456
|
+
return;
|
|
4457
|
+
}
|
|
4458
|
+
setError(null);
|
|
4459
|
+
mine.current = toJsonText(parsed.value);
|
|
4460
|
+
onChange(parsed.value);
|
|
4461
|
+
}
|
|
4462
|
+
}
|
|
4463
|
+
),
|
|
4464
|
+
error ? /* @__PURE__ */ jsx("p", { className: "sdui-insp-err", children: error }) : null
|
|
4465
|
+
] });
|
|
4466
|
+
}
|
|
4467
|
+
function BindingChip({
|
|
4468
|
+
info,
|
|
4469
|
+
onEdit,
|
|
4470
|
+
onRaw
|
|
4471
|
+
}) {
|
|
4472
|
+
return /* @__PURE__ */ jsxs("div", { className: "sdui-insp-chip", title: bindingText(info), children: [
|
|
4473
|
+
/* @__PURE__ */ jsx(Icon, { name: "link", size: 14 }),
|
|
4474
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-chip__kind", children: info.label }),
|
|
4475
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-chip__val", children: info.detail ?? "" }),
|
|
4476
|
+
/* @__PURE__ */ jsxs("span", { className: "sdui-insp-chip__tools", children: [
|
|
4477
|
+
onEdit ? /* @__PURE__ */ jsx(ToolButton, { icon: "pencil", label: "\uBC14\uC778\uB529 \uD3B8\uC9D1", onClick: onEdit }) : null,
|
|
4478
|
+
onRaw ? /* @__PURE__ */ jsx(ToolButton, { icon: "square-pen", label: "JSON\uC73C\uB85C \uD3B8\uC9D1", onClick: onRaw }) : null
|
|
4479
|
+
] })
|
|
4480
|
+
] });
|
|
4481
|
+
}
|
|
4482
|
+
function FragmentRefRow({
|
|
4483
|
+
refId,
|
|
4484
|
+
pageIds,
|
|
4485
|
+
onOpenSpec
|
|
4486
|
+
}) {
|
|
4487
|
+
let body;
|
|
4488
|
+
if (typeof refId === "string" && refId !== "") {
|
|
4489
|
+
const missing = pageIds !== void 0 && !pageIds.includes(refId);
|
|
4490
|
+
body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4491
|
+
/* @__PURE__ */ jsxs("div", { className: "sdui-insp-row__head", children: [
|
|
4492
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-row__label", children: "\uCC38\uC870 \uC2A4\uD399" }),
|
|
4493
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-row__name wp-mono-xs", children: refId }),
|
|
4494
|
+
missing ? /* @__PURE__ */ jsx("span", { className: "sdui-insp-flag sdui-insp-flag--req", children: "\uC5C6\uC74C" }) : null,
|
|
4495
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-row__tools", children: onOpenSpec ? /* @__PURE__ */ jsx(
|
|
4496
|
+
ToolButton,
|
|
4497
|
+
{
|
|
4498
|
+
icon: "external-link",
|
|
4499
|
+
label: `${refId} \uD3B8\uC9D1\uC73C\uB85C \uC5F4\uAE30`,
|
|
4500
|
+
text: "\uC5F4\uAE30",
|
|
4501
|
+
onClick: () => onOpenSpec(refId)
|
|
4502
|
+
}
|
|
4503
|
+
) : null })
|
|
4504
|
+
] }),
|
|
4505
|
+
missing ? /* @__PURE__ */ jsx("p", { className: "sdui-insp-row__warn", children: "\uC800\uC7A5\uC18C\uC5D0 \uC5C6\uB294 \uC2A4\uD399 id\uC785\uB2C8\uB2E4 \u2014 \uC774\uB300\uB85C \uC800\uC7A5\uD558\uBA74 \uC774 \uC790\uB9AC\uB294 \uD654\uBA74\uC5D0 \uADF8\uB824\uC9C0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC5F4\uAE30\uB97C \uB204\uB974\uBA74 \uD3B8\uC9D1 \uD654\uBA74\uC5D0\uC11C \uAC19\uC740 id\uB85C \uC0C8\uB85C \uB9CC\uB4E4 \uC218 \uC788\uC2B5\uB2C8\uB2E4." }) : /* @__PURE__ */ jsx("p", { className: "sdui-insp-row__desc", children: "\uC774 \uC870\uAC01\uC758 \uB0B4\uC6A9\uC740 \uC800 \uC2A4\uD399\uC758 body\uC785\uB2C8\uB2E4. \uD3B8\uC9D1\uC73C\uB85C \uC5F4\uC5B4\uB3C4 \uC9C0\uAE08 \uBB38\uC11C\uC758 \uBBF8\uC800\uC7A5 \uBCC0\uACBD\uC740 \uCD08\uC548\uC73C\uB85C \uB0A8\uC2B5\uB2C8\uB2E4." })
|
|
4506
|
+
] });
|
|
4507
|
+
} else if (isPlainObject4(refId)) {
|
|
4508
|
+
body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4509
|
+
/* @__PURE__ */ jsxs("div", { className: "sdui-insp-row__head", children: [
|
|
4510
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-row__label", children: "\uCC38\uC870 \uC2A4\uD399" }),
|
|
4511
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-flag sdui-insp-flag--unknown", children: "\uB3D9\uC801 \uCC38\uC870" })
|
|
4512
|
+
] }),
|
|
4513
|
+
/* @__PURE__ */ jsxs("p", { className: "sdui-insp-row__desc", children: [
|
|
4514
|
+
"id\uAC00 \uBC14\uC778\uB529(",
|
|
4515
|
+
Object.keys(refId)[0] ?? "$state",
|
|
4516
|
+
")\uC73C\uB85C \uC815\uD574\uC9D1\uB2C8\uB2E4 \u2014 \uC2E4\uD589 \uC2DC\uC810 \uAC12\uC774\uB77C \uD3B8\uC9D1\uAE30\uC5D0\uC11C \uC5F4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uAC12\uC740 \uC704 id \uD504\uB86D\uC5D0\uC11C \uD655\uC778\uD558\uC138\uC694."
|
|
4517
|
+
] })
|
|
4518
|
+
] });
|
|
4519
|
+
} else {
|
|
4520
|
+
body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4521
|
+
/* @__PURE__ */ jsxs("div", { className: "sdui-insp-row__head", children: [
|
|
4522
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-row__label", children: "\uCC38\uC870 \uC2A4\uD399" }),
|
|
4523
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-insp-flag sdui-insp-flag--req", children: "\uD544\uC218" })
|
|
4524
|
+
] }),
|
|
4525
|
+
/* @__PURE__ */ jsx("p", { className: "sdui-insp-row__warn", children: "id \uD504\uB86D\uC774 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uAC00\uC838\uC62C \uC2A4\uD399\uC758 id(\uC608: dialogs/asset-edit)\uB97C \uB123\uC5B4\uC57C \uB80C\uB354\uB429\uB2C8\uB2E4." })
|
|
4526
|
+
] });
|
|
4527
|
+
}
|
|
4528
|
+
return /* @__PURE__ */ jsx("section", { className: "sdui-insp-group", children: /* @__PURE__ */ jsx("div", { className: "sdui-insp-group__body", children: /* @__PURE__ */ jsx("div", { className: "sdui-insp-row", children: body }) }) });
|
|
4092
4529
|
}
|
|
4093
4530
|
var CSS2 = `
|
|
4094
4531
|
.sdui-insp {
|
|
@@ -4221,209 +4658,41 @@ var CSS2 = `
|
|
|
4221
4658
|
border: var(--wp-border-w) solid var(--wp-border-subtle); border-radius: var(--wp-radius-md);
|
|
4222
4659
|
background: var(--wp-surface-sunken);
|
|
4223
4660
|
}
|
|
4224
|
-
.sdui-insp-item__head {
|
|
4225
|
-
display: flex; align-items: center; gap: var(--wp-space-1);
|
|
4226
|
-
padding: var(--wp-space-1) var(--wp-space-2);
|
|
4227
|
-
}
|
|
4228
|
-
.sdui-insp-item__idx {
|
|
4229
|
-
font-family: var(--wp-font-mono); font-size: var(--wp-size-2xs); color: var(--wp-text-subtle);
|
|
4230
|
-
}
|
|
4231
|
-
.sdui-insp-item__sum {
|
|
4232
|
-
font-size: var(--wp-size-2xs); color: var(--wp-text-muted);
|
|
4233
|
-
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
4234
|
-
}
|
|
4235
|
-
.sdui-insp-item__tools { margin-left: auto; display: flex; gap: 0; flex: none; }
|
|
4236
|
-
.sdui-insp-item__body {
|
|
4237
|
-
display: flex; flex-direction: column; gap: var(--wp-space-2);
|
|
4238
|
-
padding: var(--wp-space-2); padding-top: 0;
|
|
4239
|
-
}
|
|
4240
|
-
/* \uBA38\uB9AC \uC5C6\uC774 \uBAB8\uD1B5\uB9CC \uC788\uB294 \uC0C1\uC790(\uD544\uB4DC \uC815\uC758\uAC00 \uC788\uB294 object \uD504\uB86D) \u2014 \uC704\uCABD \uC5EC\uBC31\uC744 \uB418\uC0B4\uB9B0\uB2E4 */
|
|
4241
|
-
.sdui-insp-item__body--solo { padding-top: var(--wp-space-2); }
|
|
4242
|
-
.sdui-insp-struct__add { align-self: flex-start; }
|
|
4243
|
-
|
|
4244
|
-
/* ---------- JSON \uC6D0\uC2DC \uD3B8\uC9D1 ---------- */
|
|
4245
|
-
.sdui-insp-json {
|
|
4246
|
-
width: 100%; min-height: calc(var(--wp-space-8) * 2); resize: vertical;
|
|
4247
|
-
font-family: var(--wp-font-mono); font-size: var(--wp-size-2xs);
|
|
4248
|
-
line-height: var(--wp-leading-snug);
|
|
4249
|
-
padding: var(--wp-space-2);
|
|
4250
|
-
border: var(--wp-border-w) solid var(--wp-border-default); border-radius: var(--wp-radius-md);
|
|
4251
|
-
background: var(--wp-surface-card); color: var(--wp-text-default);
|
|
4252
|
-
}
|
|
4253
|
-
.sdui-insp-json:focus { outline: none; border-color: var(--wp-border-focus); }
|
|
4254
|
-
.sdui-insp-json--bad { border-color: var(--wp-border-danger); }
|
|
4255
|
-
.sdui-insp-err { font-size: var(--wp-size-2xs); color: var(--wp-text-danger); }
|
|
4256
|
-
`;
|
|
4257
|
-
function InspectorStyle() {
|
|
4258
|
-
return /* @__PURE__ */ jsx("style", { href: "sdui-editor-inspector", precedence: "medium", children: CSS2 });
|
|
4259
|
-
}
|
|
4260
|
-
function ToolButton({
|
|
4261
|
-
icon,
|
|
4262
|
-
label,
|
|
4263
|
-
onClick,
|
|
4264
|
-
disabled,
|
|
4265
|
-
active: active2,
|
|
4266
|
-
text
|
|
4267
|
-
}) {
|
|
4268
|
-
return /* @__PURE__ */ jsxs(
|
|
4269
|
-
"button",
|
|
4270
|
-
{
|
|
4271
|
-
type: "button",
|
|
4272
|
-
className: `sdui-insp-tool${active2 ? " sdui-insp-tool--on" : ""}`,
|
|
4273
|
-
onClick,
|
|
4274
|
-
disabled,
|
|
4275
|
-
title: label,
|
|
4276
|
-
"aria-label": label,
|
|
4277
|
-
children: [
|
|
4278
|
-
/* @__PURE__ */ jsx(Icon, { name: icon, size: 14 }),
|
|
4279
|
-
text ? /* @__PURE__ */ jsx("span", { children: text }) : null
|
|
4280
|
-
]
|
|
4281
|
-
}
|
|
4282
|
-
);
|
|
4283
|
-
}
|
|
4284
|
-
function textCommitValue(raw, meta) {
|
|
4285
|
-
return raw === "" && !meta?.required ? void 0 : raw;
|
|
4286
|
-
}
|
|
4287
|
-
function TextWidget({ value, onChange, meta, stateKeys }) {
|
|
4288
|
-
const listId = useId();
|
|
4289
|
-
const suggest = stateKeys && stateKeys.length > 0;
|
|
4290
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4291
|
-
/* @__PURE__ */ jsx(
|
|
4292
|
-
Input,
|
|
4293
|
-
{
|
|
4294
|
-
size: "sm",
|
|
4295
|
-
value: typeof value === "string" ? value : formatScalar(value),
|
|
4296
|
-
placeholder: meta?.default !== void 0 ? `\uAE30\uBCF8\uAC12: ${formatScalar(meta.default)}` : void 0,
|
|
4297
|
-
list: suggest ? listId : void 0,
|
|
4298
|
-
onChange: (e) => onChange(textCommitValue(e.target.value, meta))
|
|
4299
|
-
}
|
|
4300
|
-
),
|
|
4301
|
-
suggest ? /* @__PURE__ */ jsx("datalist", { id: listId, children: stateKeys.slice(0, 200).map((key) => /* @__PURE__ */ jsx("option", { value: key }, key)) }) : null
|
|
4302
|
-
] });
|
|
4303
|
-
}
|
|
4304
|
-
function NumberWidget({ value, onChange, meta }) {
|
|
4305
|
-
const external = formatScalar(value);
|
|
4306
|
-
const [text, setText2] = useState(external);
|
|
4307
|
-
const mine = useRef(external);
|
|
4308
|
-
useEffect(() => {
|
|
4309
|
-
if (external !== mine.current) {
|
|
4310
|
-
mine.current = external;
|
|
4311
|
-
setText2(external);
|
|
4312
|
-
}
|
|
4313
|
-
}, [external]);
|
|
4314
|
-
return /* @__PURE__ */ jsx(
|
|
4315
|
-
Input,
|
|
4316
|
-
{
|
|
4317
|
-
size: "sm",
|
|
4318
|
-
inputMode: "decimal",
|
|
4319
|
-
value: text,
|
|
4320
|
-
placeholder: meta?.default !== void 0 ? `\uAE30\uBCF8\uAC12: ${formatScalar(meta.default)}` : void 0,
|
|
4321
|
-
onChange: (e) => {
|
|
4322
|
-
const next = e.target.value;
|
|
4323
|
-
setText2(next);
|
|
4324
|
-
const parsed = parseNumber(next);
|
|
4325
|
-
if (parsed === null) return;
|
|
4326
|
-
mine.current = formatScalar(parsed);
|
|
4327
|
-
onChange(parsed);
|
|
4328
|
-
}
|
|
4329
|
-
}
|
|
4330
|
-
);
|
|
4331
|
-
}
|
|
4332
|
-
function BoolWidget({ value, onChange, meta }) {
|
|
4333
|
-
const on = value === true;
|
|
4334
|
-
return /* @__PURE__ */ jsx(
|
|
4335
|
-
Switch,
|
|
4336
|
-
{
|
|
4337
|
-
size: "sm",
|
|
4338
|
-
checked: on,
|
|
4339
|
-
label: on ? "\uCF2C" : "\uB054",
|
|
4340
|
-
onChange: (e) => {
|
|
4341
|
-
if (e.target.checked) onChange(true);
|
|
4342
|
-
else onChange(meta?.default === true ? false : void 0);
|
|
4343
|
-
}
|
|
4344
|
-
}
|
|
4345
|
-
);
|
|
4661
|
+
.sdui-insp-item__head {
|
|
4662
|
+
display: flex; align-items: center; gap: var(--wp-space-1);
|
|
4663
|
+
padding: var(--wp-space-1) var(--wp-space-2);
|
|
4346
4664
|
}
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
const options = meta?.options ?? [];
|
|
4350
|
-
const known = options.findIndex((o) => o.value === value);
|
|
4351
|
-
const outsider = value !== void 0 && known < 0;
|
|
4352
|
-
const choices = options.map((option, index) => ({
|
|
4353
|
-
value: String(index),
|
|
4354
|
-
label: option.legacy ? `${option.label} (\uC61B \uAC12)` : option.label
|
|
4355
|
-
}));
|
|
4356
|
-
if (outsider) choices.push({ value: CURRENT, label: `${formatScalar(value)} (\uD6C4\uBCF4 \uBC16)` });
|
|
4357
|
-
return /* @__PURE__ */ jsx(
|
|
4358
|
-
Select,
|
|
4359
|
-
{
|
|
4360
|
-
size: "sm",
|
|
4361
|
-
options: choices,
|
|
4362
|
-
placeholder: meta?.default !== void 0 ? `\uAE30\uBCF8\uAC12: ${labelOf(options, meta.default)}` : "(\uC5C6\uC74C)",
|
|
4363
|
-
value: outsider ? CURRENT : known >= 0 ? String(known) : "",
|
|
4364
|
-
onChange: (e) => {
|
|
4365
|
-
const raw = e.target.value;
|
|
4366
|
-
if (raw === "") onChange(void 0);
|
|
4367
|
-
else if (raw === CURRENT) onChange(value);
|
|
4368
|
-
else onChange(options[Number(raw)]?.value);
|
|
4369
|
-
}
|
|
4370
|
-
}
|
|
4371
|
-
);
|
|
4665
|
+
.sdui-insp-item__idx {
|
|
4666
|
+
font-family: var(--wp-font-mono); font-size: var(--wp-size-2xs); color: var(--wp-text-subtle);
|
|
4372
4667
|
}
|
|
4373
|
-
|
|
4374
|
-
|
|
4668
|
+
.sdui-insp-item__sum {
|
|
4669
|
+
font-size: var(--wp-size-2xs); color: var(--wp-text-muted);
|
|
4670
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
4375
4671
|
}
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
const mine = useRef(external);
|
|
4381
|
-
useEffect(() => {
|
|
4382
|
-
if (external !== mine.current) {
|
|
4383
|
-
mine.current = external;
|
|
4384
|
-
setText2(external);
|
|
4385
|
-
setError(null);
|
|
4386
|
-
}
|
|
4387
|
-
}, [external]);
|
|
4388
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4389
|
-
/* @__PURE__ */ jsx(
|
|
4390
|
-
"textarea",
|
|
4391
|
-
{
|
|
4392
|
-
className: `sdui-insp-json${error ? " sdui-insp-json--bad" : ""}`,
|
|
4393
|
-
rows,
|
|
4394
|
-
spellCheck: false,
|
|
4395
|
-
value: text,
|
|
4396
|
-
onChange: (e) => {
|
|
4397
|
-
const next = e.target.value;
|
|
4398
|
-
setText2(next);
|
|
4399
|
-
const parsed = parseJson(next);
|
|
4400
|
-
if (!parsed.ok) {
|
|
4401
|
-
setError(parsed.error ?? "JSON\uC744 \uC77D\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
|
|
4402
|
-
return;
|
|
4403
|
-
}
|
|
4404
|
-
setError(null);
|
|
4405
|
-
mine.current = toJsonText(parsed.value);
|
|
4406
|
-
onChange(parsed.value);
|
|
4407
|
-
}
|
|
4408
|
-
}
|
|
4409
|
-
),
|
|
4410
|
-
error ? /* @__PURE__ */ jsx("p", { className: "sdui-insp-err", children: error }) : null
|
|
4411
|
-
] });
|
|
4672
|
+
.sdui-insp-item__tools { margin-left: auto; display: flex; gap: 0; flex: none; }
|
|
4673
|
+
.sdui-insp-item__body {
|
|
4674
|
+
display: flex; flex-direction: column; gap: var(--wp-space-2);
|
|
4675
|
+
padding: var(--wp-space-2); padding-top: 0;
|
|
4412
4676
|
}
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4677
|
+
/* \uBA38\uB9AC \uC5C6\uC774 \uBAB8\uD1B5\uB9CC \uC788\uB294 \uC0C1\uC790(\uD544\uB4DC \uC815\uC758\uAC00 \uC788\uB294 object \uD504\uB86D) \u2014 \uC704\uCABD \uC5EC\uBC31\uC744 \uB418\uC0B4\uB9B0\uB2E4 */
|
|
4678
|
+
.sdui-insp-item__body--solo { padding-top: var(--wp-space-2); }
|
|
4679
|
+
.sdui-insp-struct__add { align-self: flex-start; }
|
|
4680
|
+
|
|
4681
|
+
/* ---------- JSON \uC6D0\uC2DC \uD3B8\uC9D1 ---------- */
|
|
4682
|
+
.sdui-insp-json {
|
|
4683
|
+
width: 100%; min-height: calc(var(--wp-space-8) * 2); resize: vertical;
|
|
4684
|
+
font-family: var(--wp-font-mono); font-size: var(--wp-size-2xs);
|
|
4685
|
+
line-height: var(--wp-leading-snug);
|
|
4686
|
+
padding: var(--wp-space-2);
|
|
4687
|
+
border: var(--wp-border-w) solid var(--wp-border-default); border-radius: var(--wp-radius-md);
|
|
4688
|
+
background: var(--wp-surface-card); color: var(--wp-text-default);
|
|
4689
|
+
}
|
|
4690
|
+
.sdui-insp-json:focus { outline: none; border-color: var(--wp-border-focus); }
|
|
4691
|
+
.sdui-insp-json--bad { border-color: var(--wp-border-danger); }
|
|
4692
|
+
.sdui-insp-err { font-size: var(--wp-size-2xs); color: var(--wp-text-danger); }
|
|
4693
|
+
`;
|
|
4694
|
+
function InspectorStyle() {
|
|
4695
|
+
return /* @__PURE__ */ jsx("style", { href: "sdui-editor-inspector", precedence: "medium", children: CSS2 });
|
|
4427
4696
|
}
|
|
4428
4697
|
function ActionField({ value, onChange, stateKeys }) {
|
|
4429
4698
|
const wasArray = Array.isArray(value);
|
|
@@ -4916,7 +5185,15 @@ function LiteralEditor({ meta, value, onChange, ctx, propName }) {
|
|
|
4916
5185
|
const kind = meta.kind;
|
|
4917
5186
|
switch (kind) {
|
|
4918
5187
|
case "string":
|
|
4919
|
-
return /* @__PURE__ */ jsx(
|
|
5188
|
+
return /* @__PURE__ */ jsx(
|
|
5189
|
+
TextWidget,
|
|
5190
|
+
{
|
|
5191
|
+
value,
|
|
5192
|
+
onChange,
|
|
5193
|
+
meta,
|
|
5194
|
+
stateKeys: propName ? ctx.textSuggestions?.[propName] : void 0
|
|
5195
|
+
}
|
|
5196
|
+
);
|
|
4920
5197
|
case "number":
|
|
4921
5198
|
return /* @__PURE__ */ jsx(NumberWidget, { value, onChange, meta });
|
|
4922
5199
|
case "boolean":
|
|
@@ -5143,6 +5420,8 @@ function Inspector({
|
|
|
5143
5420
|
onApply,
|
|
5144
5421
|
onRequestBinding,
|
|
5145
5422
|
allowKeyEdit = true,
|
|
5423
|
+
pageIds,
|
|
5424
|
+
onOpenSpec,
|
|
5146
5425
|
className
|
|
5147
5426
|
}) {
|
|
5148
5427
|
const primary = selection.primary;
|
|
@@ -5151,9 +5430,17 @@ function Inspector({
|
|
|
5151
5430
|
const index = buildStateKeyIndex(doc);
|
|
5152
5431
|
return suggestStateKeys(index, "", 200).map((entry) => entry.key);
|
|
5153
5432
|
}, [doc]);
|
|
5433
|
+
const fragmentIds = useMemo(
|
|
5434
|
+
() => child?.kind === "node" && child.component === "Fragment" && pageIds ? pageIds.filter((id) => id.startsWith(DIALOG_PREFIX)) : void 0,
|
|
5435
|
+
[child, pageIds]
|
|
5436
|
+
);
|
|
5154
5437
|
const ctx = useMemo(
|
|
5155
|
-
() => ({
|
|
5156
|
-
|
|
5438
|
+
() => ({
|
|
5439
|
+
stateKeys,
|
|
5440
|
+
...onRequestBinding ? { onRequestBinding } : {},
|
|
5441
|
+
...fragmentIds && fragmentIds.length > 0 ? { textSuggestions: { id: fragmentIds } } : {}
|
|
5442
|
+
}),
|
|
5443
|
+
[stateKeys, onRequestBinding, fragmentIds]
|
|
5157
5444
|
);
|
|
5158
5445
|
const inspection = useMemo(
|
|
5159
5446
|
() => child && child.kind === "node" ? inspectNode(child, catalog) : null,
|
|
@@ -5179,7 +5466,9 @@ function Inspector({
|
|
|
5179
5466
|
ctx,
|
|
5180
5467
|
onApply,
|
|
5181
5468
|
onRequestBinding,
|
|
5182
|
-
allowKeyEdit
|
|
5469
|
+
allowKeyEdit,
|
|
5470
|
+
pageIds,
|
|
5471
|
+
onOpenSpec
|
|
5183
5472
|
}
|
|
5184
5473
|
) : null
|
|
5185
5474
|
] })
|
|
@@ -5196,7 +5485,9 @@ function NodePanel({
|
|
|
5196
5485
|
ctx,
|
|
5197
5486
|
onApply,
|
|
5198
5487
|
onRequestBinding,
|
|
5199
|
-
allowKeyEdit
|
|
5488
|
+
allowKeyEdit,
|
|
5489
|
+
pageIds,
|
|
5490
|
+
onOpenSpec
|
|
5200
5491
|
}) {
|
|
5201
5492
|
const open = useMemo(() => initialOpenGroups(inspection), [inspection]);
|
|
5202
5493
|
const apply = (name, next, meta) => {
|
|
@@ -5243,6 +5534,7 @@ function NodePanel({
|
|
|
5243
5534
|
},
|
|
5244
5535
|
`${node.id}:${group.key}`
|
|
5245
5536
|
)),
|
|
5537
|
+
node.component === "Fragment" ? /* @__PURE__ */ jsx(FragmentRefRow, { refId: node.props.id, pageIds, onOpenSpec }) : null,
|
|
5246
5538
|
inspection.unknown.length > 0 ? /* @__PURE__ */ jsx(UnknownSection, { entries: inspection.unknown, ctx, onChange: apply }) : null,
|
|
5247
5539
|
allowKeyEdit ? /* @__PURE__ */ jsx(KeyRow, { doc, node, onApply }) : null
|
|
5248
5540
|
] });
|
|
@@ -5624,10 +5916,10 @@ function indexChildren(doc) {
|
|
|
5624
5916
|
function logicHint(node) {
|
|
5625
5917
|
const condition = node.props.when ?? node.props.source;
|
|
5626
5918
|
if (typeof condition === "string") return condition;
|
|
5627
|
-
if (
|
|
5919
|
+
if (isPlainObject5(condition)) {
|
|
5628
5920
|
if (typeof condition.$state === "string") return `{${condition.$state}}`;
|
|
5629
5921
|
if (typeof condition.$item === "string") return `{\uD589.${condition.$item}}`;
|
|
5630
|
-
if (
|
|
5922
|
+
if (isPlainObject5(condition.$calc) && typeof condition.$calc.op === "string") {
|
|
5631
5923
|
return `{\uACC4\uC0B0:${condition.$calc.op}}`;
|
|
5632
5924
|
}
|
|
5633
5925
|
}
|
|
@@ -5638,7 +5930,7 @@ function logicHint(node) {
|
|
|
5638
5930
|
}
|
|
5639
5931
|
return void 0;
|
|
5640
5932
|
}
|
|
5641
|
-
function
|
|
5933
|
+
function isPlainObject5(v) {
|
|
5642
5934
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
5643
5935
|
}
|
|
5644
5936
|
function childCount(child) {
|
|
@@ -5720,7 +6012,7 @@ function buildRows(doc, options) {
|
|
|
5720
6012
|
}
|
|
5721
6013
|
|
|
5722
6014
|
// src/builder/tree/search.ts
|
|
5723
|
-
function
|
|
6015
|
+
function isPlainObject6(v) {
|
|
5724
6016
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
5725
6017
|
}
|
|
5726
6018
|
function collectBindings(value, out) {
|
|
@@ -5728,10 +6020,10 @@ function collectBindings(value, out) {
|
|
|
5728
6020
|
for (const item of value) collectBindings(item, out);
|
|
5729
6021
|
return;
|
|
5730
6022
|
}
|
|
5731
|
-
if (!
|
|
6023
|
+
if (!isPlainObject6(value)) return;
|
|
5732
6024
|
if (typeof value.$state === "string") out.push(value.$state);
|
|
5733
6025
|
if (typeof value.$item === "string") out.push(value.$item);
|
|
5734
|
-
if (
|
|
6026
|
+
if (isPlainObject6(value.$calc) && typeof value.$calc.op === "string") out.push(value.$calc.op);
|
|
5735
6027
|
if (typeof value.action === "string") out.push(value.action);
|
|
5736
6028
|
if (typeof value.key === "string") out.push(value.key);
|
|
5737
6029
|
if (typeof value.form === "string") out.push(value.form);
|
|
@@ -5746,7 +6038,7 @@ function collectLiterals(value, out) {
|
|
|
5746
6038
|
for (const item of value) collectLiterals(item, out);
|
|
5747
6039
|
return;
|
|
5748
6040
|
}
|
|
5749
|
-
if (!
|
|
6041
|
+
if (!isPlainObject6(value)) return;
|
|
5750
6042
|
for (const [name, sub] of Object.entries(value)) {
|
|
5751
6043
|
if (name === "$state" || name === "$item" || name === "$index") continue;
|
|
5752
6044
|
collectLiterals(sub, out);
|
|
@@ -7048,33 +7340,33 @@ function HistoryBar({
|
|
|
7048
7340
|
}
|
|
7049
7341
|
|
|
7050
7342
|
// src/builder/binding/values.ts
|
|
7051
|
-
function
|
|
7343
|
+
function isPlainObject7(v) {
|
|
7052
7344
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
7053
7345
|
}
|
|
7054
7346
|
function classifyValue(value) {
|
|
7055
|
-
if (!
|
|
7347
|
+
if (!isPlainObject7(value)) return "literal";
|
|
7056
7348
|
if (typeof value.$state === "string") return "state";
|
|
7057
7349
|
if ("$item" in value) return "item";
|
|
7058
7350
|
if ("$index" in value) return "index";
|
|
7059
|
-
if (
|
|
7351
|
+
if (isPlainObject7(value.$calc)) return "calc";
|
|
7060
7352
|
return "literal";
|
|
7061
7353
|
}
|
|
7062
7354
|
function isBinding(value) {
|
|
7063
7355
|
return classifyValue(value) !== "literal";
|
|
7064
7356
|
}
|
|
7065
7357
|
function asStateRef(value) {
|
|
7066
|
-
if (classifyValue(value) !== "state" || !
|
|
7358
|
+
if (classifyValue(value) !== "state" || !isPlainObject7(value)) return null;
|
|
7067
7359
|
const out = { $state: value.$state };
|
|
7068
7360
|
if ("default" in value) out.default = value.default;
|
|
7069
7361
|
return out;
|
|
7070
7362
|
}
|
|
7071
7363
|
function asItemRef(value) {
|
|
7072
|
-
if (classifyValue(value) !== "item" || !
|
|
7364
|
+
if (classifyValue(value) !== "item" || !isPlainObject7(value)) return null;
|
|
7073
7365
|
const raw = value.$item;
|
|
7074
7366
|
return { $item: typeof raw === "string" ? raw : true };
|
|
7075
7367
|
}
|
|
7076
7368
|
function asCalc(value) {
|
|
7077
|
-
if (classifyValue(value) !== "calc" || !
|
|
7369
|
+
if (classifyValue(value) !== "calc" || !isPlainObject7(value)) return null;
|
|
7078
7370
|
const calc = value.$calc;
|
|
7079
7371
|
const out = {
|
|
7080
7372
|
op: typeof calc.op === "string" ? calc.op : "",
|
|
@@ -7349,7 +7641,7 @@ function writeActionList(list) {
|
|
|
7349
7641
|
return all;
|
|
7350
7642
|
}
|
|
7351
7643
|
function isActionObject(value) {
|
|
7352
|
-
return
|
|
7644
|
+
return isPlainObject7(value) && typeof value.action === "string";
|
|
7353
7645
|
}
|
|
7354
7646
|
function actionNameOf(action) {
|
|
7355
7647
|
return typeof action.action === "string" ? action.action : "";
|
|
@@ -7416,7 +7708,7 @@ function formatValue(value, depth = 0) {
|
|
|
7416
7708
|
if (value.length === 0) return "[]";
|
|
7417
7709
|
return `[${value.map((item) => formatValue(item, depth + 1)).join(", ")}]`;
|
|
7418
7710
|
}
|
|
7419
|
-
if (
|
|
7711
|
+
if (isPlainObject7(value)) {
|
|
7420
7712
|
const keys = Object.keys(value);
|
|
7421
7713
|
if (keys.length === 0) return "{}";
|
|
7422
7714
|
return `{ ${keys.slice(0, 3).join(", ")}${keys.length > 3 ? ", \u2026" : ""} }`;
|
|
@@ -7816,7 +8108,7 @@ function LiteralInput({
|
|
|
7816
8108
|
}
|
|
7817
8109
|
}
|
|
7818
8110
|
function effectiveKind(value, meta) {
|
|
7819
|
-
if (Array.isArray(value) ||
|
|
8111
|
+
if (Array.isArray(value) || isPlainObject7(value)) return "json";
|
|
7820
8112
|
if (typeof value === "string" && value.includes("\n")) return "multiline";
|
|
7821
8113
|
switch (meta?.kind) {
|
|
7822
8114
|
case "number":
|
|
@@ -8421,7 +8713,7 @@ function dialogKeysOf(doc, catalog) {
|
|
|
8421
8713
|
return [...found.values()].sort((a, b) => a.value.localeCompare(b.value, "ko"));
|
|
8422
8714
|
}
|
|
8423
8715
|
function gateKeyOf(when) {
|
|
8424
|
-
if (classifyValue(when) !== "state" || !
|
|
8716
|
+
if (classifyValue(when) !== "state" || !isPlainObject7(when)) return null;
|
|
8425
8717
|
const key = when.$state;
|
|
8426
8718
|
return typeof key === "string" && key ? key : null;
|
|
8427
8719
|
}
|
|
@@ -8493,7 +8785,7 @@ function visitActions(value, visit) {
|
|
|
8493
8785
|
for (const item of value) visitActions(item, visit);
|
|
8494
8786
|
return;
|
|
8495
8787
|
}
|
|
8496
|
-
if (!
|
|
8788
|
+
if (!isPlainObject7(value)) return;
|
|
8497
8789
|
if (typeof value.action !== "string") return;
|
|
8498
8790
|
visit(value);
|
|
8499
8791
|
visitActions(value.onSuccess, visit);
|
|
@@ -8550,12 +8842,12 @@ function itemFieldsOf(doc, forEachId) {
|
|
|
8550
8842
|
function sampleRowOf(source) {
|
|
8551
8843
|
const pick = (v) => {
|
|
8552
8844
|
if (!Array.isArray(v)) return null;
|
|
8553
|
-
const first = v.find((row) =>
|
|
8554
|
-
return
|
|
8845
|
+
const first = v.find((row) => isPlainObject7(row));
|
|
8846
|
+
return isPlainObject7(first) ? first : null;
|
|
8555
8847
|
};
|
|
8556
8848
|
const direct = pick(source);
|
|
8557
8849
|
if (direct) return direct;
|
|
8558
|
-
if (classifyValue(source) === "state" &&
|
|
8850
|
+
if (classifyValue(source) === "state" && isPlainObject7(source)) {
|
|
8559
8851
|
return pick(source.default);
|
|
8560
8852
|
}
|
|
8561
8853
|
return null;
|
|
@@ -8566,7 +8858,7 @@ function collectItemFields(children, out) {
|
|
|
8566
8858
|
for (const item of value) walkValue(item);
|
|
8567
8859
|
return;
|
|
8568
8860
|
}
|
|
8569
|
-
if (!
|
|
8861
|
+
if (!isPlainObject7(value)) return;
|
|
8570
8862
|
const ref = asItemRef(value);
|
|
8571
8863
|
if (ref && typeof ref.$item === "string" && ref.$item) out.add(ref.$item);
|
|
8572
8864
|
for (const [name, sub] of Object.entries(value)) {
|
|
@@ -8575,7 +8867,7 @@ function collectItemFields(children, out) {
|
|
|
8575
8867
|
}
|
|
8576
8868
|
};
|
|
8577
8869
|
const walkChild = (child) => {
|
|
8578
|
-
if (!
|
|
8870
|
+
if (!isPlainObject7(child) || child.kind !== "node") return;
|
|
8579
8871
|
const node = child;
|
|
8580
8872
|
for (const value of Object.values(node.props)) walkValue(value);
|
|
8581
8873
|
for (const list of Object.values(node.slots)) list.forEach(walkChild);
|
|
@@ -8774,7 +9066,7 @@ function ActionRow({
|
|
|
8774
9066
|
value: action,
|
|
8775
9067
|
"aria-label": "\uC561\uC158 JSON",
|
|
8776
9068
|
onChange: (next) => {
|
|
8777
|
-
if (
|
|
9069
|
+
if (isPlainObject7(next) && typeof next.action === "string") onChange(next);
|
|
8778
9070
|
}
|
|
8779
9071
|
}
|
|
8780
9072
|
)
|
|
@@ -8793,7 +9085,7 @@ function ActionRow({
|
|
|
8793
9085
|
onChange: (next) => {
|
|
8794
9086
|
const kept = { action: name };
|
|
8795
9087
|
for (const field of meta.fields) if (field.name in action) kept[field.name] = action[field.name];
|
|
8796
|
-
onChange(
|
|
9088
|
+
onChange(isPlainObject7(next) ? { ...kept, ...next } : kept);
|
|
8797
9089
|
}
|
|
8798
9090
|
}
|
|
8799
9091
|
)
|
|
@@ -8984,17 +9276,17 @@ function IndexField({
|
|
|
8984
9276
|
}
|
|
8985
9277
|
);
|
|
8986
9278
|
}
|
|
8987
|
-
function
|
|
9279
|
+
function isPlainObject8(value) {
|
|
8988
9280
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8989
9281
|
}
|
|
8990
9282
|
function canon(value) {
|
|
8991
9283
|
if (Array.isArray(value)) return value.map(canon);
|
|
8992
|
-
if (!
|
|
9284
|
+
if (!isPlainObject8(value)) return value;
|
|
8993
9285
|
const out = {};
|
|
8994
9286
|
for (const key of Object.keys(value).sort()) {
|
|
8995
9287
|
const v = value[key];
|
|
8996
9288
|
if (key === "children" && Array.isArray(v) && v.length === 0) continue;
|
|
8997
|
-
if (key === "slots" &&
|
|
9289
|
+
if (key === "slots" && isPlainObject8(v)) {
|
|
8998
9290
|
const slots = {};
|
|
8999
9291
|
for (const name of Object.keys(v).sort()) {
|
|
9000
9292
|
const list = v[name];
|
|
@@ -9019,7 +9311,7 @@ function diffPaths(a, b, path, out) {
|
|
|
9019
9311
|
a.forEach((item, i) => diffPaths(item, b[i], `${path}[${i}]`, out));
|
|
9020
9312
|
return;
|
|
9021
9313
|
}
|
|
9022
|
-
if (
|
|
9314
|
+
if (isPlainObject8(a) && isPlainObject8(b)) {
|
|
9023
9315
|
for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) {
|
|
9024
9316
|
if (out.length >= 6) return;
|
|
9025
9317
|
if (!(key in b)) out.push(`${path}.${key} \u2014 \uBE4C\uB354\uC5D0\uC11C \uC0AC\uB77C\uC9D1\uB2C8\uB2E4`);
|
|
@@ -9034,7 +9326,7 @@ function sameSpecMeaning(a, b) {
|
|
|
9034
9326
|
return JSON.stringify(canon(a)) === JSON.stringify(canon(b));
|
|
9035
9327
|
}
|
|
9036
9328
|
function builderFidelity(spec) {
|
|
9037
|
-
if (!
|
|
9329
|
+
if (!isPlainObject8(spec)) {
|
|
9038
9330
|
return {
|
|
9039
9331
|
ok: false,
|
|
9040
9332
|
issues: [
|
|
@@ -9185,6 +9477,11 @@ function BuilderView({
|
|
|
9185
9477
|
onOpenJson,
|
|
9186
9478
|
onSave,
|
|
9187
9479
|
pageIds,
|
|
9480
|
+
onOpenSpec,
|
|
9481
|
+
useSpec,
|
|
9482
|
+
previewFetch,
|
|
9483
|
+
dataArmed,
|
|
9484
|
+
canvasInitialState,
|
|
9188
9485
|
registry,
|
|
9189
9486
|
catalog,
|
|
9190
9487
|
can,
|
|
@@ -9419,7 +9716,11 @@ function BuilderView({
|
|
|
9419
9716
|
hover: state.hover,
|
|
9420
9717
|
dispatch,
|
|
9421
9718
|
registry: canvasRegistry,
|
|
9422
|
-
can
|
|
9719
|
+
can,
|
|
9720
|
+
useSpec,
|
|
9721
|
+
previewFetch,
|
|
9722
|
+
dataArmed,
|
|
9723
|
+
initialState: canvasInitialState
|
|
9423
9724
|
}
|
|
9424
9725
|
) }) : null,
|
|
9425
9726
|
showRight ? /* @__PURE__ */ jsx("div", { className: "sdui-bv__right", children: /* @__PURE__ */ jsx(
|
|
@@ -9429,7 +9730,9 @@ function BuilderView({
|
|
|
9429
9730
|
catalog: canvasCatalog,
|
|
9430
9731
|
selection: state.selection,
|
|
9431
9732
|
onApply: (change) => dispatch({ type: "apply", ...change }),
|
|
9432
|
-
onRequestBinding: setBindingProp
|
|
9733
|
+
onRequestBinding: setBindingProp,
|
|
9734
|
+
pageIds,
|
|
9735
|
+
onOpenSpec
|
|
9433
9736
|
}
|
|
9434
9737
|
) }) : null
|
|
9435
9738
|
] }),
|
|
@@ -9498,6 +9801,227 @@ function labelOf2(doc, ids, catalog) {
|
|
|
9498
9801
|
const first = ids[0] ? getNode(doc, ids[0]) : null;
|
|
9499
9802
|
return first ? describeChild(first, catalog).label : "\uB178\uB4DC";
|
|
9500
9803
|
}
|
|
9804
|
+
function PreviewSeedPanel({
|
|
9805
|
+
specId,
|
|
9806
|
+
autoSeeds,
|
|
9807
|
+
stateKeys,
|
|
9808
|
+
value,
|
|
9809
|
+
onChange,
|
|
9810
|
+
previewEntitySearch,
|
|
9811
|
+
canFetch,
|
|
9812
|
+
onClose
|
|
9813
|
+
}) {
|
|
9814
|
+
const listId = useId();
|
|
9815
|
+
const autoKeys = Object.keys(autoSeeds);
|
|
9816
|
+
const params = patternParams(specId);
|
|
9817
|
+
const patch = (next) => onChange({ ...value, ...next });
|
|
9818
|
+
const patchRow = (index, row) => patch({ manual: value.manual.map((m, i) => i === index ? { ...m, ...row } : m) });
|
|
9819
|
+
const argsBroken = (() => {
|
|
9820
|
+
if (!value.argsOn) return false;
|
|
9821
|
+
try {
|
|
9822
|
+
const parsed = JSON.parse(value.argsText);
|
|
9823
|
+
return typeof parsed !== "object" || parsed === null || Array.isArray(parsed);
|
|
9824
|
+
} catch {
|
|
9825
|
+
return true;
|
|
9826
|
+
}
|
|
9827
|
+
})();
|
|
9828
|
+
const pickEntity = (param, picked, option) => {
|
|
9829
|
+
const key = `route.${param}`;
|
|
9830
|
+
const rest = value.manual.filter((row) => row.key !== key);
|
|
9831
|
+
const labels = { ...value.entityLabels };
|
|
9832
|
+
if (picked === null) {
|
|
9833
|
+
delete labels[param];
|
|
9834
|
+
patch({ manual: rest, entityLabels: labels });
|
|
9835
|
+
return;
|
|
9836
|
+
}
|
|
9837
|
+
labels[param] = typeof option?.label === "string" ? option.label : picked;
|
|
9838
|
+
patch({
|
|
9839
|
+
manual: [...rest, { key, text: JSON.stringify(picked) }],
|
|
9840
|
+
entityLabels: labels,
|
|
9841
|
+
dataArmed: true
|
|
9842
|
+
});
|
|
9843
|
+
};
|
|
9844
|
+
const entityValueOf = (param) => {
|
|
9845
|
+
const row = value.manual.find((m) => m.key === `route.${param}`);
|
|
9846
|
+
if (!row) return "";
|
|
9847
|
+
const parsed = parseSeedValue(row.text);
|
|
9848
|
+
return typeof parsed === "string" ? parsed : String(parsed ?? "");
|
|
9849
|
+
};
|
|
9850
|
+
return /* @__PURE__ */ jsxs("div", { className: "sdui-editor-seedpanel", children: [
|
|
9851
|
+
/* @__PURE__ */ jsxs("div", { className: "sdui-editor-seedpanel__head", children: [
|
|
9852
|
+
/* @__PURE__ */ jsx("span", { className: "wp-overline", children: "\uBBF8\uB9AC\uBCF4\uAE30 \uC2DC\uB529" }),
|
|
9853
|
+
/* @__PURE__ */ jsx("span", { className: "wp-spacer" }),
|
|
9854
|
+
/* @__PURE__ */ jsx(IconButton, { icon: "x", label: "\uD328\uB110 \uB2EB\uAE30", size: "sm", onClick: onClose })
|
|
9855
|
+
] }),
|
|
9856
|
+
/* @__PURE__ */ jsx("p", { className: "sdui-editor-seedpanel__note", children: "\uC2DC\uB4DC\uB97C \uBC14\uAFB8\uBA74 \uBBF8\uB9AC\uBCF4\uAE30\uAC00 \uB2E4\uC2DC \uB9C8\uC6B4\uD2B8\uB418\uC5B4, \uBBF8\uB9AC\uBCF4\uAE30 \uC548\uC5D0\uC11C \uC785\uB825 \uC911\uC774\uB358 \uAC12\uC740 \uCD08\uAE30\uD654\uB429\uB2C8\uB2E4." }),
|
|
9857
|
+
autoKeys.length > 0 ? /* @__PURE__ */ jsxs("section", { className: "sdui-editor-seedpanel__sec", children: [
|
|
9858
|
+
/* @__PURE__ */ jsx(
|
|
9859
|
+
Switch,
|
|
9860
|
+
{
|
|
9861
|
+
size: "sm",
|
|
9862
|
+
checked: value.autoOpen,
|
|
9863
|
+
label: `\uB2E4\uC774\uC5BC\uB85C\uADF8 \uC5F4\uB9BC \uC2DC\uB529 (${autoKeys.map((k) => `${k}=true`).join(", ")})`,
|
|
9864
|
+
onChange: (e) => patch({ autoOpen: e.target.checked })
|
|
9865
|
+
}
|
|
9866
|
+
),
|
|
9867
|
+
/* @__PURE__ */ jsxs("p", { className: "sdui-editor-seedpanel__desc", children: [
|
|
9868
|
+
"\uCD5C\uC0C1\uC704 ",
|
|
9869
|
+
/* @__PURE__ */ jsx("code", { children: "Show(when: $state)" }),
|
|
9870
|
+
" \uC544\uB798\uC758 \uB2E4\uC774\uC5BC\uB85C\uADF8\uB97C \uC5F4\uC5B4 \uB461\uB2C8\uB2E4. \uB044\uBA74 \uC2E4\uC81C \uCD08\uAE30 \uC0C1\uD0DC(\uB2EB\uD798)\uB85C \uBCF4\uC785\uB2C8\uB2E4."
|
|
9871
|
+
] })
|
|
9872
|
+
] }) : null,
|
|
9873
|
+
/* @__PURE__ */ jsxs("section", { className: "sdui-editor-seedpanel__sec", children: [
|
|
9874
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-editor-seedpanel__label", children: "\uC0C1\uD0DC \uC2DC\uB4DC (\uD0A4 \u2192 \uAC12)" }),
|
|
9875
|
+
value.manual.map((row, index) => /* @__PURE__ */ jsxs("div", { className: "sdui-editor-seedpanel__row", children: [
|
|
9876
|
+
/* @__PURE__ */ jsx(
|
|
9877
|
+
Input,
|
|
9878
|
+
{
|
|
9879
|
+
size: "sm",
|
|
9880
|
+
mono: true,
|
|
9881
|
+
placeholder: "\uC0C1\uD0DC \uD0A4",
|
|
9882
|
+
value: row.key,
|
|
9883
|
+
list: stateKeys.length > 0 ? listId : void 0,
|
|
9884
|
+
onChange: (e) => patchRow(index, { key: e.target.value })
|
|
9885
|
+
}
|
|
9886
|
+
),
|
|
9887
|
+
/* @__PURE__ */ jsx(
|
|
9888
|
+
Input,
|
|
9889
|
+
{
|
|
9890
|
+
size: "sm",
|
|
9891
|
+
mono: true,
|
|
9892
|
+
placeholder: "\uAC12 (JSON \u2014 \uBABB \uC77D\uC73C\uBA74 \uBB38\uC790\uC5F4)",
|
|
9893
|
+
value: row.text,
|
|
9894
|
+
onChange: (e) => patchRow(index, { text: e.target.value })
|
|
9895
|
+
}
|
|
9896
|
+
),
|
|
9897
|
+
/* @__PURE__ */ jsx(
|
|
9898
|
+
IconButton,
|
|
9899
|
+
{
|
|
9900
|
+
icon: "trash-2",
|
|
9901
|
+
label: "\uC2DC\uB4DC \uC0AD\uC81C",
|
|
9902
|
+
size: "sm",
|
|
9903
|
+
onClick: () => patch({ manual: value.manual.filter((_, i) => i !== index) })
|
|
9904
|
+
}
|
|
9905
|
+
)
|
|
9906
|
+
] }, index)),
|
|
9907
|
+
stateKeys.length > 0 ? /* @__PURE__ */ jsx("datalist", { id: listId, children: stateKeys.map((key) => /* @__PURE__ */ jsx("option", { value: key }, key)) }) : null,
|
|
9908
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
9909
|
+
Button,
|
|
9910
|
+
{
|
|
9911
|
+
size: "xs",
|
|
9912
|
+
icon: "plus",
|
|
9913
|
+
onClick: () => patch({ manual: [...value.manual, { key: "", text: "" }] }),
|
|
9914
|
+
children: "\uC2DC\uB4DC \uCD94\uAC00"
|
|
9915
|
+
}
|
|
9916
|
+
) })
|
|
9917
|
+
] }),
|
|
9918
|
+
/* @__PURE__ */ jsxs("section", { className: "sdui-editor-seedpanel__sec", children: [
|
|
9919
|
+
/* @__PURE__ */ jsx(
|
|
9920
|
+
Switch,
|
|
9921
|
+
{
|
|
9922
|
+
size: "sm",
|
|
9923
|
+
checked: value.argsOn,
|
|
9924
|
+
label: "args \uC0D8\uD50C \uC8FC\uC785 \u2014 Fragment\uB85C \uAC10\uC2F8 \uBBF8\uB9AC\uBCF4\uAE30",
|
|
9925
|
+
onChange: (e) => patch({ argsOn: e.target.checked })
|
|
9926
|
+
}
|
|
9927
|
+
),
|
|
9928
|
+
/* @__PURE__ */ jsxs("p", { className: "sdui-editor-seedpanel__desc", children: [
|
|
9929
|
+
"\uC774 \uC2A4\uD399\uC744 ",
|
|
9930
|
+
/* @__PURE__ */ jsxs("code", { children: [
|
|
9931
|
+
'{"component":"Fragment","props":{"id":"',
|
|
9932
|
+
specId,
|
|
9933
|
+
'","args":\u2026}}'
|
|
9934
|
+
] }),
|
|
9935
|
+
"\uC73C\uB85C \uAC10\uC2FC \uC784\uC2DC \uD398\uC774\uC9C0\uB97C \uADF8\uB9BD\uB2C8\uB2E4 \u2014 \uC870\uAC01 \uC548\uC758 ",
|
|
9936
|
+
/* @__PURE__ */ jsx("code", { children: "$arg" }),
|
|
9937
|
+
"\uAC00 \uC2E4\uC81C \uACBD\uB85C\uB85C \uD480\uB9BD\uB2C8\uB2E4."
|
|
9938
|
+
] }),
|
|
9939
|
+
value.argsOn ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
9940
|
+
/* @__PURE__ */ jsx(
|
|
9941
|
+
"textarea",
|
|
9942
|
+
{
|
|
9943
|
+
className: "sdui-editor-seedpanel__json",
|
|
9944
|
+
rows: 4,
|
|
9945
|
+
spellCheck: false,
|
|
9946
|
+
value: value.argsText,
|
|
9947
|
+
onChange: (e) => patch({ argsText: e.target.value })
|
|
9948
|
+
}
|
|
9949
|
+
),
|
|
9950
|
+
argsBroken ? /* @__PURE__ */ jsx("p", { className: "sdui-editor-seedpanel__err", children: "args\uB97C \uD3C9\uBA74 \uC624\uBE0C\uC81D\uD2B8 JSON\uC73C\uB85C \uC77D\uC9C0 \uBABB\uD574 \uB798\uD37C\uB97C \uC801\uC6A9\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2014 \uC6D0\uBCF8 \uADF8\uB300\uB85C \uBBF8\uB9AC\uBD05\uB2C8\uB2E4." }) : null
|
|
9951
|
+
] }) : null
|
|
9952
|
+
] }),
|
|
9953
|
+
/* @__PURE__ */ jsxs("section", { className: "sdui-editor-seedpanel__sec", children: [
|
|
9954
|
+
/* @__PURE__ */ jsx(
|
|
9955
|
+
Switch,
|
|
9956
|
+
{
|
|
9957
|
+
size: "sm",
|
|
9958
|
+
checked: value.dataArmed,
|
|
9959
|
+
disabled: !canFetch,
|
|
9960
|
+
label: "\uC2E4\uB370\uC774\uD130 \uC870\uD68C (GET\uB9CC \uAC1C\uBC29)",
|
|
9961
|
+
onChange: (e) => patch({ dataArmed: e.target.checked })
|
|
9962
|
+
}
|
|
9963
|
+
),
|
|
9964
|
+
/* @__PURE__ */ jsx("p", { className: "sdui-editor-seedpanel__desc", children: canFetch ? "\uCF1C\uBA74 page.data\uC758 GET \uC870\uD68C\uB9CC \uD3B8\uC9D1\uC790 \uC138\uC158\uC73C\uB85C \uB098\uAC11\uB2C8\uB2E4. \uC800\uC7A5\xB7\uC0AD\uC81C\xB7\uB2E4\uC6B4\uB85C\uB4DC\xB7\uAD6C\uB3C5\uC740 \uACC4\uC18D \uCC28\uB2E8\uB418\uACE0, \uC790\uCCB4 \uC870\uD68C \uC704\uC82F(\uC6D0\uACA9 \uBAA9\uB85D \uB4F1)\uC740 sandbox \uC120\uC5B8\uC744 \uBCF4\uACE0 \uBE48 \uD45C\uB85C \uB0A8\uC2B5\uB2C8\uB2E4." : "\uD638\uC2A4\uD2B8\uAC00 previewFetch\uB97C \uC8FC\uC785\uD558\uC9C0 \uC54A\uC544 \uC774 \uD3B8\uC9D1\uAE30\uC5D0\uC11C\uB294 \uC2E4\uB370\uC774\uD130\uB97C \uBCFC \uC218 \uC5C6\uC2B5\uB2C8\uB2E4." }),
|
|
9965
|
+
params.length > 0 ? previewEntitySearch && canFetch ? params.map((param) => /* @__PURE__ */ jsxs("div", { className: "sdui-editor-seedpanel__entity", children: [
|
|
9966
|
+
/* @__PURE__ */ jsx("span", { className: "sdui-editor-seedpanel__label wp-mono-xs", children: `route.${param}` }),
|
|
9967
|
+
/* @__PURE__ */ jsx(
|
|
9968
|
+
AutocompleteField,
|
|
9969
|
+
{
|
|
9970
|
+
placeholder: `${param} \uAC80\uC0C9\uC73C\uB85C \uCC44\uC6B0\uAE30`,
|
|
9971
|
+
minChars: 1,
|
|
9972
|
+
subKey: "sublabel",
|
|
9973
|
+
value: entityValueOf(param),
|
|
9974
|
+
selectedLabel: value.entityLabels[param] ?? entityValueOf(param),
|
|
9975
|
+
search: async (keyword, signal) => (await previewEntitySearch(specId, param, keyword, signal)).map(
|
|
9976
|
+
(option) => ({ ...option })
|
|
9977
|
+
),
|
|
9978
|
+
onChange: (picked, option) => pickEntity(param, picked, option)
|
|
9979
|
+
}
|
|
9980
|
+
)
|
|
9981
|
+
] }, param)) : /* @__PURE__ */ jsxs("p", { className: "sdui-editor-seedpanel__desc", children: [
|
|
9982
|
+
`\uD328\uD134 \uD30C\uB77C\uBBF8\uD130(${params.map((p) => `{${p}}`).join(", ")})\uAC00 \uC788\uB294 \uC2A4\uD399\uC785\uB2C8\uB2E4 \u2014 `,
|
|
9983
|
+
previewEntitySearch ? "\uC2E4\uB370\uC774\uD130\uB97C \uCF1C\uBA74 \uAC80\uC0C9\uC73C\uB85C \uCC44\uC6B8 \uC218 \uC788\uC2B5\uB2C8\uB2E4." : "\uD638\uC2A4\uD2B8\uAC00 previewEntitySearch\uB97C \uC8FC\uC785\uD558\uBA74 \uAC80\uC0C9\uC73C\uB85C \uCC44\uC6B8 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uC9C0\uAE08\uC740 \uC704 \uC0C1\uD0DC \uC2DC\uB4DC\uC5D0 route.* \uD0A4\uB97C \uC9C1\uC811 \uB123\uC73C\uC138\uC694."
|
|
9984
|
+
] }) : null
|
|
9985
|
+
] })
|
|
9986
|
+
] });
|
|
9987
|
+
}
|
|
9988
|
+
function isPlainObject9(value) {
|
|
9989
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9990
|
+
}
|
|
9991
|
+
function createEditorUseSpec(store, getOverride) {
|
|
9992
|
+
const cache = /* @__PURE__ */ new Map();
|
|
9993
|
+
const waiters = /* @__PURE__ */ new Map();
|
|
9994
|
+
return function useEditorSpec(id) {
|
|
9995
|
+
const [, bump] = useReducer((n) => n + 1, 0);
|
|
9996
|
+
useEffect(() => {
|
|
9997
|
+
if (cache.has(id)) return void 0;
|
|
9998
|
+
let set = waiters.get(id);
|
|
9999
|
+
const first = !set;
|
|
10000
|
+
if (!set) {
|
|
10001
|
+
set = /* @__PURE__ */ new Set();
|
|
10002
|
+
waiters.set(id, set);
|
|
10003
|
+
}
|
|
10004
|
+
set.add(bump);
|
|
10005
|
+
if (first) {
|
|
10006
|
+
store.read(id).then((record) => {
|
|
10007
|
+
cache.set(id, record && isPlainObject9(record.spec) ? record.spec : null);
|
|
10008
|
+
}).catch(() => {
|
|
10009
|
+
cache.set(id, null);
|
|
10010
|
+
}).then(() => {
|
|
10011
|
+
const current = waiters.get(id);
|
|
10012
|
+
waiters.delete(id);
|
|
10013
|
+
current?.forEach((notify) => notify());
|
|
10014
|
+
});
|
|
10015
|
+
}
|
|
10016
|
+
return () => {
|
|
10017
|
+
waiters.get(id)?.delete(bump);
|
|
10018
|
+
};
|
|
10019
|
+
}, [id, bump]);
|
|
10020
|
+
const override = getOverride?.(id);
|
|
10021
|
+
if (override !== void 0) return override;
|
|
10022
|
+
return cache.has(id) ? cache.get(id) : void 0;
|
|
10023
|
+
};
|
|
10024
|
+
}
|
|
9501
10025
|
var PreviewBoundary = class extends React.Component {
|
|
9502
10026
|
state = { error: null };
|
|
9503
10027
|
static getDerivedStateFromError(error) {
|
|
@@ -9538,7 +10062,17 @@ function pruneKnownComponents(issues, registry) {
|
|
|
9538
10062
|
return !Object.hasOwn(registry, issue.message.slice(UNKNOWN_COMPONENT.length));
|
|
9539
10063
|
});
|
|
9540
10064
|
}
|
|
9541
|
-
function EditorView2({
|
|
10065
|
+
function EditorView2({
|
|
10066
|
+
store,
|
|
10067
|
+
id,
|
|
10068
|
+
onBack,
|
|
10069
|
+
onPreview,
|
|
10070
|
+
registry,
|
|
10071
|
+
catalog,
|
|
10072
|
+
onOpenSpec,
|
|
10073
|
+
previewFetch,
|
|
10074
|
+
previewEntitySearch
|
|
10075
|
+
}) {
|
|
9542
10076
|
const caps = store.capabilities;
|
|
9543
10077
|
const draftKey = `sdui-draft:${id}`;
|
|
9544
10078
|
const renderRegistry = registry ?? editorRegistry;
|
|
@@ -9560,6 +10094,12 @@ function EditorView2({ store, id, onBack, onPreview, registry, catalog }) {
|
|
|
9560
10094
|
const [previewKey, setPreviewKey] = useState(0);
|
|
9561
10095
|
const [previewNotice, setPreviewNotice] = useState(null);
|
|
9562
10096
|
const noticeTimer = useRef(null);
|
|
10097
|
+
const [seedSetup, setSeedSetup] = useState(INITIAL_PREVIEW_SETUP);
|
|
10098
|
+
const [seedPanelOpen, setSeedPanelOpen] = useState(false);
|
|
10099
|
+
useEffect(() => {
|
|
10100
|
+
setSeedSetup(INITIAL_PREVIEW_SETUP);
|
|
10101
|
+
setSeedPanelOpen(false);
|
|
10102
|
+
}, [id]);
|
|
9563
10103
|
const [mode, setMode] = useState("json");
|
|
9564
10104
|
const [modeNotice, setModeNotice] = useState(null);
|
|
9565
10105
|
const [builderSpec, setBuilderSpec] = useState(null);
|
|
@@ -9830,10 +10370,37 @@ function EditorView2({ store, id, onBack, onPreview, registry, catalog }) {
|
|
|
9830
10370
|
if (noticeTimer.current) clearTimeout(noticeTimer.current);
|
|
9831
10371
|
noticeTimer.current = setTimeout(() => setPreviewNotice(null), 2500);
|
|
9832
10372
|
}, []);
|
|
10373
|
+
const parsedRef = useRef(parsed);
|
|
10374
|
+
parsedRef.current = parsed;
|
|
10375
|
+
const overrideSpec = useCallback(
|
|
10376
|
+
(specId) => specId === id ? parsedRef.current.spec ?? void 0 : void 0,
|
|
10377
|
+
[id]
|
|
10378
|
+
);
|
|
10379
|
+
const useSpec = useMemo(() => createEditorUseSpec(store, overrideSpec), [store, overrideSpec]);
|
|
9833
10380
|
const previewAdapter = useMemo(
|
|
9834
|
-
() =>
|
|
9835
|
-
|
|
10381
|
+
() => resolvePreviewAdapter({
|
|
10382
|
+
armed: seedSetup.dataArmed,
|
|
10383
|
+
previewFetch,
|
|
10384
|
+
onBlocked: notifyPreview,
|
|
10385
|
+
useSpec
|
|
10386
|
+
}),
|
|
10387
|
+
[seedSetup.dataArmed, previewFetch, notifyPreview, useSpec]
|
|
9836
10388
|
);
|
|
10389
|
+
const autoSeeds = useMemo(
|
|
10390
|
+
() => isDialogSpecId(id) && parsed.spec ? dialogOpenSeeds(parsed.spec) : {},
|
|
10391
|
+
[id, parsed.spec]
|
|
10392
|
+
);
|
|
10393
|
+
const seeds = useMemo(() => seedsOf(seedSetup, autoSeeds), [seedSetup, autoSeeds]);
|
|
10394
|
+
const seededOpen = seedSetup.autoOpen && Object.keys(autoSeeds).length > 0;
|
|
10395
|
+
const previewStateKeys = useMemo(() => collectStateKeys(parsed.spec), [parsed.spec]);
|
|
10396
|
+
const previewPage = useMemo(() => {
|
|
10397
|
+
if (!parsed.spec) return null;
|
|
10398
|
+
if (seedSetup.argsOn) {
|
|
10399
|
+
const wrapped = argsWrapperPage(id, seedSetup.argsText);
|
|
10400
|
+
if (wrapped) return wrapped.page;
|
|
10401
|
+
}
|
|
10402
|
+
return parsed.spec;
|
|
10403
|
+
}, [parsed.spec, seedSetup.argsOn, seedSetup.argsText, id]);
|
|
9837
10404
|
if (!id) {
|
|
9838
10405
|
return /* @__PURE__ */ jsxs("div", { className: "sdui-editor-page sdui-base", children: [
|
|
9839
10406
|
/* @__PURE__ */ jsx(Alert, { tone: "warning", title: "\uD398\uC774\uC9C0 id\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4", children: "\uD3B8\uC9D1\uD560 \uD398\uC774\uC9C0\uB97C \uBAA9\uB85D\uC5D0\uC11C \uC120\uD0DD\uD558\uC138\uC694." }),
|
|
@@ -9945,6 +10512,11 @@ function EditorView2({ store, id, onBack, onPreview, registry, catalog }) {
|
|
|
9945
10512
|
onOpenJson: openJson,
|
|
9946
10513
|
onSave: () => void save(),
|
|
9947
10514
|
pageIds,
|
|
10515
|
+
onOpenSpec,
|
|
10516
|
+
useSpec,
|
|
10517
|
+
previewFetch,
|
|
10518
|
+
dataArmed: seedSetup.dataArmed,
|
|
10519
|
+
canvasInitialState: seeds,
|
|
9948
10520
|
registry: renderRegistry,
|
|
9949
10521
|
catalog
|
|
9950
10522
|
}
|
|
@@ -9981,18 +10553,43 @@ function EditorView2({ store, id, onBack, onPreview, registry, catalog }) {
|
|
|
9981
10553
|
/* @__PURE__ */ jsxs("div", { className: "sdui-editor-preview", children: [
|
|
9982
10554
|
/* @__PURE__ */ jsxs("div", { className: "sdui-editor-preview__head", children: [
|
|
9983
10555
|
/* @__PURE__ */ jsx("span", { className: "wp-overline", children: "\uBBF8\uB9AC\uBCF4\uAE30" }),
|
|
9984
|
-
|
|
10556
|
+
seededOpen ? /* @__PURE__ */ jsx(Badge, { tone: "brand", children: "\uC5F4\uB9BC \uC2DC\uB529" }) : null,
|
|
10557
|
+
seedSetup.dataArmed && previewFetch ? /* @__PURE__ */ jsx(Badge, { tone: "warning", children: "\uC2E4\uB370\uC774\uD130" }) : null,
|
|
10558
|
+
previewNotice ? /* @__PURE__ */ jsx("span", { className: "sdui-editor-preview__notice", children: previewNotice }) : null,
|
|
10559
|
+
/* @__PURE__ */ jsx("span", { className: "wp-spacer" }),
|
|
10560
|
+
/* @__PURE__ */ jsx(Button, { size: "xs", icon: "sliders-horizontal", onClick: () => setSeedPanelOpen((v) => !v), children: "\uC2DC\uB529" })
|
|
9985
10561
|
] }),
|
|
9986
|
-
|
|
9987
|
-
|
|
10562
|
+
seedPanelOpen ? /* @__PURE__ */ jsx(
|
|
10563
|
+
PreviewSeedPanel,
|
|
9988
10564
|
{
|
|
9989
|
-
|
|
9990
|
-
|
|
9991
|
-
|
|
9992
|
-
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
|
|
10565
|
+
specId: id,
|
|
10566
|
+
autoSeeds,
|
|
10567
|
+
stateKeys: previewStateKeys,
|
|
10568
|
+
value: seedSetup,
|
|
10569
|
+
onChange: setSeedSetup,
|
|
10570
|
+
previewEntitySearch,
|
|
10571
|
+
canFetch: previewFetch !== void 0,
|
|
10572
|
+
onClose: () => setSeedPanelOpen(false)
|
|
10573
|
+
}
|
|
10574
|
+
) : null,
|
|
10575
|
+
/* @__PURE__ */ jsx("div", { className: "sdui-editor-preview__body", children: previewPage ? /* @__PURE__ */ jsx(
|
|
10576
|
+
PreviewBoundary,
|
|
10577
|
+
{
|
|
10578
|
+
resetKey: previewKey,
|
|
10579
|
+
signature: `${debounced}:${seedSignature(seeds)}:${seedSetup.argsOn ? seedSetup.argsText : ""}`,
|
|
10580
|
+
children: /* @__PURE__ */ jsx(
|
|
10581
|
+
SduiRenderer,
|
|
10582
|
+
{
|
|
10583
|
+
page: previewPage,
|
|
10584
|
+
registry: renderRegistry,
|
|
10585
|
+
adapter: previewAdapter,
|
|
10586
|
+
initialState: seeds,
|
|
10587
|
+
syncUrlState: false
|
|
10588
|
+
},
|
|
10589
|
+
`${previewKey}:${seedSignature(seeds)}`
|
|
10590
|
+
)
|
|
10591
|
+
}
|
|
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." }) })
|
|
9996
10593
|
] }),
|
|
9997
10594
|
helpOpen ? /* @__PURE__ */ jsx(HelpPanel, { onClose: () => setHelpOpen(false) }) : null
|
|
9998
10595
|
] })
|
|
@@ -10021,7 +10618,9 @@ function ViewerView({
|
|
|
10021
10618
|
onNavigate,
|
|
10022
10619
|
registry = editorRegistry,
|
|
10023
10620
|
adapter: hostAdapter,
|
|
10024
|
-
can
|
|
10621
|
+
can,
|
|
10622
|
+
previewFetch,
|
|
10623
|
+
previewEntitySearch
|
|
10025
10624
|
}) {
|
|
10026
10625
|
const [state, setState] = useState({
|
|
10027
10626
|
spec: null,
|
|
@@ -10055,9 +10654,46 @@ function ViewerView({
|
|
|
10055
10654
|
useEffect(() => () => {
|
|
10056
10655
|
if (blockedTimer.current) clearTimeout(blockedTimer.current);
|
|
10057
10656
|
}, []);
|
|
10657
|
+
const [seedSetup, setSeedSetup] = useState(INITIAL_PREVIEW_SETUP);
|
|
10658
|
+
const [seedPanelOpen, setSeedPanelOpen] = useState(false);
|
|
10659
|
+
useEffect(() => {
|
|
10660
|
+
setSeedSetup(INITIAL_PREVIEW_SETUP);
|
|
10661
|
+
setSeedPanelOpen(false);
|
|
10662
|
+
}, [id]);
|
|
10663
|
+
const autoSeeds = useMemo(
|
|
10664
|
+
() => isDialogSpecId(id) && state.spec ? dialogOpenSeeds(state.spec) : {},
|
|
10665
|
+
[id, state.spec]
|
|
10666
|
+
);
|
|
10667
|
+
const seeds = useMemo(() => seedsOf(seedSetup, autoSeeds), [seedSetup, autoSeeds]);
|
|
10668
|
+
const seededOpen = seedSetup.autoOpen && Object.keys(autoSeeds).length > 0;
|
|
10669
|
+
const previewStateKeys = useMemo(() => collectStateKeys(state.spec), [state.spec]);
|
|
10670
|
+
const viewPage = useMemo(() => {
|
|
10671
|
+
if (!state.spec) return null;
|
|
10672
|
+
if (seedSetup.argsOn) {
|
|
10673
|
+
const wrapped = argsWrapperPage(id, seedSetup.argsText);
|
|
10674
|
+
if (wrapped) return wrapped.page;
|
|
10675
|
+
}
|
|
10676
|
+
return state.spec;
|
|
10677
|
+
}, [state.spec, seedSetup.argsOn, seedSetup.argsText, id]);
|
|
10678
|
+
const specRef = useRef(state.spec);
|
|
10679
|
+
specRef.current = state.spec;
|
|
10680
|
+
const overrideSpec = useCallback(
|
|
10681
|
+
(specId) => specId === id ? specRef.current ?? void 0 : void 0,
|
|
10682
|
+
[id]
|
|
10683
|
+
);
|
|
10684
|
+
const useSpec = useMemo(() => createEditorUseSpec(store, overrideSpec), [store, overrideSpec]);
|
|
10058
10685
|
const adapter = useMemo(
|
|
10059
|
-
() => hostAdapter ?? {
|
|
10060
|
-
|
|
10686
|
+
() => hostAdapter ?? {
|
|
10687
|
+
...resolvePreviewAdapter({
|
|
10688
|
+
armed: seedSetup.dataArmed,
|
|
10689
|
+
previewFetch,
|
|
10690
|
+
onBlocked: notifyBlocked,
|
|
10691
|
+
useSpec
|
|
10692
|
+
}),
|
|
10693
|
+
navigate: onNavigate,
|
|
10694
|
+
refresh: load
|
|
10695
|
+
},
|
|
10696
|
+
[hostAdapter, notifyBlocked, onNavigate, load, seedSetup.dataArmed, previewFetch, useSpec]
|
|
10061
10697
|
);
|
|
10062
10698
|
useEffect(() => {
|
|
10063
10699
|
if (state.spec?.title) {
|
|
@@ -10076,10 +10712,26 @@ function ViewerView({
|
|
|
10076
10712
|
"/",
|
|
10077
10713
|
id
|
|
10078
10714
|
] }),
|
|
10715
|
+
seededOpen ? /* @__PURE__ */ jsx(Badge, { tone: "brand", children: "\uC5F4\uB9BC\uC744 \uC2DC\uB529\uD588\uC2B5\uB2C8\uB2E4" }) : null,
|
|
10716
|
+
seedSetup.dataArmed && previewFetch && !hostAdapter ? /* @__PURE__ */ jsx(Badge, { tone: "warning", children: "\uC2E4\uB370\uC774\uD130" }) : null,
|
|
10079
10717
|
/* @__PURE__ */ jsx("span", { className: "wp-spacer" }),
|
|
10080
10718
|
blocked ? /* @__PURE__ */ jsx("span", { className: "sdui-editor-preview__notice", children: blocked }) : null,
|
|
10719
|
+
/* @__PURE__ */ jsx(Button, { size: "sm", icon: "sliders-horizontal", onClick: () => setSeedPanelOpen((v) => !v), children: "\uC2DC\uB529" }),
|
|
10081
10720
|
/* @__PURE__ */ jsx(Button, { size: "sm", icon: "pencil", onClick: () => onEdit(id), children: "\uD3B8\uC9D1" })
|
|
10082
10721
|
] }),
|
|
10722
|
+
seedPanelOpen ? /* @__PURE__ */ jsx(
|
|
10723
|
+
PreviewSeedPanel,
|
|
10724
|
+
{
|
|
10725
|
+
specId: id,
|
|
10726
|
+
autoSeeds,
|
|
10727
|
+
stateKeys: previewStateKeys,
|
|
10728
|
+
value: seedSetup,
|
|
10729
|
+
onChange: setSeedSetup,
|
|
10730
|
+
previewEntitySearch,
|
|
10731
|
+
canFetch: previewFetch !== void 0 && !hostAdapter,
|
|
10732
|
+
onClose: () => setSeedPanelOpen(false)
|
|
10733
|
+
}
|
|
10734
|
+
) : null,
|
|
10083
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(
|
|
10084
10736
|
ViewerBoundary,
|
|
10085
10737
|
{
|
|
@@ -10103,12 +10755,14 @@ function ViewerView({
|
|
|
10103
10755
|
children: /* @__PURE__ */ jsx(
|
|
10104
10756
|
SduiRenderer,
|
|
10105
10757
|
{
|
|
10106
|
-
page: state.spec,
|
|
10758
|
+
page: viewPage ?? state.spec,
|
|
10107
10759
|
registry,
|
|
10108
10760
|
adapter,
|
|
10761
|
+
initialState: seeds,
|
|
10109
10762
|
can,
|
|
10110
10763
|
syncUrlState: false
|
|
10111
|
-
}
|
|
10764
|
+
},
|
|
10765
|
+
`${id}#${state.seq}:${seedSignature(seeds)}`
|
|
10112
10766
|
)
|
|
10113
10767
|
}
|
|
10114
10768
|
) })
|
|
@@ -10125,6 +10779,8 @@ function SduiEditor({
|
|
|
10125
10779
|
onNavigate,
|
|
10126
10780
|
viewerAdapter,
|
|
10127
10781
|
can,
|
|
10782
|
+
previewFetch,
|
|
10783
|
+
previewEntitySearch,
|
|
10128
10784
|
className
|
|
10129
10785
|
}) {
|
|
10130
10786
|
const [internal, setInternal] = useState(defaultView ?? { name: "list" });
|
|
@@ -10162,8 +10818,11 @@ function SduiEditor({
|
|
|
10162
10818
|
id: current.id,
|
|
10163
10819
|
onBack: openList,
|
|
10164
10820
|
onPreview: openPreview,
|
|
10821
|
+
onOpenSpec: openEdit,
|
|
10165
10822
|
registry,
|
|
10166
|
-
catalog
|
|
10823
|
+
catalog,
|
|
10824
|
+
previewFetch,
|
|
10825
|
+
previewEntitySearch
|
|
10167
10826
|
}
|
|
10168
10827
|
) : /* @__PURE__ */ jsx(
|
|
10169
10828
|
ViewerView,
|
|
@@ -10175,10 +10834,12 @@ function SduiEditor({
|
|
|
10175
10834
|
onEdit: openEdit,
|
|
10176
10835
|
onNavigate: navigateFromSpec,
|
|
10177
10836
|
adapter: viewerAdapter,
|
|
10178
|
-
can
|
|
10837
|
+
can,
|
|
10838
|
+
previewFetch,
|
|
10839
|
+
previewEntitySearch
|
|
10179
10840
|
}
|
|
10180
10841
|
)
|
|
10181
10842
|
] });
|
|
10182
10843
|
}
|
|
10183
10844
|
|
|
10184
|
-
export { ActionEditor, BindingEditor, BuilderView, COALESCE_WINDOW_MS, Canvas, DEFAULT_SLOT, EMPTY_SELECTION, EditorView2 as EditorView, HISTORY_LIMIT, HistoryBar, Inspector, PAGE_ID_PATTERN, PageExistsError, PageGoneError, PageIdConflictError, PageIdRejectedError, PageListView, Palette, ROOT_ID, RestSpecStore, SPEC_PAIR_FREQ, SduiEditor, StoreUnauthorizedError, StoreUnavailableError, StoreUnsupportedError, TEMPLATES, TEXT_CHILD, TreeView, VersionMismatchError, ViewerView, addressOf, ancestorIdsOf, bindingContextFor, breadcrumbOf, buildStateKeyIndex, builderFidelity, canDrop, canDropAt, canMoveTo, canRedo, canUndo, createBindingContext, createBindingSource, createEditorState, createRestSpecStore, describeChild, dropFrequency, dropTargetsAround, duplicate, editorReducer, editorRegistry, emptyDoc, flattenTree, formatAction, formatActionList, formatValue, fromPage, getChild, getNode, gradeIssues, inDocumentOrder, insert, isDescendantOf, isMultiSelection, isSelected, isTypingTarget, isValidPageId, looksLikeActionProp, move, readActionList, recommendedChildren, redoLabel, remove, replaceChild, sameInsertionPoint, sameSpecMeaning, setChildren, setNodeKey, setPageMeta, setProp, setProps, setText, slotsOf, specOf, stateKeyStatus, suggestStateKeys, titleOf, toPage, toSpec, topmost, undoLabel, useUndoRedoShortcuts, walkDoc, writeActionList };
|
|
10845
|
+
export { ActionEditor, BindingEditor, BuilderView, COALESCE_WINDOW_MS, Canvas, DEFAULT_SLOT, DIALOG_PREFIX, EMPTY_SELECTION, EditorView2 as EditorView, HISTORY_LIMIT, HistoryBar, INITIAL_PREVIEW_SETUP, Inspector, PAGE_ID_PATTERN, PageExistsError, PageGoneError, PageIdConflictError, PageIdRejectedError, PageListView, Palette, PreviewSeedPanel, ROOT_ID, RestSpecStore, SPEC_PAIR_FREQ, SduiEditor, StoreUnauthorizedError, StoreUnavailableError, StoreUnsupportedError, TEMPLATES, TEXT_CHILD, TreeView, VersionMismatchError, ViewerView, addressOf, ancestorIdsOf, argsWrapperPage, bindingContextFor, breadcrumbOf, buildStateKeyIndex, builderFidelity, canDrop, canDropAt, canMoveTo, canRedo, canUndo, collectStateKeys, createBindingContext, createBindingSource, createDataPreviewAdapter, createEditorState, createEditorUseSpec, createRestSpecStore, describeChild, dialogOpenSeeds, dropFrequency, dropTargetsAround, duplicate, editorReducer, editorRegistry, emptyDoc, flattenTree, formatAction, formatActionList, formatValue, fromPage, getChild, getNode, gradeIssues, inDocumentOrder, insert, isDescendantOf, isDialogSpecId, isMultiSelection, isSelected, isTypingTarget, isValidPageId, looksLikeActionProp, move, parseSeedValue, patternParams, readActionList, recommendedChildren, redoLabel, remove, replaceChild, resolvePreviewAdapter, sameInsertionPoint, sameSpecMeaning, seedSignature, seedsOf, setChildren, setNodeKey, setPageMeta, setProp, setProps, setText, slotsOf, specOf, stateKeyStatus, suggestStateKeys, titleOf, toPage, toSpec, topmost, undoLabel, useUndoRedoShortcuts, walkDoc, writeActionList };
|