@lego-build/plugins 0.0.3 → 0.0.6
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/auto.js +3 -10
- package/dist/babel-plugin.d.ts +18 -0
- package/dist/babel-plugin.js +43 -0
- package/dist/{chunk-MZJDRENL.js → chunk-2R3NUXAB.js} +13 -9
- package/dist/chunk-3TRIUWCT.js +539 -0
- package/dist/chunk-42QHGI4F.js +512 -0
- package/dist/chunk-4EX2R46A.js +528 -0
- package/dist/{chunk-RM4HZDF3.js → chunk-6EMRLRSE.js} +12 -5
- package/dist/chunk-6MOTW5WZ.js +505 -0
- package/dist/chunk-J6RRTMEB.js +553 -0
- package/dist/chunk-NYSOJK4V.js +436 -0
- package/dist/chunk-ONSLHF7O.js +553 -0
- package/dist/chunk-QMPWAJBL.js +539 -0
- package/dist/chunk-RG2IIZUF.js +560 -0
- package/dist/chunk-SQ3BWA54.js +307 -0
- package/dist/chunk-URUG7I3S.js +539 -0
- package/dist/chunk-V3KCJYHC.js +468 -0
- package/dist/chunk-XZZFN45X.js +539 -0
- package/dist/index.d.ts +4 -32
- package/dist/index.js +8 -830
- package/dist/react.d.ts +7 -0
- package/dist/react.js +18 -0
- package/dist/vite-plugin.d.ts +16 -0
- package/dist/vite-plugin.js +103 -0
- package/package.json +28 -31
- package/dist/webpack-loader.d.ts +0 -25
- package/dist/webpack-loader.js +0 -198
package/dist/index.js
CHANGED
|
@@ -1,834 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
if (typeof window !== "undefined" && window.location.hostname === "localhost") {
|
|
10
|
-
return "http://localhost:4000";
|
|
11
|
-
}
|
|
12
|
-
return "*";
|
|
13
|
-
}
|
|
14
|
-
var PARENT_ORIGIN = getParentOrigin();
|
|
15
|
-
function sendToParent(type, payload) {
|
|
16
|
-
window.parent.postMessage({ type, payload }, PARENT_ORIGIN);
|
|
17
|
-
}
|
|
18
|
-
function setupIframeBridge() {
|
|
19
|
-
const pushState = window.history.pushState.bind(window.history);
|
|
20
|
-
const originalPushState = (...args) => {
|
|
21
|
-
pushState(...args);
|
|
22
|
-
sendToParent("IFRAME_URL_CHANGED", window.location.href);
|
|
23
|
-
};
|
|
24
|
-
window.history.pushState = originalPushState;
|
|
25
|
-
const replaceState = window.history.replaceState.bind(window.history);
|
|
26
|
-
const originalReplaceState = (...args) => {
|
|
27
|
-
replaceState(...args);
|
|
28
|
-
sendToParent("IFRAME_URL_CHANGED", window.location.href);
|
|
29
|
-
};
|
|
30
|
-
window.history.replaceState = originalReplaceState;
|
|
31
|
-
window.addEventListener("popstate", () => {
|
|
32
|
-
sendToParent("IFRAME_URL_CHANGED", window.location.href);
|
|
33
|
-
});
|
|
34
|
-
window.addEventListener("message", (e) => {
|
|
35
|
-
const msg = e.data;
|
|
36
|
-
if (!msg?.type) return;
|
|
37
|
-
switch (msg.type) {
|
|
38
|
-
case "NAVIGATE_BACK":
|
|
39
|
-
window.history.back();
|
|
40
|
-
break;
|
|
41
|
-
case "NAVIGATE_FORWARD":
|
|
42
|
-
window.history.forward();
|
|
43
|
-
break;
|
|
44
|
-
case "NAVIGATE_URL":
|
|
45
|
-
if (msg.payload) {
|
|
46
|
-
window.history.pushState({}, "", msg.payload);
|
|
47
|
-
sendToParent("IFRAME_URL_CHANGED", window.location.href);
|
|
48
|
-
}
|
|
49
|
-
break;
|
|
50
|
-
case "REFRESH":
|
|
51
|
-
window.location.reload();
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// src/selector.ts
|
|
58
|
-
function createElementSelectorState() {
|
|
59
|
-
return {
|
|
60
|
-
isActive: false,
|
|
61
|
-
isEditing: false,
|
|
62
|
-
hoveredElement: null,
|
|
63
|
-
selectedElement: null,
|
|
64
|
-
overlay: null,
|
|
65
|
-
tooltip: null,
|
|
66
|
-
inlineEditor: null,
|
|
67
|
-
depth: 0,
|
|
68
|
-
originalText: ""
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
function createOverlay() {
|
|
72
|
-
const overlay = document.createElement("div");
|
|
73
|
-
overlay.id = "lego-element-selector-overlay";
|
|
74
|
-
overlay.style.cssText = `
|
|
75
|
-
position: fixed;
|
|
76
|
-
pointer-events: none;
|
|
77
|
-
z-index: 2147483646;
|
|
78
|
-
background: rgba(59, 130, 246, 0.1);
|
|
79
|
-
border: 2px solid #3b82f6;
|
|
80
|
-
border-radius: 4px;
|
|
81
|
-
transition: all 0.1s ease-out;
|
|
82
|
-
`;
|
|
83
|
-
document.body.appendChild(overlay);
|
|
84
|
-
return overlay;
|
|
85
|
-
}
|
|
86
|
-
function createTooltip() {
|
|
87
|
-
const tooltip = document.createElement("div");
|
|
88
|
-
tooltip.id = "lego-element-selector-tooltip";
|
|
89
|
-
tooltip.style.cssText = `
|
|
90
|
-
position: fixed;
|
|
91
|
-
pointer-events: none;
|
|
92
|
-
z-index: 2147483647;
|
|
93
|
-
background: #3b82f6;
|
|
94
|
-
color: white;
|
|
95
|
-
padding: 4px 8px;
|
|
96
|
-
border-radius: 4px;
|
|
97
|
-
font-family: ui-monospace, monospace;
|
|
98
|
-
font-size: 12px;
|
|
99
|
-
white-space: nowrap;
|
|
100
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
101
|
-
transition: all 0.1s ease-out;
|
|
102
|
-
`;
|
|
103
|
-
document.body.appendChild(tooltip);
|
|
104
|
-
return tooltip;
|
|
105
|
-
}
|
|
106
|
-
var EDITOR_MIN_WIDTH = 200;
|
|
107
|
-
var EDITOR_APPROX_HEIGHT = 180;
|
|
108
|
-
var EDITOR_OFFSET = 8;
|
|
109
|
-
var VIEWPORT_PADDING = 16;
|
|
110
|
-
function createInlineEditor(state, element, onSave, onCancel) {
|
|
111
|
-
const rect = element.getBoundingClientRect();
|
|
112
|
-
const elementText = getElementTextContent(element);
|
|
113
|
-
const viewportWidth = window.innerWidth;
|
|
114
|
-
const viewportHeight = window.innerHeight;
|
|
115
|
-
const editorWidth = Math.max(rect.width, EDITOR_MIN_WIDTH);
|
|
116
|
-
let left = rect.left;
|
|
117
|
-
let top = rect.bottom + EDITOR_OFFSET;
|
|
118
|
-
if (left + editorWidth > viewportWidth - VIEWPORT_PADDING) {
|
|
119
|
-
left = viewportWidth - editorWidth - VIEWPORT_PADDING;
|
|
120
|
-
}
|
|
121
|
-
if (left < VIEWPORT_PADDING) {
|
|
122
|
-
left = VIEWPORT_PADDING;
|
|
123
|
-
}
|
|
124
|
-
if (top + EDITOR_APPROX_HEIGHT > viewportHeight - VIEWPORT_PADDING) {
|
|
125
|
-
top = rect.top - EDITOR_APPROX_HEIGHT - EDITOR_OFFSET;
|
|
126
|
-
if (top < VIEWPORT_PADDING) {
|
|
127
|
-
top = VIEWPORT_PADDING;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
const editor = document.createElement("div");
|
|
131
|
-
editor.id = "lego-inline-editor";
|
|
132
|
-
editor.style.cssText = `
|
|
133
|
-
position: fixed;
|
|
134
|
-
top: ${top}px;
|
|
135
|
-
left: ${left}px;
|
|
136
|
-
width: ${editorWidth}px;
|
|
137
|
-
z-index: 2147483647;
|
|
138
|
-
background: white;
|
|
139
|
-
border: 2px solid #3b82f6;
|
|
140
|
-
border-radius: 8px;
|
|
141
|
-
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
|
142
|
-
padding: 8px;
|
|
143
|
-
font-family: ui-sans-serif, system-ui, sans-serif;
|
|
144
|
-
box-sizing: border-box;
|
|
145
|
-
`;
|
|
146
|
-
const header = document.createElement("div");
|
|
147
|
-
header.style.cssText = `
|
|
148
|
-
display: flex;
|
|
149
|
-
align-items: center;
|
|
150
|
-
justify-content: space-between;
|
|
151
|
-
margin-bottom: 8px;
|
|
152
|
-
padding-bottom: 8px;
|
|
153
|
-
border-bottom: 1px solid #e5e7eb;
|
|
154
|
-
`;
|
|
155
|
-
header.innerHTML = `
|
|
156
|
-
<span style="font-size: 11px; font-weight: 500; color: #6b7280;">
|
|
157
|
-
\u270F\uFE0F Edit Text
|
|
158
|
-
</span>
|
|
159
|
-
<span style="font-size: 10px; color: #9ca3af;">
|
|
160
|
-
Ctrl+Enter to save \u2022 Esc to cancel
|
|
161
|
-
</span>
|
|
162
|
-
`;
|
|
163
|
-
const input = document.createElement("textarea");
|
|
164
|
-
input.id = "lego-inline-editor-input";
|
|
165
|
-
input.value = elementText;
|
|
166
|
-
input.style.cssText = `
|
|
167
|
-
width: 100%;
|
|
168
|
-
min-height: 60px;
|
|
169
|
-
padding: 8px;
|
|
170
|
-
border: 1px solid #e5e7eb;
|
|
171
|
-
border-radius: 4px;
|
|
172
|
-
font-size: 14px;
|
|
173
|
-
font-family: inherit;
|
|
174
|
-
resize: vertical;
|
|
175
|
-
outline: none;
|
|
176
|
-
box-sizing: border-box;
|
|
177
|
-
`;
|
|
178
|
-
input.placeholder = "Enter text...";
|
|
179
|
-
const buttons = document.createElement("div");
|
|
180
|
-
buttons.style.cssText = `
|
|
181
|
-
display: flex;
|
|
182
|
-
gap: 8px;
|
|
183
|
-
margin-top: 8px;
|
|
184
|
-
justify-content: flex-end;
|
|
185
|
-
`;
|
|
186
|
-
const cancelBtn = document.createElement("button");
|
|
187
|
-
cancelBtn.textContent = "Cancel";
|
|
188
|
-
cancelBtn.style.cssText = `
|
|
189
|
-
padding: 6px 12px;
|
|
190
|
-
border: 1px solid #e5e7eb;
|
|
191
|
-
border-radius: 4px;
|
|
192
|
-
background: white;
|
|
193
|
-
font-size: 12px;
|
|
194
|
-
cursor: pointer;
|
|
195
|
-
transition: all 0.15s;
|
|
196
|
-
`;
|
|
197
|
-
cancelBtn.onmouseenter = () => cancelBtn.style.background = "#f3f4f6";
|
|
198
|
-
cancelBtn.onmouseleave = () => cancelBtn.style.background = "white";
|
|
199
|
-
cancelBtn.onclick = (e) => {
|
|
200
|
-
e.preventDefault();
|
|
201
|
-
e.stopPropagation();
|
|
202
|
-
onCancel();
|
|
203
|
-
};
|
|
204
|
-
const saveBtn = document.createElement("button");
|
|
205
|
-
saveBtn.textContent = "Save";
|
|
206
|
-
saveBtn.style.cssText = `
|
|
207
|
-
padding: 6px 12px;
|
|
208
|
-
border: none;
|
|
209
|
-
border-radius: 4px;
|
|
210
|
-
background: #3b82f6;
|
|
211
|
-
color: white;
|
|
212
|
-
font-size: 12px;
|
|
213
|
-
font-weight: 500;
|
|
214
|
-
cursor: pointer;
|
|
215
|
-
transition: all 0.15s;
|
|
216
|
-
`;
|
|
217
|
-
saveBtn.onmouseenter = () => saveBtn.style.background = "#2563eb";
|
|
218
|
-
saveBtn.onmouseleave = () => saveBtn.style.background = "#3b82f6";
|
|
219
|
-
saveBtn.onclick = (e) => {
|
|
220
|
-
e.preventDefault();
|
|
221
|
-
e.stopPropagation();
|
|
222
|
-
onSave();
|
|
223
|
-
};
|
|
224
|
-
editor.appendChild(header);
|
|
225
|
-
editor.appendChild(input);
|
|
226
|
-
buttons.appendChild(cancelBtn);
|
|
227
|
-
buttons.appendChild(saveBtn);
|
|
228
|
-
editor.appendChild(buttons);
|
|
229
|
-
document.body.appendChild(editor);
|
|
230
|
-
setTimeout(() => {
|
|
231
|
-
input.focus();
|
|
232
|
-
input.select();
|
|
233
|
-
}, 0);
|
|
234
|
-
input.addEventListener("keydown", (e) => {
|
|
235
|
-
if (e.key === "Escape") {
|
|
236
|
-
e.preventDefault();
|
|
237
|
-
e.stopPropagation();
|
|
238
|
-
onCancel();
|
|
239
|
-
} else if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) {
|
|
240
|
-
e.preventDefault();
|
|
241
|
-
e.stopPropagation();
|
|
242
|
-
onSave();
|
|
243
|
-
}
|
|
244
|
-
});
|
|
245
|
-
input.addEventListener("keyup", (e) => {
|
|
246
|
-
e.stopPropagation();
|
|
247
|
-
});
|
|
248
|
-
input.addEventListener("keypress", (e) => {
|
|
249
|
-
e.stopPropagation();
|
|
250
|
-
});
|
|
251
|
-
return editor;
|
|
252
|
-
}
|
|
253
|
-
function getElementTextContent(element) {
|
|
254
|
-
const MAX_TEXT_LENGTH = 200;
|
|
255
|
-
const truncateText = (text) => {
|
|
256
|
-
const trimmed = text.trim();
|
|
257
|
-
return trimmed.length > MAX_TEXT_LENGTH ? trimmed.slice(0, MAX_TEXT_LENGTH) + "..." : trimmed;
|
|
258
|
-
};
|
|
259
|
-
let directText = "";
|
|
260
|
-
for (const node of element.childNodes) {
|
|
261
|
-
if (node.nodeType === Node.TEXT_NODE) {
|
|
262
|
-
directText += node.textContent || "";
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
directText = directText.trim();
|
|
266
|
-
if (directText) {
|
|
267
|
-
return truncateText(directText);
|
|
268
|
-
}
|
|
269
|
-
if (element.children.length === 1) {
|
|
270
|
-
const child = element.children[0];
|
|
271
|
-
const simpleWrapperTags = ["span", "strong", "em", "b", "i", "small", "mark", "del", "ins", "sub", "sup"];
|
|
272
|
-
if (simpleWrapperTags.includes(child.tagName.toLowerCase())) {
|
|
273
|
-
const childText = child.textContent?.trim() || "";
|
|
274
|
-
if (childText) {
|
|
275
|
-
return truncateText(childText);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
const hasComplexChildren = Array.from(element.children).some((child) => {
|
|
280
|
-
const tagName = child.tagName.toLowerCase();
|
|
281
|
-
const complexTags = ["div", "section", "article", "ul", "ol", "table", "form", "nav", "header", "footer", "main"];
|
|
282
|
-
return complexTags.includes(tagName) || child.children.length > 0;
|
|
283
|
-
});
|
|
284
|
-
if (!hasComplexChildren && element.children.length <= 2) {
|
|
285
|
-
const fullText = element.textContent?.trim() || "";
|
|
286
|
-
if (fullText) {
|
|
287
|
-
return truncateText(fullText);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
return "";
|
|
291
|
-
}
|
|
292
|
-
function getElementDepth(element) {
|
|
293
|
-
let depth = 0;
|
|
294
|
-
let current = element;
|
|
295
|
-
while (current && current !== document.body) {
|
|
296
|
-
depth++;
|
|
297
|
-
current = current.parentElement;
|
|
298
|
-
}
|
|
299
|
-
return depth;
|
|
300
|
-
}
|
|
301
|
-
function updateOverlayPosition(state) {
|
|
302
|
-
if (!state.hoveredElement || !state.overlay || !state.tooltip) return;
|
|
303
|
-
const rect = state.hoveredElement.getBoundingClientRect();
|
|
304
|
-
const viewportWidth = window.innerWidth;
|
|
305
|
-
state.overlay.style.top = `${rect.top}px`;
|
|
306
|
-
state.overlay.style.left = `${rect.left}px`;
|
|
307
|
-
state.overlay.style.width = `${rect.width}px`;
|
|
308
|
-
state.overlay.style.height = `${rect.height}px`;
|
|
309
|
-
let tooltipTop = rect.top - 32;
|
|
310
|
-
let tooltipLeft = rect.left;
|
|
311
|
-
if (tooltipTop < 8) {
|
|
312
|
-
tooltipTop = rect.bottom + 8;
|
|
313
|
-
}
|
|
314
|
-
const estimatedTooltipWidth = state.tooltip.offsetWidth || 150;
|
|
315
|
-
if (tooltipLeft + estimatedTooltipWidth > viewportWidth - 8) {
|
|
316
|
-
tooltipLeft = viewportWidth - estimatedTooltipWidth - 8;
|
|
317
|
-
}
|
|
318
|
-
if (tooltipLeft < 8) {
|
|
319
|
-
tooltipLeft = 8;
|
|
320
|
-
}
|
|
321
|
-
state.tooltip.style.top = `${tooltipTop}px`;
|
|
322
|
-
state.tooltip.style.left = `${tooltipLeft}px`;
|
|
323
|
-
}
|
|
324
|
-
function getElementInfo(element) {
|
|
325
|
-
const filePath = element.getAttribute("data-locator-path") || "";
|
|
326
|
-
const line = element.getAttribute("data-locator-line");
|
|
327
|
-
const depth = getElementDepth(element);
|
|
328
|
-
const id = element.id ? `#${element.id}` : "";
|
|
329
|
-
const classes = element.className && typeof element.className === "string" ? element.className.split(" ").filter((c) => c).map((c) => `.${c}`).join("") : "";
|
|
330
|
-
return {
|
|
331
|
-
tagName: element.tagName.toLowerCase(),
|
|
332
|
-
selector: element.tagName.toLowerCase() + id + classes.slice(0, 50),
|
|
333
|
-
filePath,
|
|
334
|
-
line: line ? parseInt(line) : void 0,
|
|
335
|
-
depth,
|
|
336
|
-
rect: element.getBoundingClientRect()
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
function highlightElement(state, element) {
|
|
340
|
-
state.hoveredElement = element;
|
|
341
|
-
if (!state.overlay) {
|
|
342
|
-
state.overlay = createOverlay();
|
|
343
|
-
}
|
|
344
|
-
if (!state.tooltip) {
|
|
345
|
-
state.tooltip = createTooltip();
|
|
346
|
-
}
|
|
347
|
-
state.overlay.style.display = "block";
|
|
348
|
-
state.tooltip.style.display = "block";
|
|
349
|
-
const info = getElementInfo(element);
|
|
350
|
-
state.depth = info.depth;
|
|
351
|
-
state.tooltip.innerHTML = `
|
|
352
|
-
<span style="opacity: 0.8">${info.selector}</span>
|
|
353
|
-
${info.filePath ? `<span style="margin-left: 8px; opacity: 0.6">\u{1F4C4} ${info.filePath.split("/").pop()}</span>` : ""}
|
|
354
|
-
<span style="margin-left: 8px; opacity: 0.5; font-size: 10px;">Double-click to edit</span>
|
|
355
|
-
`;
|
|
356
|
-
updateOverlayPosition(state);
|
|
357
|
-
sendToParent("HOVER_ELEMENT", {
|
|
358
|
-
tagName: info.tagName,
|
|
359
|
-
rect: info.rect,
|
|
360
|
-
filePath: info.filePath || void 0,
|
|
361
|
-
line: info.line,
|
|
362
|
-
depth: info.depth
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
function navigateDOM(state, direction) {
|
|
366
|
-
if (!state.hoveredElement) return;
|
|
367
|
-
let target = null;
|
|
368
|
-
switch (direction) {
|
|
369
|
-
case "parent":
|
|
370
|
-
target = state.hoveredElement.parentElement;
|
|
371
|
-
if (target && target === document.body) target = null;
|
|
372
|
-
break;
|
|
373
|
-
case "child":
|
|
374
|
-
target = state.hoveredElement.firstElementChild;
|
|
375
|
-
break;
|
|
376
|
-
case "next":
|
|
377
|
-
target = state.hoveredElement.nextElementSibling;
|
|
378
|
-
break;
|
|
379
|
-
case "prev":
|
|
380
|
-
target = state.hoveredElement.previousElementSibling;
|
|
381
|
-
break;
|
|
382
|
-
}
|
|
383
|
-
if (target && target !== document.documentElement && target !== document.body) {
|
|
384
|
-
highlightElement(state, target);
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
function setupElementSelector() {
|
|
388
|
-
const state = createElementSelectorState();
|
|
389
|
-
function saveInlineEdit() {
|
|
390
|
-
if (!state.inlineEditor || !state.selectedElement) return;
|
|
391
|
-
const input = state.inlineEditor.querySelector(
|
|
392
|
-
"#lego-inline-editor-input"
|
|
393
|
-
);
|
|
394
|
-
const newText = input?.value || "";
|
|
395
|
-
const info = getElementInfo(state.selectedElement);
|
|
396
|
-
if (newText !== state.originalText && info.filePath) {
|
|
397
|
-
sendToParent("SAVE_INLINE_EDIT", {
|
|
398
|
-
filePath: info.filePath,
|
|
399
|
-
originalContent: state.originalText,
|
|
400
|
-
newContent: newText,
|
|
401
|
-
line: info.line
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
exitEditMode();
|
|
405
|
-
}
|
|
406
|
-
function cancelInlineEdit() {
|
|
407
|
-
sendToParent("CANCEL_INLINE_EDIT");
|
|
408
|
-
exitEditMode();
|
|
409
|
-
}
|
|
410
|
-
function exitEditMode() {
|
|
411
|
-
state.isEditing = false;
|
|
412
|
-
if (state.inlineEditor) {
|
|
413
|
-
state.inlineEditor.remove();
|
|
414
|
-
state.inlineEditor = null;
|
|
415
|
-
}
|
|
416
|
-
if (state.isActive && state.hoveredElement) {
|
|
417
|
-
if (state.overlay) state.overlay.style.display = "block";
|
|
418
|
-
if (state.tooltip) state.tooltip.style.display = "block";
|
|
419
|
-
}
|
|
420
|
-
state.selectedElement = null;
|
|
421
|
-
state.originalText = "";
|
|
422
|
-
}
|
|
423
|
-
function enterEditMode() {
|
|
424
|
-
if (!state.selectedElement) return;
|
|
425
|
-
state.isEditing = true;
|
|
426
|
-
if (state.overlay) state.overlay.style.display = "none";
|
|
427
|
-
if (state.tooltip) state.tooltip.style.display = "none";
|
|
428
|
-
state.inlineEditor = createInlineEditor(state, state.selectedElement, saveInlineEdit, cancelInlineEdit);
|
|
429
|
-
const info = getElementInfo(state.selectedElement);
|
|
430
|
-
sendToParent("START_INLINE_EDIT", {
|
|
431
|
-
tagName: info.tagName,
|
|
432
|
-
filePath: info.filePath,
|
|
433
|
-
line: info.line,
|
|
434
|
-
text: state.originalText
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
function selectElement() {
|
|
438
|
-
if (!state.hoveredElement) return;
|
|
439
|
-
state.selectedElement = state.hoveredElement;
|
|
440
|
-
const info = getElementInfo(state.hoveredElement);
|
|
441
|
-
const text = getElementTextContent(state.hoveredElement);
|
|
442
|
-
state.originalText = text;
|
|
443
|
-
sendToParent("CLICK_ELEMENT", {
|
|
444
|
-
tagName: info.tagName,
|
|
445
|
-
filePath: info.filePath,
|
|
446
|
-
line: info.line,
|
|
447
|
-
depth: info.depth,
|
|
448
|
-
text
|
|
449
|
-
});
|
|
450
|
-
}
|
|
451
|
-
function startEditing() {
|
|
452
|
-
if (!state.hoveredElement) return;
|
|
453
|
-
state.selectedElement = state.hoveredElement;
|
|
454
|
-
const info = getElementInfo(state.hoveredElement);
|
|
455
|
-
const text = getElementTextContent(state.hoveredElement);
|
|
456
|
-
state.originalText = text;
|
|
457
|
-
sendToParent("CLICK_ELEMENT", {
|
|
458
|
-
tagName: info.tagName,
|
|
459
|
-
filePath: info.filePath,
|
|
460
|
-
line: info.line,
|
|
461
|
-
depth: info.depth,
|
|
462
|
-
text
|
|
463
|
-
});
|
|
464
|
-
enterEditMode();
|
|
465
|
-
}
|
|
466
|
-
const handleMouseMove = (e) => {
|
|
467
|
-
if (!state.isActive) return;
|
|
468
|
-
const target = e.target;
|
|
469
|
-
if (target.id === "lego-element-selector-overlay" || target.id === "lego-element-selector-tooltip") {
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
if (target === state.hoveredElement) return;
|
|
473
|
-
highlightElement(state, target);
|
|
474
|
-
};
|
|
475
|
-
const handleScroll = () => {
|
|
476
|
-
if (state.isActive && state.hoveredElement) {
|
|
477
|
-
updateOverlayPosition(state);
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
const handleResize = () => {
|
|
481
|
-
if (state.isActive && state.hoveredElement) {
|
|
482
|
-
updateOverlayPosition(state);
|
|
483
|
-
}
|
|
484
|
-
};
|
|
485
|
-
const handleKeyDown = (e) => {
|
|
486
|
-
if (!state.isActive) return;
|
|
487
|
-
if (state.isEditing) {
|
|
488
|
-
if (e.key === "Escape") {
|
|
489
|
-
e.preventDefault();
|
|
490
|
-
cancelInlineEdit();
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
switch (e.key) {
|
|
496
|
-
case "Escape":
|
|
497
|
-
sendToParent("SELECTOR_EXIT", true);
|
|
498
|
-
break;
|
|
499
|
-
case "ArrowUp":
|
|
500
|
-
e.preventDefault();
|
|
501
|
-
navigateDOM(state, "parent");
|
|
502
|
-
break;
|
|
503
|
-
case "ArrowDown":
|
|
504
|
-
e.preventDefault();
|
|
505
|
-
navigateDOM(state, "child");
|
|
506
|
-
break;
|
|
507
|
-
case "ArrowLeft":
|
|
508
|
-
e.preventDefault();
|
|
509
|
-
navigateDOM(state, "prev");
|
|
510
|
-
break;
|
|
511
|
-
case "ArrowRight":
|
|
512
|
-
e.preventDefault();
|
|
513
|
-
navigateDOM(state, "next");
|
|
514
|
-
break;
|
|
515
|
-
case "Enter":
|
|
516
|
-
e.preventDefault();
|
|
517
|
-
selectElement();
|
|
518
|
-
break;
|
|
519
|
-
case "e":
|
|
520
|
-
case "E":
|
|
521
|
-
if (state.hoveredElement) {
|
|
522
|
-
e.preventDefault();
|
|
523
|
-
startEditing();
|
|
524
|
-
}
|
|
525
|
-
break;
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
const handleClick = (e) => {
|
|
529
|
-
if (!state.isActive) return;
|
|
530
|
-
e._legoSelectorHandled = true;
|
|
531
|
-
if (state.isEditing) {
|
|
532
|
-
const target = e.target;
|
|
533
|
-
if (state.inlineEditor?.contains(target)) {
|
|
534
|
-
if (target.tagName === "BUTTON") {
|
|
535
|
-
e.preventDefault();
|
|
536
|
-
e.stopPropagation();
|
|
537
|
-
if (target.textContent === "Save") {
|
|
538
|
-
saveInlineEdit();
|
|
539
|
-
} else if (target.textContent === "Cancel") {
|
|
540
|
-
cancelInlineEdit();
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
e.preventDefault();
|
|
546
|
-
e.stopPropagation();
|
|
547
|
-
cancelInlineEdit();
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
e.preventDefault();
|
|
551
|
-
e.stopPropagation();
|
|
552
|
-
selectElement();
|
|
553
|
-
};
|
|
554
|
-
const handleDoubleClick = (e) => {
|
|
555
|
-
if (!state.isActive || state.isEditing) return;
|
|
556
|
-
const target = e.target;
|
|
557
|
-
if (target.id === "lego-element-selector-overlay" || target.id === "lego-element-selector-tooltip" || target.id === "lego-inline-editor") {
|
|
558
|
-
return;
|
|
559
|
-
}
|
|
560
|
-
e._legoSelectorHandled = true;
|
|
561
|
-
e.preventDefault();
|
|
562
|
-
e.stopPropagation();
|
|
563
|
-
state.hoveredElement = target;
|
|
564
|
-
startEditing();
|
|
565
|
-
};
|
|
566
|
-
const activateSelector = () => {
|
|
567
|
-
state.isActive = true;
|
|
568
|
-
document.addEventListener("mousemove", handleMouseMove, true);
|
|
569
|
-
document.addEventListener("click", handleClick, true);
|
|
570
|
-
document.addEventListener("dblclick", handleDoubleClick, true);
|
|
571
|
-
document.addEventListener("keydown", handleKeyDown, true);
|
|
572
|
-
window.addEventListener("scroll", handleScroll, true);
|
|
573
|
-
window.addEventListener("resize", handleResize);
|
|
574
|
-
document.body.style.cursor = "crosshair";
|
|
575
|
-
state.overlay = createOverlay();
|
|
576
|
-
state.tooltip = createTooltip();
|
|
577
|
-
};
|
|
578
|
-
const deactivateSelector = () => {
|
|
579
|
-
state.isActive = false;
|
|
580
|
-
state.isEditing = false;
|
|
581
|
-
document.removeEventListener("mousemove", handleMouseMove, true);
|
|
582
|
-
document.removeEventListener("click", handleClick, true);
|
|
583
|
-
document.removeEventListener("dblclick", handleDoubleClick, true);
|
|
584
|
-
document.removeEventListener("keydown", handleKeyDown, true);
|
|
585
|
-
window.removeEventListener("scroll", handleScroll, true);
|
|
586
|
-
window.removeEventListener("resize", handleResize);
|
|
587
|
-
if (state.overlay) {
|
|
588
|
-
state.overlay.remove();
|
|
589
|
-
state.overlay = null;
|
|
590
|
-
}
|
|
591
|
-
if (state.tooltip) {
|
|
592
|
-
state.tooltip.remove();
|
|
593
|
-
state.tooltip = null;
|
|
594
|
-
}
|
|
595
|
-
if (state.inlineEditor) {
|
|
596
|
-
state.inlineEditor.remove();
|
|
597
|
-
state.inlineEditor = null;
|
|
598
|
-
}
|
|
599
|
-
state.hoveredElement = null;
|
|
600
|
-
state.selectedElement = null;
|
|
601
|
-
state.originalText = "";
|
|
602
|
-
document.body.style.cursor = "";
|
|
603
|
-
state.depth = 0;
|
|
604
|
-
};
|
|
605
|
-
window.addEventListener("message", (e) => {
|
|
606
|
-
const msg = e.data;
|
|
607
|
-
if (msg.type === "TOGGLE_ELEMENT_SELECTOR") {
|
|
608
|
-
if (msg.payload) {
|
|
609
|
-
activateSelector();
|
|
610
|
-
} else {
|
|
611
|
-
deactivateSelector();
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
});
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// src/source-locator.ts
|
|
618
|
-
import path from "path";
|
|
619
|
-
import * as parser from "@babel/parser";
|
|
620
|
-
import traverse from "@babel/traverse";
|
|
621
|
-
import generate from "@babel/generator";
|
|
622
|
-
import * as t from "@babel/types";
|
|
623
|
-
import micromatch from "micromatch";
|
|
624
|
-
import { createHash } from "crypto";
|
|
625
|
-
var HTML_TAGS = [
|
|
626
|
-
"div",
|
|
627
|
-
"span",
|
|
628
|
-
"p",
|
|
629
|
-
"h1",
|
|
630
|
-
"h2",
|
|
631
|
-
"h3",
|
|
632
|
-
"h4",
|
|
633
|
-
"h5",
|
|
634
|
-
"h6",
|
|
635
|
-
"button",
|
|
636
|
-
"a",
|
|
637
|
-
"img",
|
|
638
|
-
"input",
|
|
639
|
-
"textarea",
|
|
640
|
-
"select",
|
|
641
|
-
"form",
|
|
642
|
-
"ul",
|
|
643
|
-
"ol",
|
|
644
|
-
"li",
|
|
645
|
-
"table",
|
|
646
|
-
"thead",
|
|
647
|
-
"tbody",
|
|
648
|
-
"tr",
|
|
649
|
-
"td",
|
|
650
|
-
"th",
|
|
651
|
-
"header",
|
|
652
|
-
"footer",
|
|
653
|
-
"nav",
|
|
654
|
-
"main",
|
|
655
|
-
"section",
|
|
656
|
-
"article",
|
|
657
|
-
"aside",
|
|
658
|
-
"label",
|
|
659
|
-
"strong",
|
|
660
|
-
"em",
|
|
661
|
-
"code",
|
|
662
|
-
"pre",
|
|
663
|
-
"blockquote"
|
|
664
|
-
];
|
|
665
|
-
var TEXT_TAGS = ["label", "span", "button", "p", "div", "h1", "h2", "h3", "h4", "h5", "h6"];
|
|
666
|
-
function getWorkspaceRoot(filePath) {
|
|
667
|
-
let dir = path.resolve(filePath);
|
|
668
|
-
const { root } = path.parse(dir);
|
|
669
|
-
while (dir !== root) {
|
|
670
|
-
if (path.basename(dir) === "workspace") return dir;
|
|
671
|
-
dir = path.dirname(dir);
|
|
672
|
-
}
|
|
673
|
-
return path.resolve(process.cwd(), "..");
|
|
674
|
-
}
|
|
675
|
-
function shouldProcessTag(tagName, options) {
|
|
676
|
-
if (options.filterTag) {
|
|
677
|
-
if (Array.isArray(options.filterTag)) {
|
|
678
|
-
return options.filterTag.includes(tagName);
|
|
679
|
-
}
|
|
680
|
-
return options.filterTag(tagName);
|
|
681
|
-
}
|
|
682
|
-
return HTML_TAGS.includes(tagName.toLowerCase());
|
|
683
|
-
}
|
|
684
|
-
function getElementTextContent2(nodePath) {
|
|
685
|
-
const parent = nodePath.parent;
|
|
686
|
-
if (!t.isJSXElement(parent)) return "";
|
|
687
|
-
let text = "";
|
|
688
|
-
let hasExpression = false;
|
|
689
|
-
for (const child of parent.children) {
|
|
690
|
-
if (t.isJSXText(child)) {
|
|
691
|
-
text += child.value;
|
|
692
|
-
} else if (t.isJSXExpressionContainer(child)) {
|
|
693
|
-
hasExpression = true;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
return hasExpression ? "" : text.trim();
|
|
697
|
-
}
|
|
698
|
-
function transformJSX(code, filePath, prefix, options) {
|
|
699
|
-
const ast = parser.parse(code, {
|
|
700
|
-
sourceType: "module",
|
|
701
|
-
plugins: ["jsx", "typescript", "classProperties", "decorators-legacy"]
|
|
702
|
-
});
|
|
703
|
-
const workspaceRoot = getWorkspaceRoot(filePath);
|
|
704
|
-
const relativePath = path.relative(workspaceRoot, filePath);
|
|
705
|
-
let hasChanges = false;
|
|
706
|
-
traverse(ast, {
|
|
707
|
-
JSXOpeningElement(nodePath) {
|
|
708
|
-
const node = nodePath.node;
|
|
709
|
-
const hasLocatorAttr = node.attributes.some(
|
|
710
|
-
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name.startsWith(`data-${prefix}`)
|
|
711
|
-
);
|
|
712
|
-
if (hasLocatorAttr) return;
|
|
713
|
-
if (t.isJSXIdentifier(node.name) && node.name.name === "Fragment") return;
|
|
714
|
-
if (t.isJSXMemberExpression(node.name) && t.isJSXIdentifier(node.name.object) && node.name.object.name === "React" && t.isJSXIdentifier(node.name.property) && node.name.property.name === "Fragment")
|
|
715
|
-
return;
|
|
716
|
-
let tagName = "";
|
|
717
|
-
if (t.isJSXIdentifier(node.name)) {
|
|
718
|
-
tagName = node.name.name;
|
|
719
|
-
}
|
|
720
|
-
if (!shouldProcessTag(tagName, options)) return;
|
|
721
|
-
const line = node.loc?.start.line;
|
|
722
|
-
const column = node.loc?.start.column;
|
|
723
|
-
if (!line || column === void 0) return;
|
|
724
|
-
const textContent = TEXT_TAGS.includes(tagName.toLowerCase()) ? getElementTextContent2(nodePath) : "";
|
|
725
|
-
const attributes = [
|
|
726
|
-
t.jsxAttribute(t.jsxIdentifier(`data-${prefix}-path`), t.stringLiteral(relativePath)),
|
|
727
|
-
t.jsxAttribute(t.jsxIdentifier(`data-${prefix}-line`), t.stringLiteral(String(line))),
|
|
728
|
-
t.jsxAttribute(t.jsxIdentifier(`data-${prefix}-column`), t.stringLiteral(String(column))),
|
|
729
|
-
t.jsxAttribute(t.jsxIdentifier(`data-${prefix}-tag`), t.stringLiteral(tagName))
|
|
730
|
-
];
|
|
731
|
-
if (textContent) {
|
|
732
|
-
attributes.push(
|
|
733
|
-
t.jsxAttribute(
|
|
734
|
-
t.jsxIdentifier(`data-${prefix}-text`),
|
|
735
|
-
t.stringLiteral(textContent)
|
|
736
|
-
)
|
|
737
|
-
);
|
|
738
|
-
}
|
|
739
|
-
const spreadIndex = node.attributes.findIndex((attr) => t.isJSXSpreadAttribute(attr));
|
|
740
|
-
if (spreadIndex === -1) {
|
|
741
|
-
node.attributes.push(...attributes);
|
|
742
|
-
} else {
|
|
743
|
-
node.attributes.splice(spreadIndex, 0, ...attributes);
|
|
744
|
-
}
|
|
745
|
-
hasChanges = true;
|
|
746
|
-
}
|
|
747
|
-
});
|
|
748
|
-
if (!hasChanges) return null;
|
|
749
|
-
const result = generate(ast, {}, code);
|
|
750
|
-
return {
|
|
751
|
-
code: result.code,
|
|
752
|
-
map: result.map
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
var transformCache = /* @__PURE__ */ new Map();
|
|
756
|
-
function isEntryFile(filePath, entryFiles) {
|
|
757
|
-
if (entryFiles && entryFiles.length > 0) {
|
|
758
|
-
return entryFiles.some((entry) => filePath.endsWith(entry));
|
|
759
|
-
}
|
|
760
|
-
const fileName = path.basename(filePath);
|
|
761
|
-
const entryPatterns = [
|
|
762
|
-
"main.tsx",
|
|
763
|
-
"main.ts",
|
|
764
|
-
"main.jsx",
|
|
765
|
-
"main.js",
|
|
766
|
-
"index.tsx",
|
|
767
|
-
"index.ts",
|
|
768
|
-
"index.jsx",
|
|
769
|
-
"index.js",
|
|
770
|
-
"App.tsx",
|
|
771
|
-
"App.jsx"
|
|
772
|
-
];
|
|
773
|
-
return entryPatterns.includes(fileName);
|
|
774
|
-
}
|
|
775
|
-
function sourceLocator(options = {}) {
|
|
776
|
-
const {
|
|
777
|
-
include = ["src/**/*.{jsx,tsx,js,ts}"],
|
|
778
|
-
exclude = [],
|
|
779
|
-
prefix = "locator",
|
|
780
|
-
enable = true,
|
|
781
|
-
autoInjectBridge = true,
|
|
782
|
-
entryFiles
|
|
783
|
-
} = options;
|
|
784
|
-
const includePatterns = Array.isArray(include) ? include : [include];
|
|
785
|
-
const excludePatterns = Array.isArray(exclude) ? exclude : [exclude];
|
|
786
|
-
return {
|
|
787
|
-
name: "@lego/plugin-source-locator",
|
|
788
|
-
enforce: "pre",
|
|
789
|
-
apply: "serve",
|
|
790
|
-
version: "0.0.1",
|
|
791
|
-
async transform(code, id) {
|
|
792
|
-
if (!enable) return;
|
|
793
|
-
if (autoInjectBridge && isEntryFile(id, entryFiles)) {
|
|
794
|
-
const bridgeImport = `import "@lego-build/plugins";`;
|
|
795
|
-
if (!code.includes(bridgeImport) && !code.includes("@lego-build/plugins")) {
|
|
796
|
-
code = `${bridgeImport}
|
|
797
|
-
${code}`;
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
const relativePath = path.relative(process.cwd(), id);
|
|
801
|
-
const isIncluded = micromatch.isMatch(relativePath, includePatterns);
|
|
802
|
-
const isExcluded = excludePatterns.length > 0 && micromatch.isMatch(relativePath, excludePatterns);
|
|
803
|
-
if (!isIncluded || isExcluded) return code !== code ? { code, map: null } : null;
|
|
804
|
-
const ext = path.extname(id);
|
|
805
|
-
if (![".jsx", ".tsx", ".js", ".ts"].includes(ext)) return null;
|
|
806
|
-
const hash = createHash("md5").update(code).digest("hex");
|
|
807
|
-
const cacheKey = `${id}:${hash}`;
|
|
808
|
-
if (transformCache.has(cacheKey)) {
|
|
809
|
-
return transformCache.get(cacheKey);
|
|
810
|
-
}
|
|
811
|
-
const result = transformJSX(code, id, prefix, options);
|
|
812
|
-
if (result) {
|
|
813
|
-
transformCache.set(cacheKey, result);
|
|
814
|
-
return result;
|
|
815
|
-
}
|
|
816
|
-
return null;
|
|
817
|
-
}
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// src/index.ts
|
|
822
|
-
try {
|
|
823
|
-
if (typeof window !== "undefined" && window.parent !== window) {
|
|
824
|
-
setupIframeBridge();
|
|
825
|
-
setupElementSelector();
|
|
826
|
-
}
|
|
827
|
-
} catch {
|
|
828
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
initIframeBridge,
|
|
3
|
+
sendToParent,
|
|
4
|
+
setupElementSelector,
|
|
5
|
+
setupIframeBridge
|
|
6
|
+
} from "./chunk-4ILDPPTG.js";
|
|
829
7
|
export {
|
|
8
|
+
initIframeBridge,
|
|
830
9
|
sendToParent,
|
|
831
10
|
setupElementSelector,
|
|
832
|
-
setupIframeBridge
|
|
833
|
-
sourceLocator
|
|
11
|
+
setupIframeBridge
|
|
834
12
|
};
|