@upstart.gg/vite-plugins 0.0.37
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/vite-plugin-upstart-attrs.d.ts +29 -0
- package/dist/vite-plugin-upstart-attrs.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-attrs.js +323 -0
- package/dist/vite-plugin-upstart-attrs.js.map +1 -0
- package/dist/vite-plugin-upstart-editor/plugin.d.ts +15 -0
- package/dist/vite-plugin-upstart-editor/plugin.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-editor/plugin.js +55 -0
- package/dist/vite-plugin-upstart-editor/plugin.js.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/click-handler.d.ts +12 -0
- package/dist/vite-plugin-upstart-editor/runtime/click-handler.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/click-handler.js +57 -0
- package/dist/vite-plugin-upstart-editor/runtime/click-handler.js.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/hover-overlay.d.ts +12 -0
- package/dist/vite-plugin-upstart-editor/runtime/hover-overlay.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/hover-overlay.js +91 -0
- package/dist/vite-plugin-upstart-editor/runtime/hover-overlay.js.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/index.d.ts +22 -0
- package/dist/vite-plugin-upstart-editor/runtime/index.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/index.js +62 -0
- package/dist/vite-plugin-upstart-editor/runtime/index.js.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/text-editor.d.ts +15 -0
- package/dist/vite-plugin-upstart-editor/runtime/text-editor.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/text-editor.js +292 -0
- package/dist/vite-plugin-upstart-editor/runtime/text-editor.js.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/types.d.ts +126 -0
- package/dist/vite-plugin-upstart-editor/runtime/types.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/types.js +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/utils.d.ts +15 -0
- package/dist/vite-plugin-upstart-editor/runtime/utils.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-editor/runtime/utils.js +26 -0
- package/dist/vite-plugin-upstart-editor/runtime/utils.js.map +1 -0
- package/dist/vite-plugin-upstart-theme.d.ts +22 -0
- package/dist/vite-plugin-upstart-theme.d.ts.map +1 -0
- package/dist/vite-plugin-upstart-theme.js +179 -0
- package/dist/vite-plugin-upstart-theme.js.map +1 -0
- package/package.json +63 -0
- package/src/tests/fixtures/routes/default-layout.tsx +10 -0
- package/src/tests/fixtures/routes/dynamic-route.tsx +10 -0
- package/src/tests/fixtures/routes/missing-attributes.tsx +8 -0
- package/src/tests/fixtures/routes/missing-path.tsx +9 -0
- package/src/tests/fixtures/routes/valid-full.tsx +15 -0
- package/src/tests/fixtures/routes/valid-minimal.tsx +10 -0
- package/src/tests/fixtures/routes/with-comments.tsx +12 -0
- package/src/tests/fixtures/routes/with-nested-objects.tsx +15 -0
- package/src/tests/upstart-editor-api.test.ts +367 -0
- package/src/tests/vite-plugin-upstart-attrs.test.ts +1189 -0
- package/src/tests/vite-plugin-upstart-editor.test.ts +81 -0
- package/src/upstart-editor-api.ts +204 -0
- package/src/vite-plugin-upstart-attrs.ts +708 -0
- package/src/vite-plugin-upstart-editor/PLAN.md +1391 -0
- package/src/vite-plugin-upstart-editor/plugin.ts +73 -0
- package/src/vite-plugin-upstart-editor/runtime/click-handler.ts +80 -0
- package/src/vite-plugin-upstart-editor/runtime/hover-overlay.ts +135 -0
- package/src/vite-plugin-upstart-editor/runtime/index.ts +90 -0
- package/src/vite-plugin-upstart-editor/runtime/text-editor.ts +401 -0
- package/src/vite-plugin-upstart-editor/runtime/types.ts +120 -0
- package/src/vite-plugin-upstart-editor/runtime/utils.ts +34 -0
- package/src/vite-plugin-upstart-theme.ts +314 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { createUnplugin } from "unplugin";
|
|
4
|
+
import type { UpstartEditorPluginOptions } from "./runtime/types.js";
|
|
5
|
+
|
|
6
|
+
const DEFAULT_OPTIONS: Required<UpstartEditorPluginOptions> = {
|
|
7
|
+
enabled: false,
|
|
8
|
+
autoInject: true,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Upstart Visual Editor Vite plugin (build-time)
|
|
13
|
+
*
|
|
14
|
+
* Injects the editor runtime into the app entry during build.
|
|
15
|
+
*/
|
|
16
|
+
export const upstartEditor = createUnplugin<UpstartEditorPluginOptions>((options = {}) => {
|
|
17
|
+
const { enabled, autoInject } = { ...DEFAULT_OPTIONS, ...options };
|
|
18
|
+
|
|
19
|
+
if (!enabled) {
|
|
20
|
+
return { name: "upstart-editor-disabled" };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const runtimePath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "./runtime/index");
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
name: "upstart-editor",
|
|
27
|
+
enforce: "pre",
|
|
28
|
+
|
|
29
|
+
transform(code, id) {
|
|
30
|
+
if (!autoInject) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const [cleanId] = id.split("?");
|
|
35
|
+
if (!cleanId || cleanId.includes("node_modules")) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!/\.(t|j)sx?$/.test(cleanId)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const filename = path.basename(cleanId);
|
|
44
|
+
if (!filename.startsWith("main.") && !filename.startsWith("index.")) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (code.includes("initUpstartEditor")) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const injection = [
|
|
53
|
+
`import { initUpstartEditor } from ${JSON.stringify(runtimePath)};`,
|
|
54
|
+
"",
|
|
55
|
+
"if (typeof window !== 'undefined') {",
|
|
56
|
+
" if (document.readyState === 'loading') {",
|
|
57
|
+
" document.addEventListener('DOMContentLoaded', () => initUpstartEditor());",
|
|
58
|
+
" } else {",
|
|
59
|
+
" initUpstartEditor();",
|
|
60
|
+
" }",
|
|
61
|
+
"}",
|
|
62
|
+
"",
|
|
63
|
+
].join("\n");
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
code: `${injection}${code}`,
|
|
67
|
+
map: null,
|
|
68
|
+
};
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
export default upstartEditor.vite;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { getCurrentMode } from "./index.js";
|
|
2
|
+
import { sendToParent } from "./utils.js";
|
|
3
|
+
|
|
4
|
+
let isInitialized = false;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Initialize click handler for className editing.
|
|
8
|
+
*/
|
|
9
|
+
export function initClickHandler(): void {
|
|
10
|
+
if (typeof document === "undefined") {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (isInitialized) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.log("[Upstart Editor] Initializing click handler...");
|
|
19
|
+
document.addEventListener("click", handleClick, true);
|
|
20
|
+
isInitialized = true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Cleanup click handler.
|
|
25
|
+
*/
|
|
26
|
+
export function cleanupClickHandler(): void {
|
|
27
|
+
document.removeEventListener("click", handleClick, true);
|
|
28
|
+
isInitialized = false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function handleClick(event: MouseEvent): void {
|
|
32
|
+
if (getCurrentMode() !== "edit") {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const target = event.target as HTMLElement | null;
|
|
37
|
+
if (!target) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (target.closest("[contenteditable='true']")) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const component = target.closest<HTMLElement>("[data-upstart-component]");
|
|
46
|
+
if (!component) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
event.preventDefault();
|
|
51
|
+
event.stopPropagation();
|
|
52
|
+
|
|
53
|
+
const hash = component.dataset.upstartHash;
|
|
54
|
+
const componentName = component.dataset.upstartComponent;
|
|
55
|
+
const filePath = component.dataset.upstartFile ?? "";
|
|
56
|
+
|
|
57
|
+
if (!hash || !componentName) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const rect = component.getBoundingClientRect();
|
|
62
|
+
|
|
63
|
+
sendToParent({
|
|
64
|
+
type: "element-clicked",
|
|
65
|
+
hash,
|
|
66
|
+
componentName,
|
|
67
|
+
filePath,
|
|
68
|
+
currentClassName: component.className,
|
|
69
|
+
bounds: {
|
|
70
|
+
top: rect.top,
|
|
71
|
+
left: rect.left,
|
|
72
|
+
width: rect.width,
|
|
73
|
+
height: rect.height,
|
|
74
|
+
right: rect.right,
|
|
75
|
+
bottom: rect.bottom,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
console.log("[Upstart Editor] Element clicked:", componentName, hash);
|
|
80
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { getCurrentMode } from "./index.js";
|
|
2
|
+
import { sendToParent } from "./utils.js";
|
|
3
|
+
|
|
4
|
+
let overlay: HTMLDivElement | null = null;
|
|
5
|
+
let currentTarget: HTMLElement | null = null;
|
|
6
|
+
let isInitialized = false;
|
|
7
|
+
let rafId: number | null = null;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Initialize hover overlay.
|
|
11
|
+
*/
|
|
12
|
+
export function initHoverOverlay(): void {
|
|
13
|
+
if (typeof document === "undefined") {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (isInitialized) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log("[Upstart Editor] Initializing hover overlay...");
|
|
22
|
+
|
|
23
|
+
document.addEventListener("mouseover", handleMouseOver);
|
|
24
|
+
document.addEventListener("mouseout", handleMouseOut);
|
|
25
|
+
window.addEventListener("scroll", scheduleOverlayUpdate, { passive: true });
|
|
26
|
+
window.addEventListener("resize", scheduleOverlayUpdate, { passive: true });
|
|
27
|
+
|
|
28
|
+
isInitialized = true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Hide all overlays.
|
|
33
|
+
*/
|
|
34
|
+
export function hideOverlays(): void {
|
|
35
|
+
if (overlay) {
|
|
36
|
+
overlay.style.display = "none";
|
|
37
|
+
currentTarget = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function handleMouseOver(event: MouseEvent): void {
|
|
42
|
+
if (getCurrentMode() !== "edit") {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const target = event.target as HTMLElement | null;
|
|
47
|
+
if (!target) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const component = target.closest<HTMLElement>("[data-upstart-component]");
|
|
52
|
+
if (!component) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!overlay) {
|
|
57
|
+
createOverlay();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
currentTarget = component;
|
|
61
|
+
positionOverlay(component);
|
|
62
|
+
|
|
63
|
+
const hash = component.dataset.upstartHash;
|
|
64
|
+
if (hash) {
|
|
65
|
+
const rect = component.getBoundingClientRect();
|
|
66
|
+
sendToParent({
|
|
67
|
+
type: "element-hovered",
|
|
68
|
+
hash,
|
|
69
|
+
bounds: {
|
|
70
|
+
top: rect.top,
|
|
71
|
+
left: rect.left,
|
|
72
|
+
width: rect.width,
|
|
73
|
+
height: rect.height,
|
|
74
|
+
right: rect.right,
|
|
75
|
+
bottom: rect.bottom,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function handleMouseOut(event: MouseEvent): void {
|
|
82
|
+
const target = event.target as HTMLElement | null;
|
|
83
|
+
const relatedTarget = event.relatedTarget as HTMLElement | null;
|
|
84
|
+
|
|
85
|
+
if (!target) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const component = target.closest<HTMLElement>("[data-upstart-component]");
|
|
90
|
+
if (!component) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (relatedTarget && component.contains(relatedTarget)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
hideOverlays();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function createOverlay(): void {
|
|
102
|
+
overlay = document.createElement("div");
|
|
103
|
+
overlay.id = "upstart-hover-overlay";
|
|
104
|
+
overlay.style.cssText =
|
|
105
|
+
"position: absolute; pointer-events: none; border: 2px solid #3b82f6; " +
|
|
106
|
+
"background: rgba(59, 130, 246, 0.05); border-radius: 4px; z-index: 9999; " +
|
|
107
|
+
"transition: all 0.1s ease; display: none;";
|
|
108
|
+
document.body.appendChild(overlay);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function positionOverlay(element: HTMLElement): void {
|
|
112
|
+
if (!overlay) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const rect = element.getBoundingClientRect();
|
|
117
|
+
overlay.style.top = `${rect.top + window.scrollY}px`;
|
|
118
|
+
overlay.style.left = `${rect.left + window.scrollX}px`;
|
|
119
|
+
overlay.style.width = `${rect.width}px`;
|
|
120
|
+
overlay.style.height = `${rect.height}px`;
|
|
121
|
+
overlay.style.display = "block";
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function scheduleOverlayUpdate(): void {
|
|
125
|
+
if (rafId !== null) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
rafId = requestAnimationFrame(() => {
|
|
130
|
+
rafId = null;
|
|
131
|
+
if (currentTarget && overlay && overlay.style.display === "block") {
|
|
132
|
+
positionOverlay(currentTarget);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { initClickHandler } from "./click-handler.js";
|
|
2
|
+
import { initHoverOverlay, hideOverlays } from "./hover-overlay.js";
|
|
3
|
+
import { initTextEditor, destroyAllActiveEditors } from "./text-editor.js";
|
|
4
|
+
import { sendToParent } from "./utils.js";
|
|
5
|
+
import type { EditorMode, UpstartParentMessage } from "./types.js";
|
|
6
|
+
|
|
7
|
+
let currentMode: EditorMode = "preview";
|
|
8
|
+
let isInitialized = false;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get the current editor mode.
|
|
12
|
+
*/
|
|
13
|
+
export function getCurrentMode(): EditorMode {
|
|
14
|
+
return currentMode;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Set the current editor mode.
|
|
19
|
+
*/
|
|
20
|
+
export function setMode(mode: EditorMode): void {
|
|
21
|
+
currentMode = mode;
|
|
22
|
+
|
|
23
|
+
if (mode === "edit") {
|
|
24
|
+
enableEditMode();
|
|
25
|
+
} else {
|
|
26
|
+
disableEditMode();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize the Upstart editor runtime.
|
|
32
|
+
*/
|
|
33
|
+
export function initUpstartEditor(): void {
|
|
34
|
+
if (typeof window === "undefined") {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isInitialized) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
console.log("[Upstart Editor] Initializing...");
|
|
44
|
+
|
|
45
|
+
currentMode = "preview";
|
|
46
|
+
isInitialized = true;
|
|
47
|
+
|
|
48
|
+
window.addEventListener("message", handleParentMessage);
|
|
49
|
+
|
|
50
|
+
initTextEditor();
|
|
51
|
+
initClickHandler();
|
|
52
|
+
initHoverOverlay();
|
|
53
|
+
|
|
54
|
+
sendToParent({ type: "editor-ready" });
|
|
55
|
+
} catch (error) {
|
|
56
|
+
console.error("[Upstart Editor] Initialization failed:", error);
|
|
57
|
+
sendToParent({
|
|
58
|
+
type: "editor-error",
|
|
59
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function handleParentMessage(event: MessageEvent): void {
|
|
65
|
+
const message = event.data as UpstartParentMessage | undefined;
|
|
66
|
+
|
|
67
|
+
if (!message || message.source !== "upstart-editor-parent") {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (message.type === "set-mode") {
|
|
72
|
+
setMode(message.mode);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function enableEditMode(): void {
|
|
77
|
+
console.log("[Upstart Editor] Edit mode enabled");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function disableEditMode(): void {
|
|
81
|
+
console.log("[Upstart Editor] Preview mode enabled");
|
|
82
|
+
destroyAllActiveEditors();
|
|
83
|
+
hideOverlays();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { initTextEditor } from "./text-editor.js";
|
|
87
|
+
export { initClickHandler } from "./click-handler.js";
|
|
88
|
+
export { initHoverOverlay } from "./hover-overlay.js";
|
|
89
|
+
export { sendToParent } from "./utils.js";
|
|
90
|
+
export type { EditorMessage, UpstartEditorMessage } from "./types.js";
|