@keak/sdk 2.0.9 → 2.1.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/dist/KeakToolbarShadow.d.ts +21 -0
- package/dist/KeakToolbarShadow.d.ts.map +1 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/card.d.ts.map +1 -0
- package/dist/components/ui/html-preview.d.ts +9 -0
- package/dist/components/ui/html-preview.d.ts.map +1 -0
- package/dist/components/ui/simple-tabs.d.ts +26 -0
- package/dist/components/ui/simple-tabs.d.ts.map +1 -0
- package/dist/components/ui/spinner.d.ts +6 -0
- package/dist/components/ui/spinner.d.ts.map +1 -0
- package/dist/components/ui/tabs.d.ts +13 -0
- package/dist/components/ui/tabs.d.ts.map +1 -0
- package/dist/components/ui/textarea.d.ts +6 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/index.cjs.js +2 -198
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.js +2 -198
- package/dist/index.js.map +1 -1
- package/dist/services/telemetry/index.d.ts +20 -0
- package/dist/services/telemetry/index.d.ts.map +1 -0
- package/dist/services/telemetry/telemetryService.d.ts +66 -0
- package/dist/services/telemetry/telemetryService.d.ts.map +1 -0
- package/dist/services/telemetry/types.d.ts +64 -0
- package/dist/services/telemetry/types.d.ts.map +1 -0
- package/dist/toolbar/AIPromptPanel.d.ts +9 -0
- package/dist/toolbar/AIPromptPanel.d.ts.map +1 -0
- package/dist/toolbar/ElementSelector.d.ts.map +1 -1
- package/dist/toolbar/ExperimentPanel.d.ts +9 -0
- package/dist/toolbar/ExperimentPanel.d.ts.map +1 -0
- package/dist/toolbar/KeakToolbar.d.ts.map +1 -1
- package/dist/toolbar/MetricsPanel.d.ts +7 -0
- package/dist/toolbar/MetricsPanel.d.ts.map +1 -0
- package/dist/toolbar/PageScanPanel.d.ts +15 -0
- package/dist/toolbar/PageScanPanel.d.ts.map +1 -0
- package/dist/toolbar/components/PrimaryButton.d.ts +12 -0
- package/dist/toolbar/components/PrimaryButton.d.ts.map +1 -0
- package/dist/toolbar/components/WarningButton.d.ts +12 -0
- package/dist/toolbar/components/WarningButton.d.ts.map +1 -0
- package/dist/toolbar/components/ui/Badge.d.ts +10 -0
- package/dist/toolbar/components/ui/Badge.d.ts.map +1 -0
- package/dist/toolbar/components/ui/Button.d.ts +12 -0
- package/dist/toolbar/components/ui/Button.d.ts.map +1 -0
- package/dist/toolbar/components/ui/Progress.d.ts +5 -0
- package/dist/toolbar/components/ui/Progress.d.ts.map +1 -0
- package/dist/toolbar/components/ui/Tabs.d.ts +44 -0
- package/dist/toolbar/components/ui/Tabs.d.ts.map +1 -0
- package/dist/toolbar/components/ui/dropdown-menu.d.ts +28 -0
- package/dist/toolbar/components/ui/dropdown-menu.d.ts.map +1 -0
- package/dist/toolbar.js +2 -198
- package/dist/toolbar.js.map +1 -1
- package/package.json +1 -1
- package/src/plugins/webpack-loader-babel/index.js +1 -6
package/dist/index.js
CHANGED
|
@@ -499,116 +499,9 @@ function getSourceConfidence(sourceInfo) {
|
|
|
499
499
|
}
|
|
500
500
|
return 'low';
|
|
501
501
|
}
|
|
502
|
-
/**
|
|
503
|
-
* Check if an element is part of a dynamically generated list (.map(), .forEach(), etc.)
|
|
504
|
-
*
|
|
505
|
-
* Detection strategy:
|
|
506
|
-
* 1. Check if multiple siblings share the same source location (primary method)
|
|
507
|
-
* 2. This indicates they're generated from the same template (likely a map)
|
|
508
|
-
* 3. Also check if the element is a descendant of an element that's in a map
|
|
509
|
-
*
|
|
510
|
-
* @param element The DOM element to check
|
|
511
|
-
* @returns Object with isInMap (boolean) and reason (string) if detected
|
|
512
|
-
*/
|
|
513
|
-
function isElementInDynamicList(element) {
|
|
514
|
-
// First, check if the element itself is in a map
|
|
515
|
-
const directCheck = checkElementForMapPattern(element);
|
|
516
|
-
if (directCheck.isInMap) {
|
|
517
|
-
return directCheck;
|
|
518
|
-
}
|
|
519
|
-
// If not, check if any ancestor is in a map
|
|
520
|
-
let current = element.parentElement;
|
|
521
|
-
let depth = 0;
|
|
522
|
-
const maxDepth = 10; // Limit traversal depth to avoid performance issues
|
|
523
|
-
while (current && depth < maxDepth) {
|
|
524
|
-
const ancestorCheck = checkElementForMapPattern(current);
|
|
525
|
-
if (ancestorCheck.isInMap) {
|
|
526
|
-
return {
|
|
527
|
-
isInMap: true,
|
|
528
|
-
reason: `This element is a child of a dynamically generated list item. ${ancestorCheck.reason}`,
|
|
529
|
-
siblingCount: ancestorCheck.siblingCount
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
current = current.parentElement;
|
|
533
|
-
depth++;
|
|
534
|
-
}
|
|
535
|
-
return { isInMap: false };
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* Helper function to check if a specific element is part of a map pattern
|
|
539
|
-
*/
|
|
540
|
-
function checkElementForMapPattern(element) {
|
|
541
|
-
const parent = element.parentElement;
|
|
542
|
-
if (!parent) {
|
|
543
|
-
return { isInMap: false };
|
|
544
|
-
}
|
|
545
|
-
// Get all sibling elements (including the element itself)
|
|
546
|
-
const siblings = Array.from(parent.children).filter((sibling) => sibling instanceof HTMLElement);
|
|
547
|
-
// Need at least 2 siblings to detect a pattern
|
|
548
|
-
if (siblings.length < 2) {
|
|
549
|
-
return { isInMap: false };
|
|
550
|
-
}
|
|
551
|
-
// Get source location for the target element
|
|
552
|
-
const elementSource = getReactFiberSource(element);
|
|
553
|
-
// If we can't get source for the element, try data-keak-src attribute
|
|
554
|
-
let elementSourceKey = null;
|
|
555
|
-
if (elementSource) {
|
|
556
|
-
elementSourceKey = `${elementSource.fileName}:${elementSource.lineNumber}`;
|
|
557
|
-
}
|
|
558
|
-
else {
|
|
559
|
-
const keakSrc = element.getAttribute('data-keak-src');
|
|
560
|
-
if (keakSrc) {
|
|
561
|
-
// Format is "file:line:column", we use file:line as key
|
|
562
|
-
const parts = keakSrc.split(':');
|
|
563
|
-
if (parts.length >= 2) {
|
|
564
|
-
const fileName = parts.slice(0, -2).join(':'); // Handle Windows paths
|
|
565
|
-
const lineNumber = parts[parts.length - 2];
|
|
566
|
-
elementSourceKey = `${fileName}:${lineNumber}`;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
// If we don't have source info, we can't detect map patterns reliably
|
|
571
|
-
if (!elementSourceKey) {
|
|
572
|
-
return { isInMap: false };
|
|
573
|
-
}
|
|
574
|
-
// Check how many siblings share the same source location
|
|
575
|
-
let matchingSiblings = 0;
|
|
576
|
-
for (const sibling of siblings) {
|
|
577
|
-
const siblingSource = getReactFiberSource(sibling);
|
|
578
|
-
let siblingSourceKey = null;
|
|
579
|
-
if (siblingSource) {
|
|
580
|
-
siblingSourceKey = `${siblingSource.fileName}:${siblingSource.lineNumber}`;
|
|
581
|
-
}
|
|
582
|
-
else {
|
|
583
|
-
const keakSrc = sibling.getAttribute('data-keak-src');
|
|
584
|
-
if (keakSrc) {
|
|
585
|
-
const parts = keakSrc.split(':');
|
|
586
|
-
if (parts.length >= 2) {
|
|
587
|
-
const fileName = parts.slice(0, -2).join(':');
|
|
588
|
-
const lineNumber = parts[parts.length - 2];
|
|
589
|
-
siblingSourceKey = `${fileName}:${lineNumber}`;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
if (siblingSourceKey === elementSourceKey) {
|
|
594
|
-
matchingSiblings++;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
// If 2+ siblings share the same source location, it's likely a map/forEach
|
|
598
|
-
// We use >= 2 because the element itself counts as one
|
|
599
|
-
if (matchingSiblings >= 2) {
|
|
600
|
-
return {
|
|
601
|
-
isInMap: true,
|
|
602
|
-
reason: `Multiple elements (${matchingSiblings}) share the same source location, indicating they're generated from a .map() or similar dynamic list pattern`,
|
|
603
|
-
siblingCount: matchingSiblings
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
return { isInMap: false };
|
|
607
|
-
}
|
|
608
502
|
|
|
609
503
|
const ElementSelector = ({ onElementSelected, onCancel, }) => {
|
|
610
504
|
const [hoveredElement, setHoveredElement] = useState(null);
|
|
611
|
-
const [mapWarning, setMapWarning] = useState({ show: false, message: "" });
|
|
612
505
|
const highlightRef = useRef(null);
|
|
613
506
|
useEffect(() => {
|
|
614
507
|
const handleMouseMove = (e) => {
|
|
@@ -633,27 +526,9 @@ const ElementSelector = ({ onElementSelected, onCancel, }) => {
|
|
|
633
526
|
target.closest(".keak-toolbar") ||
|
|
634
527
|
target.closest(".keak-selector-highlight") ||
|
|
635
528
|
target.closest(".keak-selector-tooltip") ||
|
|
636
|
-
target.closest(".keak-selector-instructions")
|
|
637
|
-
target.closest(".keak-map-warning")) {
|
|
529
|
+
target.closest(".keak-selector-instructions")) {
|
|
638
530
|
return;
|
|
639
531
|
}
|
|
640
|
-
// Check if element is inside a dynamic list (.map(), .forEach(), etc.)
|
|
641
|
-
const mapCheck = isElementInDynamicList(target);
|
|
642
|
-
if (mapCheck.isInMap) {
|
|
643
|
-
// Show warning and prevent selection
|
|
644
|
-
setMapWarning({
|
|
645
|
-
show: true,
|
|
646
|
-
message: mapCheck.reason || "Element is part of a dynamically generated list",
|
|
647
|
-
siblingCount: mapCheck.siblingCount
|
|
648
|
-
});
|
|
649
|
-
// Auto-hide warning after 5 seconds
|
|
650
|
-
setTimeout(() => {
|
|
651
|
-
setMapWarning({ show: false, message: "" });
|
|
652
|
-
}, 5000);
|
|
653
|
-
return; // Prevent selection
|
|
654
|
-
}
|
|
655
|
-
// Clear any existing warning
|
|
656
|
-
setMapWarning({ show: false, message: "" });
|
|
657
532
|
onElementSelected(target);
|
|
658
533
|
};
|
|
659
534
|
const handleKeyDown = (e) => {
|
|
@@ -816,65 +691,7 @@ const ElementSelector = ({ onElementSelected, onCancel, }) => {
|
|
|
816
691
|
return { selector, text, source, impact };
|
|
817
692
|
};
|
|
818
693
|
const elementInfo = hoveredElement ? getElementInfo(hoveredElement) : null;
|
|
819
|
-
return (jsxs(Fragment, { children: [jsx("div", { ref: highlightRef, className: "keak-selector-highlight" }),
|
|
820
|
-
position: "fixed",
|
|
821
|
-
top: "140px",
|
|
822
|
-
left: "50%",
|
|
823
|
-
transform: "translateX(-50%)",
|
|
824
|
-
maxWidth: "500px",
|
|
825
|
-
background: "hsl(0 84.2% 60.2%)",
|
|
826
|
-
border: "1px solid hsl(0 72.2% 50.6%)",
|
|
827
|
-
borderRadius: "8px",
|
|
828
|
-
padding: "16px 20px",
|
|
829
|
-
boxShadow: "0 10px 30px 0 rgba(0, 0, 0, 0.3)",
|
|
830
|
-
fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
831
|
-
zIndex: 1000000,
|
|
832
|
-
color: "white",
|
|
833
|
-
animation: "slideDown 0.3s ease-out",
|
|
834
|
-
}, children: jsxs("div", { style: { display: "flex", alignItems: "flex-start", gap: "12px" }, children: [jsx("div", { style: {
|
|
835
|
-
fontSize: "20px",
|
|
836
|
-
lineHeight: "1",
|
|
837
|
-
marginTop: "2px",
|
|
838
|
-
}, children: "\u26A0\uFE0F" }), jsxs("div", { style: { flex: 1 }, children: [jsx("div", { style: {
|
|
839
|
-
fontSize: "15px",
|
|
840
|
-
fontWeight: 600,
|
|
841
|
-
marginBottom: "8px",
|
|
842
|
-
}, children: "Cannot select element from dynamic list" }), jsx("div", { style: {
|
|
843
|
-
fontSize: "13px",
|
|
844
|
-
lineHeight: "1.5",
|
|
845
|
-
opacity: 0.95,
|
|
846
|
-
marginBottom: "12px",
|
|
847
|
-
}, children: "This element is part of a dynamically generated list (.map(), .forEach(), etc.). Selecting individual items isn't supported because:" }), jsxs("ul", { style: {
|
|
848
|
-
fontSize: "13px",
|
|
849
|
-
lineHeight: "1.6",
|
|
850
|
-
margin: "0 0 12px 0",
|
|
851
|
-
paddingLeft: "20px",
|
|
852
|
-
opacity: 0.95,
|
|
853
|
-
listStyle: "none",
|
|
854
|
-
}, children: [jsxs("li", { style: { position: "relative", paddingLeft: "16px" }, children: [jsx("span", { style: { position: "absolute", left: 0 }, children: "-" }), "The data might come from props or a database"] }), jsxs("li", { style: { position: "relative", paddingLeft: "16px" }, children: [jsx("span", { style: { position: "absolute", left: 0 }, children: "-" }), "Variants would affect all items, not just one"] })] }), jsx("div", { style: {
|
|
855
|
-
fontSize: "13px",
|
|
856
|
-
fontWeight: 600,
|
|
857
|
-
marginTop: "12px",
|
|
858
|
-
paddingTop: "12px",
|
|
859
|
-
borderTop: "1px solid rgba(255, 255, 255, 0.2)",
|
|
860
|
-
}, children: "\uD83D\uDCA1 Alternatives:" }), jsxs("ul", { style: {
|
|
861
|
-
fontSize: "13px",
|
|
862
|
-
lineHeight: "1.6",
|
|
863
|
-
margin: "8px 0 0 0",
|
|
864
|
-
paddingLeft: "20px",
|
|
865
|
-
opacity: 0.95,
|
|
866
|
-
listStyle: "none",
|
|
867
|
-
}, children: [jsxs("li", { style: { position: "relative", paddingLeft: "16px" }, children: [jsx("span", { style: { position: "absolute", left: 0 }, children: "-" }), "Select the parent container to test the entire list"] }), jsxs("li", { style: { position: "relative", paddingLeft: "16px" }, children: [jsx("span", { style: { position: "absolute", left: 0 }, children: "-" }), "Extract list items into a separate component and wrap it in Experiment/Variant"] })] })] }), jsx("button", { onClick: () => setMapWarning({ show: false, message: "" }), style: {
|
|
868
|
-
background: "transparent",
|
|
869
|
-
border: "none",
|
|
870
|
-
color: "white",
|
|
871
|
-
cursor: "pointer",
|
|
872
|
-
fontSize: "18px",
|
|
873
|
-
lineHeight: "1",
|
|
874
|
-
padding: "0",
|
|
875
|
-
opacity: 0.8,
|
|
876
|
-
transition: "opacity 0.2s",
|
|
877
|
-
}, onMouseEnter: (e) => (e.currentTarget.style.opacity = "1"), onMouseLeave: (e) => (e.currentTarget.style.opacity = "0.8"), children: "\u00D7" })] }) })), hoveredElement && elementInfo && (jsxs("div", { className: "keak-selector-tooltip", style: {
|
|
694
|
+
return (jsxs(Fragment, { children: [jsx("div", { ref: highlightRef, className: "keak-selector-highlight" }), hoveredElement && elementInfo && (jsxs("div", { className: "keak-selector-tooltip", style: {
|
|
878
695
|
position: "fixed",
|
|
879
696
|
bottom: `${window.innerHeight -
|
|
880
697
|
hoveredElement.getBoundingClientRect().top +
|
|
@@ -1494,19 +1311,6 @@ const KeakToolbar = ({ position = 'bottom-right', theme = 'auto' }) => {
|
|
|
1494
1311
|
console.log('[Keak Toolbar] Tag:', element.tagName);
|
|
1495
1312
|
console.log('[Keak Toolbar] HTML (first 300 chars):', element.outerHTML.substring(0, 300));
|
|
1496
1313
|
console.log('[Keak Toolbar] All attributes:', Array.from(element.attributes).map(a => `${a.name}="${a.value}"`).join(', '));
|
|
1497
|
-
// Check if element is inside a dynamic list (.map(), .forEach(), etc.)
|
|
1498
|
-
const mapCheck = isElementInDynamicList(element);
|
|
1499
|
-
if (mapCheck.isInMap) {
|
|
1500
|
-
console.log('[Keak Toolbar] ⚠️ Element is part of a dynamic list, preventing selection');
|
|
1501
|
-
console.log('[Keak Toolbar] Reason:', mapCheck.reason);
|
|
1502
|
-
// Show a brief visual feedback
|
|
1503
|
-
element.style.transition = 'all 0.3s';
|
|
1504
|
-
element.style.outline = '3px solid #ef4444';
|
|
1505
|
-
setTimeout(() => { element.style.outline = ''; }, 2000);
|
|
1506
|
-
// Don't proceed with selection
|
|
1507
|
-
setIsSelecting(false);
|
|
1508
|
-
return;
|
|
1509
|
-
}
|
|
1510
1314
|
setSelectedElement(element);
|
|
1511
1315
|
setIsSelecting(false);
|
|
1512
1316
|
updateSelectedHighlight(element);
|