@bitovi/vybit 0.12.0 → 0.13.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/overlay/dist/overlay.js +566 -64
- package/package.json +2 -1
- package/panel/dist/assets/{DesignMode-MoLVGcFD.js → DesignMode-DotlKICs.js} +1 -1
- package/panel/dist/assets/index-BWb2WAKo.js +61 -0
- package/panel/dist/assets/index-DN-H7d0q.css +1 -0
- package/panel/dist/index.html +2 -2
- package/server/app.ts +2 -0
- package/server/mcp-tools.ts +2 -2
- package/server/queue.ts +8 -0
- package/server/tailwind-v4.ts +10 -5
- package/server/websocket.ts +10 -1
- package/storybook-addon/preview-v10.ts +17 -12
- package/storybook-addon/preview.ts +17 -12
- package/panel/dist/assets/index-By_WWRF6.css +0 -1
- package/panel/dist/assets/index-C4LjGBfX.js +0 -63
package/overlay/dist/overlay.js
CHANGED
|
@@ -44,11 +44,6 @@
|
|
|
44
44
|
function sendTo(role, data) {
|
|
45
45
|
send({ ...data, to: role });
|
|
46
46
|
}
|
|
47
|
-
window.addEventListener("message", (event) => {
|
|
48
|
-
if (event.data?.type === "STORYBOOK_STORY_RENDERED") {
|
|
49
|
-
send({ type: "RESET_SELECTION" });
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
47
|
|
|
53
48
|
// overlay/src/context.ts
|
|
54
49
|
function buildContext(target, oldClass, newClass, originalClassMap) {
|
|
@@ -686,6 +681,73 @@ ${pad}</${tag}>`;
|
|
|
686
681
|
}
|
|
687
682
|
.msg-send svg { width: 12px; height: 12px; }
|
|
688
683
|
|
|
684
|
+
/* \u2500\u2500 Mic button (voice messages) \u2500\u2500 */
|
|
685
|
+
.mic-btn {
|
|
686
|
+
width: 24px;
|
|
687
|
+
height: 24px;
|
|
688
|
+
border-radius: 5px;
|
|
689
|
+
border: none;
|
|
690
|
+
background: transparent;
|
|
691
|
+
color: #888;
|
|
692
|
+
display: flex;
|
|
693
|
+
align-items: center;
|
|
694
|
+
justify-content: center;
|
|
695
|
+
cursor: pointer;
|
|
696
|
+
flex-shrink: 0;
|
|
697
|
+
transition: all 120ms ease-out;
|
|
698
|
+
padding: 0;
|
|
699
|
+
}
|
|
700
|
+
.mic-btn:hover { color: #e5e5e5; background: rgba(255,255,255,0.06); }
|
|
701
|
+
.mic-btn svg { width: 13px; height: 13px; }
|
|
702
|
+
.mic-btn.listening {
|
|
703
|
+
background: #F5532D;
|
|
704
|
+
color: white;
|
|
705
|
+
animation: mic-pulse 1.5s ease-in-out infinite;
|
|
706
|
+
}
|
|
707
|
+
.mic-btn.error { color: #F5532D; }
|
|
708
|
+
@keyframes mic-pulse {
|
|
709
|
+
0%, 100% { box-shadow: 0 0 0 0 rgba(245, 83, 45, 0.4); }
|
|
710
|
+
50% { box-shadow: 0 0 0 4px rgba(245, 83, 45, 0); }
|
|
711
|
+
}
|
|
712
|
+
/* \u2500\u2500 Mic-blocked banner \u2500\u2500 */
|
|
713
|
+
.mic-banner {
|
|
714
|
+
position: fixed;
|
|
715
|
+
top: 0;
|
|
716
|
+
left: 0;
|
|
717
|
+
right: 0;
|
|
718
|
+
z-index: 9999999;
|
|
719
|
+
display: flex;
|
|
720
|
+
align-items: center;
|
|
721
|
+
justify-content: center;
|
|
722
|
+
gap: 12px;
|
|
723
|
+
padding: 10px 16px;
|
|
724
|
+
background: #F5532D;
|
|
725
|
+
color: white;
|
|
726
|
+
font-family: 'Inter', system-ui, sans-serif;
|
|
727
|
+
font-size: 13px;
|
|
728
|
+
font-weight: 500;
|
|
729
|
+
box-shadow: 0 2px 12px rgba(0,0,0,0.3);
|
|
730
|
+
opacity: 0;
|
|
731
|
+
transform: translateY(-100%);
|
|
732
|
+
transition: opacity 0.25s ease-out, transform 0.25s ease-out;
|
|
733
|
+
}
|
|
734
|
+
.mic-banner.visible {
|
|
735
|
+
opacity: 1;
|
|
736
|
+
transform: translateY(0);
|
|
737
|
+
}
|
|
738
|
+
.mic-banner-dismiss {
|
|
739
|
+
background: none;
|
|
740
|
+
border: none;
|
|
741
|
+
color: white;
|
|
742
|
+
font-size: 18px;
|
|
743
|
+
cursor: pointer;
|
|
744
|
+
padding: 0 4px;
|
|
745
|
+
line-height: 1;
|
|
746
|
+
opacity: 0.8;
|
|
747
|
+
flex-shrink: 0;
|
|
748
|
+
}
|
|
749
|
+
.mic-banner-dismiss:hover { opacity: 1; }
|
|
750
|
+
|
|
689
751
|
/* \u2500\u2500 Text editing action bar \u2500\u2500 */
|
|
690
752
|
.text-action-bar {
|
|
691
753
|
position: fixed;
|
|
@@ -1524,6 +1586,9 @@ ${pad}</${tag}>`;
|
|
|
1524
1586
|
bottom: "top",
|
|
1525
1587
|
top: "bottom"
|
|
1526
1588
|
};
|
|
1589
|
+
function clamp(start, value, end) {
|
|
1590
|
+
return max(start, min(value, end));
|
|
1591
|
+
}
|
|
1527
1592
|
function evaluate(value, param) {
|
|
1528
1593
|
return typeof value === "function" ? value(param) : value;
|
|
1529
1594
|
}
|
|
@@ -2011,6 +2076,79 @@ ${pad}</${tag}>`;
|
|
|
2011
2076
|
}
|
|
2012
2077
|
};
|
|
2013
2078
|
};
|
|
2079
|
+
var shift = function(options) {
|
|
2080
|
+
if (options === void 0) {
|
|
2081
|
+
options = {};
|
|
2082
|
+
}
|
|
2083
|
+
return {
|
|
2084
|
+
name: "shift",
|
|
2085
|
+
options,
|
|
2086
|
+
async fn(state2) {
|
|
2087
|
+
const {
|
|
2088
|
+
x,
|
|
2089
|
+
y,
|
|
2090
|
+
placement,
|
|
2091
|
+
platform: platform2
|
|
2092
|
+
} = state2;
|
|
2093
|
+
const {
|
|
2094
|
+
mainAxis: checkMainAxis = true,
|
|
2095
|
+
crossAxis: checkCrossAxis = false,
|
|
2096
|
+
limiter = {
|
|
2097
|
+
fn: (_ref) => {
|
|
2098
|
+
let {
|
|
2099
|
+
x: x2,
|
|
2100
|
+
y: y2
|
|
2101
|
+
} = _ref;
|
|
2102
|
+
return {
|
|
2103
|
+
x: x2,
|
|
2104
|
+
y: y2
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
},
|
|
2108
|
+
...detectOverflowOptions
|
|
2109
|
+
} = evaluate(options, state2);
|
|
2110
|
+
const coords = {
|
|
2111
|
+
x,
|
|
2112
|
+
y
|
|
2113
|
+
};
|
|
2114
|
+
const overflow = await platform2.detectOverflow(state2, detectOverflowOptions);
|
|
2115
|
+
const crossAxis = getSideAxis(getSide(placement));
|
|
2116
|
+
const mainAxis = getOppositeAxis(crossAxis);
|
|
2117
|
+
let mainAxisCoord = coords[mainAxis];
|
|
2118
|
+
let crossAxisCoord = coords[crossAxis];
|
|
2119
|
+
if (checkMainAxis) {
|
|
2120
|
+
const minSide = mainAxis === "y" ? "top" : "left";
|
|
2121
|
+
const maxSide = mainAxis === "y" ? "bottom" : "right";
|
|
2122
|
+
const min2 = mainAxisCoord + overflow[minSide];
|
|
2123
|
+
const max2 = mainAxisCoord - overflow[maxSide];
|
|
2124
|
+
mainAxisCoord = clamp(min2, mainAxisCoord, max2);
|
|
2125
|
+
}
|
|
2126
|
+
if (checkCrossAxis) {
|
|
2127
|
+
const minSide = crossAxis === "y" ? "top" : "left";
|
|
2128
|
+
const maxSide = crossAxis === "y" ? "bottom" : "right";
|
|
2129
|
+
const min2 = crossAxisCoord + overflow[minSide];
|
|
2130
|
+
const max2 = crossAxisCoord - overflow[maxSide];
|
|
2131
|
+
crossAxisCoord = clamp(min2, crossAxisCoord, max2);
|
|
2132
|
+
}
|
|
2133
|
+
const limitedCoords = limiter.fn({
|
|
2134
|
+
...state2,
|
|
2135
|
+
[mainAxis]: mainAxisCoord,
|
|
2136
|
+
[crossAxis]: crossAxisCoord
|
|
2137
|
+
});
|
|
2138
|
+
return {
|
|
2139
|
+
...limitedCoords,
|
|
2140
|
+
data: {
|
|
2141
|
+
x: limitedCoords.x - x,
|
|
2142
|
+
y: limitedCoords.y - y,
|
|
2143
|
+
enabled: {
|
|
2144
|
+
[mainAxis]: checkMainAxis,
|
|
2145
|
+
[crossAxis]: checkCrossAxis
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
2151
|
+
};
|
|
2014
2152
|
|
|
2015
2153
|
// node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.mjs
|
|
2016
2154
|
function hasWindow() {
|
|
@@ -2761,6 +2899,7 @@ ${pad}</${tag}>`;
|
|
|
2761
2899
|
};
|
|
2762
2900
|
}
|
|
2763
2901
|
var offset2 = offset;
|
|
2902
|
+
var shift2 = shift;
|
|
2764
2903
|
var flip2 = flip;
|
|
2765
2904
|
var computePosition2 = (reference, floating, options) => {
|
|
2766
2905
|
const cache2 = /* @__PURE__ */ new Map();
|
|
@@ -3239,6 +3378,117 @@ ${pad}</${tag}>`;
|
|
|
3239
3378
|
}
|
|
3240
3379
|
};
|
|
3241
3380
|
|
|
3381
|
+
// overlay/src/angular-detect.ts
|
|
3382
|
+
function getNgApi() {
|
|
3383
|
+
const ng = window.ng;
|
|
3384
|
+
if (ng?.getComponent && ng?.getOwningComponent) return ng;
|
|
3385
|
+
return null;
|
|
3386
|
+
}
|
|
3387
|
+
function isAngularElement(el) {
|
|
3388
|
+
if ("__ngContext__" in el) return true;
|
|
3389
|
+
return Array.from(el.attributes).some(
|
|
3390
|
+
(a) => a.name.startsWith("_nghost-") || a.name.startsWith("_ngcontent-")
|
|
3391
|
+
);
|
|
3392
|
+
}
|
|
3393
|
+
function findAngularComponentBoundary(el) {
|
|
3394
|
+
const ng = getNgApi();
|
|
3395
|
+
if (ng) {
|
|
3396
|
+
const component = ng.getComponent(el) ?? ng.getOwningComponent(el);
|
|
3397
|
+
if (component) {
|
|
3398
|
+
const raw = component.constructor?.name || "Unknown";
|
|
3399
|
+
const name = raw.replace(/^_+/, "");
|
|
3400
|
+
return {
|
|
3401
|
+
componentType: component.constructor,
|
|
3402
|
+
componentName: name,
|
|
3403
|
+
componentFiber: component
|
|
3404
|
+
// reuse field for the component instance
|
|
3405
|
+
};
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
const hostAttr = findAttrStartingWith(el, "_nghost-");
|
|
3409
|
+
if (hostAttr) {
|
|
3410
|
+
return {
|
|
3411
|
+
componentType: el.tagName.toLowerCase(),
|
|
3412
|
+
componentName: formatTagAsComponentName(el.tagName),
|
|
3413
|
+
componentFiber: el
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
const contentAttr = findAttrStartingWith(el, "_ngcontent-");
|
|
3417
|
+
if (contentAttr) {
|
|
3418
|
+
const suffix = contentAttr.name.replace("_ngcontent-", "");
|
|
3419
|
+
const host = el.closest(`[_nghost-${suffix}]`);
|
|
3420
|
+
if (host) {
|
|
3421
|
+
return {
|
|
3422
|
+
componentType: host.tagName.toLowerCase(),
|
|
3423
|
+
componentName: formatTagAsComponentName(host.tagName),
|
|
3424
|
+
componentFiber: host
|
|
3425
|
+
};
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
return null;
|
|
3429
|
+
}
|
|
3430
|
+
function findAllAngularInstances(tagOrType) {
|
|
3431
|
+
const ng = getNgApi();
|
|
3432
|
+
if (ng && typeof tagOrType === "function") {
|
|
3433
|
+
const sampleEl = document.querySelector(tagOrType.\u0275cmp?.selectors?.[0]?.[0] ?? "");
|
|
3434
|
+
if (!sampleEl) {
|
|
3435
|
+
return findAllAngularInstancesByClass(ng, tagOrType);
|
|
3436
|
+
}
|
|
3437
|
+
return Array.from(document.querySelectorAll(sampleEl.tagName.toLowerCase()));
|
|
3438
|
+
}
|
|
3439
|
+
if (typeof tagOrType === "string") {
|
|
3440
|
+
return Array.from(document.querySelectorAll(tagOrType));
|
|
3441
|
+
}
|
|
3442
|
+
return [];
|
|
3443
|
+
}
|
|
3444
|
+
function findAllAngularInstancesByClass(ng, componentClass) {
|
|
3445
|
+
const results = [];
|
|
3446
|
+
const allCustomElements = document.querySelectorAll("*");
|
|
3447
|
+
for (const el of allCustomElements) {
|
|
3448
|
+
const comp = ng.getComponent(el);
|
|
3449
|
+
if (comp instanceof componentClass) {
|
|
3450
|
+
results.push(el);
|
|
3451
|
+
}
|
|
3452
|
+
}
|
|
3453
|
+
return results;
|
|
3454
|
+
}
|
|
3455
|
+
function collectAngularComponentDOMNodes(hostEl, tagName) {
|
|
3456
|
+
const hostAttr = findAttrStartingWith(hostEl, "_nghost-");
|
|
3457
|
+
if (!hostAttr) {
|
|
3458
|
+
return Array.from(hostEl.querySelectorAll(tagName.toLowerCase()));
|
|
3459
|
+
}
|
|
3460
|
+
const suffix = hostAttr.name.replace("_nghost-", "");
|
|
3461
|
+
return Array.from(
|
|
3462
|
+
document.querySelectorAll(
|
|
3463
|
+
`${tagName.toLowerCase()}[_ngcontent-${suffix}]`
|
|
3464
|
+
)
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3467
|
+
function findAttrStartingWith(el, prefix) {
|
|
3468
|
+
return Array.from(el.attributes).find((a) => a.name.startsWith(prefix)) ?? null;
|
|
3469
|
+
}
|
|
3470
|
+
function formatTagAsComponentName(tagName) {
|
|
3471
|
+
const lower = tagName.toLowerCase();
|
|
3472
|
+
const stripped = lower.replace(/^app-/, "");
|
|
3473
|
+
const pascal = stripped.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
3474
|
+
return pascal + "Component";
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
// overlay/src/framework-detect.ts
|
|
3478
|
+
var cachedFramework = null;
|
|
3479
|
+
function detectComponent(el) {
|
|
3480
|
+
const fiber = getFiber(el);
|
|
3481
|
+
if (fiber) {
|
|
3482
|
+
cachedFramework = "react";
|
|
3483
|
+
return findComponentBoundary(fiber);
|
|
3484
|
+
}
|
|
3485
|
+
if (isAngularElement(el)) {
|
|
3486
|
+
cachedFramework = "angular";
|
|
3487
|
+
return findAngularComponentBoundary(el);
|
|
3488
|
+
}
|
|
3489
|
+
return null;
|
|
3490
|
+
}
|
|
3491
|
+
|
|
3242
3492
|
// overlay/src/design-canvas/vb-design-canvas.ts
|
|
3243
3493
|
var VbDesignCanvas = class extends HTMLElement {
|
|
3244
3494
|
static observedAttributes = ["src", "width", "height", "min-height"];
|
|
@@ -3286,6 +3536,7 @@ ${pad}</${tag}>`;
|
|
|
3286
3536
|
this.iframe.allow = "microphone";
|
|
3287
3537
|
this.iframe.style.cssText = css(DESIGN_CANVAS_IFRAME);
|
|
3288
3538
|
this.iframe.addEventListener("load", () => {
|
|
3539
|
+
console.log("[tw-debug] vb-design-canvas iframe load event fired, src=", this.iframe.src);
|
|
3289
3540
|
this.dispatchEvent(new CustomEvent("vb-canvas-ready", {
|
|
3290
3541
|
bubbles: true,
|
|
3291
3542
|
detail: { iframe: this.iframe }
|
|
@@ -3338,7 +3589,9 @@ ${pad}</${tag}>`;
|
|
|
3338
3589
|
/** Sync observed attributes to internal DOM. */
|
|
3339
3590
|
syncAttributes() {
|
|
3340
3591
|
const src = this.getAttribute("src");
|
|
3592
|
+
console.log("[tw-debug] vb-design-canvas syncAttributes, src=", src, "current iframe.src=", this.iframe.src);
|
|
3341
3593
|
if (src && this.iframe.src !== src) {
|
|
3594
|
+
console.log("[tw-debug] vb-design-canvas setting iframe.src =", src);
|
|
3342
3595
|
this.iframe.src = src;
|
|
3343
3596
|
}
|
|
3344
3597
|
const w = this.getAttribute("width");
|
|
@@ -3379,6 +3632,7 @@ ${pad}</${tag}>`;
|
|
|
3379
3632
|
var TEXT_SVG = `<svg viewBox="0 0 16 16" fill="currentColor"><path d="M14.895,2.553l-1-2c-.169-.339-.516-.553-.895-.553H3c-.379,0-.725,.214-.895,.553L1.105,2.553c-.247,.494-.047,1.095,.447,1.342,.496,.248,1.095,.046,1.342-.447l.724-1.447h3.382V14h-2c-.552,0-1,.448-1,1s.448,1,1,1h6c.552,0,1-.448,1-1s-.448-1-1-1h-2V2h3.382l.724,1.447c.175,.351,.528,.553,.896,.553,.15,0,.303-.034,.446-.105,.494-.247,.694-.848,.447-1.342Z"/></svg>`;
|
|
3380
3633
|
var REPLACE_SVG = `<svg viewBox="0 0 16 16" fill="currentColor"><path d="M6,15H1a1,1,0,0,1-1-1V2A1,1,0,0,1,1,1H6A1,1,0,0,1,7,2V14A1,1,0,0,1,6,15Z"/><rect x="9" y="6" width="2" height="4"/><path d="M14,13H11V12H9v2a1,1,0,0,0,1,1h5a1,1,0,0,0,1-1V12H14Z"/><path d="M15,1H10A1,1,0,0,0,9,2V4h2V3h3V4h2V2A1,1,0,0,0,15,1Z"/><rect x="14" y="6" width="2" height="4"/></svg>`;
|
|
3381
3634
|
var SEND_SVG = `<svg viewBox="0 0 16 16" fill="currentColor"><path d="M15.7,7.3l-14-7C1.4,0.1,1.1,0.1,0.8,0.3C0.6,0.4,0.5,0.7,0.5,1l1.8,6H9v2H2.3L0.5,15c-0.1,0.3,0,0.6,0.2,0.7C0.8,15.9,1,16,1.1,16c0.1,0,0.3,0,0.4-0.1l14-7C15.8,8.7,16,8.4,16,8S15.8,7.3,15.7,7.3z"/></svg>`;
|
|
3635
|
+
var MIC_SVG = `<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 1a4 4 0 0 1 4 4v7a4 4 0 0 1-8 0V5a4 4 0 0 1 4-4zm-1.5 4v7a1.5 1.5 0 0 0 3 0V5a1.5 1.5 0 0 0-3 0zM6 11a1 1 0 0 1 1 1 5 5 0 0 0 10 0 1 1 0 1 1 2 0 7 7 0 0 1-6 6.93V21h2a1 1 0 1 1 0 2H9a1 1 0 1 1 0-2h2v-2.07A7 7 0 0 1 5 12a1 1 0 0 1 1-1z"/></svg>`;
|
|
3382
3636
|
var VYBIT_LOGO_SVG = `<svg width="26" height="27" viewBox="0 0 210 221" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
3383
3637
|
<path class="eb-fill" d="M141.54 137.71L103.87 140.38C102.98 140.44 102.2 140.97 101.8 141.77C101.41 142.57 101.47 143.51 101.96 144.25C102.27 144.72 109.46 155.39 121.96 155.39C122.3 155.39 122.65 155.39 123 155.37C138.61 154.64 143.83 141.66 144.05 141.11C144.36 140.31 144.24 139.41 143.73 138.72C143.22 138.03 142.4 137.65 141.54 137.71Z"/>
|
|
3384
3638
|
<path class="eb-eye-l eb-fill" d="M80.6401 93.03C76.7801 93.22 73.8 96.5 73.99 100.36L74.7501 115.96C74.9401 119.85 78.2701 122.84 82.1501 122.61C85.9801 122.38 88.9101 119.11 88.7301 115.28L87.9701 99.68C87.7801 95.82 84.5001 92.84 80.6401 93.03Z"/>
|
|
@@ -3422,13 +3676,23 @@ ${pad}</${tag}>`;
|
|
|
3422
3676
|
function findExactMatches(clickedEl, shadowHost) {
|
|
3423
3677
|
const classes = parseClassList(typeof clickedEl.className === "string" ? clickedEl.className : "");
|
|
3424
3678
|
const tag = clickedEl.tagName;
|
|
3425
|
-
const
|
|
3426
|
-
const boundary = fiber ? findComponentBoundary(fiber) : null;
|
|
3679
|
+
const boundary = detectComponent(clickedEl);
|
|
3427
3680
|
const componentName = boundary?.componentName ?? null;
|
|
3681
|
+
const fiber = getFiber(clickedEl);
|
|
3682
|
+
const reactBoundary = fiber ? findComponentBoundary(fiber) : null;
|
|
3428
3683
|
let exactMatches;
|
|
3429
|
-
if (
|
|
3430
|
-
const rootFiber = getRootFiberFrom(
|
|
3431
|
-
const allNodes = rootFiber ? collectComponentDOMNodes(rootFiber,
|
|
3684
|
+
if (reactBoundary) {
|
|
3685
|
+
const rootFiber = getRootFiberFrom(reactBoundary.componentFiber) ?? getRootFiber();
|
|
3686
|
+
const allNodes = rootFiber ? collectComponentDOMNodes(rootFiber, reactBoundary.componentType, tag) : [];
|
|
3687
|
+
exactMatches = allNodes.filter(
|
|
3688
|
+
(n) => n.tagName === tag && n.className === clickedEl.className
|
|
3689
|
+
);
|
|
3690
|
+
} else if (boundary && isAngularElement(clickedEl)) {
|
|
3691
|
+
const instances = findAllAngularInstances(boundary.componentType);
|
|
3692
|
+
const allNodes = [];
|
|
3693
|
+
for (const host of instances) {
|
|
3694
|
+
allNodes.push(...collectAngularComponentDOMNodes(host, tag));
|
|
3695
|
+
}
|
|
3432
3696
|
exactMatches = allNodes.filter(
|
|
3433
3697
|
(n) => n.tagName === tag && n.className === clickedEl.className
|
|
3434
3698
|
);
|
|
@@ -3464,14 +3728,23 @@ ${pad}</${tag}>`;
|
|
|
3464
3728
|
const tag = clickedEl.tagName;
|
|
3465
3729
|
const refSet = new Set(classes);
|
|
3466
3730
|
if (classes.length === 0) return [];
|
|
3731
|
+
const boundary = detectComponent(clickedEl);
|
|
3467
3732
|
const fiber = getFiber(clickedEl);
|
|
3468
|
-
const
|
|
3733
|
+
const reactBoundary = fiber ? findComponentBoundary(fiber) : null;
|
|
3469
3734
|
let candidates;
|
|
3470
|
-
if (
|
|
3471
|
-
const rootFiber = getRootFiberFrom(
|
|
3472
|
-
candidates = rootFiber ? collectComponentDOMNodes(rootFiber,
|
|
3735
|
+
if (reactBoundary) {
|
|
3736
|
+
const rootFiber = getRootFiberFrom(reactBoundary.componentFiber) ?? getRootFiber();
|
|
3737
|
+
candidates = rootFiber ? collectComponentDOMNodes(rootFiber, reactBoundary.componentType, tag) : [];
|
|
3473
3738
|
candidates = candidates.filter((n) => !exactMatchSet.has(n));
|
|
3474
|
-
console.log("[grouping] React path \u2014 component:",
|
|
3739
|
+
console.log("[grouping] React path \u2014 component:", reactBoundary.componentName, "tag:", tag, "candidates:", candidates.length, candidates.map((n) => n.className.split(" ")[0]));
|
|
3740
|
+
} else if (boundary && isAngularElement(clickedEl)) {
|
|
3741
|
+
const instances = findAllAngularInstances(boundary.componentType);
|
|
3742
|
+
const allNodes = [];
|
|
3743
|
+
for (const host of instances) {
|
|
3744
|
+
allNodes.push(...collectAngularComponentDOMNodes(host, tag));
|
|
3745
|
+
}
|
|
3746
|
+
candidates = allNodes.filter((n) => !exactMatchSet.has(n));
|
|
3747
|
+
console.log("[grouping] Angular path \u2014 component:", boundary.componentName, "tag:", tag, "candidates:", candidates.length);
|
|
3475
3748
|
} else {
|
|
3476
3749
|
const seen = new Set(exactMatchSet);
|
|
3477
3750
|
candidates = [];
|
|
@@ -3544,21 +3817,42 @@ ${pad}</${tag}>`;
|
|
|
3544
3817
|
}
|
|
3545
3818
|
function findSamePathElements(clickedEl) {
|
|
3546
3819
|
const fiber = getFiber(clickedEl);
|
|
3547
|
-
if (
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3820
|
+
if (fiber) {
|
|
3821
|
+
const boundary = findComponentBoundary(fiber);
|
|
3822
|
+
if (!boundary) return null;
|
|
3823
|
+
const { label, path } = buildPathLabel(fiber, boundary);
|
|
3824
|
+
const rootFiber = getRootFiberFrom(boundary.componentFiber) ?? getRootFiber();
|
|
3825
|
+
if (!rootFiber) return null;
|
|
3826
|
+
const instances = findAllInstances(rootFiber, boundary.componentType);
|
|
3827
|
+
const elements = [];
|
|
3828
|
+
for (const inst of instances) {
|
|
3829
|
+
const node = resolvePathToDOM(inst, path);
|
|
3830
|
+
if (node && !elements.includes(node)) {
|
|
3831
|
+
elements.push(node);
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
return elements.length > 0 ? { elements, label } : null;
|
|
3835
|
+
}
|
|
3836
|
+
if (isAngularElement(clickedEl)) {
|
|
3837
|
+
const boundary = detectComponent(clickedEl);
|
|
3838
|
+
if (!boundary) return null;
|
|
3839
|
+
const instances = findAllAngularInstances(boundary.componentType);
|
|
3840
|
+
if (instances.length < 2) return null;
|
|
3841
|
+
const tag = clickedEl.tagName;
|
|
3842
|
+
const elements = [];
|
|
3843
|
+
for (const host of instances) {
|
|
3844
|
+
const nodes = collectAngularComponentDOMNodes(host, tag);
|
|
3845
|
+
const match = nodes.find(
|
|
3846
|
+
(n) => n.tagName === clickedEl.tagName && n.className === clickedEl.className
|
|
3847
|
+
);
|
|
3848
|
+
if (match && !elements.includes(match)) {
|
|
3849
|
+
elements.push(match);
|
|
3850
|
+
}
|
|
3559
3851
|
}
|
|
3852
|
+
const label = `${boundary.componentName} > ${tag.toLowerCase()}`;
|
|
3853
|
+
return elements.length > 0 ? { elements, label } : null;
|
|
3560
3854
|
}
|
|
3561
|
-
return
|
|
3855
|
+
return null;
|
|
3562
3856
|
}
|
|
3563
3857
|
|
|
3564
3858
|
// overlay/src/patcher.ts
|
|
@@ -3811,13 +4105,52 @@ ${pad}</${tag}>`;
|
|
|
3811
4105
|
clearHoverPreview();
|
|
3812
4106
|
return;
|
|
3813
4107
|
}
|
|
3814
|
-
const
|
|
3815
|
-
const boundary = fiber ? findComponentBoundary(fiber) : null;
|
|
4108
|
+
const boundary = detectComponent(target);
|
|
3816
4109
|
const label = boundary?.componentName ?? target.tagName.toLowerCase();
|
|
3817
4110
|
showHoverPreview(target, label);
|
|
3818
4111
|
}
|
|
3819
4112
|
|
|
3820
4113
|
// overlay/src/element-toolbar.ts
|
|
4114
|
+
var SpeechRecognitionAPI = typeof window !== "undefined" ? window.SpeechRecognition ?? window.webkitSpeechRecognition ?? null : null;
|
|
4115
|
+
var activeBanner = null;
|
|
4116
|
+
var bannerTimeout = null;
|
|
4117
|
+
function showMicBanner(message) {
|
|
4118
|
+
if (activeBanner) {
|
|
4119
|
+
activeBanner.remove();
|
|
4120
|
+
activeBanner = null;
|
|
4121
|
+
}
|
|
4122
|
+
if (bannerTimeout) {
|
|
4123
|
+
clearTimeout(bannerTimeout);
|
|
4124
|
+
bannerTimeout = null;
|
|
4125
|
+
}
|
|
4126
|
+
const banner = document.createElement("div");
|
|
4127
|
+
banner.className = "mic-banner";
|
|
4128
|
+
const text = document.createElement("span");
|
|
4129
|
+
text.textContent = message;
|
|
4130
|
+
banner.appendChild(text);
|
|
4131
|
+
const dismiss = document.createElement("button");
|
|
4132
|
+
dismiss.className = "mic-banner-dismiss";
|
|
4133
|
+
dismiss.textContent = "\xD7";
|
|
4134
|
+
dismiss.addEventListener("click", () => {
|
|
4135
|
+
banner.classList.remove("visible");
|
|
4136
|
+
setTimeout(() => banner.remove(), 250);
|
|
4137
|
+
activeBanner = null;
|
|
4138
|
+
if (bannerTimeout) {
|
|
4139
|
+
clearTimeout(bannerTimeout);
|
|
4140
|
+
bannerTimeout = null;
|
|
4141
|
+
}
|
|
4142
|
+
});
|
|
4143
|
+
banner.appendChild(dismiss);
|
|
4144
|
+
state.shadowRoot.appendChild(banner);
|
|
4145
|
+
activeBanner = banner;
|
|
4146
|
+
requestAnimationFrame(() => banner.classList.add("visible"));
|
|
4147
|
+
bannerTimeout = setTimeout(() => {
|
|
4148
|
+
banner.classList.remove("visible");
|
|
4149
|
+
setTimeout(() => banner.remove(), 250);
|
|
4150
|
+
activeBanner = null;
|
|
4151
|
+
bannerTimeout = null;
|
|
4152
|
+
}, 8e3);
|
|
4153
|
+
}
|
|
3821
4154
|
var setSelectMode;
|
|
3822
4155
|
var showToast;
|
|
3823
4156
|
var onBrowseLocked;
|
|
@@ -3830,10 +4163,11 @@ ${pad}</${tag}>`;
|
|
|
3830
4163
|
rebuildSelectionFromSources = deps2.rebuildSelectionFromSources;
|
|
3831
4164
|
setAddMode = deps2.setAddMode;
|
|
3832
4165
|
}
|
|
3833
|
-
async function positionWithFlip(anchor, floating, placement = "top-start") {
|
|
4166
|
+
async function positionWithFlip(anchor, floating, placement = "top-start", options) {
|
|
4167
|
+
const middleware = options?.disableFlip ? [offset2(6)] : [offset2(6), flip2()];
|
|
3834
4168
|
const { x, y, placement: resolved } = await computePosition2(anchor, floating, {
|
|
3835
4169
|
placement,
|
|
3836
|
-
middleware
|
|
4170
|
+
middleware
|
|
3837
4171
|
});
|
|
3838
4172
|
floating.style.left = `${x}px`;
|
|
3839
4173
|
floating.style.top = `${y}px`;
|
|
@@ -3844,9 +4178,9 @@ ${pad}</${tag}>`;
|
|
|
3844
4178
|
if (!msgRow) return;
|
|
3845
4179
|
const msgPlacement = await positionWithFlip(targetEl, msgRow, "bottom-start");
|
|
3846
4180
|
if (toolbarPlacement === "bottom-start" && msgPlacement === "bottom-start") {
|
|
3847
|
-
await positionWithFlip(toolbar, msgRow, "bottom-start");
|
|
4181
|
+
await positionWithFlip(toolbar, msgRow, "bottom-start", { disableFlip: true });
|
|
3848
4182
|
} else if (toolbarPlacement === "top-start" && msgPlacement === "top-start") {
|
|
3849
|
-
await positionWithFlip(toolbar, msgRow, "top-start");
|
|
4183
|
+
await positionWithFlip(toolbar, msgRow, "top-start", { disableFlip: true });
|
|
3850
4184
|
}
|
|
3851
4185
|
}
|
|
3852
4186
|
function showDrawButton(targetEl) {
|
|
@@ -3878,10 +4212,8 @@ ${pad}</${tag}>`;
|
|
|
3878
4212
|
state.cachedExactMatches = null;
|
|
3879
4213
|
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
3880
4214
|
state.addMode = false;
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
sendTo("panel", { type: "MODE_CHANGED", mode: "select" });
|
|
3884
|
-
setSelectMode(true);
|
|
4215
|
+
setSelectMode(false);
|
|
4216
|
+
sendTo("panel", { type: "MODE_CHANGED", mode: null });
|
|
3885
4217
|
});
|
|
3886
4218
|
selectGroup.appendChild(selectBtn);
|
|
3887
4219
|
const innerSep = document.createElement("div");
|
|
@@ -3950,6 +4282,7 @@ ${pad}</${tag}>`;
|
|
|
3950
4282
|
clearLockedInsert();
|
|
3951
4283
|
revertPreview();
|
|
3952
4284
|
clearHighlights();
|
|
4285
|
+
setSelectMode(false);
|
|
3953
4286
|
state.currentEquivalentNodes = [];
|
|
3954
4287
|
state.currentTargetEl = null;
|
|
3955
4288
|
state.currentBoundary = null;
|
|
@@ -3957,6 +4290,10 @@ ${pad}</${tag}>`;
|
|
|
3957
4290
|
state.cachedExactMatches = null;
|
|
3958
4291
|
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
3959
4292
|
state.addMode = false;
|
|
4293
|
+
if (state.currentMode === "insert") {
|
|
4294
|
+
sendTo("panel", { type: "MODE_CHANGED", mode: null });
|
|
4295
|
+
return;
|
|
4296
|
+
}
|
|
3960
4297
|
state.currentMode = "insert";
|
|
3961
4298
|
if (state.tabPreference === "design") state.tabPreference = "component";
|
|
3962
4299
|
state.currentTab = resolveTab();
|
|
@@ -4008,20 +4345,79 @@ ${pad}</${tag}>`;
|
|
|
4008
4345
|
placeBtn.innerHTML = `Place`;
|
|
4009
4346
|
toolbar.appendChild(placeBtn);
|
|
4010
4347
|
}
|
|
4348
|
+
let msgRow;
|
|
4349
|
+
msgRow = createMsgRow(state.currentBoundary, () => positionBothMenus(targetEl, toolbar, msgRow));
|
|
4350
|
+
state.shadowRoot.appendChild(msgRow);
|
|
4351
|
+
state.msgRowEl = msgRow;
|
|
4352
|
+
positionBothMenus(targetEl, toolbar, msgRow);
|
|
4353
|
+
}
|
|
4354
|
+
function getCanvasMessageText() {
|
|
4355
|
+
const textarea = canvasMsgRow?.querySelector("textarea");
|
|
4356
|
+
return textarea?.value.trim() ?? "";
|
|
4357
|
+
}
|
|
4358
|
+
function createMsgRow(boundary, onReposition, options) {
|
|
4359
|
+
const showSendButton = options?.showSendButton ?? true;
|
|
4011
4360
|
const msgRow = document.createElement("div");
|
|
4012
4361
|
msgRow.className = "msg-row";
|
|
4013
4362
|
msgRow.style.left = "0px";
|
|
4014
4363
|
msgRow.style.top = "0px";
|
|
4015
|
-
state.shadowRoot.appendChild(msgRow);
|
|
4016
|
-
state.msgRowEl = msgRow;
|
|
4017
4364
|
const msgInput = document.createElement("textarea");
|
|
4018
4365
|
msgInput.rows = 1;
|
|
4019
4366
|
msgInput.placeholder = "add your message";
|
|
4020
4367
|
msgRow.appendChild(msgInput);
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4368
|
+
let recognition = null;
|
|
4369
|
+
let micBtn = null;
|
|
4370
|
+
if (SpeechRecognitionAPI) {
|
|
4371
|
+
micBtn = document.createElement("button");
|
|
4372
|
+
micBtn.className = "mic-btn";
|
|
4373
|
+
micBtn.title = "Record voice message";
|
|
4374
|
+
micBtn.innerHTML = MIC_SVG;
|
|
4375
|
+
msgRow.appendChild(micBtn);
|
|
4376
|
+
micBtn.addEventListener("click", (e) => {
|
|
4377
|
+
e.stopPropagation();
|
|
4378
|
+
if (recognition) {
|
|
4379
|
+
recognition.stop();
|
|
4380
|
+
return;
|
|
4381
|
+
}
|
|
4382
|
+
const baseText = msgInput.value;
|
|
4383
|
+
recognition = new SpeechRecognitionAPI();
|
|
4384
|
+
recognition.continuous = false;
|
|
4385
|
+
recognition.interimResults = true;
|
|
4386
|
+
recognition.lang = navigator.language || "en-US";
|
|
4387
|
+
recognition.onresult = (event) => {
|
|
4388
|
+
let transcript = "";
|
|
4389
|
+
for (let i = 0; i < event.results.length; i++) {
|
|
4390
|
+
transcript += event.results[i][0].transcript;
|
|
4391
|
+
}
|
|
4392
|
+
const separator = baseText && !baseText.endsWith("\n") ? "\n" : "";
|
|
4393
|
+
msgInput.value = baseText + separator + transcript;
|
|
4394
|
+
msgInput.style.height = "auto";
|
|
4395
|
+
msgInput.style.height = msgInput.scrollHeight + "px";
|
|
4396
|
+
onReposition();
|
|
4397
|
+
};
|
|
4398
|
+
recognition.onend = () => {
|
|
4399
|
+
micBtn.classList.remove("listening");
|
|
4400
|
+
recognition = null;
|
|
4401
|
+
};
|
|
4402
|
+
recognition.onerror = (event) => {
|
|
4403
|
+
micBtn.classList.remove("listening");
|
|
4404
|
+
if (event.error === "not-allowed" || event.error === "service-not-allowed") {
|
|
4405
|
+
micBtn.classList.add("error");
|
|
4406
|
+
showMicBanner("Microphone blocked \u2014 allow access in your browser's address bar");
|
|
4407
|
+
}
|
|
4408
|
+
recognition = null;
|
|
4409
|
+
};
|
|
4410
|
+
micBtn.classList.remove("error");
|
|
4411
|
+
micBtn.classList.add("listening");
|
|
4412
|
+
recognition.start();
|
|
4413
|
+
});
|
|
4414
|
+
}
|
|
4415
|
+
const msgSendBtn = showSendButton ? document.createElement("button") : null;
|
|
4416
|
+
if (msgSendBtn) {
|
|
4417
|
+
msgSendBtn.className = "msg-send";
|
|
4418
|
+
msgSendBtn.innerHTML = SEND_SVG;
|
|
4419
|
+
msgRow.appendChild(msgSendBtn);
|
|
4420
|
+
}
|
|
4025
4421
|
function sendMessage() {
|
|
4026
4422
|
const text = msgInput.value.trim();
|
|
4027
4423
|
if (!text) return;
|
|
@@ -4030,15 +4426,15 @@ ${pad}</${tag}>`;
|
|
|
4030
4426
|
type: "MESSAGE_STAGE",
|
|
4031
4427
|
id,
|
|
4032
4428
|
message: text,
|
|
4033
|
-
elementKey:
|
|
4034
|
-
component:
|
|
4429
|
+
elementKey: boundary?.componentName ?? "",
|
|
4430
|
+
component: boundary ? { name: boundary.componentName } : void 0
|
|
4035
4431
|
});
|
|
4036
4432
|
msgInput.value = "";
|
|
4037
4433
|
msgInput.style.height = "auto";
|
|
4038
|
-
|
|
4434
|
+
onReposition();
|
|
4039
4435
|
showToast("Message staged");
|
|
4040
4436
|
}
|
|
4041
|
-
msgSendBtn
|
|
4437
|
+
msgSendBtn?.addEventListener("click", (e) => {
|
|
4042
4438
|
e.stopPropagation();
|
|
4043
4439
|
sendMessage();
|
|
4044
4440
|
});
|
|
@@ -4054,10 +4450,45 @@ ${pad}</${tag}>`;
|
|
|
4054
4450
|
msgInput.addEventListener("input", () => {
|
|
4055
4451
|
msgInput.style.height = "auto";
|
|
4056
4452
|
msgInput.style.height = msgInput.scrollHeight + "px";
|
|
4057
|
-
|
|
4453
|
+
onReposition();
|
|
4058
4454
|
});
|
|
4059
4455
|
msgRow.addEventListener("click", (e) => e.stopPropagation());
|
|
4060
|
-
|
|
4456
|
+
return msgRow;
|
|
4457
|
+
}
|
|
4458
|
+
var canvasMsgRow = null;
|
|
4459
|
+
var canvasMsgRowObserver = null;
|
|
4460
|
+
function showCanvasMessageRow(canvasWrapper, boundary, shadowRoot) {
|
|
4461
|
+
hideCanvasMessageRow();
|
|
4462
|
+
const msgRow = createMsgRow(boundary, () => positionCanvasMsgRow(canvasWrapper, msgRow), { showSendButton: false });
|
|
4463
|
+
msgRow.setAttribute("data-canvas-anchor", "true");
|
|
4464
|
+
shadowRoot.appendChild(msgRow);
|
|
4465
|
+
canvasMsgRow = msgRow;
|
|
4466
|
+
positionCanvasMsgRow(canvasWrapper, msgRow);
|
|
4467
|
+
canvasMsgRowObserver = new ResizeObserver(() => {
|
|
4468
|
+
positionCanvasMsgRow(canvasWrapper, msgRow);
|
|
4469
|
+
});
|
|
4470
|
+
canvasMsgRowObserver.observe(canvasWrapper);
|
|
4471
|
+
}
|
|
4472
|
+
function hideCanvasMessageRow() {
|
|
4473
|
+
canvasMsgRowObserver?.disconnect();
|
|
4474
|
+
canvasMsgRowObserver = null;
|
|
4475
|
+
canvasMsgRow?.remove();
|
|
4476
|
+
canvasMsgRow = null;
|
|
4477
|
+
}
|
|
4478
|
+
function positionCanvasMsgRow(canvasWrapper, msgRow) {
|
|
4479
|
+
computePosition2(canvasWrapper, msgRow, {
|
|
4480
|
+
placement: "bottom-start",
|
|
4481
|
+
middleware: [
|
|
4482
|
+
shift2({ padding: 8 }),
|
|
4483
|
+
flip2()
|
|
4484
|
+
]
|
|
4485
|
+
}).then(({ x, y }) => {
|
|
4486
|
+
Object.assign(msgRow.style, {
|
|
4487
|
+
position: "fixed",
|
|
4488
|
+
left: `${x}px`,
|
|
4489
|
+
top: `${y}px`
|
|
4490
|
+
});
|
|
4491
|
+
});
|
|
4061
4492
|
}
|
|
4062
4493
|
function showGroupPicker(anchorBtn, onClose, onCountChange) {
|
|
4063
4494
|
if (state.pickerCloseHandler) {
|
|
@@ -5151,6 +5582,7 @@ ${pad}</${tag}>`;
|
|
|
5151
5582
|
showToastFn = deps2.showToast;
|
|
5152
5583
|
}
|
|
5153
5584
|
function injectDesignCanvas(insertMode) {
|
|
5585
|
+
console.log("[tw-debug] injectDesignCanvas called, insertMode=", insertMode, "currentTargetEl=", state.currentTargetEl, "currentBoundary=", state.currentBoundary);
|
|
5154
5586
|
if (!state.currentTargetEl || !state.currentBoundary) {
|
|
5155
5587
|
showToastFn("Select an element first");
|
|
5156
5588
|
return;
|
|
@@ -5158,7 +5590,9 @@ ${pad}</${tag}>`;
|
|
|
5158
5590
|
clearHighlights();
|
|
5159
5591
|
const targetEl = state.currentTargetEl;
|
|
5160
5592
|
const canvas = document.createElement("vb-design-canvas");
|
|
5161
|
-
|
|
5593
|
+
const canvasSrc = `${serverOrigin}/panel/?mode=design`;
|
|
5594
|
+
console.log("[tw-debug] creating vb-design-canvas, src=", canvasSrc, "targetEl=", targetEl, "insertMode=", insertMode);
|
|
5595
|
+
canvas.setAttribute("src", canvasSrc);
|
|
5162
5596
|
const wrapper = canvas.getWrapper();
|
|
5163
5597
|
let replacedNodes = null;
|
|
5164
5598
|
let replacedParent = null;
|
|
@@ -5193,7 +5627,10 @@ ${pad}</${tag}>`;
|
|
|
5193
5627
|
parent: replacedParent,
|
|
5194
5628
|
anchor: replacedAnchor
|
|
5195
5629
|
});
|
|
5630
|
+
requestAnimationFrame(() => showCanvasMessageRow(canvas.getWrapper(), state.currentBoundary, state.shadowRoot));
|
|
5631
|
+
console.log("[tw-debug] canvas inserted into DOM, listening for vb-canvas-ready...");
|
|
5196
5632
|
canvas.addEventListener("vb-canvas-ready", () => {
|
|
5633
|
+
console.log("[tw-debug] vb-canvas-ready fired!");
|
|
5197
5634
|
const contextMsg = {
|
|
5198
5635
|
type: "ELEMENT_CONTEXT",
|
|
5199
5636
|
componentName: state.currentBoundary?.componentName ?? "",
|
|
@@ -5276,6 +5713,7 @@ ${pad}</${tag}>`;
|
|
|
5276
5713
|
parent.insertBefore(canvas, marker);
|
|
5277
5714
|
marker.remove();
|
|
5278
5715
|
state.designCanvasWrappers.push({ wrapper: canvas, replacedNodes, parent, anchor: canvas.nextSibling });
|
|
5716
|
+
requestAnimationFrame(() => showCanvasMessageRow(canvas.getWrapper(), state.currentBoundary, state.shadowRoot));
|
|
5279
5717
|
canvas.addEventListener("vb-canvas-ready", () => {
|
|
5280
5718
|
const contextMsg = {
|
|
5281
5719
|
type: "ELEMENT_CONTEXT",
|
|
@@ -5299,6 +5737,12 @@ ${pad}</${tag}>`;
|
|
|
5299
5737
|
setTimeout(trySend, 200);
|
|
5300
5738
|
});
|
|
5301
5739
|
}
|
|
5740
|
+
function removeAllDesignCanvases() {
|
|
5741
|
+
for (const entry of state.designCanvasWrappers) {
|
|
5742
|
+
entry.wrapper.remove();
|
|
5743
|
+
}
|
|
5744
|
+
state.designCanvasWrappers.length = 0;
|
|
5745
|
+
}
|
|
5302
5746
|
function handleDesignSubmitted(msg) {
|
|
5303
5747
|
const lastEntry = state.designCanvasWrappers[state.designCanvasWrappers.length - 1];
|
|
5304
5748
|
const last = lastEntry?.wrapper;
|
|
@@ -5315,6 +5759,11 @@ ${pad}</${tag}>`;
|
|
|
5315
5759
|
last.appendChild(img);
|
|
5316
5760
|
}
|
|
5317
5761
|
}
|
|
5762
|
+
const messageText = getCanvasMessageText();
|
|
5763
|
+
if (messageText && msg.patchId) {
|
|
5764
|
+
send({ type: "CANVAS_MESSAGE_ATTACH", patchId: msg.patchId, message: messageText });
|
|
5765
|
+
}
|
|
5766
|
+
hideCanvasMessageRow();
|
|
5318
5767
|
}
|
|
5319
5768
|
function handleDesignClose() {
|
|
5320
5769
|
const last = state.designCanvasWrappers.pop();
|
|
@@ -5326,6 +5775,7 @@ ${pad}</${tag}>`;
|
|
|
5326
5775
|
}
|
|
5327
5776
|
last.wrapper.remove();
|
|
5328
5777
|
}
|
|
5778
|
+
hideCanvasMessageRow();
|
|
5329
5779
|
}
|
|
5330
5780
|
|
|
5331
5781
|
// overlay/src/recording/console-interceptor/console-interceptor.ts
|
|
@@ -6825,8 +7275,7 @@ ${pad}</${tag}>`;
|
|
|
6825
7275
|
function onBrowseLocked2(target) {
|
|
6826
7276
|
state.currentTargetEl = target;
|
|
6827
7277
|
state.currentEquivalentNodes = [target];
|
|
6828
|
-
const
|
|
6829
|
-
const boundary = fiber ? findComponentBoundary(fiber) : null;
|
|
7278
|
+
const boundary = detectComponent(target);
|
|
6830
7279
|
state.currentBoundary = boundary ? { componentName: boundary.componentName } : { componentName: target.tagName.toLowerCase() };
|
|
6831
7280
|
state.cachedNearGroups = null;
|
|
6832
7281
|
showDrawButton(target);
|
|
@@ -7088,6 +7537,24 @@ ${pad}</${tag}>`;
|
|
|
7088
7537
|
setTimeout(() => toast.remove(), 200);
|
|
7089
7538
|
}, duration);
|
|
7090
7539
|
}
|
|
7540
|
+
function resetOnNavigation() {
|
|
7541
|
+
if (isTextEditing()) endTextEdit(false);
|
|
7542
|
+
revertPreview();
|
|
7543
|
+
clearHighlights();
|
|
7544
|
+
cancelInsert();
|
|
7545
|
+
clearLockedInsert();
|
|
7546
|
+
removeAllDesignCanvases();
|
|
7547
|
+
state.currentEquivalentNodes = [];
|
|
7548
|
+
state.currentTargetEl = null;
|
|
7549
|
+
state.currentBoundary = null;
|
|
7550
|
+
state.cachedNearGroups = null;
|
|
7551
|
+
state.cachedExactMatches = null;
|
|
7552
|
+
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
7553
|
+
state.addMode = false;
|
|
7554
|
+
setSelectMode2(false);
|
|
7555
|
+
sendTo("panel", { type: "RESET_SELECTION" });
|
|
7556
|
+
sendTo("panel", { type: "COMPONENT_DISARMED" });
|
|
7557
|
+
}
|
|
7091
7558
|
function getDefaultContainer() {
|
|
7092
7559
|
try {
|
|
7093
7560
|
const stored = localStorage.getItem("tw-panel-container");
|
|
@@ -7099,6 +7566,8 @@ ${pad}</${tag}>`;
|
|
|
7099
7566
|
return "popover";
|
|
7100
7567
|
}
|
|
7101
7568
|
function init() {
|
|
7569
|
+
const params = new URLSearchParams(location.search);
|
|
7570
|
+
if (params.get("viewMode") === "story" || params.get("vybit-ghost") === "1") return;
|
|
7102
7571
|
state.shadowHost = document.createElement("div");
|
|
7103
7572
|
state.shadowHost.id = "tw-visual-editor-host";
|
|
7104
7573
|
state.shadowHost.style.cssText = css(SHADOW_HOST);
|
|
@@ -7125,6 +7594,16 @@ ${pad}</${tag}>`;
|
|
|
7125
7594
|
btn.style.display = "none";
|
|
7126
7595
|
}
|
|
7127
7596
|
state.shadowRoot.appendChild(btn);
|
|
7597
|
+
createNavigationInterceptor(() => {
|
|
7598
|
+
if (state.active) resetOnNavigation();
|
|
7599
|
+
});
|
|
7600
|
+
window.addEventListener("message", (event) => {
|
|
7601
|
+
if (event.data?.type === "STORYBOOK_STORY_RENDERED") {
|
|
7602
|
+
if (state.active) {
|
|
7603
|
+
resetOnNavigation();
|
|
7604
|
+
}
|
|
7605
|
+
}
|
|
7606
|
+
});
|
|
7128
7607
|
document.addEventListener("keydown", (e) => {
|
|
7129
7608
|
if (e.key === "Escape") {
|
|
7130
7609
|
if (state.addMode) {
|
|
@@ -7141,11 +7620,14 @@ ${pad}</${tag}>`;
|
|
|
7141
7620
|
state.cachedExactMatches = null;
|
|
7142
7621
|
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
7143
7622
|
state.addMode = false;
|
|
7144
|
-
sendTo("panel", { type: "RESET_SELECTION" });
|
|
7145
7623
|
if (state.currentMode === "select") {
|
|
7146
7624
|
setSelectMode2(true);
|
|
7625
|
+
sendTo("panel", { type: "DESELECT_ELEMENT" });
|
|
7147
7626
|
} else if (state.currentMode === "insert") {
|
|
7627
|
+
sendTo("panel", { type: "DESELECT_ELEMENT" });
|
|
7148
7628
|
startBrowse(state.shadowHost, onBrowseLocked2);
|
|
7629
|
+
} else {
|
|
7630
|
+
sendTo("panel", { type: "RESET_SELECTION" });
|
|
7149
7631
|
}
|
|
7150
7632
|
} else if (state.selectModeOn) {
|
|
7151
7633
|
setSelectMode2(false);
|
|
@@ -7162,6 +7644,8 @@ ${pad}</${tag}>`;
|
|
|
7162
7644
|
onMessage((msg) => {
|
|
7163
7645
|
if (msg.type === "TOGGLE_SELECT_MODE") {
|
|
7164
7646
|
if (msg.active) {
|
|
7647
|
+
state.active = true;
|
|
7648
|
+
sessionStorage.setItem(PANEL_OPEN_KEY, "1");
|
|
7165
7649
|
setSelectMode2(true);
|
|
7166
7650
|
if (!insideStorybook) {
|
|
7167
7651
|
const panelUrl = `${SERVER_ORIGIN}/panel`;
|
|
@@ -7171,6 +7655,10 @@ ${pad}</${tag}>`;
|
|
|
7171
7655
|
setSelectMode2(false);
|
|
7172
7656
|
}
|
|
7173
7657
|
} else if (msg.type === "MODE_CHANGED") {
|
|
7658
|
+
if (msg.mode) {
|
|
7659
|
+
state.active = true;
|
|
7660
|
+
sessionStorage.setItem(PANEL_OPEN_KEY, "1");
|
|
7661
|
+
}
|
|
7174
7662
|
revertPreview();
|
|
7175
7663
|
clearHighlights();
|
|
7176
7664
|
cancelInsert();
|
|
@@ -7181,6 +7669,7 @@ ${pad}</${tag}>`;
|
|
|
7181
7669
|
state.cachedNearGroups = null;
|
|
7182
7670
|
state.currentMode = msg.mode;
|
|
7183
7671
|
if (msg.mode === "insert") {
|
|
7672
|
+
setSelectMode2(false);
|
|
7184
7673
|
if (state.tabPreference === "design") state.tabPreference = "component";
|
|
7185
7674
|
state.currentTab = resolveTab();
|
|
7186
7675
|
startBrowse(state.shadowHost, onBrowseLocked2);
|
|
@@ -7295,22 +7784,36 @@ ${pad}</${tag}>`;
|
|
|
7295
7784
|
}
|
|
7296
7785
|
} else {
|
|
7297
7786
|
const locked2 = getLockedInsert();
|
|
7787
|
+
console.log("[tw-debug] INSERT_DESIGN_CANVAS else branch, locked=", locked2, "currentTargetEl=", state.currentTargetEl);
|
|
7298
7788
|
if (locked2) {
|
|
7299
7789
|
state.currentTargetEl = locked2.target;
|
|
7300
|
-
const
|
|
7301
|
-
const boundary = fiber ? findComponentBoundary(fiber) : null;
|
|
7790
|
+
const boundary = detectComponent(locked2.target);
|
|
7302
7791
|
state.currentBoundary = boundary ? { componentName: boundary.componentName } : { componentName: locked2.target.tagName.toLowerCase() };
|
|
7303
7792
|
state.currentEquivalentNodes = [locked2.target];
|
|
7304
7793
|
clearLockedInsert();
|
|
7794
|
+
console.log("[tw-debug] locked path \u2014 calling injectDesignCanvas, position=", locked2.position, "boundary=", state.currentBoundary);
|
|
7305
7795
|
injectDesignCanvas(locked2.position);
|
|
7306
7796
|
} else {
|
|
7797
|
+
console.log("[tw-debug] arming generic insert...");
|
|
7307
7798
|
armGenericInsert("Place: Canvas", state.shadowHost, (target, position) => {
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7799
|
+
console.log("[tw-debug] armGenericInsert callback fired, target=", target, "position=", position);
|
|
7800
|
+
try {
|
|
7801
|
+
console.log("[tw-debug] step 1: setting currentTargetEl");
|
|
7802
|
+
state.currentTargetEl = target;
|
|
7803
|
+
console.log("[tw-debug] step 2: calling detectComponent");
|
|
7804
|
+
const boundary = detectComponent(target);
|
|
7805
|
+
console.log("[tw-debug] step 3: boundary=", boundary);
|
|
7806
|
+
state.currentBoundary = boundary ? { componentName: boundary.componentName } : { componentName: target.tagName.toLowerCase() };
|
|
7807
|
+
state.currentEquivalentNodes = [target];
|
|
7808
|
+
console.log("[tw-debug] step 4: state set, currentBoundary=", state.currentBoundary, "\u2014 calling injectDesignCanvas");
|
|
7809
|
+
injectDesignCanvas(position);
|
|
7810
|
+
console.log("[tw-debug] injectDesignCanvas returned OK");
|
|
7811
|
+
} catch (err) {
|
|
7812
|
+
console.error("[tw-debug] CALLBACK THREW (this is the real error):", err);
|
|
7813
|
+
if (err instanceof Error) {
|
|
7814
|
+
console.error("[tw-debug] message:", err.message, "stack:", err.stack);
|
|
7815
|
+
}
|
|
7816
|
+
}
|
|
7314
7817
|
});
|
|
7315
7818
|
}
|
|
7316
7819
|
}
|
|
@@ -7439,8 +7942,7 @@ ${pad}</${tag}>`;
|
|
|
7439
7942
|
if (!target || target === state.shadowHost || e.composedPath().some((el) => el === state.shadowHost)) {
|
|
7440
7943
|
return;
|
|
7441
7944
|
}
|
|
7442
|
-
const
|
|
7443
|
-
const boundary = fiber ? findComponentBoundary(fiber) : null;
|
|
7945
|
+
const boundary = detectComponent(target);
|
|
7444
7946
|
const selectorPath = buildSelectorPath2(target);
|
|
7445
7947
|
const rect = target.getBoundingClientRect();
|
|
7446
7948
|
const element = {
|