<commit_before>import * as React from 'react'
import { FindOptions, ResultTable } from './Search';
import * as Finder from './Finder';
import * as Navigator from './Navigator';
import { Entity, Lite, liteKey, isEntity } from './Signum.Entities';
import { Type, QueryTokenString } from './Reflection';

export function useForceUpdate(): () => void {
  var [object, setObject] = React.useState({});
  return () => {
    setObject({});
  }
}

export function useUpdatedRef<T>(newValue: T): React.MutableRefObject<T> {
  const ref = React.useRef(newValue);
  ref.current = newValue;
  return ref;
}

export function useForceUpdatePromise(): () => Promise<void> {
  var [object, setObject] = useStateWithPromise({});
  return () => setObject({}) as Promise<any>;
}

export function useInterval<T>(interval: number | undefined | null, initialState: T, newState: (oldState: T) => T) {
  const [val, setVal] = React.useState(initialState);

  React.useEffect(() => {
    var insideVal = val;
    if (interval) {
      var handler = setInterval(() => {
        setVal(insideVal = newState(insideVal));
      }, interval);
      return () => clearInterval(handler);
    }
  }, [interval]);

  return val;
}

export function usePrevious<T>(value: T): T | undefined {
  var ref = React.useRef<T | undefined>();
  React.useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}

export function useExpand() {
  React.useEffect(() => {
    const wasExpanded = Navigator.Expander.setExpanded(true);
    return () => { Navigator.Expander.setExpanded(wasExpanded); }
  }, []);

}


interface Size {
  width: number;
  height: number;
}

export function useSize<T extends HTMLElement = HTMLDivElement>(): { size: Size | undefined, setContainer: (element: T | null) => void } {
  const [size, setSize] = React.useState<Size | undefined>();
  const divElement = React.useRef<T | null>(null);
  function setNewSize() {
    const rect = divElement.current!.getBoundingClientRect();
    if (size == null || size.width != rect.width || size.height != rect.height)
      setSize({ width: rect.width, height: rect.height });
  }

  function setContainer(div: T | null) {
    if (divElement.current = div) {
      setNewSize();
    }
  }
  const handler = React.useRef<number | null>(null);
  React.useEffect(() => {
    function onResize() {
      if (handler.current != null)
        clearTimeout(handler.current);

      handler.current = setTimeout(() => {
        if (divElement.current) {
          setNewSize()
        }
      }, 300);
    }

    window.addEventListener('resize', onResize);

    return () => {
      if (handler.current)
        clearTimeout(handler.current);

      window.removeEventListener("resize", onResize);
    };
  }, []);

  return { size, setContainer };
}

interface APIHookOptions {
  avoidReset?: boolean;
}

export function useStateWithPromise<T>(defaultValue: T): [T, (newValue: React.SetStateAction<T>) => Promise<T>] {
  const [state, setState] = React.useState({ value: defaultValue, resolve: (val: T) => { } });

  React.useEffect(() => state.resolve(state.value), [state]);

  return [
    state.value,
    updaterOrValue => new Promise(resolve => {
      setState(prevState => {
        let nextVal = typeof updaterOrValue == "function" ? (updaterOrValue as ((val: T) => T))(prevState.value) : updaterOrValue;
        return {
          value: nextVal,
          resolve: resolve
        };
      })
    })
  ]
}

export function useTitle(title: string, deps?: readonly any[]) {
  React.useEffect(() => {
    Navigator.setTitle(title);
    return () => Navigator.setTitle();
  }, deps);
}

export function useAPIWithReload<T>(makeCall: (signal: AbortSignal, oldData: T | undefined) => Promise<T>, deps: ReadonlyArray<any> | undefined, options?: APIHookOptions): [T | undefined, () => void] {
  const [count, setCount] = React.useState(0);
  const value = useAPI<T>(makeCall, [...(deps || []), count], options);
  return [value, () => setCount(count + 1)];
}



export function useAPI<T>(makeCall: (signal: AbortSignal, oldData: T | undefined) => Promise<T>, deps: ReadonlyArray<any>, options?: APIHookOptions): T | undefined {

  const [data, setData] = React.useState<{ deps: ReadonlyArray<any>; result: T } | undefined>(undefined);

  React.useEffect(() => {
    var abortController = new AbortController();

    makeCall(abortController.signal, data && data.result)
      .then(result => !abortController.signal.aborted && setData({ result, deps }))
      .done();

    return () => {
      abortController.abort();
    }
  }, deps);

  if (!(options && options.avoidReset)) {
    if (data && !areEqual(data.deps, deps))
      return undefined;
  }

  return data && data.result;
}

function areEqual(depsA: ReadonlyArray<any>, depsB: ReadonlyArray<any>) {

  if (depsA.length !== depsB.length)<commit_msg>fix potential useAPIWithReload clousure problems<commit_after>import * as React from 'react'
import { FindOptions, ResultTable } from './Search';
import * as Finder from './Finder';
import * as Navigator from './Navigator';
import { Entity, Lite, liteKey, isEntity } from './Signum.Entities';
import { Type, QueryTokenString } from './Reflection';

export function useForceUpdate(): () => void {
  var [object, setObject] = React.useState({});
  return () => {
    setObject({});
  }
}

export function useUpdatedRef<T>(newValue: T): React.MutableRefObject<T> {
  const ref = React.useRef(newValue);
  ref.current = newValue;
  return ref;
}

export function useForceUpdatePromise(): () => Promise<void> {
  var [object, setObject] = useStateWithPromise({});
  return () => setObject({}) as Promise<any>;
}

export function useInterval<T>(interval: number | undefined | null, initialState: T, newState: (oldState: T) => T) {
  const [val, setVal] = React.useState(initialState);

  React.useEffect(() => {
    var insideVal = val;
    if (interval) {
      var handler = setInterval(() => {
        setVal(insideVal = newState(insideVal));
      }, interval);
      return () => clearInterval(handler);
    }
  }, [interval]);

  return val;
}

export function usePrevious<T>(value: T): T | undefined {
  var ref = React.useRef<T | undefined>();
  React.useEffect(() => {
    ref.current = value;
  }, [value]);

  return ref.current;
}

export function useExpand() {
  React.useEffect(() => {
    const wasExpanded = Navigator.Expander.setExpanded(true);
    return () => { Navigator.Expander.setExpanded(wasExpanded); }
  }, []);

}


interface Size {
  width: number;
  height: number;
}

export function useSize<T extends HTMLElement = HTMLDivElement>(): { size: Size | undefined, setContainer: (element: T | null) => void } {
  const [size, setSize] = React.useState<Size | undefined>();
  const divElement = React.useRef<T | null>(null);
  function setNewSize() {
    const rect = divElement.current!.getBoundingClientRect();
    if (size == null || size.width != rect.width || size.height != rect.height)
      setSize({ width: rect.width, height: rect.height });
  }

  function setContainer(div: T | null) {
    if (divElement.current = div) {
      setNewSize();
    }
  }
  const handler = React.useRef<number | null>(null);
  React.useEffect(() => {
    function onResize() {
      if (handler.current != null)
        clearTimeout(handler.current);

      handler.current = setTimeout(() => {
        if (divElement.current) {
          setNewSize()
        }
      }, 300);
    }

    window.addEventListener('resize', onResize);

    return () => {
      if (handler.current)
        clearTimeout(handler.current);

      window.removeEventListener("resize", onResize);
    };
  }, []);

  return { size, setContainer };
}

interface APIHookOptions {
  avoidReset?: boolean;
}

export function useStateWithPromise<T>(defaultValue: T): [T, (newValue: React.SetStateAction<T>) => Promise<T>] {
  const [state, setState] = React.useState({ value: defaultValue, resolve: (val: T) => { } });

  React.useEffect(() => state.resolve(state.value), [state]);

  return [
    state.value,
    updaterOrValue => new Promise(resolve => {
      setState(prevState => {
        let nextVal = typeof updaterOrValue == "function" ? (updaterOrValue as ((val: T) => T))(prevState.value) : updaterOrValue;
        return {
          value: nextVal,
          resolve: resolve
        };
      })
    })
  ]
}

export function useTitle(title: string, deps?: readonly any[]) {
  React.useEffect(() => {
    Navigator.setTitle(title);
    return () => Navigator.setTitle();
  }, deps);
}

export function useAPIWithReload<T>(makeCall: (signal: AbortSignal, oldData: T | undefined) => Promise<T>, deps: ReadonlyArray<any>, options?: APIHookOptions): [T | undefined, () => void] {
  const [obj, setObj] = React.useState({});
  const value = useAPI<T>(makeCall, [...(deps || []), obj], options);
  return [value, () => setObj({})];
}



export function useAPI<T>(makeCall: (signal: AbortSignal, oldData: T | undefined) => Promise<T>, deps: ReadonlyArray<any>, options?: APIHookOptions): T | undefined {

  const [data, setData] = React.useState<{ deps: ReadonlyArray<any>; result: T } | undefined>(undefined);

  React.useEffect(() => {
    var abortController = new AbortController();

    makeCall(abortController.signal, data && data.result)
      .then(result => !abortController.signal.aborted && setData({ result, deps }))
      .done();

    return () => {
      abortController.abort();
    }
  }, deps);

  if (!(options && options.avoidReset)) {
    if (data && !areEqual(data.deps, deps))
      return undefined;
  }

  return data && data.result;
}

function areEqual(depsA: ReadonlyArray<any>, depsB: ReadonlyArray<any>) {

  if (depsA.length !== depsB.length)
{'fraction_non_alphanumeric': 0.16363075023155293, 'fraction_numerical': 0.0008232993722342287, 'mean_word_length': 3.6342393896041965, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 115, 'https://': 0, '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': '4201000', 'n_tokens_mistral': 3045, 'n_tokens_neox': 3025, 'n_words': 713}