@jxsuite/studio 0.7.0 → 0.9.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/studio.js +125373 -124927
- package/dist/studio.js.map +87 -73
- package/package.json +2 -2
- package/src/canvas/canvas-utils.js +313 -0
- package/src/editor/component-inline-edit.js +316 -0
- package/src/editor/content-inline-edit.js +220 -0
- package/src/editor/insertion-helper.js +301 -0
- package/src/editor/slash-menu.js +111 -37
- package/src/panels/block-action-bar.js +436 -0
- package/src/panels/canvas-dnd.js +165 -0
- package/src/panels/dnd.js +332 -0
- package/src/panels/editors.js +196 -0
- package/src/panels/left-panel.js +3 -2
- package/src/panels/panel-events.js +263 -0
- package/src/panels/preview-render.js +103 -0
- package/src/panels/properties-panel.js +1340 -0
- package/src/panels/pseudo-preview.js +64 -0
- package/src/panels/right-panel.js +2 -1
- package/src/panels/shared.js +74 -0
- package/src/panels/stylebook-panel.js +1052 -0
- package/src/studio.js +121 -4874
- package/src/utils/edit-display.js +197 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pseudo-state preview — extracted from studio.js (Phase 4m). When a pseudo-selector (:hover,
|
|
3
|
+
* :focus, etc.) is active in the style sidebar, force those styles onto the selected element.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { getState, getNodeAtPath } from "../store.js";
|
|
7
|
+
import { view } from "../view.js";
|
|
8
|
+
|
|
9
|
+
/** @type {any} */
|
|
10
|
+
let _ctx = null;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Initialize the pseudo-preview module.
|
|
14
|
+
*
|
|
15
|
+
* @param {{ getActivePanel: Function; findCanvasElement: Function }} ctx
|
|
16
|
+
*/
|
|
17
|
+
export function initPseudoPreview(ctx) {
|
|
18
|
+
_ctx = ctx;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function updateForcedPseudoPreview() {
|
|
22
|
+
if (view.forcedStyleTag) {
|
|
23
|
+
view.forcedStyleTag.remove();
|
|
24
|
+
view.forcedStyleTag = null;
|
|
25
|
+
}
|
|
26
|
+
if (view.forcedAttrEl) {
|
|
27
|
+
view.forcedAttrEl.removeAttribute("data-studio-forced");
|
|
28
|
+
view.forcedAttrEl = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const S = getState();
|
|
32
|
+
const sel = S.ui?.activeSelector;
|
|
33
|
+
if (!sel || !sel.startsWith(":") || !S.selection) return;
|
|
34
|
+
|
|
35
|
+
const panel = _ctx.getActivePanel();
|
|
36
|
+
if (!panel) return;
|
|
37
|
+
const el = _ctx.findCanvasElement(S.selection, panel.canvas);
|
|
38
|
+
if (!el) return;
|
|
39
|
+
|
|
40
|
+
const node = getNodeAtPath(S.document, S.selection);
|
|
41
|
+
if (!node?.style) return;
|
|
42
|
+
const activeTab = S.ui.activeMedia;
|
|
43
|
+
/** @type {any} */
|
|
44
|
+
const ctx = activeTab ? node.style[`@${activeTab}`] || {} : node.style;
|
|
45
|
+
const rules = ctx[sel];
|
|
46
|
+
if (!rules || typeof rules !== "object") return;
|
|
47
|
+
|
|
48
|
+
const cssProps = Object.entries(rules)
|
|
49
|
+
.filter(([k]) => typeof rules[k] === "string" || typeof rules[k] === "number")
|
|
50
|
+
.map(
|
|
51
|
+
([k, v]) =>
|
|
52
|
+
`${k.replace(/[A-Z]/g, (/** @type {any} */ c) => `-${c.toLowerCase()}`)}: ${v} !important`,
|
|
53
|
+
)
|
|
54
|
+
.join("; ");
|
|
55
|
+
if (!cssProps) return;
|
|
56
|
+
|
|
57
|
+
el.setAttribute("data-studio-forced", "1");
|
|
58
|
+
view.forcedAttrEl = el;
|
|
59
|
+
|
|
60
|
+
const tag = document.createElement("style");
|
|
61
|
+
tag.textContent = `[data-studio-forced] { ${cssProps} }`;
|
|
62
|
+
document.head.appendChild(tag);
|
|
63
|
+
view.forcedStyleTag = tag;
|
|
64
|
+
}
|
|
@@ -12,6 +12,7 @@ import { isCustomElementDoc } from "./signals-panel.js";
|
|
|
12
12
|
import { ensureLitState } from "./shared.js";
|
|
13
13
|
import { isColorPopoverOpen } from "../ui/color-selector.js";
|
|
14
14
|
import { renderStylePanelTemplate } from "./style-panel.js";
|
|
15
|
+
import { renderPropertiesPanelTemplate } from "./properties-panel.js";
|
|
15
16
|
|
|
16
17
|
/** @type {any} */
|
|
17
18
|
let _ctx = null;
|
|
@@ -110,7 +111,7 @@ function rightPanelTemplate() {
|
|
|
110
111
|
/** @type {any} */
|
|
111
112
|
let bodyT = nothing;
|
|
112
113
|
if (tab === "properties") {
|
|
113
|
-
bodyT = _ctx.
|
|
114
|
+
bodyT = renderPropertiesPanelTemplate({ navigateToComponent: _ctx.navigateToComponent });
|
|
114
115
|
} else if (tab === "events") {
|
|
115
116
|
bodyT = eventsSidebarTemplate(S, {
|
|
116
117
|
isCustomElementDoc: () => isCustomElementDoc(S),
|
package/src/panels/shared.js
CHANGED
|
@@ -39,3 +39,77 @@ export function ensureLitState(container) {
|
|
|
39
39
|
delete container["_$litPart$"];
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
|
|
43
|
+
export const unsafeTags = new Set(["script", "style", "link", "iframe", "object", "embed"]);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Generate a sensible default Jx node for a given tag name.
|
|
47
|
+
*
|
|
48
|
+
* @param {any} tag
|
|
49
|
+
*/
|
|
50
|
+
export function defaultDef(tag) {
|
|
51
|
+
/** @type {any} */
|
|
52
|
+
const def = { tagName: tag };
|
|
53
|
+
if (/^h[1-6]$/.test(tag)) def.textContent = "Heading";
|
|
54
|
+
else if (tag === "p") def.textContent = "Paragraph text";
|
|
55
|
+
else if (
|
|
56
|
+
tag === "span" ||
|
|
57
|
+
tag === "strong" ||
|
|
58
|
+
tag === "em" ||
|
|
59
|
+
tag === "small" ||
|
|
60
|
+
tag === "mark" ||
|
|
61
|
+
tag === "code" ||
|
|
62
|
+
tag === "abbr" ||
|
|
63
|
+
tag === "q" ||
|
|
64
|
+
tag === "sub" ||
|
|
65
|
+
tag === "sup" ||
|
|
66
|
+
tag === "time"
|
|
67
|
+
)
|
|
68
|
+
def.textContent = "Text";
|
|
69
|
+
else if (tag === "a") {
|
|
70
|
+
def.textContent = "Link";
|
|
71
|
+
def.attributes = { href: "#" };
|
|
72
|
+
} else if (tag === "button") def.textContent = "Button";
|
|
73
|
+
else if (tag === "label") def.textContent = "Label";
|
|
74
|
+
else if (tag === "legend") def.textContent = "Legend";
|
|
75
|
+
else if (tag === "caption") def.textContent = "Caption";
|
|
76
|
+
else if (tag === "summary") def.textContent = "Summary";
|
|
77
|
+
else if (
|
|
78
|
+
tag === "li" ||
|
|
79
|
+
tag === "dt" ||
|
|
80
|
+
tag === "dd" ||
|
|
81
|
+
tag === "th" ||
|
|
82
|
+
tag === "td" ||
|
|
83
|
+
tag === "option"
|
|
84
|
+
)
|
|
85
|
+
def.textContent = "Item";
|
|
86
|
+
else if (tag === "blockquote") def.textContent = "Quote";
|
|
87
|
+
else if (tag === "pre") def.textContent = "Preformatted text";
|
|
88
|
+
else if (tag === "input") def.attributes = { type: "text", placeholder: "Enter text..." };
|
|
89
|
+
else if (tag === "img") def.attributes = { src: "", alt: "Image" };
|
|
90
|
+
else if (tag === "iframe") def.attributes = { src: "" };
|
|
91
|
+
else if (tag === "select") def.children = [{ tagName: "option", textContent: "Option 1" }];
|
|
92
|
+
else if (tag === "ul" || tag === "ol") def.children = [{ tagName: "li", textContent: "Item" }];
|
|
93
|
+
else if (tag === "dl")
|
|
94
|
+
def.children = [
|
|
95
|
+
{ tagName: "dt", textContent: "Term" },
|
|
96
|
+
{ tagName: "dd", textContent: "Definition" },
|
|
97
|
+
];
|
|
98
|
+
else if (tag === "table")
|
|
99
|
+
def.children = [
|
|
100
|
+
{
|
|
101
|
+
tagName: "thead",
|
|
102
|
+
children: [{ tagName: "tr", children: [{ tagName: "th", textContent: "Header" }] }],
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
tagName: "tbody",
|
|
106
|
+
children: [{ tagName: "tr", children: [{ tagName: "td", textContent: "Cell" }] }],
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
else if (tag === "details")
|
|
110
|
+
def.children = [
|
|
111
|
+
{ tagName: "summary", textContent: "Summary" },
|
|
112
|
+
{ tagName: "p", textContent: "Detail content" },
|
|
113
|
+
];
|
|
114
|
+
return def;
|
|
115
|
+
}
|