• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

springload / draftail / 4072114586

pending completion
4072114586

push

github

Thibaud Colas
Stop running editor benchmarks on mount

376 of 523 branches covered (71.89%)

870 of 1066 relevant lines covered (81.61%)

40.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.0
/src/components/Tooltip/Tooltip.tsx
1
import React, { useEffect, useRef, useState } from "react";
9✔
2
import Tippy, { TippyProps } from "@tippyjs/react";
9✔
3

4
export type TooltipPlacement = TippyProps["placement"];
5
export type PopperInstance = Parameters<NonNullable<TippyProps["onMount"]>>[0];
6

7
const hideTooltipOnEsc = {
9✔
8
  name: "hideOnEsc",
9
  defaultValue: true,
10
  fn(instance: PopperInstance) {
11
    function onKeyDown(e: KeyboardEvent) {
12
      if (e.key === "Escape") {
×
13
        instance.hide();
×
14
      }
15
    }
16

17
    return {
49✔
18
      onShow() {
19
        document.addEventListener("keydown", onKeyDown);
×
20
      },
21
      onHide() {
22
        document.removeEventListener("keydown", onKeyDown);
×
23
      },
24
    };
25
  },
26
};
27

28
const hideOnPopperBlur = {
9✔
29
  name: "hideOnPopperBlur",
30
  defaultValue: true,
31
  fn(instance: PopperInstance) {
32
    return {
49✔
33
      onCreate() {
34
        instance.popper.addEventListener("focusout", (event: FocusEvent) => {
49✔
35
          if (
×
36
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
37
            // @ts-ignore
38
            instance.props.hideOnPopperBlur &&
×
39
            event.relatedTarget &&
40
            !instance.popper.contains(event.relatedTarget as HTMLElement)
41
          ) {
42
            instance.hide();
×
43
          }
44
        });
45
      },
46
    };
47
  },
48
};
49

50
const zeroWidthSpacer = "\u200B";
9✔
51

52
const tippyPlugins = [hideTooltipOnEsc, hideOnPopperBlur];
9✔
53

54
// https://atomiks.github.io/tippyjs/v6/all-props/#duration
55
const duration: [number, number] = [300, 0];
9✔
56

57
export interface TooltipPosition {
58
  top: number;
59
  left: number | string;
60
}
61

62
export interface TooltipProps {
63
  shouldOpen: boolean;
64
  getTargetPosition?: (editorRect: DOMRect) => TooltipPosition | null;
65
  content: React.ReactNode;
66
  children?: React.ReactElement;
67
  showBackdrop?: boolean;
68
  zIndex?: number;
69
  placement?: TooltipPlacement;
70
  onHide?: () => void;
71
  onClickOutside?: () => void;
72
  onMount?: (instance: PopperInstance) => void;
73
}
74

75
const Tooltip = ({
9✔
76
  content,
77
  children,
78
  shouldOpen,
79
  getTargetPosition,
80
  showBackdrop = false,
86✔
81
  zIndex = 100,
74✔
82
  placement = "top" as TooltipPlacement,
74✔
83
  onHide,
84
  onClickOutside,
85
  onMount,
86
}: TooltipProps) => {
87
  const parentRef = useRef<HTMLDivElement>(null);
98✔
88
  const [position, setPosition] = useState<TooltipPosition | null>();
98✔
89

90
  useEffect(() => {
98✔
91
    if (!children && getTargetPosition && parentRef.current) {
55✔
92
      if (shouldOpen) {
43!
93
        const editor = parentRef.current.closest<HTMLDivElement>(
×
94
          "[data-draftail-editor]",
95
        );
96
        const editorRect = editor!.getBoundingClientRect();
×
97
        setPosition(getTargetPosition(editorRect));
×
98
      } else {
99
        setPosition(null);
43✔
100
      }
101
    }
102
  }, [shouldOpen, getTargetPosition, children]);
103

104
  const visible = shouldOpen && Boolean(position || children);
98!
105

106
  return (
98✔
107
    <>
108
      {showBackdrop ? (
98!
109
        <div
110
          className={`Draftail-Tooltip__backdrop${
111
            visible ? " Draftail-Tooltip__backdrop--visible" : ""
×
112
          }`}
113
        />
114
      ) : null}
115
      <div
116
        hidden
117
        contentEditable="false"
118
        suppressContentEditableWarning
119
        ref={parentRef}
120
      />
121
      <Tippy
122
        className="Draftail-Tooltip"
123
        visible={visible}
124
        interactive
125
        onHide={onHide}
126
        onClickOutside={onClickOutside || onHide}
184✔
127
        onMount={onMount}
128
        placement={placement}
129
        maxWidth="100%"
130
        zIndex={zIndex}
131
        duration={duration}
132
        arrow={false}
133
        appendTo={() => {
134
          const editor = parentRef.current!.closest<HTMLDivElement>(
×
135
            "[data-draftail-editor]",
136
          );
137
          const tooltipParent = editor!.querySelector(
×
138
            "[data-draftail-tooltip-parent]",
139
          );
140
          return tooltipParent as HTMLDivElement;
×
141
        }}
142
        plugins={tippyPlugins}
143
        content={content}
144
      >
145
        {children || (
184✔
146
          <div
147
            className="Draftail-Tooltip__target"
148
            style={position || undefined}
172✔
149
          >
150
            {zeroWidthSpacer}
151
          </div>
152
        )}
153
      </Tippy>
154
    </>
155
  );
156
};
157

158
export default Tooltip;
9✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc