@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.
Files changed (52) hide show
  1. package/dist/KeakToolbarShadow.d.ts +21 -0
  2. package/dist/KeakToolbarShadow.d.ts.map +1 -0
  3. package/dist/components/ui/card.d.ts +9 -0
  4. package/dist/components/ui/card.d.ts.map +1 -0
  5. package/dist/components/ui/html-preview.d.ts +9 -0
  6. package/dist/components/ui/html-preview.d.ts.map +1 -0
  7. package/dist/components/ui/simple-tabs.d.ts +26 -0
  8. package/dist/components/ui/simple-tabs.d.ts.map +1 -0
  9. package/dist/components/ui/spinner.d.ts +6 -0
  10. package/dist/components/ui/spinner.d.ts.map +1 -0
  11. package/dist/components/ui/tabs.d.ts +13 -0
  12. package/dist/components/ui/tabs.d.ts.map +1 -0
  13. package/dist/components/ui/textarea.d.ts +6 -0
  14. package/dist/components/ui/textarea.d.ts.map +1 -0
  15. package/dist/index.cjs.js +2 -198
  16. package/dist/index.cjs.js.map +1 -1
  17. package/dist/index.js +2 -198
  18. package/dist/index.js.map +1 -1
  19. package/dist/services/telemetry/index.d.ts +20 -0
  20. package/dist/services/telemetry/index.d.ts.map +1 -0
  21. package/dist/services/telemetry/telemetryService.d.ts +66 -0
  22. package/dist/services/telemetry/telemetryService.d.ts.map +1 -0
  23. package/dist/services/telemetry/types.d.ts +64 -0
  24. package/dist/services/telemetry/types.d.ts.map +1 -0
  25. package/dist/toolbar/AIPromptPanel.d.ts +9 -0
  26. package/dist/toolbar/AIPromptPanel.d.ts.map +1 -0
  27. package/dist/toolbar/ElementSelector.d.ts.map +1 -1
  28. package/dist/toolbar/ExperimentPanel.d.ts +9 -0
  29. package/dist/toolbar/ExperimentPanel.d.ts.map +1 -0
  30. package/dist/toolbar/KeakToolbar.d.ts.map +1 -1
  31. package/dist/toolbar/MetricsPanel.d.ts +7 -0
  32. package/dist/toolbar/MetricsPanel.d.ts.map +1 -0
  33. package/dist/toolbar/PageScanPanel.d.ts +15 -0
  34. package/dist/toolbar/PageScanPanel.d.ts.map +1 -0
  35. package/dist/toolbar/components/PrimaryButton.d.ts +12 -0
  36. package/dist/toolbar/components/PrimaryButton.d.ts.map +1 -0
  37. package/dist/toolbar/components/WarningButton.d.ts +12 -0
  38. package/dist/toolbar/components/WarningButton.d.ts.map +1 -0
  39. package/dist/toolbar/components/ui/Badge.d.ts +10 -0
  40. package/dist/toolbar/components/ui/Badge.d.ts.map +1 -0
  41. package/dist/toolbar/components/ui/Button.d.ts +12 -0
  42. package/dist/toolbar/components/ui/Button.d.ts.map +1 -0
  43. package/dist/toolbar/components/ui/Progress.d.ts +5 -0
  44. package/dist/toolbar/components/ui/Progress.d.ts.map +1 -0
  45. package/dist/toolbar/components/ui/Tabs.d.ts +44 -0
  46. package/dist/toolbar/components/ui/Tabs.d.ts.map +1 -0
  47. package/dist/toolbar/components/ui/dropdown-menu.d.ts +28 -0
  48. package/dist/toolbar/components/ui/dropdown-menu.d.ts.map +1 -0
  49. package/dist/toolbar.js +2 -198
  50. package/dist/toolbar.js.map +1 -1
  51. package/package.json +1 -1
  52. 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" }), mapWarning.show && (jsx("div", { className: "keak-map-warning", style: {
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);