vite-plugin-ai-annotator 1.0.1 → 1.0.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.
@@ -6508,6 +6508,7 @@
6508
6508
  document.body.appendChild(badge);
6509
6509
  const cleanup = autoUpdate(element, badge, () => {
6510
6510
  computePosition2(element, badge, {
6511
+ strategy: "fixed",
6511
6512
  placement: "top-start",
6512
6513
  middleware: [
6513
6514
  offset2({ mainAxis: -5, crossAxis: 7 }),
@@ -6569,14 +6570,17 @@
6569
6570
  const color = colors[colorIndex % colors.length];
6570
6571
  const index = selectedElements.size + 1;
6571
6572
  colorIndex++;
6572
- element.style.outline = `3px solid ${color}`;
6573
- element.style.outlineOffset = "-1px";
6573
+ const el = element;
6574
+ const originalOutline = el.style.outline;
6575
+ const originalOutlineOffset = el.style.outlineOffset;
6576
+ el.style.outline = `3px solid ${color}`;
6577
+ el.style.outlineOffset = "-1px";
6574
6578
  const badge = createBadge(index, color, element, componentFinder);
6575
6579
  badges.set(element, badge);
6576
6580
  selectedElements.set(element, {
6577
6581
  color,
6578
- originalOutline: element.style.outline,
6579
- originalOutlineOffset: element.style.outlineOffset,
6582
+ originalOutline,
6583
+ originalOutlineOffset,
6580
6584
  index
6581
6585
  });
6582
6586
  },
@@ -6584,11 +6588,10 @@
6584
6588
  const elementData = selectedElements.get(element);
6585
6589
  if (elementData) {
6586
6590
  ;
6587
- element.style.outline = "";
6588
- element.style.outlineOffset = "";
6591
+ element.style.outline = elementData.originalOutline;
6592
+ element.style.outlineOffset = elementData.originalOutlineOffset;
6589
6593
  const badge = badges.get(element);
6590
6594
  if (badge) {
6591
- ;
6592
6595
  badge._cleanup?.();
6593
6596
  badge.remove();
6594
6597
  badges.delete(element);
@@ -6598,13 +6601,12 @@
6598
6601
  }
6599
6602
  },
6600
6603
  clearAllSelections() {
6601
- selectedElements.forEach((_2, element) => {
6604
+ selectedElements.forEach((data, element) => {
6602
6605
  ;
6603
- element.style.outline = "";
6604
- element.style.outlineOffset = "";
6606
+ element.style.outline = data.originalOutline;
6607
+ element.style.outlineOffset = data.originalOutlineOffset;
6605
6608
  });
6606
6609
  badges.forEach((badge) => {
6607
- ;
6608
6610
  badge._cleanup?.();
6609
6611
  badge.remove();
6610
6612
  });
@@ -6700,7 +6702,8 @@
6700
6702
  }
6701
6703
 
6702
6704
  // src/annotator/inspection.ts
6703
- function createInspectionManager(onElementSelect, shouldIgnoreElement, isElementSelected) {
6705
+ function createInspectionManager(callbacks = {}) {
6706
+ const { onElementSelect, shouldIgnoreElement, isElementSelected, onEscape, onCopy } = callbacks;
6704
6707
  let isInspecting = false;
6705
6708
  let currentHoveredElement = null;
6706
6709
  let inspectionStyleElement = null;
@@ -6709,8 +6712,15 @@
6709
6712
  inspectionStyleElement.id = "annotator-toolbar-styles";
6710
6713
  inspectionStyleElement.textContent = `
6711
6714
  * {
6715
+ pointer-events: none !important;
6712
6716
  cursor: crosshair !important;
6713
6717
  }
6718
+ annotator-toolbar, annotator-toolbar *,
6719
+ .annotator-badge, .annotator-badge *,
6720
+ .annotator-ignore {
6721
+ pointer-events: auto !important;
6722
+ cursor: default !important;
6723
+ }
6714
6724
  `;
6715
6725
  document.head.appendChild(inspectionStyleElement);
6716
6726
  }
@@ -6730,29 +6740,36 @@
6730
6740
  currentHoveredElement = null;
6731
6741
  }
6732
6742
  }
6733
- function handleMouseOver(e5) {
6734
- const target = e5.target;
6735
- if (shouldIgnoreElement?.(target)) return;
6743
+ function getElementAtPoint(x2, y3) {
6744
+ if (inspectionStyleElement) {
6745
+ inspectionStyleElement.disabled = true;
6746
+ }
6747
+ const element = document.elementFromPoint(x2, y3);
6748
+ if (inspectionStyleElement) {
6749
+ inspectionStyleElement.disabled = false;
6750
+ }
6751
+ return element;
6752
+ }
6753
+ function handleMouseMove(e5) {
6754
+ const target = getElementAtPoint(e5.clientX, e5.clientY);
6755
+ if (!target || shouldIgnoreElement?.(target)) {
6756
+ removeHoverHighlight();
6757
+ return;
6758
+ }
6759
+ if (target === currentHoveredElement) return;
6736
6760
  removeHoverHighlight();
6737
6761
  target.style.outline = "3px solid #3B82F6";
6738
6762
  target.style.outlineOffset = "-1px";
6739
6763
  currentHoveredElement = target;
6740
6764
  }
6741
- function handleMouseOut(e5) {
6742
- const target = e5.target;
6743
- if (shouldIgnoreElement?.(target)) return;
6744
- if (!isElementSelected?.(target)) {
6745
- ;
6746
- target.style.outline = "";
6747
- target.style.outlineOffset = "";
6748
- }
6749
- }
6750
- function handleElementClick(e5) {
6751
- const target = e5.target;
6752
- if (shouldIgnoreElement?.(target)) return;
6765
+ function handleClick(e5) {
6766
+ const clickedElement = e5.target;
6767
+ if (shouldIgnoreElement?.(clickedElement)) return;
6753
6768
  e5.preventDefault();
6754
6769
  e5.stopPropagation();
6755
6770
  e5.stopImmediatePropagation();
6771
+ const target = getElementAtPoint(e5.clientX, e5.clientY);
6772
+ if (!target || shouldIgnoreElement?.(target)) return;
6756
6773
  onElementSelect?.(target);
6757
6774
  }
6758
6775
  function preventMouseEvents(e5) {
@@ -6762,30 +6779,44 @@
6762
6779
  e5.stopPropagation();
6763
6780
  e5.stopImmediatePropagation();
6764
6781
  }
6782
+ function handleKeyDown(e5) {
6783
+ if (e5.key === "Escape") {
6784
+ e5.preventDefault();
6785
+ onEscape?.();
6786
+ return;
6787
+ }
6788
+ if ((e5.metaKey || e5.ctrlKey) && e5.key === "c") {
6789
+ const selection = window.getSelection();
6790
+ if (!selection || selection.isCollapsed) {
6791
+ e5.preventDefault();
6792
+ onCopy?.();
6793
+ }
6794
+ }
6795
+ }
6765
6796
  return {
6766
6797
  enterInspectionMode() {
6767
6798
  if (isInspecting) return;
6768
6799
  isInspecting = true;
6769
6800
  addInspectionStyles();
6770
- document.addEventListener("mouseover", handleMouseOver, true);
6771
- document.addEventListener("mouseout", handleMouseOut, true);
6772
- document.addEventListener("click", handleElementClick, true);
6801
+ document.addEventListener("mousemove", handleMouseMove, true);
6802
+ document.addEventListener("click", handleClick, true);
6773
6803
  document.addEventListener("mousedown", preventMouseEvents, true);
6774
6804
  document.addEventListener("mouseup", preventMouseEvents, true);
6775
6805
  document.addEventListener("dblclick", preventMouseEvents, true);
6776
6806
  document.addEventListener("contextmenu", preventMouseEvents, true);
6807
+ document.addEventListener("keydown", handleKeyDown);
6777
6808
  },
6778
6809
  exitInspectionMode() {
6779
6810
  if (!isInspecting) return;
6780
6811
  isInspecting = false;
6781
6812
  removeInspectionStyles();
6782
- document.removeEventListener("mouseover", handleMouseOver, true);
6783
- document.removeEventListener("mouseout", handleMouseOut, true);
6784
- document.removeEventListener("click", handleElementClick, true);
6813
+ document.removeEventListener("mousemove", handleMouseMove, true);
6814
+ document.removeEventListener("click", handleClick, true);
6785
6815
  document.removeEventListener("mousedown", preventMouseEvents, true);
6786
6816
  document.removeEventListener("mouseup", preventMouseEvents, true);
6787
6817
  document.removeEventListener("dblclick", preventMouseEvents, true);
6788
6818
  document.removeEventListener("contextmenu", preventMouseEvents, true);
6819
+ document.removeEventListener("keydown", handleKeyDown);
6789
6820
  removeHoverHighlight();
6790
6821
  },
6791
6822
  isInInspectionMode() {
@@ -6795,13 +6826,13 @@
6795
6826
  if (isInspecting) {
6796
6827
  isInspecting = false;
6797
6828
  removeInspectionStyles();
6798
- document.removeEventListener("mouseover", handleMouseOver, true);
6799
- document.removeEventListener("mouseout", handleMouseOut, true);
6800
- document.removeEventListener("click", handleElementClick, true);
6829
+ document.removeEventListener("mousemove", handleMouseMove, true);
6830
+ document.removeEventListener("click", handleClick, true);
6801
6831
  document.removeEventListener("mousedown", preventMouseEvents, true);
6802
6832
  document.removeEventListener("mouseup", preventMouseEvents, true);
6803
6833
  document.removeEventListener("dblclick", preventMouseEvents, true);
6804
6834
  document.removeEventListener("contextmenu", preventMouseEvents, true);
6835
+ document.removeEventListener("keydown", handleKeyDown);
6805
6836
  removeHoverHighlight();
6806
6837
  }
6807
6838
  }
@@ -6828,14 +6859,15 @@
6828
6859
  const logger = createLogger(verbose);
6829
6860
  try {
6830
6861
  let componentInfo = getVueComponentInfo(element);
6862
+ const el = element;
6831
6863
  if (componentInfo) {
6832
6864
  logger.log("\u{1F7E2} Vue component found:", componentInfo);
6833
6865
  } else {
6834
6866
  logger.log("\u{1F50D} No Vue component found for element:", element.tagName, "Checking properties:", {
6835
- __vnode: !!element.__vnode,
6836
- __vueParentComponent: !!element.__vueParentComponent,
6837
- __vue__: !!element.__vue__,
6838
- __v_inspector: !!element.__v_inspector
6867
+ __vnode: !!el.__vnode,
6868
+ __vueParentComponent: !!el.__vueParentComponent,
6869
+ __vue__: !!el.__vue__,
6870
+ __v_inspector: !!el.__v_inspector
6839
6871
  });
6840
6872
  }
6841
6873
  if (!componentInfo) {
@@ -6877,14 +6909,14 @@
6877
6909
  }
6878
6910
  function getReactComponentInfo(element) {
6879
6911
  if (!element) return null;
6880
- const elementAny = element;
6881
- const fiberKey = Object.keys(elementAny).find(
6912
+ const el = element;
6913
+ const fiberKey = Object.keys(el).find(
6882
6914
  (key) => key.startsWith("__reactFiber") || key.startsWith("__reactInternalInstance") || key.startsWith("_reactInternalFiber")
6883
6915
  );
6884
6916
  if (!fiberKey) {
6885
6917
  return null;
6886
6918
  }
6887
- const fiber = elementAny[fiberKey];
6919
+ const fiber = el[fiberKey];
6888
6920
  if (!fiber) {
6889
6921
  return null;
6890
6922
  }
@@ -6902,18 +6934,18 @@
6902
6934
  let componentName = "";
6903
6935
  let componentFile = "";
6904
6936
  while (currentFiber) {
6905
- if (currentFiber.type && typeof currentFiber.type === "function") {
6906
- componentName = currentFiber.type.name || currentFiber.type.displayName || "Anonymous";
6907
- if (currentFiber.type.__source) {
6908
- componentFile = currentFiber.type.__source.fileName || "";
6937
+ const fiberType = currentFiber.type;
6938
+ if (fiberType && typeof fiberType === "object") {
6939
+ componentName = fiberType.name || fiberType.displayName || "Anonymous";
6940
+ if (fiberType.__source) {
6941
+ componentFile = fiberType.__source.fileName || "";
6942
+ }
6943
+ if (fiberType.prototype?.render) {
6944
+ componentName = fiberType.name || "Component";
6909
6945
  }
6910
6946
  break;
6911
6947
  }
6912
- if (currentFiber.type && currentFiber.type.prototype && currentFiber.type.prototype.render) {
6913
- componentName = currentFiber.type.name || "Component";
6914
- break;
6915
- }
6916
- currentFiber = currentFiber.return || currentFiber._debugOwner;
6948
+ currentFiber = currentFiber.return ?? currentFiber._debugOwner;
6917
6949
  }
6918
6950
  if (!componentName && !componentFile) {
6919
6951
  return null;
@@ -6958,13 +6990,14 @@
6958
6990
  const parts2 = [];
6959
6991
  let currentFiber = fiber;
6960
6992
  while (currentFiber && parts2.length < 3) {
6961
- if (currentFiber.type && typeof currentFiber.type === "function") {
6962
- const name = currentFiber.type.name || currentFiber.type.displayName;
6993
+ const fiberType = currentFiber.type;
6994
+ if (fiberType && typeof fiberType === "object") {
6995
+ const name = fiberType.name || fiberType.displayName;
6963
6996
  if (name && name !== "Fragment") {
6964
6997
  parts2.unshift(name);
6965
6998
  }
6966
- } else if (currentFiber.type && typeof currentFiber.type === "string") {
6967
- parts2.push(currentFiber.type);
6999
+ } else if (fiberType && typeof fiberType === "string") {
7000
+ parts2.push(fiberType);
6968
7001
  }
6969
7002
  currentFiber = currentFiber.return;
6970
7003
  }
@@ -6982,11 +7015,13 @@
6982
7015
  function extractReactSourceMap(fiber) {
6983
7016
  try {
6984
7017
  if (fiber._debugSource) {
7018
+ const fiberType = fiber.type;
7019
+ const typeName = fiberType && typeof fiberType === "object" ? fiberType.name || fiberType.displayName : void 0;
6985
7020
  return {
6986
7021
  originalLine: fiber._debugSource.lineNumber || 0,
6987
7022
  originalColumn: fiber._debugSource.columnNumber || 0,
6988
7023
  originalSource: fiber._debugSource.fileName || "",
6989
- originalName: fiber.type?.name || fiber.type?.displayName
7024
+ originalName: typeName
6990
7025
  };
6991
7026
  }
6992
7027
  return null;
@@ -7007,26 +7042,26 @@
7007
7042
  }
7008
7043
  function getVueComponentInfo(element) {
7009
7044
  if (!element) return null;
7010
- const elementAny = element;
7011
- let codeLocation = elementAny.__vnode?.props?.__v_inspector;
7045
+ const el = element;
7046
+ let codeLocation = el.__vnode?.props?.__v_inspector;
7012
7047
  let vueInstance = null;
7013
7048
  let vnode = null;
7014
7049
  if (!codeLocation) {
7015
- codeLocation = elementAny.__vueParentComponent?.vnode?.props?.__v_inspector;
7016
- vueInstance = elementAny.__vueParentComponent;
7017
- vnode = elementAny.__vueParentComponent?.vnode;
7050
+ codeLocation = el.__vueParentComponent?.vnode?.props?.__v_inspector;
7051
+ vueInstance = el.__vueParentComponent ?? null;
7052
+ vnode = el.__vueParentComponent?.vnode ?? null;
7018
7053
  }
7019
7054
  if (!codeLocation) {
7020
- codeLocation = elementAny.__v_inspector;
7055
+ codeLocation = el.__v_inspector;
7021
7056
  }
7022
7057
  if (!codeLocation) {
7023
- vueInstance = elementAny.__vue__ || elementAny.__vueParentComponent;
7058
+ vueInstance = el.__vue__ ?? el.__vueParentComponent ?? null;
7024
7059
  if (vueInstance) {
7025
7060
  codeLocation = vueInstance.__v_inspector || vueInstance.$options?.__v_inspector || vueInstance.type?.__v_inspector;
7026
7061
  }
7027
7062
  }
7028
7063
  if (!codeLocation && !vnode) {
7029
- vnode = elementAny.__vnode || elementAny.$vnode;
7064
+ vnode = el.__vnode ?? el.$vnode ?? null;
7030
7065
  if (vnode) {
7031
7066
  codeLocation = vnode.__v_inspector || vnode.props?.__v_inspector || vnode.componentOptions?.__v_inspector;
7032
7067
  }
@@ -7287,6 +7322,7 @@
7287
7322
  }
7288
7323
 
7289
7324
  // src/annotator-toolbar.ts
7325
+ var CONSOLE_METHODS = ["log", "info", "warn", "error", "debug"];
7290
7326
  var AnnotatorToolbar = class extends i4 {
7291
7327
  constructor() {
7292
7328
  super(...arguments);
@@ -7297,7 +7333,9 @@
7297
7333
  this.selectionCount = 0;
7298
7334
  this.isInspecting = false;
7299
7335
  this.commentPopover = { visible: false, element: null, comment: "" };
7336
+ this.toastMessage = "";
7300
7337
  this.popoverCleanup = null;
7338
+ this.toastTimeout = null;
7301
7339
  this.socket = null;
7302
7340
  this.rpc = null;
7303
7341
  this.selectionManager = null;
@@ -7329,24 +7367,27 @@
7329
7367
  this.selectionManager.setOnEditClick((element) => {
7330
7368
  this.showCommentPopoverForElement(element);
7331
7369
  });
7332
- this.inspectionManager = createInspectionManager(
7333
- (element) => this.handleElementSelected(element),
7334
- (element) => this.shouldIgnoreElement(element),
7335
- (element) => this.selectionManager?.hasElement(element) || false
7336
- );
7370
+ this.inspectionManager = createInspectionManager({
7371
+ onElementSelect: (element) => this.handleElementSelected(element),
7372
+ shouldIgnoreElement: (element) => this.shouldIgnoreElement(element),
7373
+ isElementSelected: (element) => this.selectionManager?.hasElement(element) || false,
7374
+ onEscape: () => this.exitInspectingMode(),
7375
+ onCopy: () => this.copySelectedElements()
7376
+ });
7337
7377
  }
7338
7378
  initializeConsoleCapture() {
7339
- const methods = ["log", "info", "warn", "error", "debug"];
7340
- methods.forEach((method) => {
7379
+ CONSOLE_METHODS.forEach((method) => {
7341
7380
  this.originalConsoleMethods[method] = console[method].bind(console);
7342
7381
  console[method] = (...args) => {
7382
+ const MAX_ARG_LENGTH = 1e4;
7343
7383
  this.consoleBuffer.push({
7344
7384
  type: method,
7345
7385
  args: args.map((arg) => {
7346
7386
  try {
7347
- return typeof arg === "object" ? JSON.stringify(arg) : String(arg);
7387
+ const str = typeof arg === "object" ? JSON.stringify(arg) : String(arg);
7388
+ return str.length > MAX_ARG_LENGTH ? str.slice(0, MAX_ARG_LENGTH) + "...[truncated]" : str;
7348
7389
  } catch {
7349
- return String(arg);
7390
+ return "[circular or unserializable]";
7350
7391
  }
7351
7392
  }),
7352
7393
  timestamp: Date.now()
@@ -7359,8 +7400,7 @@
7359
7400
  });
7360
7401
  }
7361
7402
  restoreConsoleMethods() {
7362
- const methods = ["log", "info", "warn", "error", "debug"];
7363
- methods.forEach((method) => {
7403
+ CONSOLE_METHODS.forEach((method) => {
7364
7404
  if (this.originalConsoleMethods[method]) {
7365
7405
  console[method] = this.originalConsoleMethods[method];
7366
7406
  }
@@ -7431,9 +7471,8 @@
7431
7471
  );
7432
7472
  const addComments = (items, selectedElements) => {
7433
7473
  for (const item of items) {
7434
- for (const [element] of selectedElements) {
7435
- const info = selectedElements.get(element);
7436
- if (info?.index === item.index) {
7474
+ for (const [element, info] of selectedElements) {
7475
+ if (info.index === item.index) {
7437
7476
  const comment = this.elementComments.get(element);
7438
7477
  if (comment) {
7439
7478
  item.comment = comment;
@@ -7536,7 +7575,7 @@
7536
7575
  injectCSS(css) {
7537
7576
  try {
7538
7577
  const style = document.createElement("style");
7539
- style.setAttribute("data-injected-by", "instantcode");
7578
+ style.setAttribute("data-injected-by", "ai-annotator");
7540
7579
  style.textContent = css;
7541
7580
  document.head.appendChild(style);
7542
7581
  return { success: true };
@@ -7613,14 +7652,17 @@
7613
7652
  document.addEventListener("keydown", this.handlePopoverKeydown);
7614
7653
  this.updateComplete.then(() => {
7615
7654
  const popoverEl = this.shadowRoot?.querySelector(".popover");
7655
+ const inputEl = this.shadowRoot?.querySelector(".popover-input");
7616
7656
  if (!popoverEl || !element) return;
7657
+ inputEl?.focus();
7617
7658
  this.popoverCleanup = autoUpdate(element, popoverEl, () => {
7618
7659
  computePosition2(element, popoverEl, {
7619
- placement: "bottom",
7660
+ strategy: "fixed",
7661
+ placement: "bottom-start",
7620
7662
  middleware: [
7621
- offset2(10),
7622
- flip2({ fallbackPlacements: ["top", "right", "left"] }),
7623
- shift2({ padding: 10 })
7663
+ offset2(8),
7664
+ flip2({ fallbackPlacements: ["top-start", "bottom-end", "top-end", "right", "left"] }),
7665
+ shift2({ padding: 8 })
7624
7666
  ]
7625
7667
  }).then(({ x: x2, y: y3 }) => {
7626
7668
  Object.assign(popoverEl.style, {
@@ -7631,6 +7673,16 @@
7631
7673
  });
7632
7674
  });
7633
7675
  }
7676
+ handlePopoverInputKeydown(e5) {
7677
+ if (e5.key === "Enter") {
7678
+ e5.preventDefault();
7679
+ this.hideCommentPopover();
7680
+ } else if (e5.key === "Escape") {
7681
+ e5.preventDefault();
7682
+ e5.stopPropagation();
7683
+ this.hideCommentPopover();
7684
+ }
7685
+ }
7634
7686
  hideCommentPopover() {
7635
7687
  document.removeEventListener("keydown", this.handlePopoverKeydown);
7636
7688
  if (this.popoverCleanup) {
@@ -7656,9 +7708,20 @@
7656
7708
  }
7657
7709
  }
7658
7710
  shouldIgnoreElement(element) {
7659
- if (element.closest("annotator-toolbar")) return true;
7660
- if (element.classList.contains("annotator-badge")) return true;
7661
- if (element.classList.contains("annotator-ignore")) return true;
7711
+ let current = element;
7712
+ while (current) {
7713
+ if (current instanceof Element) {
7714
+ if (current.tagName.toLowerCase() === "annotator-toolbar") return true;
7715
+ if (current.classList.contains("annotator-badge")) return true;
7716
+ if (current.classList.contains("annotator-ignore")) return true;
7717
+ }
7718
+ const parent = current.parentNode;
7719
+ if (parent instanceof ShadowRoot) {
7720
+ current = parent.host;
7721
+ } else {
7722
+ current = parent;
7723
+ }
7724
+ }
7662
7725
  return false;
7663
7726
  }
7664
7727
  cleanup() {
@@ -7674,22 +7737,43 @@
7674
7737
  }
7675
7738
  log(...args) {
7676
7739
  if (this.verbose) {
7677
- console.log("[InstantCode]", ...args);
7740
+ console.log("[AI Annotator]", ...args);
7678
7741
  }
7679
7742
  }
7680
- toggleInspect() {
7743
+ exitInspectingMode() {
7681
7744
  if (this.isInspecting) {
7682
7745
  this.inspectionManager?.exitInspectionMode();
7683
7746
  this.isInspecting = false;
7684
7747
  if (this.commentPopover.visible) {
7685
7748
  this.hideCommentPopover();
7686
7749
  }
7750
+ }
7751
+ }
7752
+ async copySelectedElements() {
7753
+ const elements = this.getSelectedElements();
7754
+ if (elements.length === 0) {
7755
+ this.showToast("No elements selected");
7756
+ return;
7757
+ }
7758
+ const text = JSON.stringify(elements, null, 2);
7759
+ try {
7760
+ await navigator.clipboard.writeText(text);
7761
+ this.showToast(`Copied ${elements.length} element(s)`);
7762
+ } catch (error) {
7763
+ this.showToast("Failed to copy");
7764
+ this.log("Failed to copy:", error);
7765
+ }
7766
+ }
7767
+ toggleInspect() {
7768
+ if (this.isInspecting) {
7769
+ this.exitInspectingMode();
7687
7770
  } else {
7688
7771
  this.inspectionManager?.enterInspectionMode();
7689
7772
  this.isInspecting = true;
7690
7773
  }
7691
7774
  }
7692
7775
  handleClearClick() {
7776
+ this.exitInspectingMode();
7693
7777
  this.clearSelection();
7694
7778
  if (this.socket?.connected) {
7695
7779
  this.socket.emit("selectionChanged", {
@@ -7719,13 +7803,44 @@
7719
7803
  <path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9 5.25h.008v.008H12v-.008z" />
7720
7804
  </svg>`;
7721
7805
  }
7806
+ renderClipboardIcon() {
7807
+ return x`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
7808
+ <path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9.75a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184" />
7809
+ </svg>`;
7810
+ }
7811
+ showToast(message) {
7812
+ if (this.toastTimeout) {
7813
+ clearTimeout(this.toastTimeout);
7814
+ }
7815
+ this.toastMessage = message;
7816
+ this.toastTimeout = setTimeout(() => {
7817
+ this.toastMessage = "";
7818
+ }, 2e3);
7819
+ }
7820
+ async copySessionId() {
7821
+ this.exitInspectingMode();
7822
+ if (!this.sessionId) {
7823
+ this.showToast("No session ID");
7824
+ return;
7825
+ }
7826
+ const text = `use annotator tool (session: ${this.sessionId}) to read my live feedback`;
7827
+ try {
7828
+ await navigator.clipboard.writeText(text);
7829
+ this.showToast("Copied!");
7830
+ this.log("Copied to clipboard:", text);
7831
+ } catch (error) {
7832
+ this.showToast("Failed to copy");
7833
+ this.log("Failed to copy:", error);
7834
+ }
7835
+ }
7722
7836
  renderErrorIcon() {
7723
7837
  return x`<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
7724
7838
  <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
7725
7839
  </svg>`;
7726
7840
  }
7727
7841
  openHelpPage() {
7728
- window.open("https://instantcode.dev", "_blank");
7842
+ this.exitInspectingMode();
7843
+ window.open("https://ai-annotator.dev", "_blank");
7729
7844
  }
7730
7845
  render() {
7731
7846
  if (!this.connected) {
@@ -7733,18 +7848,13 @@
7733
7848
  <div class="toolbar">
7734
7849
  <div class="error-message">
7735
7850
  ${this.renderErrorIcon()}
7736
- <span>Cannot connect to InstantCode server</span>
7851
+ <span>Cannot connect to AI Annotator server</span>
7737
7852
  </div>
7738
7853
  </div>
7739
7854
  `;
7740
7855
  }
7741
7856
  return x`
7742
7857
  <div class="toolbar">
7743
- ${this.selectionCount > 0 ? x`
7744
- <span class="selection-badge">${this.selectionCount}</span>
7745
- <div class="divider"></div>
7746
- ` : ""}
7747
-
7748
7858
  <button
7749
7859
  class="toolbar-btn ${this.isInspecting ? "active" : ""}"
7750
7860
  @click=${this.toggleInspect}
@@ -7753,17 +7863,28 @@
7753
7863
  ${this.renderCursorIcon()}
7754
7864
  </button>
7755
7865
 
7866
+ <div class="btn-with-badge">
7867
+ <button
7868
+ class="toolbar-btn"
7869
+ @click=${this.handleClearClick}
7870
+ title="Clear all selections"
7871
+ ?disabled=${this.selectionCount === 0}
7872
+ >
7873
+ ${this.renderTrashIcon()}
7874
+ </button>
7875
+ ${this.selectionCount > 0 ? x`<span class="badge">${this.selectionCount}</span>` : ""}
7876
+ </div>
7877
+
7878
+ <div class="divider"></div>
7879
+
7756
7880
  <button
7757
7881
  class="toolbar-btn"
7758
- @click=${this.handleClearClick}
7759
- title="Clear all selections"
7760
- ?disabled=${this.selectionCount === 0}
7882
+ @click=${this.copySessionId}
7883
+ title="Copy session ID"
7761
7884
  >
7762
- ${this.renderTrashIcon()}
7885
+ ${this.renderClipboardIcon()}
7763
7886
  </button>
7764
7887
 
7765
- <div class="divider"></div>
7766
-
7767
7888
  <button
7768
7889
  class="toolbar-btn"
7769
7890
  @click=${this.openHelpPage}
@@ -7771,27 +7892,27 @@
7771
7892
  >
7772
7893
  ${this.renderHelpIcon()}
7773
7894
  </button>
7895
+
7896
+ ${this.toastMessage ? x`<div class="toast">${this.toastMessage}</div>` : ""}
7774
7897
  </div>
7775
7898
 
7776
7899
  ${this.commentPopover.visible ? x`
7777
7900
  <div class="popover">
7778
- <div class="popover-header">
7779
- <div class="popover-title">
7780
- ${this.elementComments.has(this.commentPopover.element) ? "Edit Comment" : "Add Comment"}
7781
- <span class="tag">${this.commentPopover.element?.tagName?.toLowerCase() || "element"}</span>
7782
- </div>
7783
- <button class="popover-close" @click=${this.hideCommentPopover}>
7784
- ${this.renderCloseIcon()}
7785
- </button>
7786
- </div>
7787
- <textarea
7788
- class="popover-textarea"
7789
- placeholder="Describe what you want to change about this element..."
7901
+ <input
7902
+ type="text"
7903
+ class="popover-input"
7904
+ placeholder="Add a note..."
7790
7905
  .value=${this.commentPopover.comment}
7791
7906
  @input=${this.handlePopoverInput}
7792
- ></textarea>
7907
+ @keydown=${this.handlePopoverInputKeydown}
7908
+ />
7793
7909
  <div class="popover-actions">
7794
- <button class="popover-btn popover-btn-danger" @click=${this.removeSelectedElement}>Remove</button>
7910
+ <button class="popover-btn danger" @click=${this.removeSelectedElement} title="Remove selection">
7911
+ ${this.renderTrashIcon()}
7912
+ </button>
7913
+ <button class="popover-btn" @click=${this.hideCommentPopover} title="Close (Esc)">
7914
+ ${this.renderCloseIcon()}
7915
+ </button>
7795
7916
  </div>
7796
7917
  </div>
7797
7918
  ` : ""}
@@ -7808,6 +7929,7 @@
7808
7929
  }
7809
7930
 
7810
7931
  .toolbar {
7932
+ position: relative;
7811
7933
  display: flex;
7812
7934
  align-items: center;
7813
7935
  gap: 4px;
@@ -7862,13 +7984,26 @@
7862
7984
  margin: 0 4px;
7863
7985
  }
7864
7986
 
7865
- .selection-badge {
7987
+ .btn-with-badge {
7988
+ position: relative;
7989
+ }
7990
+
7991
+ .badge {
7992
+ position: absolute;
7993
+ top: -4px;
7994
+ right: -4px;
7995
+ min-width: 16px;
7996
+ height: 16px;
7997
+ padding: 0 4px;
7866
7998
  background: #3b82f6;
7867
- padding: 2px 8px;
7868
- border-radius: 10px;
7869
- font-size: 11px;
7999
+ border-radius: 8px;
8000
+ font-size: 10px;
7870
8001
  font-weight: 600;
7871
8002
  color: white;
8003
+ display: flex;
8004
+ align-items: center;
8005
+ justify-content: center;
8006
+ pointer-events: none;
7872
8007
  }
7873
8008
 
7874
8009
  .error-message {
@@ -7886,117 +8021,113 @@
7886
8021
  flex-shrink: 0;
7887
8022
  }
7888
8023
 
7889
- /* Popover styles */
8024
+ /* Minimal Popover */
7890
8025
  .popover {
7891
8026
  position: fixed;
7892
8027
  top: 0;
7893
8028
  left: 0;
7894
8029
  z-index: 1000000;
7895
- background: white;
7896
- border-radius: 10px;
7897
- box-shadow: 0 8px 30px rgba(0, 0, 0, 0.2);
7898
- padding: 12px;
7899
- min-width: 280px;
7900
- max-width: 350px;
7901
- }
7902
-
7903
- .popover-header {
7904
- display: flex;
7905
- align-items: center;
7906
- justify-content: space-between;
7907
- margin-bottom: 10px;
7908
- padding-bottom: 8px;
7909
- border-bottom: 1px solid #eee;
7910
- }
7911
-
7912
- .popover-title {
7913
- font-size: 13px;
7914
- font-weight: 600;
7915
- color: #333;
7916
8030
  display: flex;
7917
- align-items: center;
7918
- gap: 6px;
8031
+ align-items: stretch;
8032
+ background: #1a1a1a;
8033
+ border-radius: 8px;
8034
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.08);
8035
+ overflow: hidden;
8036
+ animation: popover-in 0.15s ease-out;
7919
8037
  }
7920
8038
 
7921
- .popover-title .tag {
7922
- background: #f0f0f0;
7923
- padding: 2px 6px;
7924
- border-radius: 4px;
7925
- font-size: 11px;
7926
- color: #666;
7927
- font-weight: 500;
8039
+ @keyframes popover-in {
8040
+ from {
8041
+ opacity: 0;
8042
+ transform: scale(0.95) translateY(-4px);
8043
+ }
8044
+ to {
8045
+ opacity: 1;
8046
+ transform: scale(1) translateY(0);
8047
+ }
7928
8048
  }
7929
8049
 
7930
- .popover-close {
7931
- background: none;
8050
+ .popover-input {
8051
+ flex: 1;
8052
+ min-width: 180px;
8053
+ max-width: 260px;
8054
+ padding: 10px 12px;
7932
8055
  border: none;
7933
- color: #999;
7934
- cursor: pointer;
7935
- padding: 4px;
7936
- border-radius: 4px;
7937
- display: flex;
7938
- align-items: center;
7939
- justify-content: center;
7940
- }
7941
-
7942
- .popover-close:hover {
7943
- background: #f0f0f0;
7944
- color: #333;
7945
- }
7946
-
7947
- .popover-close svg {
7948
- width: 16px;
7949
- height: 16px;
7950
- }
7951
-
7952
- .popover-textarea {
7953
- width: 100%;
7954
- min-height: 80px;
7955
- border: 1px solid #ddd;
7956
- border-radius: 6px;
7957
- padding: 10px;
8056
+ background: transparent;
8057
+ color: #fff;
7958
8058
  font-size: 13px;
7959
8059
  font-family: inherit;
7960
- resize: vertical;
7961
- box-sizing: border-box;
8060
+ outline: none;
7962
8061
  }
7963
8062
 
7964
- .popover-textarea:focus {
7965
- outline: none;
7966
- border-color: #3b82f6;
7967
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);
8063
+ .popover-input::placeholder {
8064
+ color: #555;
7968
8065
  }
7969
8066
 
7970
8067
  .popover-actions {
7971
8068
  display: flex;
7972
8069
  align-items: center;
7973
- gap: 8px;
7974
- margin-top: 10px;
8070
+ border-left: 1px solid rgba(255, 255, 255, 0.06);
7975
8071
  }
7976
8072
 
7977
8073
  .popover-btn {
7978
- padding: 6px 14px;
7979
- border-radius: 6px;
7980
- font-size: 12px;
7981
- font-weight: 500;
8074
+ display: flex;
8075
+ align-items: center;
8076
+ justify-content: center;
8077
+ width: 36px;
8078
+ height: 100%;
8079
+ border: none;
8080
+ background: transparent;
8081
+ color: #666;
7982
8082
  cursor: pointer;
7983
- transition: all 0.15s ease;
8083
+ transition: all 0.12s ease;
7984
8084
  }
7985
8085
 
7986
- .popover-btn-danger {
7987
- background: transparent;
7988
- border: 1px solid #ef4444;
7989
- color: #ef4444;
8086
+ .popover-btn:hover {
8087
+ background: rgba(255, 255, 255, 0.06);
8088
+ color: #fff;
7990
8089
  }
7991
8090
 
7992
- .popover-btn-danger:hover {
7993
- background: #ef4444;
7994
- color: white;
8091
+ .popover-btn.danger:hover {
8092
+ background: rgba(239, 68, 68, 0.15);
8093
+ color: #f87171;
8094
+ }
8095
+
8096
+ .popover-btn svg {
8097
+ width: 14px;
8098
+ height: 14px;
7995
8099
  }
7996
8100
 
7997
8101
  .hidden {
7998
8102
  display: none;
7999
8103
  }
8104
+
8105
+ /* Toast */
8106
+ .toast {
8107
+ position: absolute;
8108
+ bottom: 100%;
8109
+ right: 0;
8110
+ margin-bottom: 8px;
8111
+ padding: 8px 12px;
8112
+ background: rgba(0, 0, 0, 0.9);
8113
+ border-radius: 6px;
8114
+ font-size: 12px;
8115
+ color: #10b981;
8116
+ white-space: nowrap;
8117
+ animation: toast-in 0.2s ease-out;
8118
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
8119
+ }
8120
+
8121
+ @keyframes toast-in {
8122
+ from {
8123
+ opacity: 0;
8124
+ transform: translateY(4px);
8125
+ }
8126
+ to {
8127
+ opacity: 1;
8128
+ transform: translateY(0);
8129
+ }
8130
+ }
8000
8131
  `;
8001
8132
  __decorateClass([
8002
8133
  n4({ attribute: "ws-endpoint" })
@@ -8019,6 +8150,9 @@
8019
8150
  __decorateClass([
8020
8151
  r5()
8021
8152
  ], AnnotatorToolbar.prototype, "commentPopover", 2);
8153
+ __decorateClass([
8154
+ r5()
8155
+ ], AnnotatorToolbar.prototype, "toastMessage", 2);
8022
8156
  AnnotatorToolbar = __decorateClass([
8023
8157
  t3("annotator-toolbar")
8024
8158
  ], AnnotatorToolbar);