function _assert_this_initialized(self) {
    if (self === void 0) {
        throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
    }
    return self;
}
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
    try {
        var info = gen[key](arg);
        var value = info.value;
    } catch (error) {
        reject(error);
        return;
    }
    if (info.done) {
        resolve(value);
    } else {
        Promise.resolve(value).then(_next, _throw);
    }
}
function _async_to_generator(fn) {
    return function() {
        var self = this, args = arguments;
        return new Promise(function(resolve, reject) {
            var gen = fn.apply(self, args);
            function _next(value) {
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
            }
            function _throw(err) {
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
            }
            _next(undefined);
        });
    };
}
function _call_super(_this, derived, args) {
    derived = _get_prototype_of(derived);
    return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
}
function _class_call_check(instance, Constructor) {
    if (!(instance instanceof Constructor)) {
        throw new TypeError("Cannot call a class as a function");
    }
}
function _defineProperties(target, props) {
    for(var i = 0; i < props.length; i++){
        var descriptor = props[i];
        descriptor.enumerable = descriptor.enumerable || false;
        descriptor.configurable = true;
        if ("value" in descriptor) descriptor.writable = true;
        Object.defineProperty(target, descriptor.key, descriptor);
    }
}
function _create_class(Constructor, protoProps, staticProps) {
    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
    if (staticProps) _defineProperties(Constructor, staticProps);
    return Constructor;
}
function _define_property(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, {
            value: value,
            enumerable: true,
            configurable: true,
            writable: true
        });
    } else {
        obj[key] = value;
    }
    return obj;
}
function _get_prototype_of(o) {
    _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
        return o.__proto__ || Object.getPrototypeOf(o);
    };
    return _get_prototype_of(o);
}
function _inherits(subClass, superClass) {
    if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function");
    }
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            writable: true,
            configurable: true
        }
    });
    if (superClass) _set_prototype_of(subClass, superClass);
}
function _possible_constructor_return(self, call) {
    if (call && (_type_of(call) === "object" || typeof call === "function")) {
        return call;
    }
    return _assert_this_initialized(self);
}
function _set_prototype_of(o, p) {
    _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
        o.__proto__ = p;
        return o;
    };
    return _set_prototype_of(o, p);
}
function _type_of(obj) {
    "@swc/helpers - typeof";
    return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
}
function _is_native_reflect_construct() {
    try {
        var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
    } catch (_) {}
    return (_is_native_reflect_construct = function() {
        return !!result;
    })();
}
function _ts_generator(thisArg, body) {
    var f, y, t, _ = {
        label: 0,
        sent: function() {
            if (t[0] & 1) throw t[1];
            return t[1];
        },
        trys: [],
        ops: []
    }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
    return d(g, "next", {
        value: verb(0)
    }), d(g, "throw", {
        value: verb(1)
    }), d(g, "return", {
        value: verb(2)
    }), typeof Symbol === "function" && d(g, Symbol.iterator, {
        value: function() {
            return this;
        }
    }), g;
    function verb(n) {
        return function(v) {
            return step([
                n,
                v
            ]);
        };
    }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while(g && (g = 0, op[0] && (_ = 0)), _)try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [
                op[0] & 2,
                t.value
            ];
            switch(op[0]){
                case 0:
                case 1:
                    t = op;
                    break;
                case 4:
                    _.label++;
                    return {
                        value: op[1],
                        done: false
                    };
                case 5:
                    _.label++;
                    y = op[1];
                    op = [
                        0
                    ];
                    continue;
                case 7:
                    op = _.ops.pop();
                    _.trys.pop();
                    continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
                        _ = 0;
                        continue;
                    }
                    if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
                        _.label = op[1];
                        break;
                    }
                    if (op[0] === 6 && _.label < t[1]) {
                        _.label = t[1];
                        t = op;
                        break;
                    }
                    if (t && _.label < t[2]) {
                        _.label = t[2];
                        _.ops.push(op);
                        break;
                    }
                    if (t[2]) _.ops.pop();
                    _.trys.pop();
                    continue;
            }
            op = body.call(thisArg, _);
        } catch (e) {
            op = [
                6,
                e
            ];
            y = 0;
        } finally{
            f = t = 0;
        }
        if (op[0] & 5) throw op[1];
        return {
            value: op[0] ? op[1] : void 0,
            done: true
        };
    }
}
import { select } from "d3-selection";
import { computePosition, arrow as arrowMiddleware, offset, flip, shift } from "@floating-ui/dom";
import { colorContrast, colorDefaults } from "@d3plus/color";
import { elem, stylize } from "@d3plus/dom";
import { fontFamily, fontFamilyStringify } from "@d3plus/text";
import { accessor, BaseClass, constant } from "../utils/index.js";
/**
 * Creates a virtual reference element for Floating UI.
 * @param {Number[]} position
 * @private
*/ function generateReference() {
    var position = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : [
        0,
        0
    ];
    return {
        getBoundingClientRect: function getBoundingClientRect() {
            return {
                width: 0,
                height: 0,
                x: position[0],
                y: position[1],
                top: position[1],
                right: position[0],
                bottom: position[1],
                left: position[0]
            };
        }
    };
}
/**
 * Positions a tooltip using Floating UI.
 * @private
 */ function positionTooltip(reference, tooltip, arrowEl, offsetVal, arrowDistance, arrowHeight) {
    return _async_to_generator(function() {
        var _middlewareData_arrow, _ref, x, y, placement, middlewareData, flipped, border;
        return _ts_generator(this, function(_state) {
            switch(_state.label){
                case 0:
                    return [
                        4,
                        computePosition(reference, tooltip, {
                            placement: "top",
                            middleware: [
                                offset(offsetVal + arrowDistance),
                                flip({
                                    fallbackPlacements: [
                                        "bottom"
                                    ],
                                    padding: 5
                                }),
                                shift({
                                    padding: 5
                                }),
                                arrowMiddleware({
                                    element: arrowEl
                                })
                            ]
                        })
                    ];
                case 1:
                    _ref = _state.sent(), x = _ref.x, y = _ref.y, placement = _ref.placement, middlewareData = _ref.middlewareData;
                    Object.assign(tooltip.style, {
                        position: "absolute",
                        left: "".concat(x, "px"),
                        top: "".concat(y, "px"),
                        visibility: "visible"
                    });
                    flipped = placement === "bottom";
                    border = parseFloat(arrowEl.style.borderRightWidth) || 0;
                    if (flipped) {
                        arrowEl.style.transform = "rotate(225deg)";
                        arrowEl.style.top = "-".concat(arrowHeight / 2 + border, "px");
                        arrowEl.style.bottom = "";
                    } else {
                        arrowEl.style.transform = "rotate(45deg)";
                        arrowEl.style.bottom = "-".concat(arrowHeight / 2 + border, "px");
                        arrowEl.style.top = "";
                    }
                    arrowEl.style.left = ((_middlewareData_arrow = middlewareData.arrow) === null || _middlewareData_arrow === void 0 ? void 0 : _middlewareData_arrow.x) != null ? "".concat(middlewareData.arrow.x, "px") : "";
                    return [
                        2
                    ];
            }
        });
    })();
}
var Tooltip = /*#__PURE__*/ function(BaseClass) {
    "use strict";
    _inherits(Tooltip, BaseClass);
    function Tooltip() {
        _class_call_check(this, Tooltip);
        var _this;
        _this = _call_super(this, Tooltip), _define_property(_this, "_arrow", void 0), _define_property(_this, "_arrowStyle", void 0), _define_property(_this, "_background", void 0), _define_property(_this, "_body", void 0), _define_property(_this, "_bodyStyle", void 0), _define_property(_this, "_border", void 0), _define_property(_this, "_borderRadius", void 0), _define_property(_this, "_className", void 0), _define_property(_this, "_data", void 0), _define_property(_this, "_footer", void 0), _define_property(_this, "_footerStyle", void 0), _define_property(_this, "_height", void 0), _define_property(_this, "_id", void 0), _define_property(_this, "_offset", void 0), _define_property(_this, "_padding", void 0), _define_property(_this, "_pointerEvents", void 0), _define_property(_this, "_tooltipRefs", void 0), _define_property(_this, "_position", void 0), _define_property(_this, "_tableStyle", void 0), _define_property(_this, "_tbody", void 0), _define_property(_this, "_tbodyStyle", void 0), _define_property(_this, "_thead", void 0), _define_property(_this, "_theadStyle", void 0), _define_property(_this, "_title", void 0), _define_property(_this, "_titleStyle", void 0), _define_property(_this, "_tooltipStyle", void 0), _define_property(_this, "_trStyle", void 0), _define_property(_this, "_tdStyle", void 0), _define_property(_this, "_maxWidth", void 0), _define_property(_this, "_minWidth", void 0), _define_property(_this, "_width", void 0);
        _this._arrow = accessor("arrow", "");
        _this._arrowStyle = {
            content: "",
            background: "inherit",
            border: "inherit",
            "border-width": "0 1px 1px 0",
            height: "10px",
            position: "absolute",
            transform: "rotate(45deg)",
            width: "10px"
        };
        _this._background = constant(colorDefaults.light);
        _this._body = accessor("body", "");
        _this._bodyStyle = {
            "font-size": "12px",
            "font-weight": "400",
            "z-index": "1"
        };
        _this._border = constant("1px solid rgba(0, 0, 0, 0.25)");
        _this._borderRadius = constant("4px");
        _this._className = "d3plus-tooltip";
        _this._data = [];
        _this._footer = accessor("footer", "");
        _this._footerStyle = {
            "font-size": "9px",
            "font-weight": "400",
            "margin-top": "5px",
            "z-index": "1"
        };
        _this._height = constant("auto");
        _this._id = function(d, i) {
            return "".concat(i);
        };
        _this._offset = constant(5);
        _this._padding = constant("10px");
        _this._pointerEvents = constant("auto");
        _this._tooltipRefs = {};
        _this._position = function(d) {
            return [
                d.x,
                d.y
            ];
        };
        _this._tableStyle = {
            "border-collapse": "collapse",
            "border-spacing": "0",
            width: "100%"
        };
        _this._tbody = [];
        _this._tbodyStyle = {
            "font-size": "12px",
            "text-align": "center"
        };
        _this._thead = [];
        _this._theadStyle = {
            "font-size": "12px",
            "font-weight": "600",
            "text-align": "center"
        };
        _this._title = accessor("title", "");
        _this._titleStyle = {
            "font-size": "14px",
            "font-weight": "600",
            "margin-bottom": "5px",
            "text-align": "center"
        };
        _this._tooltipStyle = {
            "box-shadow": "0 1px 5px rgba(0, 0, 0, 0.25)",
            color: function color(d, i) {
                return colorContrast(_this._background(d, i));
            },
            "font-family": fontFamilyStringify(fontFamily)
        };
        _this._trStyle = {
            "border-top": function(d, i) {
                return i ? "1px solid rgba(0, 0, 0, 0.1)" : "none";
            }
        };
        _this._tdStyle = {};
        _this._maxWidth = constant("200px");
        _this._minWidth = constant("100px");
        _this._width = constant("auto");
        return _this;
    }
    _create_class(Tooltip, [
        {
            /**
      The inner return object and draw function that gets assigned the public methods.
      @private
*/ key: "render",
            value: function render(callback) {
                var _this = this;
                var that = this;
                var portal = elem("div#d3plus-portal");
                var tooltips = portal.selectAll(".".concat(this._className))// eslint-disable-next-line @typescript-eslint/no-explicit-any
                .data(this._data, this._id);
                var enter = tooltips.enter().append("div").attr("class", this._className);
                var update = tooltips.merge(enter);
                stylize(update, this._tooltipStyle);
                /**
        Creates DIV elements with a unique class and styles.
        @private
*/ function divElement(cat) {
                    enter.append("div").attr("class", "d3plus-tooltip-".concat(cat)).attr("id", function(d, i) {
                        return "d3plus-tooltip-".concat(cat, "-").concat(d ? that._id(d, i) : "");
                    });
                    var div = update.select(".d3plus-tooltip-".concat(cat)).html(function(d, i) {
                        return that["_".concat(cat)](d, i);
                    }).style("display", function(d, i) {
                        var val = that["_".concat(cat)](d, i);
                        var visible = val !== false && val !== undefined && val !== null;
                        return visible ? "block" : "none";
                    });
                    stylize(div, that["_".concat(cat, "Style")]);
                }
                /**
        Fetches table contents given functions or values.
        @private
*/ function cellContent(d) {
                    if (typeof d === "function") {
                        var datum = select(this.parentNode.parentNode).datum();
                        return d(datum, that._data.indexOf(datum));
                    } else return d;
                }
                /**
        Sets styles for both enter and update.
        @private
*/ function boxStyles(box) {
                    box.style("background", that._background).style("border-radius", that._borderRadius).style("pointer-events", that._pointerEvents).style("padding", that._padding).style("max-width", that._maxWidth).style("min-width", that._minWidth).style("width", that._width).style("height", that._height).style("border", that._border);
                }
                divElement("title");
                divElement("body");
                var tableEnter = enter.append("table").attr("class", "d3plus-tooltip-table");
                var table = update.select(".d3plus-tooltip-table");
                stylize(table, this._tableStyle);
                tableEnter.append("thead").attr("class", "d3plus-tooltip-thead");
                var tableHead = update.select(".d3plus-tooltip-thead");
                stylize(tableHead, this._theadStyle);
                var theadTr = tableHead.selectAll("tr").data([
                    0
                ]);
                var theadTrEnter = theadTr.enter().append("tr");
                theadTr.exit().remove();
                var theadTrUpdate = theadTr.merge(theadTrEnter);
                stylize(theadTrUpdate, this._trStyle);
                var th = theadTrUpdate.selectAll("th").data(this._thead);
                th.enter().append("th").merge(th).html(cellContent);
                th.exit().remove();
                tableEnter.append("tbody").attr("class", "d3plus-tooltip-tbody");
                var tableBody = update.select(".d3plus-tooltip-tbody");
                stylize(tableBody, this._tbodyStyle);
                var tr = tableBody.selectAll("tr").data(this._tbody);
                var trEnter = tr.enter().append("tr");
                tr.exit().remove();
                var trUpdate = tr.merge(trEnter);
                stylize(trUpdate, this._trStyle);
                var td = trUpdate.selectAll("td").data(function(d) {
                    return d;
                });
                td.enter().append("td").merge(td).html(cellContent);
                stylize(td, this._tdStyle);
                divElement("footer");
                divElement("arrow");
                enter.attr("id", function(d, i) {
                    return "d3plus-tooltip-".concat(d ? _this._id(d, i) : "");
                }).style("visibility", "hidden").call(boxStyles).each(function(d, i) {
                    var id = that._id(d, i);
                    var tooltip = document.getElementById("d3plus-tooltip-".concat(id));
                    var arrowEl = document.getElementById("d3plus-tooltip-arrow-".concat(id));
                    var arrowHeight = arrowEl.offsetHeight;
                    var arrowDistance = arrowEl.getBoundingClientRect().height / 2;
                    arrowEl.style.bottom = "-".concat(arrowHeight / 2, "px");
                    var position = that._position(d, i);
                    var reference = Array.isArray(position) ? generateReference(position) : position;
                    _this._tooltipRefs[id] = {
                        reference: reference,
                        arrowEl: arrowEl,
                        tooltip: tooltip,
                        arrowHeight: arrowHeight,
                        arrowDistance: arrowDistance
                    };
                    positionTooltip(reference, tooltip, arrowEl, that._offset(d, i), arrowDistance, arrowHeight);
                });
                update.each(function(d, i) {
                    var id = that._id(d, i);
                    var position = that._position(d, i);
                    var ref = _this._tooltipRefs[id];
                    if (ref) {
                        ref.reference = Array.isArray(position) ? generateReference(position) : position;
                        positionTooltip(ref.reference, ref.tooltip, ref.arrowEl, that._offset(d, i), ref.arrowDistance, ref.arrowHeight);
                    }
                }).call(boxStyles);
                tooltips.exit().each(function(d, i) {
                    var id = that._id(d, i);
                    delete _this._tooltipRefs[id];
                }).remove();
                if (callback) setTimeout(callback, 100);
                return this;
            }
        },
        {
            key: "arrow",
            value: function arrow(_) {
                return arguments.length ? (this._arrow = typeof _ === "function" ? _ : constant(_), this) : this._arrow;
            }
        },
        {
            key: "arrowStyle",
            value: function arrowStyle(_) {
                return arguments.length ? (this._arrowStyle = Object.assign(this._arrowStyle, _), this) : this._arrowStyle;
            }
        },
        {
            key: "background",
            value: function background(_) {
                return arguments.length ? (this._background = typeof _ === "function" ? _ : constant(_), this) : this._background;
            }
        },
        {
            key: "body",
            value: function body(_) {
                return arguments.length ? (this._body = typeof _ === "function" ? _ : constant(_), this) : this._body;
            }
        },
        {
            key: "bodyStyle",
            value: function bodyStyle(_) {
                return arguments.length ? (this._bodyStyle = Object.assign(this._bodyStyle, _), this) : this._bodyStyle;
            }
        },
        {
            key: "border",
            value: function border(_) {
                return arguments.length ? (this._border = typeof _ === "function" ? _ : constant(_), this) : this._border;
            }
        },
        {
            key: "borderRadius",
            value: function borderRadius(_) {
                return arguments.length ? (this._borderRadius = typeof _ === "function" ? _ : constant(_), this) : this._borderRadius;
            }
        },
        {
            key: "className",
            value: function className(_) {
                return arguments.length ? (this._className = _, this) : this._className;
            }
        },
        {
            key: "data",
            value: function data(_) {
                return arguments.length ? (this._data = _, this) : this._data;
            }
        },
        {
            key: "footer",
            value: function footer(_) {
                return arguments.length ? (this._footer = typeof _ === "function" ? _ : constant(_), this) : this._footer;
            }
        },
        {
            key: "footerStyle",
            value: function footerStyle(_) {
                return arguments.length ? (this._footerStyle = Object.assign(this._footerStyle, _), this) : this._footerStyle;
            }
        },
        {
            key: "height",
            value: function height(_) {
                return arguments.length ? (this._height = typeof _ === "function" ? _ : constant(_), this) : this._height;
            }
        },
        {
            key: "id",
            value: function id(_) {
                return arguments.length ? (this._id = typeof _ === "function" ? _ : constant(_), this) : this._id;
            }
        },
        {
            key: "offset",
            value: function offset(_) {
                return arguments.length ? (this._offset = typeof _ === "function" ? _ : constant(_), this) : this._offset;
            }
        },
        {
            key: "padding",
            value: function padding(_) {
                return arguments.length ? (this._padding = typeof _ === "function" ? _ : constant(_), this) : this._padding;
            }
        },
        {
            key: "pointerEvents",
            value: function pointerEvents(_) {
                return arguments.length ? (this._pointerEvents = typeof _ === "function" ? _ : constant(_), this) : this._pointerEvents;
            }
        },
        {
            key: "position",
            value: function position(_) {
                return arguments.length ? (this._position = typeof _ === "string" ? constant(select(_).node() || [
                    0,
                    0
                ]) : typeof _ === "function" ? _ : constant(_), this) : this._position;
            }
        },
        {
            key: "tableStyle",
            value: function tableStyle(_) {
                return arguments.length ? (this._tableStyle = Object.assign(this._tableStyle, _), this) : this._tableStyle;
            }
        },
        {
            key: "tbody",
            value: function tbody(_) {
                return arguments.length ? (this._tbody = _, this) : this._tbody;
            }
        },
        {
            key: "tbodyStyle",
            value: function tbodyStyle(_) {
                return arguments.length ? (this._tbodyStyle = Object.assign(this._tbodyStyle, _), this) : this._tbodyStyle;
            }
        },
        {
            key: "thead",
            value: function thead(_) {
                return arguments.length ? (this._thead = _, this) : this._thead;
            }
        },
        {
            key: "theadStyle",
            value: function theadStyle(_) {
                return arguments.length ? (this._theadStyle = Object.assign(this._theadStyle, _), this) : this._theadStyle;
            }
        },
        {
            key: "title",
            value: function title(_) {
                return arguments.length ? (this._title = typeof _ === "function" ? _ : constant(_), this) : this._title;
            }
        },
        {
            key: "titleStyle",
            value: function titleStyle(_) {
                return arguments.length ? (this._titleStyle = Object.assign(this._titleStyle, _), this) : this._titleStyle;
            }
        },
        {
            key: "tooltipStyle",
            value: function tooltipStyle(_) {
                return arguments.length ? (this._tooltipStyle = Object.assign(this._tooltipStyle, _), this) : this._tooltipStyle;
            }
        },
        {
            key: "trStyle",
            value: function trStyle(_) {
                return arguments.length ? (this._trStyle = Object.assign(this._trStyle, _), this) : this._trStyle;
            }
        },
        {
            key: "tdStyle",
            value: function tdStyle(_) {
                return arguments.length ? (this._tdStyle = Object.assign(this._tdStyle, _), this) : this._tdStyle;
            }
        },
        {
            key: "maxWidth",
            value: function maxWidth(_) {
                return arguments.length ? (this._maxWidth = typeof _ === "function" ? _ : constant(_), this) : this._maxWidth;
            }
        },
        {
            key: "minWidth",
            value: function minWidth(_) {
                return arguments.length ? (this._minWidth = typeof _ === "function" ? _ : constant(_), this) : this._minWidth;
            }
        },
        {
            key: "width",
            value: function width(_) {
                return arguments.length ? (this._width = typeof _ === "function" ? _ : constant(_), this) : this._width;
            }
        }
    ]);
    return Tooltip;
}(BaseClass);
/**
    Creates HTML tooltips in the body of a webpage.
*/ export { Tooltip as default };
