@bitovi/vybit 0.12.0 → 0.13.1
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 +583 -105
- 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
|
+
}
|
|
3559
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
|
+
}
|
|
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,11 +4178,24 @@ ${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
|
}
|
|
4186
|
+
function clearSelection() {
|
|
4187
|
+
cancelInsert();
|
|
4188
|
+
clearLockedInsert();
|
|
4189
|
+
revertPreview();
|
|
4190
|
+
clearHighlights();
|
|
4191
|
+
state.currentEquivalentNodes = [];
|
|
4192
|
+
state.currentTargetEl = null;
|
|
4193
|
+
state.currentBoundary = null;
|
|
4194
|
+
state.cachedNearGroups = null;
|
|
4195
|
+
state.cachedExactMatches = null;
|
|
4196
|
+
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
4197
|
+
state.addMode = false;
|
|
4198
|
+
}
|
|
3852
4199
|
function showDrawButton(targetEl) {
|
|
3853
4200
|
removeDrawButton();
|
|
3854
4201
|
const instanceCount = state.currentEquivalentNodes.length;
|
|
@@ -3867,21 +4214,9 @@ ${pad}</${tag}>`;
|
|
|
3867
4214
|
selectBtn.style.cssText = "color: #5fd4da; border-radius: 0;";
|
|
3868
4215
|
selectBtn.addEventListener("click", (e) => {
|
|
3869
4216
|
e.stopPropagation();
|
|
3870
|
-
|
|
3871
|
-
clearLockedInsert();
|
|
3872
|
-
revertPreview();
|
|
3873
|
-
clearHighlights();
|
|
3874
|
-
state.currentEquivalentNodes = [];
|
|
3875
|
-
state.currentTargetEl = null;
|
|
3876
|
-
state.currentBoundary = null;
|
|
3877
|
-
state.cachedNearGroups = null;
|
|
3878
|
-
state.cachedExactMatches = null;
|
|
3879
|
-
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
3880
|
-
state.addMode = false;
|
|
3881
|
-
state.currentMode = "select";
|
|
3882
|
-
state.currentTab = resolveTab();
|
|
3883
|
-
sendTo("panel", { type: "MODE_CHANGED", mode: "select" });
|
|
4217
|
+
clearSelection();
|
|
3884
4218
|
setSelectMode(true);
|
|
4219
|
+
sendTo("panel", { type: "DESELECT_ELEMENT" });
|
|
3885
4220
|
});
|
|
3886
4221
|
selectGroup.appendChild(selectBtn);
|
|
3887
4222
|
const innerSep = document.createElement("div");
|
|
@@ -3918,17 +4253,7 @@ ${pad}</${tag}>`;
|
|
|
3918
4253
|
selectBtn.style.cssText = "opacity: 0.4;";
|
|
3919
4254
|
selectBtn.addEventListener("click", (e) => {
|
|
3920
4255
|
e.stopPropagation();
|
|
3921
|
-
|
|
3922
|
-
clearLockedInsert();
|
|
3923
|
-
revertPreview();
|
|
3924
|
-
clearHighlights();
|
|
3925
|
-
state.currentEquivalentNodes = [];
|
|
3926
|
-
state.currentTargetEl = null;
|
|
3927
|
-
state.currentBoundary = null;
|
|
3928
|
-
state.cachedNearGroups = null;
|
|
3929
|
-
state.cachedExactMatches = null;
|
|
3930
|
-
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
3931
|
-
state.addMode = false;
|
|
4256
|
+
clearSelection();
|
|
3932
4257
|
state.currentMode = "select";
|
|
3933
4258
|
state.currentTab = resolveTab();
|
|
3934
4259
|
sendTo("panel", { type: "MODE_CHANGED", mode: "select" });
|
|
@@ -3946,17 +4271,13 @@ ${pad}</${tag}>`;
|
|
|
3946
4271
|
}
|
|
3947
4272
|
insertBtn.addEventListener("click", (e) => {
|
|
3948
4273
|
e.stopPropagation();
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
state.cachedNearGroups = null;
|
|
3957
|
-
state.cachedExactMatches = null;
|
|
3958
|
-
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
3959
|
-
state.addMode = false;
|
|
4274
|
+
clearSelection();
|
|
4275
|
+
setSelectMode(false);
|
|
4276
|
+
if (state.currentMode === "insert") {
|
|
4277
|
+
sendTo("panel", { type: "DESELECT_ELEMENT" });
|
|
4278
|
+
startBrowse(state.shadowHost, onBrowseLocked);
|
|
4279
|
+
return;
|
|
4280
|
+
}
|
|
3960
4281
|
state.currentMode = "insert";
|
|
3961
4282
|
if (state.tabPreference === "design") state.tabPreference = "component";
|
|
3962
4283
|
state.currentTab = resolveTab();
|
|
@@ -4008,20 +4329,79 @@ ${pad}</${tag}>`;
|
|
|
4008
4329
|
placeBtn.innerHTML = `Place`;
|
|
4009
4330
|
toolbar.appendChild(placeBtn);
|
|
4010
4331
|
}
|
|
4332
|
+
let msgRow;
|
|
4333
|
+
msgRow = createMsgRow(state.currentBoundary, () => positionBothMenus(targetEl, toolbar, msgRow));
|
|
4334
|
+
state.shadowRoot.appendChild(msgRow);
|
|
4335
|
+
state.msgRowEl = msgRow;
|
|
4336
|
+
positionBothMenus(targetEl, toolbar, msgRow);
|
|
4337
|
+
}
|
|
4338
|
+
function getCanvasMessageText() {
|
|
4339
|
+
const textarea = canvasMsgRow?.querySelector("textarea");
|
|
4340
|
+
return textarea?.value.trim() ?? "";
|
|
4341
|
+
}
|
|
4342
|
+
function createMsgRow(boundary, onReposition, options) {
|
|
4343
|
+
const showSendButton = options?.showSendButton ?? true;
|
|
4011
4344
|
const msgRow = document.createElement("div");
|
|
4012
4345
|
msgRow.className = "msg-row";
|
|
4013
4346
|
msgRow.style.left = "0px";
|
|
4014
4347
|
msgRow.style.top = "0px";
|
|
4015
|
-
state.shadowRoot.appendChild(msgRow);
|
|
4016
|
-
state.msgRowEl = msgRow;
|
|
4017
4348
|
const msgInput = document.createElement("textarea");
|
|
4018
4349
|
msgInput.rows = 1;
|
|
4019
4350
|
msgInput.placeholder = "add your message";
|
|
4020
4351
|
msgRow.appendChild(msgInput);
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4352
|
+
let recognition = null;
|
|
4353
|
+
let micBtn = null;
|
|
4354
|
+
if (SpeechRecognitionAPI) {
|
|
4355
|
+
micBtn = document.createElement("button");
|
|
4356
|
+
micBtn.className = "mic-btn";
|
|
4357
|
+
micBtn.title = "Record voice message";
|
|
4358
|
+
micBtn.innerHTML = MIC_SVG;
|
|
4359
|
+
msgRow.appendChild(micBtn);
|
|
4360
|
+
micBtn.addEventListener("click", (e) => {
|
|
4361
|
+
e.stopPropagation();
|
|
4362
|
+
if (recognition) {
|
|
4363
|
+
recognition.stop();
|
|
4364
|
+
return;
|
|
4365
|
+
}
|
|
4366
|
+
const baseText = msgInput.value;
|
|
4367
|
+
recognition = new SpeechRecognitionAPI();
|
|
4368
|
+
recognition.continuous = false;
|
|
4369
|
+
recognition.interimResults = true;
|
|
4370
|
+
recognition.lang = navigator.language || "en-US";
|
|
4371
|
+
recognition.onresult = (event) => {
|
|
4372
|
+
let transcript = "";
|
|
4373
|
+
for (let i = 0; i < event.results.length; i++) {
|
|
4374
|
+
transcript += event.results[i][0].transcript;
|
|
4375
|
+
}
|
|
4376
|
+
const separator = baseText && !baseText.endsWith("\n") ? "\n" : "";
|
|
4377
|
+
msgInput.value = baseText + separator + transcript;
|
|
4378
|
+
msgInput.style.height = "auto";
|
|
4379
|
+
msgInput.style.height = msgInput.scrollHeight + "px";
|
|
4380
|
+
onReposition();
|
|
4381
|
+
};
|
|
4382
|
+
recognition.onend = () => {
|
|
4383
|
+
micBtn.classList.remove("listening");
|
|
4384
|
+
recognition = null;
|
|
4385
|
+
};
|
|
4386
|
+
recognition.onerror = (event) => {
|
|
4387
|
+
micBtn.classList.remove("listening");
|
|
4388
|
+
if (event.error === "not-allowed" || event.error === "service-not-allowed") {
|
|
4389
|
+
micBtn.classList.add("error");
|
|
4390
|
+
showMicBanner("Microphone blocked \u2014 allow access in your browser's address bar");
|
|
4391
|
+
}
|
|
4392
|
+
recognition = null;
|
|
4393
|
+
};
|
|
4394
|
+
micBtn.classList.remove("error");
|
|
4395
|
+
micBtn.classList.add("listening");
|
|
4396
|
+
recognition.start();
|
|
4397
|
+
});
|
|
4398
|
+
}
|
|
4399
|
+
const msgSendBtn = showSendButton ? document.createElement("button") : null;
|
|
4400
|
+
if (msgSendBtn) {
|
|
4401
|
+
msgSendBtn.className = "msg-send";
|
|
4402
|
+
msgSendBtn.innerHTML = SEND_SVG;
|
|
4403
|
+
msgRow.appendChild(msgSendBtn);
|
|
4404
|
+
}
|
|
4025
4405
|
function sendMessage() {
|
|
4026
4406
|
const text = msgInput.value.trim();
|
|
4027
4407
|
if (!text) return;
|
|
@@ -4030,15 +4410,15 @@ ${pad}</${tag}>`;
|
|
|
4030
4410
|
type: "MESSAGE_STAGE",
|
|
4031
4411
|
id,
|
|
4032
4412
|
message: text,
|
|
4033
|
-
elementKey:
|
|
4034
|
-
component:
|
|
4413
|
+
elementKey: boundary?.componentName ?? "",
|
|
4414
|
+
component: boundary ? { name: boundary.componentName } : void 0
|
|
4035
4415
|
});
|
|
4036
4416
|
msgInput.value = "";
|
|
4037
4417
|
msgInput.style.height = "auto";
|
|
4038
|
-
|
|
4418
|
+
onReposition();
|
|
4039
4419
|
showToast("Message staged");
|
|
4040
4420
|
}
|
|
4041
|
-
msgSendBtn
|
|
4421
|
+
msgSendBtn?.addEventListener("click", (e) => {
|
|
4042
4422
|
e.stopPropagation();
|
|
4043
4423
|
sendMessage();
|
|
4044
4424
|
});
|
|
@@ -4054,10 +4434,45 @@ ${pad}</${tag}>`;
|
|
|
4054
4434
|
msgInput.addEventListener("input", () => {
|
|
4055
4435
|
msgInput.style.height = "auto";
|
|
4056
4436
|
msgInput.style.height = msgInput.scrollHeight + "px";
|
|
4057
|
-
|
|
4437
|
+
onReposition();
|
|
4058
4438
|
});
|
|
4059
4439
|
msgRow.addEventListener("click", (e) => e.stopPropagation());
|
|
4060
|
-
|
|
4440
|
+
return msgRow;
|
|
4441
|
+
}
|
|
4442
|
+
var canvasMsgRow = null;
|
|
4443
|
+
var canvasMsgRowObserver = null;
|
|
4444
|
+
function showCanvasMessageRow(canvasWrapper, boundary, shadowRoot) {
|
|
4445
|
+
hideCanvasMessageRow();
|
|
4446
|
+
const msgRow = createMsgRow(boundary, () => positionCanvasMsgRow(canvasWrapper, msgRow), { showSendButton: false });
|
|
4447
|
+
msgRow.setAttribute("data-canvas-anchor", "true");
|
|
4448
|
+
shadowRoot.appendChild(msgRow);
|
|
4449
|
+
canvasMsgRow = msgRow;
|
|
4450
|
+
positionCanvasMsgRow(canvasWrapper, msgRow);
|
|
4451
|
+
canvasMsgRowObserver = new ResizeObserver(() => {
|
|
4452
|
+
positionCanvasMsgRow(canvasWrapper, msgRow);
|
|
4453
|
+
});
|
|
4454
|
+
canvasMsgRowObserver.observe(canvasWrapper);
|
|
4455
|
+
}
|
|
4456
|
+
function hideCanvasMessageRow() {
|
|
4457
|
+
canvasMsgRowObserver?.disconnect();
|
|
4458
|
+
canvasMsgRowObserver = null;
|
|
4459
|
+
canvasMsgRow?.remove();
|
|
4460
|
+
canvasMsgRow = null;
|
|
4461
|
+
}
|
|
4462
|
+
function positionCanvasMsgRow(canvasWrapper, msgRow) {
|
|
4463
|
+
computePosition2(canvasWrapper, msgRow, {
|
|
4464
|
+
placement: "bottom-start",
|
|
4465
|
+
middleware: [
|
|
4466
|
+
shift2({ padding: 8 }),
|
|
4467
|
+
flip2()
|
|
4468
|
+
]
|
|
4469
|
+
}).then(({ x, y }) => {
|
|
4470
|
+
Object.assign(msgRow.style, {
|
|
4471
|
+
position: "fixed",
|
|
4472
|
+
left: `${x}px`,
|
|
4473
|
+
top: `${y}px`
|
|
4474
|
+
});
|
|
4475
|
+
});
|
|
4061
4476
|
}
|
|
4062
4477
|
function showGroupPicker(anchorBtn, onClose, onCountChange) {
|
|
4063
4478
|
if (state.pickerCloseHandler) {
|
|
@@ -5151,6 +5566,7 @@ ${pad}</${tag}>`;
|
|
|
5151
5566
|
showToastFn = deps2.showToast;
|
|
5152
5567
|
}
|
|
5153
5568
|
function injectDesignCanvas(insertMode) {
|
|
5569
|
+
console.log("[tw-debug] injectDesignCanvas called, insertMode=", insertMode, "currentTargetEl=", state.currentTargetEl, "currentBoundary=", state.currentBoundary);
|
|
5154
5570
|
if (!state.currentTargetEl || !state.currentBoundary) {
|
|
5155
5571
|
showToastFn("Select an element first");
|
|
5156
5572
|
return;
|
|
@@ -5158,7 +5574,9 @@ ${pad}</${tag}>`;
|
|
|
5158
5574
|
clearHighlights();
|
|
5159
5575
|
const targetEl = state.currentTargetEl;
|
|
5160
5576
|
const canvas = document.createElement("vb-design-canvas");
|
|
5161
|
-
|
|
5577
|
+
const canvasSrc = `${serverOrigin}/panel/?mode=design`;
|
|
5578
|
+
console.log("[tw-debug] creating vb-design-canvas, src=", canvasSrc, "targetEl=", targetEl, "insertMode=", insertMode);
|
|
5579
|
+
canvas.setAttribute("src", canvasSrc);
|
|
5162
5580
|
const wrapper = canvas.getWrapper();
|
|
5163
5581
|
let replacedNodes = null;
|
|
5164
5582
|
let replacedParent = null;
|
|
@@ -5193,7 +5611,10 @@ ${pad}</${tag}>`;
|
|
|
5193
5611
|
parent: replacedParent,
|
|
5194
5612
|
anchor: replacedAnchor
|
|
5195
5613
|
});
|
|
5614
|
+
requestAnimationFrame(() => showCanvasMessageRow(canvas.getWrapper(), state.currentBoundary, state.shadowRoot));
|
|
5615
|
+
console.log("[tw-debug] canvas inserted into DOM, listening for vb-canvas-ready...");
|
|
5196
5616
|
canvas.addEventListener("vb-canvas-ready", () => {
|
|
5617
|
+
console.log("[tw-debug] vb-canvas-ready fired!");
|
|
5197
5618
|
const contextMsg = {
|
|
5198
5619
|
type: "ELEMENT_CONTEXT",
|
|
5199
5620
|
componentName: state.currentBoundary?.componentName ?? "",
|
|
@@ -5276,6 +5697,7 @@ ${pad}</${tag}>`;
|
|
|
5276
5697
|
parent.insertBefore(canvas, marker);
|
|
5277
5698
|
marker.remove();
|
|
5278
5699
|
state.designCanvasWrappers.push({ wrapper: canvas, replacedNodes, parent, anchor: canvas.nextSibling });
|
|
5700
|
+
requestAnimationFrame(() => showCanvasMessageRow(canvas.getWrapper(), state.currentBoundary, state.shadowRoot));
|
|
5279
5701
|
canvas.addEventListener("vb-canvas-ready", () => {
|
|
5280
5702
|
const contextMsg = {
|
|
5281
5703
|
type: "ELEMENT_CONTEXT",
|
|
@@ -5299,6 +5721,12 @@ ${pad}</${tag}>`;
|
|
|
5299
5721
|
setTimeout(trySend, 200);
|
|
5300
5722
|
});
|
|
5301
5723
|
}
|
|
5724
|
+
function removeAllDesignCanvases() {
|
|
5725
|
+
for (const entry of state.designCanvasWrappers) {
|
|
5726
|
+
entry.wrapper.remove();
|
|
5727
|
+
}
|
|
5728
|
+
state.designCanvasWrappers.length = 0;
|
|
5729
|
+
}
|
|
5302
5730
|
function handleDesignSubmitted(msg) {
|
|
5303
5731
|
const lastEntry = state.designCanvasWrappers[state.designCanvasWrappers.length - 1];
|
|
5304
5732
|
const last = lastEntry?.wrapper;
|
|
@@ -5315,6 +5743,11 @@ ${pad}</${tag}>`;
|
|
|
5315
5743
|
last.appendChild(img);
|
|
5316
5744
|
}
|
|
5317
5745
|
}
|
|
5746
|
+
const messageText = getCanvasMessageText();
|
|
5747
|
+
if (messageText && msg.patchId) {
|
|
5748
|
+
send({ type: "CANVAS_MESSAGE_ATTACH", patchId: msg.patchId, message: messageText });
|
|
5749
|
+
}
|
|
5750
|
+
hideCanvasMessageRow();
|
|
5318
5751
|
}
|
|
5319
5752
|
function handleDesignClose() {
|
|
5320
5753
|
const last = state.designCanvasWrappers.pop();
|
|
@@ -5326,6 +5759,7 @@ ${pad}</${tag}>`;
|
|
|
5326
5759
|
}
|
|
5327
5760
|
last.wrapper.remove();
|
|
5328
5761
|
}
|
|
5762
|
+
hideCanvasMessageRow();
|
|
5329
5763
|
}
|
|
5330
5764
|
|
|
5331
5765
|
// overlay/src/recording/console-interceptor/console-interceptor.ts
|
|
@@ -6825,8 +7259,7 @@ ${pad}</${tag}>`;
|
|
|
6825
7259
|
function onBrowseLocked2(target) {
|
|
6826
7260
|
state.currentTargetEl = target;
|
|
6827
7261
|
state.currentEquivalentNodes = [target];
|
|
6828
|
-
const
|
|
6829
|
-
const boundary = fiber ? findComponentBoundary(fiber) : null;
|
|
7262
|
+
const boundary = detectComponent(target);
|
|
6830
7263
|
state.currentBoundary = boundary ? { componentName: boundary.componentName } : { componentName: target.tagName.toLowerCase() };
|
|
6831
7264
|
state.cachedNearGroups = null;
|
|
6832
7265
|
showDrawButton(target);
|
|
@@ -7088,6 +7521,24 @@ ${pad}</${tag}>`;
|
|
|
7088
7521
|
setTimeout(() => toast.remove(), 200);
|
|
7089
7522
|
}, duration);
|
|
7090
7523
|
}
|
|
7524
|
+
function resetOnNavigation() {
|
|
7525
|
+
if (isTextEditing()) endTextEdit(false);
|
|
7526
|
+
revertPreview();
|
|
7527
|
+
clearHighlights();
|
|
7528
|
+
cancelInsert();
|
|
7529
|
+
clearLockedInsert();
|
|
7530
|
+
removeAllDesignCanvases();
|
|
7531
|
+
state.currentEquivalentNodes = [];
|
|
7532
|
+
state.currentTargetEl = null;
|
|
7533
|
+
state.currentBoundary = null;
|
|
7534
|
+
state.cachedNearGroups = null;
|
|
7535
|
+
state.cachedExactMatches = null;
|
|
7536
|
+
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
7537
|
+
state.addMode = false;
|
|
7538
|
+
setSelectMode2(false);
|
|
7539
|
+
sendTo("panel", { type: "RESET_SELECTION" });
|
|
7540
|
+
sendTo("panel", { type: "COMPONENT_DISARMED" });
|
|
7541
|
+
}
|
|
7091
7542
|
function getDefaultContainer() {
|
|
7092
7543
|
try {
|
|
7093
7544
|
const stored = localStorage.getItem("tw-panel-container");
|
|
@@ -7099,6 +7550,8 @@ ${pad}</${tag}>`;
|
|
|
7099
7550
|
return "popover";
|
|
7100
7551
|
}
|
|
7101
7552
|
function init() {
|
|
7553
|
+
const params = new URLSearchParams(location.search);
|
|
7554
|
+
if (params.get("viewMode") === "story" || params.get("vybit-ghost") === "1") return;
|
|
7102
7555
|
state.shadowHost = document.createElement("div");
|
|
7103
7556
|
state.shadowHost.id = "tw-visual-editor-host";
|
|
7104
7557
|
state.shadowHost.style.cssText = css(SHADOW_HOST);
|
|
@@ -7125,6 +7578,16 @@ ${pad}</${tag}>`;
|
|
|
7125
7578
|
btn.style.display = "none";
|
|
7126
7579
|
}
|
|
7127
7580
|
state.shadowRoot.appendChild(btn);
|
|
7581
|
+
createNavigationInterceptor(() => {
|
|
7582
|
+
if (state.active) resetOnNavigation();
|
|
7583
|
+
});
|
|
7584
|
+
window.addEventListener("message", (event) => {
|
|
7585
|
+
if (event.data?.type === "STORYBOOK_STORY_RENDERED") {
|
|
7586
|
+
if (state.active) {
|
|
7587
|
+
resetOnNavigation();
|
|
7588
|
+
}
|
|
7589
|
+
}
|
|
7590
|
+
});
|
|
7128
7591
|
document.addEventListener("keydown", (e) => {
|
|
7129
7592
|
if (e.key === "Escape") {
|
|
7130
7593
|
if (state.addMode) {
|
|
@@ -7132,20 +7595,15 @@ ${pad}</${tag}>`;
|
|
|
7132
7595
|
return;
|
|
7133
7596
|
}
|
|
7134
7597
|
if (state.currentTargetEl) {
|
|
7135
|
-
|
|
7136
|
-
clearHighlights();
|
|
7137
|
-
state.currentEquivalentNodes = [];
|
|
7138
|
-
state.currentTargetEl = null;
|
|
7139
|
-
state.currentBoundary = null;
|
|
7140
|
-
state.cachedNearGroups = null;
|
|
7141
|
-
state.cachedExactMatches = null;
|
|
7142
|
-
state.manuallyAddedNodes = /* @__PURE__ */ new Set();
|
|
7143
|
-
state.addMode = false;
|
|
7144
|
-
sendTo("panel", { type: "RESET_SELECTION" });
|
|
7598
|
+
clearSelection();
|
|
7145
7599
|
if (state.currentMode === "select") {
|
|
7146
7600
|
setSelectMode2(true);
|
|
7601
|
+
sendTo("panel", { type: "DESELECT_ELEMENT" });
|
|
7147
7602
|
} else if (state.currentMode === "insert") {
|
|
7603
|
+
sendTo("panel", { type: "DESELECT_ELEMENT" });
|
|
7148
7604
|
startBrowse(state.shadowHost, onBrowseLocked2);
|
|
7605
|
+
} else {
|
|
7606
|
+
sendTo("panel", { type: "RESET_SELECTION" });
|
|
7149
7607
|
}
|
|
7150
7608
|
} else if (state.selectModeOn) {
|
|
7151
7609
|
setSelectMode2(false);
|
|
@@ -7162,6 +7620,8 @@ ${pad}</${tag}>`;
|
|
|
7162
7620
|
onMessage((msg) => {
|
|
7163
7621
|
if (msg.type === "TOGGLE_SELECT_MODE") {
|
|
7164
7622
|
if (msg.active) {
|
|
7623
|
+
state.active = true;
|
|
7624
|
+
sessionStorage.setItem(PANEL_OPEN_KEY, "1");
|
|
7165
7625
|
setSelectMode2(true);
|
|
7166
7626
|
if (!insideStorybook) {
|
|
7167
7627
|
const panelUrl = `${SERVER_ORIGIN}/panel`;
|
|
@@ -7171,6 +7631,10 @@ ${pad}</${tag}>`;
|
|
|
7171
7631
|
setSelectMode2(false);
|
|
7172
7632
|
}
|
|
7173
7633
|
} else if (msg.type === "MODE_CHANGED") {
|
|
7634
|
+
if (msg.mode) {
|
|
7635
|
+
state.active = true;
|
|
7636
|
+
sessionStorage.setItem(PANEL_OPEN_KEY, "1");
|
|
7637
|
+
}
|
|
7174
7638
|
revertPreview();
|
|
7175
7639
|
clearHighlights();
|
|
7176
7640
|
cancelInsert();
|
|
@@ -7181,6 +7645,7 @@ ${pad}</${tag}>`;
|
|
|
7181
7645
|
state.cachedNearGroups = null;
|
|
7182
7646
|
state.currentMode = msg.mode;
|
|
7183
7647
|
if (msg.mode === "insert") {
|
|
7648
|
+
setSelectMode2(false);
|
|
7184
7649
|
if (state.tabPreference === "design") state.tabPreference = "component";
|
|
7185
7650
|
state.currentTab = resolveTab();
|
|
7186
7651
|
startBrowse(state.shadowHost, onBrowseLocked2);
|
|
@@ -7295,22 +7760,36 @@ ${pad}</${tag}>`;
|
|
|
7295
7760
|
}
|
|
7296
7761
|
} else {
|
|
7297
7762
|
const locked2 = getLockedInsert();
|
|
7763
|
+
console.log("[tw-debug] INSERT_DESIGN_CANVAS else branch, locked=", locked2, "currentTargetEl=", state.currentTargetEl);
|
|
7298
7764
|
if (locked2) {
|
|
7299
7765
|
state.currentTargetEl = locked2.target;
|
|
7300
|
-
const
|
|
7301
|
-
const boundary = fiber ? findComponentBoundary(fiber) : null;
|
|
7766
|
+
const boundary = detectComponent(locked2.target);
|
|
7302
7767
|
state.currentBoundary = boundary ? { componentName: boundary.componentName } : { componentName: locked2.target.tagName.toLowerCase() };
|
|
7303
7768
|
state.currentEquivalentNodes = [locked2.target];
|
|
7304
7769
|
clearLockedInsert();
|
|
7770
|
+
console.log("[tw-debug] locked path \u2014 calling injectDesignCanvas, position=", locked2.position, "boundary=", state.currentBoundary);
|
|
7305
7771
|
injectDesignCanvas(locked2.position);
|
|
7306
7772
|
} else {
|
|
7773
|
+
console.log("[tw-debug] arming generic insert...");
|
|
7307
7774
|
armGenericInsert("Place: Canvas", state.shadowHost, (target, position) => {
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7775
|
+
console.log("[tw-debug] armGenericInsert callback fired, target=", target, "position=", position);
|
|
7776
|
+
try {
|
|
7777
|
+
console.log("[tw-debug] step 1: setting currentTargetEl");
|
|
7778
|
+
state.currentTargetEl = target;
|
|
7779
|
+
console.log("[tw-debug] step 2: calling detectComponent");
|
|
7780
|
+
const boundary = detectComponent(target);
|
|
7781
|
+
console.log("[tw-debug] step 3: boundary=", boundary);
|
|
7782
|
+
state.currentBoundary = boundary ? { componentName: boundary.componentName } : { componentName: target.tagName.toLowerCase() };
|
|
7783
|
+
state.currentEquivalentNodes = [target];
|
|
7784
|
+
console.log("[tw-debug] step 4: state set, currentBoundary=", state.currentBoundary, "\u2014 calling injectDesignCanvas");
|
|
7785
|
+
injectDesignCanvas(position);
|
|
7786
|
+
console.log("[tw-debug] injectDesignCanvas returned OK");
|
|
7787
|
+
} catch (err) {
|
|
7788
|
+
console.error("[tw-debug] CALLBACK THREW (this is the real error):", err);
|
|
7789
|
+
if (err instanceof Error) {
|
|
7790
|
+
console.error("[tw-debug] message:", err.message, "stack:", err.stack);
|
|
7791
|
+
}
|
|
7792
|
+
}
|
|
7314
7793
|
});
|
|
7315
7794
|
}
|
|
7316
7795
|
}
|
|
@@ -7439,8 +7918,7 @@ ${pad}</${tag}>`;
|
|
|
7439
7918
|
if (!target || target === state.shadowHost || e.composedPath().some((el) => el === state.shadowHost)) {
|
|
7440
7919
|
return;
|
|
7441
7920
|
}
|
|
7442
|
-
const
|
|
7443
|
-
const boundary = fiber ? findComponentBoundary(fiber) : null;
|
|
7921
|
+
const boundary = detectComponent(target);
|
|
7444
7922
|
const selectorPath = buildSelectorPath2(target);
|
|
7445
7923
|
const rect = target.getBoundingClientRect();
|
|
7446
7924
|
const element = {
|