<commit_before>// We're importing every item on its own to enable webpack tree shaking
import capitalize from "lodash/capitalize"
import chunk from "lodash/chunk"
import clone from "lodash/clone"
import cloneDeep from "lodash/cloneDeep"
import compact from "lodash/compact"
import countBy from "lodash/countBy"
import debounce from "lodash/debounce"
import difference from "lodash/difference"
import extend from "lodash/extend"
import findIndex from "lodash/findIndex"
import flatten from "lodash/flatten"
import groupBy from "lodash/groupBy"
import identity from "lodash/identity"
import invert from "lodash/invert"
import isEmpty from "lodash/isEmpty"
import isEqual from "lodash/isEqual"
import isNumber from "lodash/isNumber"
import isObject from "lodash/isObject"
import isString from "lodash/isString"
import keyBy from "lodash/keyBy"
import max from "lodash/max"
import maxBy from "lodash/maxBy"
import memoize from "lodash/memoize"
import min from "lodash/min"
import minBy from "lodash/minBy"
import noop from "lodash/noop"
import omit from "lodash/omit"
import once from "lodash/once"
import orderBy from "lodash/orderBy"
import partition from "lodash/partition"
import pick from "lodash/pick"
import range from "lodash/range"
import reverse from "lodash/reverse"
import round from "lodash/round"
import sample from "lodash/sample"
import sampleSize from "lodash/sampleSize"
import sortBy from "lodash/sortBy"
import startCase from "lodash/startCase"
import sum from "lodash/sum"
import sumBy from "lodash/sumBy"
import takeWhile from "lodash/takeWhile"
import throttle from "lodash/throttle"
import toString from "lodash/toString"
import union from "lodash/union"
import uniq from "lodash/uniq"
import uniqBy from "lodash/uniqBy"
import uniqWith from "lodash/uniqWith"
import upperFirst from "lodash/upperFirst"
import without from "lodash/without"
export {
    capitalize,
    chunk,
    clone,
    cloneDeep,
    compact,
    countBy,
    debounce,
    difference,
    extend,
    findIndex,
    flatten,
    groupBy,
    identity,
    invert,
    isEmpty,
    isEqual,
    isNumber,
    isString,
    keyBy,
    max,
    maxBy,
    memoize,
    min,
    minBy,
    noop,
    omit,
    once,
    orderBy,
    partition,
    pick,
    range,
    reverse,
    sample,
    sampleSize,
    sortBy,
    startCase,
    sum,
    sumBy,
    takeWhile,
    throttle,
    toString,
    union,
    uniq,
    uniqBy,
    uniqWith,
    upperFirst,
    without,
}
import { extent, pairs } from "d3-array"
export { pairs }
import moment from "moment"
import { formatLocale } from "d3-format"
import striptags from "striptags"
import parseUrl from "url-parse"
import linkifyHtml from "linkifyjs/html"
import { SortOrder, Integer, Time, EPOCH_DATE, ScaleType } from "./owidTypes"
import { PointVector } from "./PointVector"
import { isNegativeInfinity, isPositiveInfinity } from "./TimeBounds"

export type NoUndefinedValues<T> = {
    [P in keyof T]: Required<NonNullable<T[P]>>
}

// d3 v6 changed the default minus sign used in d3-format to "−" (Unicode minus sign), which looks
// nicer but can cause issues when copy-pasting values into a spreadsheet or script.
// For that reason we change that back to a plain old hyphen.
// See https://observablehq.com/@d3/d3v6-migration-guide#minus
export const d3Format = formatLocale({
    decimal: ".",
    thousands: ",",
    grouping: [3],
    minus: "-",
    currency: ["$", ""],
}).format

export const getRelativeMouse = (
    node: Element,
    event: TouchEvent | { clientX: number; clientY: number }
): PointVector => {
    const isTouchEvent = !!(event as TouchEvent).targetTouches
    const eventOwner = isTouchEvent
        ? (event as TouchEvent).targetTouches[0]
        : (event as MouseEvent)

    const { clientX, clientY } = eventOwner

    // TODO: this does not typecheck anymore now that SVGElement is not redifined as any?
    // const svg = node.ownerSVGElement || node
    // if (svg.createSVGPoint) {
    //     const svgPoint = svg.createSVGPoint()
    //     svgPoint.x = clientX
    //     svgPoint.y = clientY
    //     const point = svgPoint.matrixTransform(node.getScreenCTM().inverse())
    //     return new PointVector(point.x, point.y)
    // }

    const rect = node.getBoundingClientRect()
    return new PointVector(
        clientX - rect.left - node.clientLeft,
        clientY - rect.top - node.clientTop<commit_msg>style(clientUtils): add correct types for `getRelativeMouse()`<commit_after>// We're importing every item on its own to enable webpack tree shaking
import capitalize from "lodash/capitalize"
import chunk from "lodash/chunk"
import clone from "lodash/clone"
import cloneDeep from "lodash/cloneDeep"
import compact from "lodash/compact"
import countBy from "lodash/countBy"
import debounce from "lodash/debounce"
import difference from "lodash/difference"
import extend from "lodash/extend"
import findIndex from "lodash/findIndex"
import flatten from "lodash/flatten"
import groupBy from "lodash/groupBy"
import identity from "lodash/identity"
import invert from "lodash/invert"
import isEmpty from "lodash/isEmpty"
import isEqual from "lodash/isEqual"
import isNumber from "lodash/isNumber"
import isObject from "lodash/isObject"
import isString from "lodash/isString"
import keyBy from "lodash/keyBy"
import max from "lodash/max"
import maxBy from "lodash/maxBy"
import memoize from "lodash/memoize"
import min from "lodash/min"
import minBy from "lodash/minBy"
import noop from "lodash/noop"
import omit from "lodash/omit"
import once from "lodash/once"
import orderBy from "lodash/orderBy"
import partition from "lodash/partition"
import pick from "lodash/pick"
import range from "lodash/range"
import reverse from "lodash/reverse"
import round from "lodash/round"
import sample from "lodash/sample"
import sampleSize from "lodash/sampleSize"
import sortBy from "lodash/sortBy"
import startCase from "lodash/startCase"
import sum from "lodash/sum"
import sumBy from "lodash/sumBy"
import takeWhile from "lodash/takeWhile"
import throttle from "lodash/throttle"
import toString from "lodash/toString"
import union from "lodash/union"
import uniq from "lodash/uniq"
import uniqBy from "lodash/uniqBy"
import uniqWith from "lodash/uniqWith"
import upperFirst from "lodash/upperFirst"
import without from "lodash/without"
export {
    capitalize,
    chunk,
    clone,
    cloneDeep,
    compact,
    countBy,
    debounce,
    difference,
    extend,
    findIndex,
    flatten,
    groupBy,
    identity,
    invert,
    isEmpty,
    isEqual,
    isNumber,
    isString,
    keyBy,
    max,
    maxBy,
    memoize,
    min,
    minBy,
    noop,
    omit,
    once,
    orderBy,
    partition,
    pick,
    range,
    reverse,
    sample,
    sampleSize,
    sortBy,
    startCase,
    sum,
    sumBy,
    takeWhile,
    throttle,
    toString,
    union,
    uniq,
    uniqBy,
    uniqWith,
    upperFirst,
    without,
}
import { extent, pairs } from "d3-array"
export { pairs }
import moment from "moment"
import { formatLocale } from "d3-format"
import striptags from "striptags"
import parseUrl from "url-parse"
import linkifyHtml from "linkifyjs/html"
import { SortOrder, Integer, Time, EPOCH_DATE, ScaleType } from "./owidTypes"
import { PointVector } from "./PointVector"
import { isNegativeInfinity, isPositiveInfinity } from "./TimeBounds"

export type NoUndefinedValues<T> = {
    [P in keyof T]: Required<NonNullable<T[P]>>
}

// d3 v6 changed the default minus sign used in d3-format to "−" (Unicode minus sign), which looks
// nicer but can cause issues when copy-pasting values into a spreadsheet or script.
// For that reason we change that back to a plain old hyphen.
// See https://observablehq.com/@d3/d3v6-migration-guide#minus
export const d3Format = formatLocale({
    decimal: ".",
    thousands: ",",
    grouping: [3],
    minus: "-",
    currency: ["$", ""],
}).format

const getRootSVG = (
    element: Element | SVGElement | SVGSVGElement
): SVGSVGElement | undefined => {
    if ("createSVGPoint" in element) return element
    if ("ownerSVGElement" in element)
        return element.ownerSVGElement || undefined
    return undefined
}

export const getRelativeMouse = (
    node: Element | SVGElement | SVGSVGElement,
    event: TouchEvent | { clientX: number; clientY: number }
): PointVector => {
    const isTouchEvent = !!(event as TouchEvent).targetTouches
    const eventOwner = isTouchEvent
        ? (event as TouchEvent).targetTouches[0]
        : (event as MouseEvent)

    const { clientX, clientY } = eventOwner

    const svg = getRootSVG(node)
    if (svg) {
        const svgPoint = svg.createSVGPoint()
        svgPoint.x = clientX
        svgPoint.y = clientY
        const point = svgPoint.matrixTransform(svg.getScreenCTM()?.inverse())
        return new PointVector(point.x, point.y)
    }

    const rect = node.getBoundingClientRect()
    return new PointVector(
        clientX - rect.left - node.clientLeft,
        clientY - rect.top - node.clientTop
{'fraction_non_alphanumeric': 0.09604707972462803, 'fraction_numerical': 0.0024428159005107706, 'mean_word_length': 3.6475748194014446, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 12, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6300868', 'n_tokens_mistral': 2981, 'n_tokens_neox': 2829, 'n_words': 894}