Repository: excalidraw/excalidraw
File: src/packages/excalidraw/example/App.js (JavaScript)

Code before:
  const onCopy = async (type) => {
    await exportToClipboard({
      elements: excalidrawRef.current.getSceneElements(),
      appState: excalidrawRef.current.getAppState(),
      files: excalidrawRef.current.getFiles(),
      type,
    });
    window.alert(`Copied to clipboard as ${type} sucessfully`);
  };

  const onCustomElementPointerDown = (activeTool, pointerDownState) => {
    if (activeTool.type === "custom" && activeTool.customType === "comment") {
      const { x, y } = pointerDownState.origin;
      setComment({ x, y, value: "" });
    }
  };

  const rerenderCommentIcons = () => {
    const commentIconsElements =
      appRef.current.querySelectorAll(".comment-icon");
    commentIconsElements.forEach((ele) => {
      const id = ele.id;
      const { x, y } = sceneCoordsToViewportCoords(
        { sceneX: commentIcons[id].x, sceneY: commentIcons[id].y },
        excalidrawRef.current.getAppState(),
      );
      ele.style.left = `${x - 16}px`;
      ele.style.top = `${y - 16}px`;
    });
  };

  const onPointerMoveFromPointerDownHandler = (pointerDownState) => {
    return withBatchedUpdatesThrottled((event) => {
      const { x, y } = viewportCoordsToSceneCoords(
        { clientX: event.clientX, clientY: event.clientY },
        excalidrawRef.current.getAppState(),
      );
      const distance = distance2d(
        pointerDownState.x,
        pointerDownState.y,
        event.clientX,
        event.clientY,
      );
      if (distance > DRAGGING_THRESHOLD) {
        setCommentIcons({
          ...commentIcons,
          [pointerDownState.hitElement.id]: {
            ...commentIcons[pointerDownState.hitElement.id],
            x,
            y,
          },

Review comment (bug):
we'll want to wrap the excalidraw component into a positioned container with `overflow: hidden` so that comments don't overflow the container when scrolled. That will mess with the positioning, as it'll no longer be relative to viewport, but to the component.

And we'll also need to ensure the comment popup doesn't overflow the component, so use the same positioning logic as we do with contextmenu.

Code after:
  };

  const onLinkOpen = useCallback((element, event) => {
    const link = element.link;
    const { nativeEvent } = event.detail;
    const isNewTab = nativeEvent.ctrlKey || nativeEvent.metaKey;
    const isNewWindow = nativeEvent.shiftKey;
    const isInternalLink =
      link.startsWith("/") || link.includes(window.location.origin);
    if (isInternalLink && !isNewTab && !isNewWindow) {
      // signal that we're handling the redirect ourselves
      event.preventDefault();
      // do a custom redirect, such as passing to react-router
      // ...
    }
  }, []);

  const onCopy = async (type) => {
    await exportToClipboard({
      elements: excalidrawRef.current.getSceneElements(),
      appState: excalidrawRef.current.getAppState(),
      files: excalidrawRef.current.getFiles(),
      type,
    });
    window.alert(`Copied to clipboard as ${type} sucessfully`);
  };

  const onPointerDown = (activeTool, pointerDownState) => {
    if (activeTool.type === "custom" && activeTool.customType === "comment") {
      const { x, y } = pointerDownState.origin;
      setComment({ x, y, value: "" });
    }
  };

  const rerenderCommentIcons = () => {
    const commentIconsElements =
      appRef.current.querySelectorAll(".comment-icon");
    commentIconsElements.forEach((ele) => {
      const id = ele.id;
      const appstate = excalidrawRef.current.getAppState();
      const { x, y } = sceneCoordsToViewportCoords(
        { sceneX: commentIcons[id].x, sceneY: commentIcons[id].y },
        appstate,
      );
      ele.style.left = `${
        x - COMMENT_ICON_DIMENSION / 2 - appstate.offsetLeft
      }px`;
      ele.style.top = `${
        y - COMMENT_ICON_DIMENSION / 2 - appstate.offsetTop
      }px`;
    });