veo-sdk 0.6.2 → 0.6.3
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/builder-PPLIAUCM.mjs +5 -0
- package/dist/{builder-ENKEIVF2.mjs.map → builder-PPLIAUCM.mjs.map} +1 -1
- package/dist/builder.cjs +354 -92
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.d.cts +76 -6
- package/dist/builder.d.ts +76 -6
- package/dist/builder.mjs +4 -4
- package/dist/{chunk-L3QQJLDJ.mjs → chunk-3JEAPZ6A.mjs} +3 -3
- package/dist/{chunk-L3QQJLDJ.mjs.map → chunk-3JEAPZ6A.mjs.map} +1 -1
- package/dist/{chunk-4QZDNJJE.mjs → chunk-DU6I4ZU2.mjs} +284 -15
- package/dist/chunk-DU6I4ZU2.mjs.map +1 -0
- package/dist/{chunk-ZILDR4YE.mjs → chunk-SZCIXA5X.mjs} +70 -69
- package/dist/chunk-SZCIXA5X.mjs.map +1 -0
- package/dist/index.cjs +601 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.mjs +306 -6
- package/dist/index.mjs.map +1 -1
- package/dist/veo-builder.js +54 -19
- package/dist/veo-builder.js.map +1 -1
- package/dist/veo.js +2 -2
- package/dist/veo.js.map +1 -1
- package/package.json +1 -1
- package/dist/builder-ENKEIVF2.mjs +0 -5
- package/dist/chunk-4QZDNJJE.mjs.map +0 -1
- package/dist/chunk-ZILDR4YE.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -251,7 +251,8 @@ var init_constants = __esm({
|
|
|
251
251
|
throttleMs: 100,
|
|
252
252
|
maxTextLength: 200,
|
|
253
253
|
captureElementMetadata: true,
|
|
254
|
-
captureAncestors: 5
|
|
254
|
+
captureAncestors: 5,
|
|
255
|
+
captureClickQuality: true
|
|
255
256
|
};
|
|
256
257
|
MAX_ANCESTORS = 10;
|
|
257
258
|
ALWAYS_BLOCK_SELECTORS = [
|
|
@@ -5690,14 +5691,19 @@ function injectBuilderChrome(opts) {
|
|
|
5690
5691
|
let previewOn = false;
|
|
5691
5692
|
let hiddenOn = false;
|
|
5692
5693
|
let heightCb = null;
|
|
5693
|
-
|
|
5694
|
+
let tagging = false;
|
|
5695
|
+
const height = () => CHROME_TOPBAR_H + (collapsed || tagging ? 0 : CHROME_STEPS_H);
|
|
5694
5696
|
const applyHeight = () => {
|
|
5695
5697
|
const h = previewOn || hiddenOn ? 0 : height();
|
|
5696
5698
|
html.style.marginTop = dock === "top" ? `${h}px` : prevMarginTop;
|
|
5697
5699
|
html.style.marginBottom = dock === "bottom" ? `${h}px` : prevMarginBottom;
|
|
5698
5700
|
root.style.setProperty("--veo-chrome-h", `${height()}px`);
|
|
5699
5701
|
root.classList.toggle("is-bottom", dock === "bottom");
|
|
5700
|
-
stepsBar.hidden = collapsed;
|
|
5702
|
+
stepsBar.hidden = collapsed || tagging;
|
|
5703
|
+
togglePill.hidden = tagging;
|
|
5704
|
+
preview.hidden = tagging;
|
|
5705
|
+
saveGroup.hidden = tagging;
|
|
5706
|
+
showPanel.title = tagging ? "Mostrar el panel" : "Mostrar el editor";
|
|
5701
5707
|
const open = dock === "top" ? "chevronUp" : "chevronDown";
|
|
5702
5708
|
const closedIcon = dock === "top" ? "chevronDown" : "chevronUp";
|
|
5703
5709
|
togglePill.innerHTML = `<span>${collapsed ? "Mostrar pasos" : "Ocultar pasos"}</span>${svg(
|
|
@@ -5750,8 +5756,13 @@ function injectBuilderChrome(opts) {
|
|
|
5750
5756
|
const render = () => {
|
|
5751
5757
|
const s = current;
|
|
5752
5758
|
if (!s) return;
|
|
5759
|
+
const nextTagging = s.variant === "tagging";
|
|
5760
|
+
if (nextTagging !== tagging) {
|
|
5761
|
+
tagging = nextTagging;
|
|
5762
|
+
applyHeight();
|
|
5763
|
+
}
|
|
5753
5764
|
const date = shortDate(s.createdAt);
|
|
5754
|
-
nameEl.textContent = `${s.guideName.trim() || "Sin nombre"}${date ? ` \xB7 ${date}` : ""}`;
|
|
5765
|
+
nameEl.textContent = tagging ? s.guideName.trim() || "Modo tagging" : `${s.guideName.trim() || "Sin nombre"}${date ? ` \xB7 ${date}` : ""}`;
|
|
5755
5766
|
if (s.status) {
|
|
5756
5767
|
statusEl.hidden = false;
|
|
5757
5768
|
statusEl.textContent = s.status.label;
|
|
@@ -5871,6 +5882,8 @@ var init_builder_chrome = __esm({
|
|
|
5871
5882
|
font-size: 14px; color: #1c1917;
|
|
5872
5883
|
}
|
|
5873
5884
|
.veo-chrome[hidden] { display: none; }
|
|
5885
|
+
/* Modo tagging oculta controles por atributo: gana a los display de sus clases. */
|
|
5886
|
+
.veo-chrome [hidden], .veo-steps-toggle[hidden] { display: none !important; }
|
|
5874
5887
|
.veo-chrome.is-bottom { top: auto; bottom: 0; flex-direction: column-reverse; }
|
|
5875
5888
|
.veo-chrome.is-bottom .veo-tb-menu { top: auto; bottom: calc(100% + 8px); }
|
|
5876
5889
|
.veo-chrome.is-bottom .veo-steps { border-bottom: 0; border-top: 1px solid #d6cfc8; }
|
|
@@ -6503,6 +6516,65 @@ var init_design_manipulator = __esm({
|
|
|
6503
6516
|
}
|
|
6504
6517
|
});
|
|
6505
6518
|
|
|
6519
|
+
// src/plugins/builder/interactive-elements.ts
|
|
6520
|
+
function isInteractiveElement(element) {
|
|
6521
|
+
try {
|
|
6522
|
+
return element.matches(INTERACTIVE_SELECTOR);
|
|
6523
|
+
} catch {
|
|
6524
|
+
return false;
|
|
6525
|
+
}
|
|
6526
|
+
}
|
|
6527
|
+
function closestInteractive(element) {
|
|
6528
|
+
try {
|
|
6529
|
+
return element.closest(INTERACTIVE_SELECTOR);
|
|
6530
|
+
} catch {
|
|
6531
|
+
return null;
|
|
6532
|
+
}
|
|
6533
|
+
}
|
|
6534
|
+
function elementLabelText(element, max = 120) {
|
|
6535
|
+
const clean = (raw) => (raw ?? "").replace(EMOJI_RE, "").replace(/\s+/g, " ").trim();
|
|
6536
|
+
const text = clean(element.textContent);
|
|
6537
|
+
if (text) return text.slice(0, max);
|
|
6538
|
+
const fallback = clean(element.getAttribute("aria-label")) || clean(element.getAttribute("title"));
|
|
6539
|
+
return fallback.slice(0, max);
|
|
6540
|
+
}
|
|
6541
|
+
var INTERACTIVE_ROLES, INTERACTIVE_SELECTOR, EMOJI_RE;
|
|
6542
|
+
var init_interactive_elements = __esm({
|
|
6543
|
+
"src/plugins/builder/interactive-elements.ts"() {
|
|
6544
|
+
INTERACTIVE_ROLES = [
|
|
6545
|
+
"button",
|
|
6546
|
+
"link",
|
|
6547
|
+
"tab",
|
|
6548
|
+
"menuitem",
|
|
6549
|
+
"menuitemcheckbox",
|
|
6550
|
+
"menuitemradio",
|
|
6551
|
+
"checkbox",
|
|
6552
|
+
"radio",
|
|
6553
|
+
"switch",
|
|
6554
|
+
"option",
|
|
6555
|
+
"combobox",
|
|
6556
|
+
"textbox",
|
|
6557
|
+
"searchbox",
|
|
6558
|
+
"slider",
|
|
6559
|
+
"spinbutton"
|
|
6560
|
+
];
|
|
6561
|
+
INTERACTIVE_SELECTOR = [
|
|
6562
|
+
"button",
|
|
6563
|
+
"a[href]",
|
|
6564
|
+
'input:not([type="hidden"])',
|
|
6565
|
+
"select",
|
|
6566
|
+
"textarea",
|
|
6567
|
+
"form",
|
|
6568
|
+
"summary",
|
|
6569
|
+
'[contenteditable="true"]',
|
|
6570
|
+
"[onclick]",
|
|
6571
|
+
"[data-veo-tag]",
|
|
6572
|
+
...INTERACTIVE_ROLES.map((r) => `[role="${r}"]`)
|
|
6573
|
+
].join(", ");
|
|
6574
|
+
EMOJI_RE = /\p{Extended_Pictographic}|\p{Emoji_Modifier}|\u{FE0F}|\u{200D}|\u{20E3}/gu;
|
|
6575
|
+
}
|
|
6576
|
+
});
|
|
6577
|
+
|
|
6506
6578
|
// src/plugins/builder/element-picker.ts
|
|
6507
6579
|
function startElementPicker(options) {
|
|
6508
6580
|
if (!hasDocument()) {
|
|
@@ -6521,6 +6593,7 @@ var init_element_picker = __esm({
|
|
|
6521
6593
|
"src/plugins/builder/element-picker.ts"() {
|
|
6522
6594
|
init_safe_env();
|
|
6523
6595
|
init_selector_builder();
|
|
6596
|
+
init_interactive_elements();
|
|
6524
6597
|
PICKER_Z = 2147483646;
|
|
6525
6598
|
PICKER_HOST_ATTR = "data-veo-picker";
|
|
6526
6599
|
DEFAULT_MAX_ANCESTORS = 5;
|
|
@@ -6590,21 +6663,24 @@ var init_element_picker = __esm({
|
|
|
6590
6663
|
this.label = null;
|
|
6591
6664
|
this.current = null;
|
|
6592
6665
|
this.maxAncestors = DEFAULT_MAX_ANCESTORS;
|
|
6666
|
+
this.only = null;
|
|
6593
6667
|
this.onPick = null;
|
|
6594
6668
|
this.onCancel = null;
|
|
6595
6669
|
this.onMove = (event) => {
|
|
6596
|
-
|
|
6597
|
-
|
|
6670
|
+
if (!(event.target instanceof Element) || this.isOwn(event.target)) return;
|
|
6671
|
+
const target = this.resolveTarget(event.target);
|
|
6598
6672
|
this.current = target;
|
|
6599
|
-
this.draw(target);
|
|
6673
|
+
if (target) this.draw(target);
|
|
6674
|
+
else this.hideBox();
|
|
6600
6675
|
};
|
|
6601
6676
|
this.onClick = (event) => {
|
|
6602
6677
|
if (event.altKey) return;
|
|
6603
|
-
|
|
6604
|
-
if (!target || this.isOwn(target)) return;
|
|
6678
|
+
if (this.isOwn(event.target)) return;
|
|
6605
6679
|
event.preventDefault();
|
|
6606
6680
|
event.stopPropagation();
|
|
6607
6681
|
event.stopImmediatePropagation();
|
|
6682
|
+
const target = this.current ?? this.resolveTarget(event.target);
|
|
6683
|
+
if (!target) return;
|
|
6608
6684
|
const picked = this.describe(target);
|
|
6609
6685
|
const cb = this.onPick;
|
|
6610
6686
|
this.stop();
|
|
@@ -6631,6 +6707,7 @@ var init_element_picker = __esm({
|
|
|
6631
6707
|
start(options) {
|
|
6632
6708
|
this.stop();
|
|
6633
6709
|
this.maxAncestors = options.maxAncestors ?? DEFAULT_MAX_ANCESTORS;
|
|
6710
|
+
this.only = options.only ?? null;
|
|
6634
6711
|
this.onPick = options.onPick;
|
|
6635
6712
|
this.onCancel = options.onCancel ?? null;
|
|
6636
6713
|
const host = document.createElement("div");
|
|
@@ -6693,9 +6770,19 @@ var init_element_picker = __esm({
|
|
|
6693
6770
|
this.box = null;
|
|
6694
6771
|
this.label = null;
|
|
6695
6772
|
this.current = null;
|
|
6773
|
+
this.only = null;
|
|
6696
6774
|
this.onPick = null;
|
|
6697
6775
|
this.onCancel = null;
|
|
6698
6776
|
}
|
|
6777
|
+
/** Elemento que se elegiría para el nodo bajo el cursor (o null si no hay). */
|
|
6778
|
+
resolveTarget(target) {
|
|
6779
|
+
if (!(target instanceof Element) || this.isOwn(target)) return null;
|
|
6780
|
+
return this.only === "interactive" ? closestInteractive(target) : target;
|
|
6781
|
+
}
|
|
6782
|
+
hideBox() {
|
|
6783
|
+
if (this.box) this.box.style.display = "none";
|
|
6784
|
+
if (this.label) this.label.style.display = "none";
|
|
6785
|
+
}
|
|
6699
6786
|
/** ¿Es un nodo de nuestro propio overlay? (no debe ser seleccionable). */
|
|
6700
6787
|
isOwn(target) {
|
|
6701
6788
|
return target instanceof Node && this.host !== null && this.host.contains(target);
|
|
@@ -6732,7 +6819,7 @@ var init_element_picker = __esm({
|
|
|
6732
6819
|
tag: element.tagName.toLowerCase(),
|
|
6733
6820
|
id: element.id || null,
|
|
6734
6821
|
classes: filterHumanClasses(element),
|
|
6735
|
-
text: (element
|
|
6822
|
+
text: elementLabelText(element),
|
|
6736
6823
|
rect: {
|
|
6737
6824
|
x: Math.round(rect.left),
|
|
6738
6825
|
y: Math.round(rect.top),
|
|
@@ -7728,7 +7815,7 @@ function initBuilderMode() {
|
|
|
7728
7815
|
if (h && hoverCard && !previewMode) renderCardChrome(h, previewStepIndex);
|
|
7729
7816
|
}
|
|
7730
7817
|
panel?.setTitle(
|
|
7731
|
-
cmd.state.section === "activation" ? "Ajustes de activaci\xF3n" : cmd.state.section === "badge" ? "Ajustes de badge" : cmd.state.section === "target" ? "Ajustes del elemento objetivo" : cmd.state.section === "row" ? "Editar fila" : cmd.state.blockLabel ? `Editor \xB7 ${cmd.state.blockLabel}` : cmd.state.steps[cmd.state.activeStep]?.label ?? "Paso"
|
|
7818
|
+
cmd.state.panelTitle ?? (cmd.state.section === "activation" ? "Ajustes de activaci\xF3n" : cmd.state.section === "badge" ? "Ajustes de badge" : cmd.state.section === "target" ? "Ajustes del elemento objetivo" : cmd.state.section === "row" ? "Editar fila" : cmd.state.blockLabel ? `Editor \xB7 ${cmd.state.blockLabel}` : cmd.state.steps[cmd.state.activeStep]?.label ?? "Paso")
|
|
7732
7819
|
);
|
|
7733
7820
|
break;
|
|
7734
7821
|
case "panel-visibility":
|
|
@@ -7766,7 +7853,8 @@ function initBuilderMode() {
|
|
|
7766
7853
|
post({ type: "pick-cancelled" });
|
|
7767
7854
|
},
|
|
7768
7855
|
...cmd.maxAncestors !== void 0 ? { maxAncestors: cmd.maxAncestors } : {},
|
|
7769
|
-
...cmd.hint !== void 0 ? { hint: cmd.hint } : {}
|
|
7856
|
+
...cmd.hint !== void 0 ? { hint: cmd.hint } : {},
|
|
7857
|
+
...cmd.only !== void 0 ? { only: cmd.only } : {}
|
|
7770
7858
|
});
|
|
7771
7859
|
break;
|
|
7772
7860
|
}
|
|
@@ -7775,6 +7863,15 @@ function initBuilderMode() {
|
|
|
7775
7863
|
picker = null;
|
|
7776
7864
|
chrome?.setHidden(false);
|
|
7777
7865
|
break;
|
|
7866
|
+
case "scan-page":
|
|
7867
|
+
post({ type: "page-scan", payload: scanPage(cmd.selectors) });
|
|
7868
|
+
break;
|
|
7869
|
+
case "highlight":
|
|
7870
|
+
setHighlight(cmd.selector);
|
|
7871
|
+
break;
|
|
7872
|
+
case "show-confirmation":
|
|
7873
|
+
showConfirmation(cmd.payload);
|
|
7874
|
+
break;
|
|
7778
7875
|
case "preview":
|
|
7779
7876
|
if (!cmd.guide) break;
|
|
7780
7877
|
if (manipulator?.isDragging()) pendingPreview = cmd;
|
|
@@ -7859,10 +7956,154 @@ function initBuilderMode() {
|
|
|
7859
7956
|
post({ type: "closed" });
|
|
7860
7957
|
panel?.teardown();
|
|
7861
7958
|
panel = null;
|
|
7959
|
+
highlightBox?.remove();
|
|
7960
|
+
highlightBox = null;
|
|
7961
|
+
confirmation?.remove();
|
|
7962
|
+
confirmation = null;
|
|
7963
|
+
if (confirmationKey) document.removeEventListener("keydown", confirmationKey, true);
|
|
7964
|
+
confirmationKey = null;
|
|
7862
7965
|
chrome?.teardown();
|
|
7863
7966
|
chrome = null;
|
|
7864
7967
|
clearBuilderToken();
|
|
7865
7968
|
};
|
|
7969
|
+
const scanPage = (selectors) => {
|
|
7970
|
+
const present = selectors.filter((sel) => {
|
|
7971
|
+
try {
|
|
7972
|
+
return document.querySelector(sel) !== null;
|
|
7973
|
+
} catch {
|
|
7974
|
+
return false;
|
|
7975
|
+
}
|
|
7976
|
+
});
|
|
7977
|
+
const taggedEls = /* @__PURE__ */ new Set();
|
|
7978
|
+
for (const sel of present) {
|
|
7979
|
+
try {
|
|
7980
|
+
for (const e of Array.from(document.querySelectorAll(sel))) taggedEls.add(e);
|
|
7981
|
+
} catch {
|
|
7982
|
+
}
|
|
7983
|
+
}
|
|
7984
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7985
|
+
const candidates = [];
|
|
7986
|
+
const nodes = document.querySelectorAll(INTERACTIVE_SELECTOR);
|
|
7987
|
+
for (const element of Array.from(nodes)) {
|
|
7988
|
+
if (candidates.length >= 200) break;
|
|
7989
|
+
if (element.closest("[data-veo-builder-chrome],[data-veo-builder-panel],[data-veo-picker]")) {
|
|
7990
|
+
continue;
|
|
7991
|
+
}
|
|
7992
|
+
if (element.getClientRects().length === 0) continue;
|
|
7993
|
+
let tagged = false;
|
|
7994
|
+
for (let n = element; n; n = n.parentElement) {
|
|
7995
|
+
if (taggedEls.has(n)) {
|
|
7996
|
+
tagged = true;
|
|
7997
|
+
break;
|
|
7998
|
+
}
|
|
7999
|
+
}
|
|
8000
|
+
if (tagged) continue;
|
|
8001
|
+
const selector = buildSelectorPath(element, 5);
|
|
8002
|
+
if (!selector || seen.has(selector)) continue;
|
|
8003
|
+
seen.add(selector);
|
|
8004
|
+
candidates.push({
|
|
8005
|
+
selector,
|
|
8006
|
+
shortSelector: buildSelectorPath(element, 0),
|
|
8007
|
+
tag: element.tagName.toLowerCase(),
|
|
8008
|
+
id: element.id || null,
|
|
8009
|
+
classes: filterHumanClasses(element),
|
|
8010
|
+
text: elementLabelText(element)
|
|
8011
|
+
});
|
|
8012
|
+
}
|
|
8013
|
+
const { pathname, hash } = window.location;
|
|
8014
|
+
const routePath = /^#\/./.test(hash) ? `${pathname}${hash}` : pathname;
|
|
8015
|
+
return { pagePath: pathname, routePath, candidates, present };
|
|
8016
|
+
};
|
|
8017
|
+
let confirmation = null;
|
|
8018
|
+
let confirmationKey = null;
|
|
8019
|
+
const closeConfirmation = () => {
|
|
8020
|
+
if (!confirmation) return;
|
|
8021
|
+
confirmation.remove();
|
|
8022
|
+
confirmation = null;
|
|
8023
|
+
if (confirmationKey) document.removeEventListener("keydown", confirmationKey, true);
|
|
8024
|
+
confirmationKey = null;
|
|
8025
|
+
panel?.setVisible(true);
|
|
8026
|
+
post({ type: "confirmation-closed" });
|
|
8027
|
+
};
|
|
8028
|
+
const showConfirmation = (card) => {
|
|
8029
|
+
if (confirmation) {
|
|
8030
|
+
confirmation.remove();
|
|
8031
|
+
confirmation = null;
|
|
8032
|
+
}
|
|
8033
|
+
panel?.setVisible(false);
|
|
8034
|
+
const host = document.createElement("div");
|
|
8035
|
+
host.setAttribute("data-veo-builder-chrome", "");
|
|
8036
|
+
host.setAttribute("data-veo-confirmation", "");
|
|
8037
|
+
const shadow = host.attachShadow({ mode: "open" });
|
|
8038
|
+
const style = document.createElement("style");
|
|
8039
|
+
style.textContent = CONFIRMATION_STYLES;
|
|
8040
|
+
const backdrop = document.createElement("div");
|
|
8041
|
+
backdrop.className = "veo-confirm-backdrop";
|
|
8042
|
+
const dialog = document.createElement("div");
|
|
8043
|
+
dialog.className = "veo-confirm";
|
|
8044
|
+
dialog.setAttribute("role", "dialog");
|
|
8045
|
+
dialog.setAttribute("aria-modal", "true");
|
|
8046
|
+
dialog.setAttribute("aria-label", card.title);
|
|
8047
|
+
const badge = document.createElement("div");
|
|
8048
|
+
badge.className = "veo-confirm-check";
|
|
8049
|
+
badge.innerHTML = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>';
|
|
8050
|
+
const title = document.createElement("h2");
|
|
8051
|
+
title.className = "veo-confirm-title";
|
|
8052
|
+
title.textContent = card.title;
|
|
8053
|
+
const message = document.createElement("p");
|
|
8054
|
+
message.className = "veo-confirm-msg";
|
|
8055
|
+
message.textContent = card.message;
|
|
8056
|
+
const rows = document.createElement("dl");
|
|
8057
|
+
rows.className = "veo-confirm-rows";
|
|
8058
|
+
for (const r of card.rows) {
|
|
8059
|
+
const row = document.createElement("div");
|
|
8060
|
+
row.className = "veo-confirm-row";
|
|
8061
|
+
const dt = document.createElement("dt");
|
|
8062
|
+
dt.textContent = r.label;
|
|
8063
|
+
const dd = document.createElement("dd");
|
|
8064
|
+
dd.textContent = r.value;
|
|
8065
|
+
row.append(dt, dd);
|
|
8066
|
+
rows.appendChild(row);
|
|
8067
|
+
}
|
|
8068
|
+
const button = document.createElement("button");
|
|
8069
|
+
button.type = "button";
|
|
8070
|
+
button.className = "veo-confirm-btn";
|
|
8071
|
+
button.textContent = card.buttonLabel ?? "Listo";
|
|
8072
|
+
button.addEventListener("click", closeConfirmation);
|
|
8073
|
+
dialog.append(badge, title, message);
|
|
8074
|
+
if (card.rows.length > 0) dialog.appendChild(rows);
|
|
8075
|
+
dialog.appendChild(button);
|
|
8076
|
+
shadow.append(style, backdrop, dialog);
|
|
8077
|
+
document.body.appendChild(host);
|
|
8078
|
+
confirmation = host;
|
|
8079
|
+
confirmationKey = (e) => {
|
|
8080
|
+
if (e.key !== "Escape") return;
|
|
8081
|
+
e.preventDefault();
|
|
8082
|
+
e.stopPropagation();
|
|
8083
|
+
closeConfirmation();
|
|
8084
|
+
};
|
|
8085
|
+
document.addEventListener("keydown", confirmationKey, true);
|
|
8086
|
+
button.focus();
|
|
8087
|
+
};
|
|
8088
|
+
let highlightBox = null;
|
|
8089
|
+
const setHighlight = (selector) => {
|
|
8090
|
+
highlightBox?.remove();
|
|
8091
|
+
highlightBox = null;
|
|
8092
|
+
if (!selector) return;
|
|
8093
|
+
let target = null;
|
|
8094
|
+
try {
|
|
8095
|
+
target = document.querySelector(selector);
|
|
8096
|
+
} catch {
|
|
8097
|
+
return;
|
|
8098
|
+
}
|
|
8099
|
+
if (!target) return;
|
|
8100
|
+
const r = target.getBoundingClientRect();
|
|
8101
|
+
const box = document.createElement("div");
|
|
8102
|
+
box.setAttribute("data-veo-builder-chrome", "");
|
|
8103
|
+
box.style.cssText = `position:fixed;left:${r.left - 3}px;top:${r.top - 3}px;width:${r.width + 6}px;height:${r.height + 6}px;border:2px solid #FF5B35;border-radius:6px;background:rgba(255,91,53,0.10);pointer-events:none;z-index:2147483646;`;
|
|
8104
|
+
document.body.appendChild(box);
|
|
8105
|
+
highlightBox = box;
|
|
8106
|
+
};
|
|
7866
8107
|
if (ctx.panel) {
|
|
7867
8108
|
chrome = injectBuilderChrome({
|
|
7868
8109
|
appLabel: window.location.hostname,
|
|
@@ -7990,10 +8231,12 @@ function previewProgressFetcher() {
|
|
|
7990
8231
|
return data.items ?? [];
|
|
7991
8232
|
};
|
|
7992
8233
|
}
|
|
8234
|
+
var CONFIRMATION_STYLES;
|
|
7993
8235
|
var init_builder_mode = __esm({
|
|
7994
8236
|
"src/plugins/builder/builder-mode.ts"() {
|
|
7995
8237
|
init_builder_token();
|
|
7996
8238
|
init_safe_env();
|
|
8239
|
+
init_selector_builder();
|
|
7997
8240
|
init_activation_devices();
|
|
7998
8241
|
init_activation_rules();
|
|
7999
8242
|
init_block_builder();
|
|
@@ -8008,6 +8251,42 @@ var init_builder_mode = __esm({
|
|
|
8008
8251
|
init_builder_panel();
|
|
8009
8252
|
init_design_manipulator();
|
|
8010
8253
|
init_element_picker();
|
|
8254
|
+
init_interactive_elements();
|
|
8255
|
+
CONFIRMATION_STYLES = `
|
|
8256
|
+
:host { all: initial; }
|
|
8257
|
+
.veo-confirm-backdrop {
|
|
8258
|
+
position: fixed; inset: 0; z-index: 2147483645;
|
|
8259
|
+
background: rgba(20, 16, 14, 0.45);
|
|
8260
|
+
}
|
|
8261
|
+
.veo-confirm {
|
|
8262
|
+
position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%);
|
|
8263
|
+
z-index: 2147483646; box-sizing: border-box;
|
|
8264
|
+
width: min(432px, calc(100vw - 32px)); padding: 28px 24px 24px;
|
|
8265
|
+
border-radius: 16px; background: #fff; color: #1d1917;
|
|
8266
|
+
box-shadow: 0 24px 64px rgba(0,0,0,0.28);
|
|
8267
|
+
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
|
|
8268
|
+
text-align: center;
|
|
8269
|
+
}
|
|
8270
|
+
.veo-confirm-check {
|
|
8271
|
+
width: 64px; height: 64px; margin: 0 auto; border-radius: 50%;
|
|
8272
|
+
background: #e6f6df; color: #2f9a4e; display: flex; align-items: center; justify-content: center;
|
|
8273
|
+
}
|
|
8274
|
+
.veo-confirm-check svg { width: 30px; height: 30px; }
|
|
8275
|
+
.veo-confirm-title { margin: 18px 0 0; font-size: 17px; font-weight: 600; }
|
|
8276
|
+
.veo-confirm-msg { margin: 8px 0 0; font-size: 13px; color: #6b6461; }
|
|
8277
|
+
.veo-confirm-rows {
|
|
8278
|
+
margin: 18px 0 0; padding: 12px 14px; border-radius: 12px; background: #f6f2ef; text-align: left;
|
|
8279
|
+
}
|
|
8280
|
+
.veo-confirm-row { display: flex; justify-content: space-between; gap: 16px; font-size: 13px; padding: 4px 0; }
|
|
8281
|
+
.veo-confirm-row dt { color: #6b6461; margin: 0; }
|
|
8282
|
+
.veo-confirm-row dd { margin: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
8283
|
+
.veo-confirm-btn {
|
|
8284
|
+
display: block; width: 100%; margin-top: 18px; height: 44px; border: 0; border-radius: 10px;
|
|
8285
|
+
background: #b74d00; color: #fff; font: inherit; font-size: 15px; font-weight: 600; cursor: pointer;
|
|
8286
|
+
}
|
|
8287
|
+
.veo-confirm-btn:hover { background: #953c00; }
|
|
8288
|
+
.veo-confirm-btn:focus-visible { outline: 3px solid rgba(183,77,0,0.35); outline-offset: 2px; }
|
|
8289
|
+
`;
|
|
8011
8290
|
}
|
|
8012
8291
|
});
|
|
8013
8292
|
|
|
@@ -8140,11 +8419,15 @@ var init_builder_session = __esm({
|
|
|
8140
8419
|
// src/plugins/builder/index.ts
|
|
8141
8420
|
var builder_exports = {};
|
|
8142
8421
|
__export(builder_exports, {
|
|
8422
|
+
INTERACTIVE_SELECTOR: () => INTERACTIVE_SELECTOR,
|
|
8143
8423
|
VEO_BLOCK_MIME: () => VEO_BLOCK_MIME,
|
|
8144
8424
|
attachBlockDropTarget: () => attachBlockDropTarget,
|
|
8145
8425
|
attachDesignManipulator: () => attachDesignManipulator,
|
|
8426
|
+
closestInteractive: () => closestInteractive,
|
|
8146
8427
|
createBuilderSession: () => createBuilderSession,
|
|
8428
|
+
elementLabelText: () => elementLabelText,
|
|
8147
8429
|
initBuilderMode: () => initBuilderMode,
|
|
8430
|
+
isInteractiveElement: () => isInteractiveElement,
|
|
8148
8431
|
startElementPicker: () => startElementPicker,
|
|
8149
8432
|
stopElementPicker: () => stopElementPicker
|
|
8150
8433
|
});
|
|
@@ -8155,6 +8438,7 @@ var init_builder = __esm({
|
|
|
8155
8438
|
init_builder_session();
|
|
8156
8439
|
init_design_manipulator();
|
|
8157
8440
|
init_element_picker();
|
|
8441
|
+
init_interactive_elements();
|
|
8158
8442
|
}
|
|
8159
8443
|
});
|
|
8160
8444
|
|
|
@@ -8694,6 +8978,298 @@ function definePlugin(plugin) {
|
|
|
8694
8978
|
|
|
8695
8979
|
// src/plugins/autocapture/dom-listener.ts
|
|
8696
8980
|
init_safe_env();
|
|
8981
|
+
|
|
8982
|
+
// src/plugins/autocapture/click-quality.ts
|
|
8983
|
+
init_safe_env();
|
|
8984
|
+
init_selector_builder();
|
|
8985
|
+
var NO_DEAD_TAGS = /* @__PURE__ */ new Set(["input", "textarea", "select", "option", "label"]);
|
|
8986
|
+
var MAX_ERROR_MESSAGE = 200;
|
|
8987
|
+
var HISTORY_MS = 3e3;
|
|
8988
|
+
var DEFAULTS = {
|
|
8989
|
+
reactionWindowMs: 1e3,
|
|
8990
|
+
errorWindowMs: 2e3,
|
|
8991
|
+
rageClicks: 3,
|
|
8992
|
+
rageWindowMs: 1e3,
|
|
8993
|
+
rageClicksSlow: 5,
|
|
8994
|
+
rageWindowSlowMs: 3e3,
|
|
8995
|
+
maxPerElement: 50
|
|
8996
|
+
};
|
|
8997
|
+
function describeError(value) {
|
|
8998
|
+
let text;
|
|
8999
|
+
if (value instanceof Error) text = `${value.name}: ${value.message}`;
|
|
9000
|
+
else if (typeof value === "string") text = value;
|
|
9001
|
+
else {
|
|
9002
|
+
try {
|
|
9003
|
+
text = JSON.stringify(value) ?? String(value);
|
|
9004
|
+
} catch {
|
|
9005
|
+
text = String(value);
|
|
9006
|
+
}
|
|
9007
|
+
}
|
|
9008
|
+
return text.slice(0, MAX_ERROR_MESSAGE);
|
|
9009
|
+
}
|
|
9010
|
+
var ClickQualityTracker = class {
|
|
9011
|
+
constructor(emit, options = {}) {
|
|
9012
|
+
this.emit = emit;
|
|
9013
|
+
this.installed = false;
|
|
9014
|
+
this.cleanups = [];
|
|
9015
|
+
// Sensores globales (contadores: cada observación compara su foto inicial).
|
|
9016
|
+
this.netCount = 0;
|
|
9017
|
+
this.navCount = 0;
|
|
9018
|
+
this.focusCount = 0;
|
|
9019
|
+
this.unloading = false;
|
|
9020
|
+
this.errors = [];
|
|
9021
|
+
this.history = /* @__PURE__ */ new Map();
|
|
9022
|
+
this.bursts = /* @__PURE__ */ new Map();
|
|
9023
|
+
this.emitted = /* @__PURE__ */ new Map();
|
|
9024
|
+
this.opts = { ...DEFAULTS, ...options };
|
|
9025
|
+
}
|
|
9026
|
+
install() {
|
|
9027
|
+
if (this.installed || !hasWindow()) return;
|
|
9028
|
+
this.installed = true;
|
|
9029
|
+
const on = (type, handler, capture = true) => {
|
|
9030
|
+
window.addEventListener(type, handler, capture);
|
|
9031
|
+
this.cleanups.push(() => window.removeEventListener(type, handler, capture));
|
|
9032
|
+
};
|
|
9033
|
+
on("error", (e) => {
|
|
9034
|
+
const err = e;
|
|
9035
|
+
this.pushError("error", err.error ?? err.message ?? "error");
|
|
9036
|
+
});
|
|
9037
|
+
on("unhandledrejection", (e) => {
|
|
9038
|
+
this.pushError("unhandledrejection", e.reason ?? "rejection");
|
|
9039
|
+
});
|
|
9040
|
+
on("popstate", () => this.navCount++);
|
|
9041
|
+
on("hashchange", () => this.navCount++);
|
|
9042
|
+
on("focusin", () => this.focusCount++);
|
|
9043
|
+
on("pagehide", () => {
|
|
9044
|
+
this.unloading = true;
|
|
9045
|
+
});
|
|
9046
|
+
on("beforeunload", () => {
|
|
9047
|
+
this.unloading = true;
|
|
9048
|
+
});
|
|
9049
|
+
this.patchHistory();
|
|
9050
|
+
this.patchConsole();
|
|
9051
|
+
this.patchFetch();
|
|
9052
|
+
this.patchXhr();
|
|
9053
|
+
}
|
|
9054
|
+
destroy() {
|
|
9055
|
+
for (const c of this.cleanups) c();
|
|
9056
|
+
this.cleanups = [];
|
|
9057
|
+
for (const b of this.bursts.values()) window.clearTimeout(b.timer);
|
|
9058
|
+
this.bursts.clear();
|
|
9059
|
+
this.history.clear();
|
|
9060
|
+
this.installed = false;
|
|
9061
|
+
}
|
|
9062
|
+
/** Llamar por cada clic real sobre un elemento interactivo, ANTES del throttle. */
|
|
9063
|
+
onClick(element, event) {
|
|
9064
|
+
if (!this.installed) return;
|
|
9065
|
+
const now = Date.now();
|
|
9066
|
+
const obs = { at: now, reacted: false };
|
|
9067
|
+
this.remember(element, obs);
|
|
9068
|
+
this.observeReaction(element, obs, event);
|
|
9069
|
+
this.observeErrors(element, now);
|
|
9070
|
+
this.trackRage(element, now);
|
|
9071
|
+
}
|
|
9072
|
+
// ---------------------------------------------------------------- dead ----
|
|
9073
|
+
observeReaction(element, obs, event) {
|
|
9074
|
+
const netAtClick = this.netCount;
|
|
9075
|
+
const navAtClick = this.navCount;
|
|
9076
|
+
const focusAtClick = this.focusCount;
|
|
9077
|
+
const hrefAtClick = window.location.href;
|
|
9078
|
+
const skipDead = this.isDeadExempt(element, event);
|
|
9079
|
+
let observer = null;
|
|
9080
|
+
if (typeof MutationObserver !== "undefined") {
|
|
9081
|
+
observer = new MutationObserver(() => {
|
|
9082
|
+
obs.reacted = true;
|
|
9083
|
+
observer?.disconnect();
|
|
9084
|
+
observer = null;
|
|
9085
|
+
});
|
|
9086
|
+
observer.observe(document.documentElement, {
|
|
9087
|
+
childList: true,
|
|
9088
|
+
attributes: true,
|
|
9089
|
+
characterData: true,
|
|
9090
|
+
subtree: true
|
|
9091
|
+
});
|
|
9092
|
+
}
|
|
9093
|
+
window.setTimeout(() => {
|
|
9094
|
+
observer?.disconnect();
|
|
9095
|
+
const reacted = obs.reacted || this.unloading || this.netCount !== netAtClick || this.navCount !== navAtClick || this.focusCount !== focusAtClick || window.location.href !== hrefAtClick;
|
|
9096
|
+
obs.reacted = reacted;
|
|
9097
|
+
if (!reacted && !skipDead) this.report("$dead_click", element, {});
|
|
9098
|
+
}, this.opts.reactionWindowMs);
|
|
9099
|
+
}
|
|
9100
|
+
isDeadExempt(element, event) {
|
|
9101
|
+
if (event && (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey)) return true;
|
|
9102
|
+
if (event && typeof event.button === "number" && event.button !== 0) return true;
|
|
9103
|
+
const tag = element.tagName.toLowerCase();
|
|
9104
|
+
if (NO_DEAD_TAGS.has(tag)) return true;
|
|
9105
|
+
if (element.closest('[contenteditable=""],[contenteditable="true"]')) return true;
|
|
9106
|
+
const anchor = element.closest("a");
|
|
9107
|
+
if (anchor) {
|
|
9108
|
+
if (anchor.target === "_blank" || anchor.hasAttribute("download")) return true;
|
|
9109
|
+
const href = anchor.getAttribute("href") ?? "";
|
|
9110
|
+
if (/^(mailto|tel|sms):/i.test(href)) return true;
|
|
9111
|
+
}
|
|
9112
|
+
return false;
|
|
9113
|
+
}
|
|
9114
|
+
// --------------------------------------------------------------- error ----
|
|
9115
|
+
observeErrors(element, clickedAt) {
|
|
9116
|
+
const deadline = clickedAt + this.opts.errorWindowMs;
|
|
9117
|
+
const check = () => {
|
|
9118
|
+
const err = this.errors.find((e) => e.at >= clickedAt && e.at <= deadline);
|
|
9119
|
+
if (err) {
|
|
9120
|
+
this.report("$click_error", element, {
|
|
9121
|
+
$error_source: err.source,
|
|
9122
|
+
$error_message: err.message
|
|
9123
|
+
});
|
|
9124
|
+
return;
|
|
9125
|
+
}
|
|
9126
|
+
if (Date.now() < deadline) window.setTimeout(check, 250);
|
|
9127
|
+
};
|
|
9128
|
+
window.setTimeout(check, 250);
|
|
9129
|
+
}
|
|
9130
|
+
pushError(source, value) {
|
|
9131
|
+
const message = describeError(value);
|
|
9132
|
+
if (message.startsWith("[veo]")) return;
|
|
9133
|
+
this.errors.push({ at: Date.now(), source, message });
|
|
9134
|
+
const cutoff = Date.now() - this.opts.errorWindowMs - 1e3;
|
|
9135
|
+
while (this.errors.length > 0 && this.errors[0].at < cutoff) {
|
|
9136
|
+
this.errors.shift();
|
|
9137
|
+
}
|
|
9138
|
+
if (this.errors.length > 50) this.errors.splice(0, this.errors.length - 50);
|
|
9139
|
+
}
|
|
9140
|
+
// ---------------------------------------------------------------- rage ----
|
|
9141
|
+
remember(element, obs) {
|
|
9142
|
+
const list = this.history.get(element) ?? [];
|
|
9143
|
+
const cutoff = obs.at - HISTORY_MS;
|
|
9144
|
+
const kept = list.filter((o) => o.at >= cutoff);
|
|
9145
|
+
kept.push(obs);
|
|
9146
|
+
this.history.set(element, kept);
|
|
9147
|
+
if (this.history.size > 100) {
|
|
9148
|
+
for (const [el2, obsList] of this.history) {
|
|
9149
|
+
if (obsList.every((o) => o.at < cutoff)) this.history.delete(el2);
|
|
9150
|
+
}
|
|
9151
|
+
}
|
|
9152
|
+
}
|
|
9153
|
+
trackRage(element, now) {
|
|
9154
|
+
const list = this.history.get(element) ?? [];
|
|
9155
|
+
const fast = list.filter((o) => o.at >= now - this.opts.rageWindowMs).length;
|
|
9156
|
+
const slow = list.filter((o) => o.at >= now - this.opts.rageWindowSlowMs).length;
|
|
9157
|
+
const existing = this.bursts.get(element);
|
|
9158
|
+
const isRage = fast >= this.opts.rageClicks || slow >= this.opts.rageClicksSlow;
|
|
9159
|
+
if (!existing && !isRage) return;
|
|
9160
|
+
const burst = existing ?? {
|
|
9161
|
+
startedAt: (list.find((o) => o.at >= now - this.opts.rageWindowSlowMs) ?? { at: now }).at,
|
|
9162
|
+
count: 0,
|
|
9163
|
+
timer: 0
|
|
9164
|
+
};
|
|
9165
|
+
burst.count = list.filter((o) => o.at >= burst.startedAt).length;
|
|
9166
|
+
window.clearTimeout(burst.timer);
|
|
9167
|
+
burst.timer = window.setTimeout(() => {
|
|
9168
|
+
this.bursts.delete(element);
|
|
9169
|
+
const clicks = (this.history.get(element) ?? []).filter((o) => o.at >= burst.startedAt);
|
|
9170
|
+
this.report("$rage_click", element, {
|
|
9171
|
+
$click_count: Math.max(clicks.length, burst.count),
|
|
9172
|
+
$reacted_clicks: clicks.filter((o) => o.reacted).length
|
|
9173
|
+
});
|
|
9174
|
+
}, this.opts.reactionWindowMs + 50);
|
|
9175
|
+
this.bursts.set(element, burst);
|
|
9176
|
+
}
|
|
9177
|
+
// ---------------------------------------------------------------- emit ----
|
|
9178
|
+
report(kind, element, extra) {
|
|
9179
|
+
const key = buildSelectorPath(element, 5);
|
|
9180
|
+
const counts = this.emitted.get(key) ?? { $dead_click: 0, $rage_click: 0, $click_error: 0 };
|
|
9181
|
+
if (counts[kind] >= this.opts.maxPerElement) return;
|
|
9182
|
+
counts[kind]++;
|
|
9183
|
+
this.emitted.set(key, counts);
|
|
9184
|
+
try {
|
|
9185
|
+
this.emit(kind, element, extra);
|
|
9186
|
+
} catch {
|
|
9187
|
+
}
|
|
9188
|
+
}
|
|
9189
|
+
// ------------------------------------------------------------- patches ----
|
|
9190
|
+
patchHistory() {
|
|
9191
|
+
const h = window.history;
|
|
9192
|
+
if (!h) return;
|
|
9193
|
+
const origPush = h.pushState;
|
|
9194
|
+
const origReplace = h.replaceState;
|
|
9195
|
+
const self = this;
|
|
9196
|
+
h.pushState = function(...args) {
|
|
9197
|
+
self.navCount++;
|
|
9198
|
+
return origPush.apply(this, args);
|
|
9199
|
+
};
|
|
9200
|
+
h.replaceState = function(...args) {
|
|
9201
|
+
self.navCount++;
|
|
9202
|
+
return origReplace.apply(this, args);
|
|
9203
|
+
};
|
|
9204
|
+
this.cleanups.push(() => {
|
|
9205
|
+
h.pushState = origPush;
|
|
9206
|
+
h.replaceState = origReplace;
|
|
9207
|
+
});
|
|
9208
|
+
}
|
|
9209
|
+
patchConsole() {
|
|
9210
|
+
const orig = console.error;
|
|
9211
|
+
const self = this;
|
|
9212
|
+
console.error = function(...args) {
|
|
9213
|
+
try {
|
|
9214
|
+
self.pushError("console", args.map(describeError).join(" "));
|
|
9215
|
+
} catch {
|
|
9216
|
+
}
|
|
9217
|
+
return orig.apply(this, args);
|
|
9218
|
+
};
|
|
9219
|
+
this.cleanups.push(() => {
|
|
9220
|
+
console.error = orig;
|
|
9221
|
+
});
|
|
9222
|
+
}
|
|
9223
|
+
/**
|
|
9224
|
+
* `fetch`: cuenta la petición (reacción) y registra respuestas ≥500 o
|
|
9225
|
+
* rechazos como error. Se observa con `.then(ok, err)` sobre la promesa
|
|
9226
|
+
* original: eso marca el rechazo como manejado para el navegador, así que
|
|
9227
|
+
* un fetch fallido sin catch de la app no dispara `unhandledrejection` —
|
|
9228
|
+
* lo registramos nosotros como error de red.
|
|
9229
|
+
*/
|
|
9230
|
+
patchFetch() {
|
|
9231
|
+
if (typeof window.fetch !== "function") return;
|
|
9232
|
+
const orig = window.fetch;
|
|
9233
|
+
const self = this;
|
|
9234
|
+
window.fetch = function(...args) {
|
|
9235
|
+
self.netCount++;
|
|
9236
|
+
const p = orig.apply(this, args);
|
|
9237
|
+
if (p && typeof p.then === "function") {
|
|
9238
|
+
p.then(
|
|
9239
|
+
(res) => {
|
|
9240
|
+
if (res && res.status >= 500) self.pushError("fetch", `${res.status} ${res.url}`);
|
|
9241
|
+
},
|
|
9242
|
+
(err) => self.pushError("fetch", err)
|
|
9243
|
+
);
|
|
9244
|
+
}
|
|
9245
|
+
return p;
|
|
9246
|
+
};
|
|
9247
|
+
this.cleanups.push(() => {
|
|
9248
|
+
window.fetch = orig;
|
|
9249
|
+
});
|
|
9250
|
+
}
|
|
9251
|
+
patchXhr() {
|
|
9252
|
+
const proto = typeof XMLHttpRequest !== "undefined" ? XMLHttpRequest.prototype : null;
|
|
9253
|
+
if (!proto) return;
|
|
9254
|
+
const origSend = proto.send;
|
|
9255
|
+
const self = this;
|
|
9256
|
+
proto.send = function(...args) {
|
|
9257
|
+
self.netCount++;
|
|
9258
|
+
try {
|
|
9259
|
+
this.addEventListener("loadend", () => {
|
|
9260
|
+
if (this.status >= 500) self.pushError("xhr", `${this.status} ${this.responseURL}`);
|
|
9261
|
+
});
|
|
9262
|
+
} catch {
|
|
9263
|
+
}
|
|
9264
|
+
return origSend.apply(this, args);
|
|
9265
|
+
};
|
|
9266
|
+
this.cleanups.push(() => {
|
|
9267
|
+
proto.send = origSend;
|
|
9268
|
+
});
|
|
9269
|
+
}
|
|
9270
|
+
};
|
|
9271
|
+
|
|
9272
|
+
// src/plugins/autocapture/dom-listener.ts
|
|
8697
9273
|
init_constants();
|
|
8698
9274
|
|
|
8699
9275
|
// src/plugins/autocapture/element-serializer.ts
|
|
@@ -8804,6 +9380,7 @@ var DomListener = class {
|
|
|
8804
9380
|
constructor(client, config) {
|
|
8805
9381
|
this.client = client;
|
|
8806
9382
|
this.cleanups = [];
|
|
9383
|
+
this.quality = null;
|
|
8807
9384
|
const d = DEFAULT_AUTOCAPTURE_CONFIG;
|
|
8808
9385
|
this.config = {
|
|
8809
9386
|
enabled: config.enabled ?? d.enabled,
|
|
@@ -8816,12 +9393,20 @@ var DomListener = class {
|
|
|
8816
9393
|
throttleMs: config.throttleMs ?? d.throttleMs,
|
|
8817
9394
|
maxTextLength: config.maxTextLength ?? d.maxTextLength,
|
|
8818
9395
|
captureElementMetadata: config.captureElementMetadata ?? d.captureElementMetadata,
|
|
8819
|
-
captureAncestors: Math.min(config.captureAncestors ?? d.captureAncestors, MAX_ANCESTORS)
|
|
9396
|
+
captureAncestors: Math.min(config.captureAncestors ?? d.captureAncestors, MAX_ANCESTORS),
|
|
9397
|
+
captureClickQuality: config.captureClickQuality ?? d.captureClickQuality
|
|
8820
9398
|
};
|
|
8821
9399
|
this.throttle = new ElementThrottle(this.config.throttleMs);
|
|
8822
9400
|
}
|
|
8823
9401
|
install() {
|
|
8824
9402
|
if (!hasDocument() || !this.config.enabled) return;
|
|
9403
|
+
if (this.config.captureClicks && this.config.captureClickQuality) {
|
|
9404
|
+
this.quality = new ClickQualityTracker((kind, element, extra) => {
|
|
9405
|
+
const payload = buildAutocapturePayload("click", element, this.config);
|
|
9406
|
+
this.client.track(kind, { ...payload, ...extra });
|
|
9407
|
+
});
|
|
9408
|
+
this.quality.install();
|
|
9409
|
+
}
|
|
8825
9410
|
if (this.config.captureClicks) this.attach("click", (e) => this.handleClick(e));
|
|
8826
9411
|
if (this.config.captureSubmits) this.attach("submit", (e) => this.handleSubmit(e), true);
|
|
8827
9412
|
if (this.config.captureChanges) this.attach("change", (e) => this.handleChange(e), true);
|
|
@@ -8829,6 +9414,8 @@ var DomListener = class {
|
|
|
8829
9414
|
destroy() {
|
|
8830
9415
|
for (const cleanup of this.cleanups) cleanup();
|
|
8831
9416
|
this.cleanups = [];
|
|
9417
|
+
this.quality?.destroy();
|
|
9418
|
+
this.quality = null;
|
|
8832
9419
|
}
|
|
8833
9420
|
attach(eventName, handler, useCapture = false) {
|
|
8834
9421
|
const listener = (e) => {
|
|
@@ -8847,6 +9434,7 @@ var DomListener = class {
|
|
|
8847
9434
|
const meaningful = this.findMeaningfulAncestor(target);
|
|
8848
9435
|
if (!meaningful) return;
|
|
8849
9436
|
if (isElementBlocked(meaningful, this.config.blockSelectors)) return;
|
|
9437
|
+
this.quality?.onClick(meaningful, event);
|
|
8850
9438
|
if (!this.throttle.shouldFire(meaningful)) return;
|
|
8851
9439
|
this.emit("click", meaningful);
|
|
8852
9440
|
}
|