{"version":3,"file":"index.mjs","sources":["../../src/path-fx.ts","../../src/utils.ts","../../src/tree/subject.ts","../../src/tree/tree.ts","../../src/file-tree.ts","../../src/use-node-plugins.ts","../../src/node.tsx","../../src/use-observer.ts","../../src/use-dnd.ts","../../src/use-visible-nodes.ts","../../src/use-filter.ts","../../src/use-hotkeys.ts","../../src/use-file-tree-snapshot.ts","../../src/use-traits.ts","../../src/use-roving-focus.ts","../../src/use-selections.ts","../../src/use-resize-observer.ts","../../src/use-transition.ts","../../src/use-virtualize.ts","../../src/tree/nodes-by-id.ts","../../src/tree/leaf.ts","../../src/tree/branch.ts","../../src/observable-data.ts","../../src/use-deferred-value.ts"],"sourcesContent":["export const SEP = \"/\";\nconst SEP_NEGATE_RE = /[^/]+/g;\nconst TRAILING_SEP_RE = /\\/$/;\n\n/**\n * Returns `true` if the path is relative.\n *\n * @param path - The path to check\n */\nexport function isRelative(path: string): boolean {\n  return path[0] !== SEP;\n}\n\n/**\n * Join all arguments together and normalize the resulting path.\n *\n * @param paths - The paths to join\n */\nexport function join(...paths: string[]) {\n  const composed = [];\n  const hasLeadingSlash = paths[0][0] === SEP;\n  const lastPath = paths[paths.length - 1];\n  const hasTrailingSlash = lastPath[lastPath.length - 1] === SEP;\n\n  for (let i = 0; i < paths.length; i++) {\n    const path = paths[i];\n    const parts = split(path);\n\n    for (let j = 0; j < parts.length; j++) {\n      const part = parts[j];\n\n      if (part === \".\") {\n        continue;\n      } else if (part.length === 2 && part[0] === \".\" && part[1] === \".\") {\n        composed.pop();\n      } else {\n        composed.push(part);\n      }\n    }\n  }\n\n  if (hasLeadingSlash) {\n    composed.unshift(\"\");\n  }\n\n  if (hasTrailingSlash) {\n    composed.push(\"\");\n  }\n\n  return composed.join(SEP);\n}\n\n/**\n * Solve the relative path from `from` to `to`. Paths must be absolute.\n *\n * @param from - The absolute path to start from\n * @param to - The absolute path to solve to\n */\nexport function relative(from: string, to: string) {\n  if (isRelative(from) || isRelative(to)) {\n    throw new Error(`Paths must be absolute`);\n  }\n\n  const fromFrags = split(from);\n  const toFrags = split(to);\n  const hasTrailingSep = to[to.length - 1] === SEP;\n\n  for (let i = 0; i < fromFrags.length; i++) {\n    const fromFrag = fromFrags[i];\n\n    if (fromFrag !== toFrags[i]) {\n      const remainder = fromFrags.length - i;\n\n      return new Array(remainder).fill(\"..\").concat(toFrags.slice(i)).join(SEP);\n    }\n  }\n\n  return removeTrailingSlashes(\n    toFrags.slice(fromFrags.length).join(SEP) + (hasTrailingSep ? SEP : \"\")\n  );\n}\n\n/**\n * Splits a path into an array of path segments.\n *\n * @param path - The path to split.\n */\nexport function split(path: string): string[] {\n  return path.match(SEP_NEGATE_RE) ?? [];\n}\n\n/**\n * Normalize a path, taking care of `..` and `.`, and removing redundant slashes\n * while preserving trailing slashes.\n *\n * @param path - The path to normalize.\n */\nexport function normalize(path: string): string {\n  // Hot path for known roots\n  if (path === \"\" || path === \"/\") return path;\n  return join(path);\n}\n\n/**\n * Returns `true` if `path` is inside `dir`.\n *\n * @param path - The path to check\n * @param dir - The directory to check if the path is inside of.\n */\nexport function isPathInside(path: string, dir: string): boolean {\n  const pathFrags = split(dir);\n  const contPathFrags = split(path);\n  return pathFrags.every((fragment, i) => fragment === contPathFrags[i]);\n}\n\n/**\n * Get the depth of a path.\n *\n * @param path - The path to split.\n */\nexport function depth(path: string): number {\n  return split(path).length;\n}\n\n/**\n * Return the last fragment of a path.\n *\n * @param path - The path to get the basename of.\n */\nexport function basename(path: string): string {\n  const frags = split(path);\n  const lastIndex = frags.length - 1;\n  return lastIndex === -1 ? \"\" : frags[lastIndex];\n}\n\n/**\n * Returns the extension of a file path, which is the part of the path after the last `.`.\n * If the path has no extension, returns an empty string.\n *\n * @param path - The path to get the extension of.\n */\nexport function extname(path: string): string {\n  const name = basename(path);\n  const i = name.lastIndexOf(\".\");\n  return i < 0 ? \"\" : name.slice(i);\n}\n\n/**\n * Return the directory name of a path.\n *\n * @param path - The path to get the directory name of.\n */\nexport function dirname(path: string): string {\n  const parts = split(path);\n  const hasLeadingSep = path[0] === SEP;\n  parts.pop();\n\n  if (parts.length === 0) {\n    return hasLeadingSep ? SEP : \".\";\n  }\n\n  if (hasLeadingSep) {\n    parts.unshift(\"\");\n  }\n\n  return parts.join(SEP);\n}\n\n/**\n * Remove any trailing slashes from a path.\n *\n * @param path - The path to remove trailing slashes from.\n */\nexport function removeTrailingSlashes(path: string) {\n  return path.replace(TRAILING_SEP_RE, \"\");\n}\n","// @react-aria/utils\n// Credit: https://github.com/adobe/react-spectrum/tree/main/packages/%40react-aria\nimport {\n  clearRequestTimeout,\n  requestTimeout,\n} from \"@essentials/request-timeout\";\nimport clsx from \"clsx\";\n\n/**\n * Merges multiple props objects together. Event handlers are chained,\n * classNames are combined, and styles are combined.\n *\n * For all other props, the last prop object overrides all previous ones.\n *\n * @param args - Multiple sets of props to merge together.\n */\nexport function mergeProps<T extends Props[]>(\n  args: T\n): UnionToIntersection<TupleTypes<T>> {\n  // Start with a base clone of the first argument. This is a lot faster than starting\n  // with an empty object and adding properties as we go.\n  const result: Props = { ...args[0], style: { ...args[0]?.style } };\n\n  for (let i = 1; i < args.length; i++) {\n    const props = args[i];\n\n    for (const key in props) {\n      const a = result[key];\n      const b = props[key];\n\n      // Chain events\n      if (\n        typeof a === \"function\" &&\n        typeof b === \"function\" &&\n        // This is a lot faster than a regex.\n        key[0] === \"o\" &&\n        key[1] === \"n\" &&\n        key.charCodeAt(2) >= /* 'A' */ 65 &&\n        key.charCodeAt(2) <= /* 'Z' */ 90\n      ) {\n        result[key] = chain(a, b);\n        // Merge classnames, sometimes classNames are empty string which eval to false,\n        // so we just need to do a type check\n      } else if (\n        (key === \"className\" || key === \"UNSAFE_className\") &&\n        typeof a === \"string\" &&\n        typeof b === \"string\"\n      ) {\n        result[key] = clsx(a, b);\n      } else if (\n        key === \"style\" &&\n        typeof a === \"object\" &&\n        typeof b === \"object\"\n      ) {\n        result[key] = Object.assign(a, b);\n      } else {\n        result[key] = b;\n      }\n    }\n  }\n\n  return result as UnionToIntersection<TupleTypes<T>>;\n}\n\n/**\n * Calls all functions in the order they were chained with the same arguments.\n *\n * @param  callbacks - Callbacks to chain together\n */\nexport function chain<Args extends any[]>(\n  ...callbacks: Args\n): (...args: Args) => void {\n  return (...args: any[]) => {\n    for (let i = 0; i < callbacks.length; i++) {\n      const callback = callbacks[i];\n\n      if (typeof callback === \"function\") {\n        callback(...args);\n      }\n    }\n  };\n}\n\nexport function throttle<CallbackArguments extends any[]>(\n  callback: (...args: CallbackArguments) => void,\n  fps = 30,\n  leading = false\n): (...args: CallbackArguments) => void {\n  const ms = 1000 / fps;\n  let prev = 0;\n  let trailingTimeout: ReturnType<typeof requestTimeout>;\n  const clearTrailing = () =>\n    trailingTimeout && clearRequestTimeout(trailingTimeout);\n\n  return function () {\n    // eslint-disable-next-line prefer-rest-params\n    const args = arguments;\n    const rightNow = performance.now();\n    const call = () => {\n      prev = rightNow;\n      clearTrailing();\n      // @ts-expect-error: IArguments isn't assignable, but they're the same thing\n      // eslint-disable-next-line prefer-spread\n      callback.apply(null, args);\n    };\n    const current = prev;\n    // leading\n    if (leading && current === 0) return call();\n    const delta = rightNow - current;\n    // body\n    if (rightNow - current > ms) {\n      if (current > 0) return call();\n      prev = rightNow;\n    }\n    // trailing\n    clearTrailing();\n    trailingTimeout = requestTimeout(() => {\n      call();\n      prev = 0;\n    }, ms - delta);\n  };\n}\n\nexport function shallowEqual<\n  A extends Record<string | number | symbol, unknown> | null,\n  B extends Record<string | number | symbol, unknown> | null\n>(objA: A, objB: B | A): boolean {\n  if (objA === objB) return true;\n  if (objA === null || objB === null) return false;\n  for (const key in objA) if (objA[key] !== objB[key]) return false;\n  return true;\n}\n\n/**\n * Retry a promise until it resolves or the max number of retries is reached.\n *\n * @param promiseFn - A function that returns a promise to retry\n * @param config - Options\n * @param config.maxRetries - Max number of retries\n * @param config.initialDelay - Initial delay before first retry\n * @param config.delayMultiple - Multiplier for each subsequent retry\n * @param config.shouldRetry - A function that should return `false` to stop retrying\n */\nexport async function retryWithBackoff<T>(\n  promiseFn: () => Promise<T>,\n  config: RetryWithBackoffConfig = {}\n): Promise<T> {\n  const {\n    maxRetries = 4,\n    initialDelay = 100,\n    delayMultiple = 2,\n    shouldRetry,\n  } = config;\n\n  try {\n    const result = await promiseFn();\n    return result;\n  } catch (err) {\n    if (\n      maxRetries === 0 ||\n      (typeof shouldRetry === \"function\" && !shouldRetry(err))\n    ) {\n      throw err;\n    }\n\n    await new Promise((resolve) => setTimeout(resolve, initialDelay));\n    return retryWithBackoff(promiseFn, {\n      maxRetries: maxRetries - 1,\n      initialDelay: initialDelay * delayMultiple,\n      delayMultiple,\n      shouldRetry,\n    });\n  }\n}\n\nexport interface RetryWithBackoffConfig {\n  /**\n   * Max number of retries\n   *\n   * @default 4\n   */\n  maxRetries?: number;\n  /**\n   * Initial delay before first retry\n   *\n   * @default 100\n   */\n  initialDelay?: number;\n  /**\n   * Multiplier for each subsequent retry\n   *\n   * @default 2\n   */\n  delayMultiple?: number;\n  /**\n   * A function that should return `false` to stop retrying\n   *\n   * @param error - The error that caused the retry\n   */\n  shouldRetry?: (error: unknown) => boolean;\n}\n\ninterface Props {\n  [key: string]: any;\n}\n\n// Taken from:\n// https://stackoverflow.com/questions/51603250/typescript-3-parameter-list-intersection-type/51604379#51604379\ntype TupleTypes<T> = { [P in keyof T]: T[P] } extends { [key: number]: infer V }\n  ? V\n  : never;\n\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n  k: infer I\n) => void\n  ? I\n  : never;\n","/**\n * A utility for emitting abd subscribing to changes to a value.\n *\n * @param  initialState - The initial value of the subject.\n */\nexport function subject<T>(initialState: T): Subject<T> {\n  const observers: Set<Observer<T>> = new Set();\n  let state = initialState;\n\n  return {\n    setState(nextState: T) {\n      state = nextState;\n\n      for (const listener of observers) {\n        listener(nextState);\n      }\n    },\n\n    getState() {\n      return state;\n    },\n\n    observe(observer: Observer<T>) {\n      observers.add(observer);\n\n      return () => {\n        observers.delete(observer);\n      };\n    },\n\n    unobserve(observer: Observer<T>) {\n      observers.delete(observer);\n    },\n  };\n}\n\nexport function pureSubject<T>(\n  initialValue: T,\n  areEqual: (current: T, next: T) => boolean = (current, next) =>\n    current === next\n): Subject<T> {\n  const observers: Set<Observer<T>> = new Set();\n  let state = initialValue;\n\n  return {\n    setState(nextState: T) {\n      if (areEqual(state, nextState)) return;\n      state = nextState;\n\n      for (const listener of observers) {\n        listener(nextState);\n      }\n    },\n\n    getState() {\n      return state;\n    },\n\n    observe(observer: Observer<T>) {\n      observers.add(observer);\n\n      return () => {\n        observers.delete(observer);\n      };\n    },\n\n    unobserve(observer: Observer<T>) {\n      observers.delete(observer);\n    },\n  };\n}\n\nexport type Subject<T> = {\n  /**\n   * Emit a new state.\n   *\n   * @param state - The new state\n   */\n  setState(state: T): void;\n  /**\n   * Get the current state.\n   */\n  getState(): T;\n  /**\n   * Observe changes to the state.\n   *\n   * @param observer - A callback that is invoked when the value changes\n   */\n  observe(observer: Observer<T>): () => void;\n  /**\n   * Remove a observer from the list of observers\n   *\n   * @param observer - A callback that is invoked when the value changes\n   */\n  unobserve(observer: Observer<T>): void;\n};\n\nexport type Observer<T> = {\n  (state: T): void;\n};\n","import memoizeOne from \"@essentials/memoize-one\";\nimport { retryWithBackoff } from \"../utils\";\nimport type { Node } from \"./branch\";\nimport { Branch } from \"./branch\";\nimport { Leaf } from \"./leaf\";\nimport { nodesById } from \"./nodes-by-id\";\nimport { subject } from \"./subject\";\n\nexport class Tree<NodeData = {}> {\n  protected loadingBranches = new Map<Branch<NodeData>, Promise<void>>();\n  private getNodes: GetNodes<NodeData>;\n  comparator?: (a: Node<NodeData>, b: Node<NodeData>) => number;\n  flatView = subject(0);\n  root: Branch<NodeData>;\n  nodesById = nodesById as Node<NodeData>[];\n\n  constructor({\n    getNodes,\n    root,\n    comparator,\n  }: {\n    getNodes: GetNodes<NodeData>;\n    root: Branch<NodeData>;\n    comparator?: (a: Node<NodeData>, b: Node<NodeData>) => number;\n  }) {\n    this.root = root;\n    this.getNodes = getNodes;\n    this.comparator = comparator;\n    retryWithBackoff(() => this.expand(this.root), {\n      shouldRetry: () => {\n        return !this.isExpanded(this.root);\n      },\n    }).catch(() => {});\n  }\n\n  get visibleNodes(): number[] {\n    return this.createVisibleNodes(this.flatView.getState());\n  }\n\n  getSnapshot = () => {\n    return this.visibleNodes;\n  };\n\n  getById(id: number): Node<NodeData> | undefined {\n    return this.nodesById[id];\n  }\n\n  /**\n   * Ensures that the children of any given branch have been loaded and ready to be worked with.\n   *\n   * Call this method without any arguments to check if the root branch is loaded.\n   *\n   * ⚠ \"Loaded\" doesn't mean expanded, it just means the contents are \"ready\". Except when no arguments are given, the\n   * branch being checked is root, and root is always expanded.\n   *\n   * @param branch - The branch to check\n   */\n  async ensureLoaded(branch: Branch<NodeData> = this.root): Promise<void> {\n    if (!branch.nodes) {\n      await this.loadNodes(branch);\n    }\n  }\n\n  async expand(\n    branch: Branch<NodeData>,\n    options: {\n      ensureVisible?: boolean;\n      recursive?: boolean;\n    } = {}\n  ): Promise<void> {\n    const { ensureVisible = false, recursive = false } = options;\n    const isVisibilitySkippable =\n      !ensureVisible || (ensureVisible && this.isVisible(branch));\n\n    if (!recursive && this.isExpanded(branch) && isVisibilitySkippable) {\n      return;\n    }\n\n    branch.expanded = true;\n    await this.ensureLoaded(branch);\n\n    // Check again as collapse might have been called in the meantime\n    if (branch.expanded) {\n      if (ensureVisible) {\n        while (branch.parent) {\n          const node = branch.parent;\n\n          if (isBranch(node)) {\n            branch = node;\n            branch.expanded = true;\n          }\n        }\n      }\n\n      if (recursive && branch.nodes) {\n        await Promise.all(\n          branch.nodes.map((nodeId) => {\n            const node = this.nodesById[nodeId];\n            return isBranch(node) ? this.expand(node, options) : null;\n          })\n        );\n      }\n\n      this.invalidate();\n    }\n  }\n\n  collapse(branch: Branch<NodeData>): void {\n    if (branch.expanded) {\n      branch.expanded = false;\n      this.invalidate();\n    }\n  }\n\n  protected _produce(\n    branch: Branch<NodeData>,\n    produceFn: (context: {\n      get draft(): Node<NodeData>[];\n      insert<NodeType extends Node<NodeData>>(\n        node: NodeType,\n        insertionIndex?: number\n      ): NodeType;\n      revert(): void;\n    }) => void | Node<NodeData>[]\n  ): void {\n    const nodes = (branch.nodes ?? []).map((nodeId) => this.nodesById[nodeId]);\n    let draftResult = createDraft(nodes);\n\n    draftResult.draft =\n      produceFn({\n        get draft() {\n          return draftResult.draft;\n        },\n        insert(node, insertionIndex) {\n          draftResult.modified = true;\n          draftResult.draft.splice(insertionIndex ?? Infinity, 0, node);\n          return node;\n        },\n        revert: () => {\n          draftResult = createDraft(\n            (branch.nodes ?? []).map((nodeId) => this.nodesById[nodeId])\n          );\n        },\n      }) ?? draftResult.draft;\n\n    if (draftResult.modified) {\n      this.setNodes(branch, draftResult.draft);\n      this.invalidate();\n    }\n  }\n\n  remove(nodeToRemove: Node<NodeData>): void {\n    if (isBranch(nodeToRemove) && nodeToRemove.nodes) {\n      const nodes = [...nodeToRemove.nodes];\n      let nodeId: number | undefined;\n\n      while ((nodeId = nodes.pop())) {\n        const node = this.nodesById[nodeId];\n\n        if (isBranch(node) && node.nodes) {\n          nodes.push(...node.nodes);\n        }\n      }\n\n      for (let i = 0; i < nodes.length; i++) {\n        // @ts-expect-error\n        nodesById[nodes[i]] = undefined;\n      }\n    }\n\n    const nodeToRemoveParent = nodeToRemove.parent ?? this.root;\n\n    // @ts-expect-error\n    nodesById[nodeToRemove.id] = undefined;\n\n    if (nodeToRemoveParent?.nodes) {\n      let found = 0;\n      const nextNodes: number[] = new Array(\n        Math.max(nodeToRemoveParent.nodes.length - 1, 0)\n      );\n\n      for (let i = 0; i < nodeToRemoveParent.nodes.length; i++) {\n        const nodeId = nodeToRemoveParent.nodes[i];\n\n        if (nodeId !== nodeToRemove.id) {\n          nextNodes[i - found] = nodeId;\n        } else {\n          found = 1;\n        }\n      }\n\n      this.setNodes(nodeToRemoveParent, nextNodes);\n    }\n\n    this.invalidate();\n  }\n\n  async move(node: Node<NodeData>, to: Branch<NodeData>): Promise<void> {\n    const initialParent = node.parent ?? this.root;\n\n    if (\n      // If the node is already in the target branch, do nothing\n      initialParent === to ||\n      // You can't move a node to a child of itself\n      (isBranch(node) && node.contains(to))\n    ) {\n      return;\n    }\n\n    if (!to.nodes) {\n      await this.expand(to);\n    }\n\n    // Parent may have changed in the meantime\n    if (node.parent === initialParent) {\n      if (initialParent?.nodes) {\n        const nextNodes: number[] = new Array(\n          Math.max(initialParent.nodes.length - 1, 0)\n        );\n        let found = 0;\n\n        for (let i = 0; i < initialParent.nodes.length; i++) {\n          const nodeId = initialParent.nodes[i];\n\n          if (nodeId !== node.id) {\n            nextNodes[i - found] = nodeId;\n          } else {\n            found = 1;\n          }\n        }\n\n        this.setNodes(initialParent, nextNodes);\n      }\n\n      if (to.nodes) {\n        node.parentId = to.id;\n        const nextNodes = [...to.nodes];\n        nextNodes[nextNodes.length] = node.id;\n        this.setNodes(to, nextNodes);\n      }\n\n      this.invalidate();\n    }\n  }\n\n  /**\n   * Invalidate the list of visible nodes. This is useful for re-rendering your tree\n   * when node data changes.\n   */\n  invalidate(): void {\n    this.flatView.setState(this.flatView.getState() + 1);\n  }\n\n  /**\n   * A more accurate and real-time representation of whether a branch is expanded.\n   *\n   * `Branch#expanded` represents the \"optimistic\" expansion state of the branch in\n   * question not the actual status, because the child nodes might still need to be\n   * loaded before the change can be seen in the tree.\n   *\n   * @param branch - The branch to check\n   */\n  isExpanded(branch: Branch<NodeData>): boolean {\n    return !!(branch.nodes && branch.expanded);\n  }\n\n  /**\n   * Returns `true` if the node and its parents are visible in the tree.\n   *\n   * @param node - The node to check\n   */\n  isVisible(node: Node<NodeData>): boolean {\n    let p = node.parent;\n\n    while (p) {\n      if (!p.expanded) return false;\n      p = p.parent;\n    }\n\n    return true;\n  }\n\n  /**\n   * You can use this method to manually trigger a reload of a branch in the tree.\n   *\n   * @param branch - The branch to load nodes for\n   */\n  async loadNodes(branch: Branch<NodeData>): Promise<void> {\n    const promise = this.loadingBranches.get(branch);\n\n    if (!promise) {\n      const promise = (async (): Promise<void> => {\n        const nodes = await this.getNodes(branch);\n        this.setNodes(branch, nodes);\n\n        for (let i = 0; i < nodes.length; i++) {\n          const node = nodes[i];\n\n          if (isBranch(node) && node.expanded) {\n            retryWithBackoff(() => this.expand(node), {\n              shouldRetry: () => {\n                return node.expanded && !this.isExpanded(node);\n              },\n            }).catch(() => {});\n          }\n        }\n      })();\n\n      promise.finally(() => this.loadingBranches.delete(branch));\n      this.loadingBranches.set(branch, promise);\n      return promise;\n    }\n\n    return promise;\n  }\n\n  protected setNodes(\n    branch: Branch<NodeData>,\n    nodeIds: number[] | Node<NodeData>[]\n  ): void {\n    const comparator = this.comparator;\n    let nodes: Node<NodeData>[] = nodeIds as Node<NodeData>[];\n\n    if (typeof nodeIds[0] === \"number\") {\n      for (let i = 0; i < nodeIds.length; i++) {\n        const nodeId = nodeIds[i] as number;\n        nodes[i] = this.nodesById[nodeId];\n      }\n    }\n\n    nodes = comparator ? nodes.sort(comparator) : nodes;\n\n    branch.nodes = new Array(nodes.length);\n    this.nodesById[branch.id] = branch;\n\n    for (let i = 0; i < nodes.length; i++) {\n      const node = nodes[i];\n      branch.nodes[i] = node.id;\n      this.nodesById[node.id] = node;\n    }\n  }\n\n  private createVisibleNodes = memoizeOne(\n    (id: number) => {\n      const flatView: number[] = [];\n\n      if (this.root.nodes) {\n        const nodes: number[] = [...this.root.nodes].reverse();\n        let nodeId: number | undefined;\n\n        while ((nodeId = nodes.pop())) {\n          flatView.push(nodeId);\n          const node = this.nodesById[nodeId];\n\n          if (\n            isBranch(node) &&\n            node.expanded &&\n            node.nodes &&\n            node.nodes.length > 0\n          ) {\n            nodes.push(...[...node.nodes].reverse());\n          }\n        }\n      }\n\n      return flatView;\n    },\n    (prevArgs, args) => prevArgs[0] === args[0]\n  );\n\n  dispose(): void {\n    // @ts-expect-error\n    nodesById[this.root.id] = undefined;\n\n    for (let i = 0; i < this.visibleNodes.length; i++) {\n      // @ts-expect-error\n      nodesById[this.visibleNodes[i]] = undefined;\n    }\n  }\n}\n\nfunction createDraft<NodeData = {}>(\n  nodes: ReadonlyArray<Node<NodeData>>\n): { draft: Node<NodeData>[]; modified: boolean } {\n  const draft = new Proxy([...nodes], {\n    set(target, index, value) {\n      if (typeof index === \"string\" || typeof index === \"number\") {\n        target[parseInt(index)] = value;\n        draftResult.modified = true;\n      }\n\n      return true;\n    },\n  });\n\n  const draftResult = { draft, modified: false };\n\n  Object.getOwnPropertyNames(Array.prototype).forEach((prop) => {\n    switch (prop) {\n      case \"pop\":\n      case \"push\":\n      case \"shift\":\n      case \"unshift\":\n      case \"reverse\":\n      case \"sort\":\n      case \"splice\":\n        Object.defineProperty(draft, prop, {\n          value: (...args: any[]) => {\n            draftResult.modified = true;\n            // eslint-disable-next-line prefer-spread\n            return Array.prototype[prop].apply(draft, args);\n          },\n        });\n    }\n  });\n\n  return draftResult;\n}\n\nexport function isLeaf<T>(node: Node<T> | undefined): node is Leaf<T> {\n  return node instanceof Leaf && !(node instanceof Branch);\n}\n\nexport function isBranch<T>(node: Node<T> | undefined): node is Branch<T> {\n  return node instanceof Branch;\n}\n\nexport type GetNodes<NodeData = {}> = {\n  (parent: Branch<NodeData>): Node<NodeData>[] | Promise<Node<NodeData>[]>;\n};\n","import * as pathFx from \"./path-fx\";\nimport { Branch } from \"./tree/branch\";\nimport { Leaf } from \"./tree/leaf\";\nimport { nodesById } from \"./tree/nodes-by-id\";\nimport type { GetNodes as GetNodesBase } from \"./tree/tree\";\nimport { Tree } from \"./tree/tree\";\nimport type { FileTreeSnapshot } from \"./types\";\n\n/**\n * Create a file tree that can be used with the React API.\n *\n * @param getNodes - A function that returns the nodes of the file tree.\n * @param config - Configuration options for the file tree.\n * @param config.comparator - A function that compares two nodes for sorting.\n * @param config.root - The root node data of the file tree.\n */\nexport function createFileTree<Meta = {}>(\n  getNodes: GetNodes<Meta>,\n  config: FileTreeConfig<Meta> = {}\n) {\n  const { comparator = defaultComparator, root, restoreFromSnapshot } = config;\n\n  const tree = new FileTree<Meta>({\n    async getNodes(parent) {\n      const factory: Omit<FileTreeFactory<Meta>, \"createPrompt\"> = {\n        createFile(data) {\n          return new File(parent, data);\n        },\n\n        createDir(data, expanded?: boolean) {\n          const path =\n            parent.id === -1\n              ? data.name\n              : pathFx.join(\n                  // @ts-expect-error: branch type but is dir\n                  parent.path,\n                  pathFx.basename(data.name)\n                );\n\n          return new Dir(\n            parent,\n            data,\n            expanded ??\n              !!(\n                restoreFromSnapshot &&\n                (restoreFromSnapshot.expandedPaths.includes(path) ||\n                  restoreFromSnapshot.buriedPaths.includes(path))\n              )\n          );\n        },\n      };\n\n      return getNodes(parent as Dir<Meta>, factory);\n    },\n    comparator,\n    root: new Dir(null, root ? { ...root } : { name: pathFx.SEP }),\n  });\n\n  return tree;\n}\n\nexport class FileTree<Meta = {}> extends Tree<FileTreeData<Meta>> {\n  /**\n   * The root directory of the file tree\n   */\n  declare root: Dir<Meta>;\n  protected declare treeNodeMap: Map<number, File<Meta> | Dir<Meta>>;\n  declare nodesById: FileTreeNode<Meta>[];\n  protected declare loadingBranches: Map<Dir<Meta>, Promise<void>>;\n\n  /**\n   * Get a node by its ID.\n   *\n   * @param id - The ID of the node\n   */\n  declare getById: (id: number) => FileTreeNode<Meta> | undefined;\n  /**\n   * Expand a directory in the tree.\n   *\n   * @param dir - The directory to expand\n   * @param options - Options for expanding the directory\n   */\n  declare expand: (\n    dir: Dir<Meta>,\n    options?: {\n      /**\n       * Ensure that the directory's parents are visible in the tree, as well.\n       */\n      ensureVisible?: boolean;\n      /**\n       * Expand all of the directory's child directories.\n       */\n      recursive?: boolean;\n    }\n  ) => Promise<void>;\n  /**\n   * Collapse a directory in the tree.\n   *\n   * @param dir - The directory to collapse\n   */\n  declare collapse: (dir: Dir<Meta>) => void;\n  /**\n   * Remove a node and its descendants from the tree.\n   */\n  declare remove: (node: FileTreeNode<Meta>) => void;\n  /**\n   * You can use this method to manually trigger a reload of a directory in the tree.\n   *\n   * @param dir - The branch to load nodes for\n   */\n  declare loadNodes: (dir: Dir<Meta>) => Promise<void>;\n\n  constructor({\n    getNodes,\n    comparator,\n    root,\n  }: {\n    getNodes: GetNodesBase<FileTreeData<Meta>>;\n    comparator: (a: FileTreeNode<Meta>, b: FileTreeNode<Meta>) => number;\n    root: Dir<Meta>;\n  }) {\n    super({ getNodes, root });\n    // @ts-expect-error\n    this.comparator = comparator;\n  }\n\n  /**\n   * Get a node in the tree by its path. Note that this requires walking the tree,\n   * which has O(n) complexity. It should therefore be avoided unless absolutely necessary.\n   *\n   * @param path - The path to search for in the tree\n   */\n  getByPath(path: string) {\n    let found: FileTreeNode<Meta> | undefined;\n    path = pathFx.removeTrailingSlashes(pathFx.normalize(path));\n\n    this.walk(this.root, (node) => {\n      if (node.path === path) {\n        found = node;\n        return false;\n      }\n    });\n\n    return found;\n  }\n\n  /**\n   * Walks the tree starting at a given directory and calls a visitor\n   * function for each node.\n   *\n   * @param dir - The directory to walk\n   * @param visitor - A function that is called for each node in the tree. Returning\n   *   `false` will stop the walk.\n   * @example\n   * tree.walk(tree.root, node => {\n   *   console.log(node.path);\n   *\n   *   if (node.path === '/foo/bar') {\n   *     return false\n   *   }\n   * })\n   */\n  walk(\n    dir: Dir<Meta>,\n    visitor: (\n      node: FileTreeNode<Meta>,\n      parent: FileTreeNode<Meta>\n    ) => boolean | void\n  ) {\n    const nodeIds = !dir.nodes ? [] : [...dir.nodes];\n    let nodeId: number | undefined;\n\n    while ((nodeId = nodeIds.pop())) {\n      const node = this.getById(nodeId);\n      if (!node) continue;\n\n      const shouldContinue = visitor(node, dir);\n      if (shouldContinue === false) return;\n\n      if (isDir(node) && node.nodes) {\n        nodeIds.push(...node.nodes);\n      }\n    }\n  }\n\n  /**\n   * Produce a new tree with the given function applied to the given node.\n   * This is similar to `immer`'s produce function as you're working on a draft\n   * and can freely mutate the object.\n   *\n   * @param dir - The directory to produce the tree for\n   * @param produceFn - The function to produce the tree with\n   */\n  produce(\n    dir: Dir<Meta>,\n    produceFn: (\n      context: FileTreeFactory<Meta> & {\n        /**\n         * The draft of the directory.\n         */\n        get draft(): FileTreeNode<Meta>[];\n        /**\n         * Insert a node into the draft.\n         *\n         * @param node - The node to insert\n         */\n        insert<NodeType extends FileTreeNode<Meta>>(node: NodeType): NodeType;\n        /**\n         * Revert the draft back to its original state.\n         */\n        revert(): void;\n      }\n    ) => void | (Dir<Meta> | File<Meta>)[]\n  ) {\n    return this._produce(dir, (context) => {\n      const producer = produceFn({\n        get draft() {\n          return context.draft as (Dir<Meta> | File<Meta>)[];\n        },\n\n        insert(node) {\n          const insertedNode = context.insert(node, 0);\n          return insertedNode;\n        },\n\n        revert() {\n          context.revert();\n        },\n\n        createFile(data) {\n          return new File(dir, data);\n        },\n\n        createDir(data, expanded?: boolean) {\n          return new Dir(dir, data, expanded);\n        },\n\n        createPrompt() {\n          return new Prompt(dir, { name: \"\" });\n        },\n      });\n\n      return producer;\n    });\n  }\n\n  /**\n   * Move a node to a new parent.\n   *\n   * @param node - The node to move\n   * @param to - The new parent\n   */\n  move(node: File<Meta> | Dir<Meta>, to: Dir<Meta>) {\n    return super.move(node, to);\n  }\n\n  /**\n   * Create a new file in a given directory.\n   *\n   * @param inDir - The directory to create the file in\n   * @param withData - The data for the file\n   */\n  newFile(inDir: Dir<Meta>, withData: FileTreeData<Meta>) {\n    const file = new File(inDir, withData);\n\n    this.produce(inDir, ({ insert }) => {\n      insert(file);\n    });\n\n    return file;\n  }\n\n  /**\n   * Create a new directory in a given directory.\n   *\n   * @param inDir - The directory to create the directory in\n   * @param withData - The data for the directory\n   * @param expanded - Whether the directory should be expanded by default\n   */\n  newDir(inDir: Dir<Meta>, withData: FileTreeData<Meta>, expanded?: boolean) {\n    const dir = new Dir(inDir, withData, expanded);\n\n    this.produce(inDir, ({ insert }) => {\n      insert(dir);\n    });\n\n    return dir;\n  }\n\n  /**\n   * Create a new directory in a given directory.\n   *\n   * @param inDir - The directory to create the directory in\n   */\n  newPrompt(inDir: Dir<Meta>) {\n    const prompt = new Prompt(inDir, { name: \"\" });\n\n    this.produce(inDir, ({ insert }) => {\n      insert(prompt);\n    });\n\n    return prompt;\n  }\n\n  /**\n   * Rename a node.\n   *\n   * @param node - The node to rename\n   * @param newName - The new name for the node\n   */\n  rename(node: File<Meta> | Dir<Meta>, newName: string) {\n    node.data.name = newName;\n    const parent = node.parent;\n\n    if (parent && parent.nodes) {\n      this.setNodes(parent, [...parent.nodes]);\n    }\n  }\n}\n\nexport class File<Meta = {}> extends Leaf<FileTreeData<Meta>> {\n  readonly $$type = \"file\";\n  private _basenameName?: string;\n  private _basename?: string;\n\n  /**\n   * The parent directory of the file\n   */\n  get parent(): Dir<Meta> | null {\n    return this.parentId === -1\n      ? null\n      : (nodesById[this.parentId] as Dir<Meta>);\n  }\n\n  /**\n   * The basename of the file\n   */\n  get basename() {\n    if (this._basenameName === this.data.name) {\n      return this._basename!;\n    }\n\n    this._basenameName = this.data.name;\n    return (this._basename = pathFx.basename(this.data.name));\n  }\n\n  /**\n   * The full path of the file\n   */\n  get path(): string {\n    return getPath(this);\n  }\n}\n\nexport class Dir<Meta = {}> extends Branch<FileTreeData<Meta>> {\n  readonly $$type = \"dir\";\n  private _basenameName?: string;\n  private _basename?: string;\n\n  /**\n   * The parent directory of this directory\n   */\n  get parent(): Dir<Meta> | null {\n    return this.parentId === -1\n      ? null\n      : (nodesById[this.parentId] as Dir<Meta>);\n  }\n\n  /**\n   * The basename of the directory\n   */\n  get basename() {\n    if (this._basenameName === this.data.name) {\n      return this._basename!;\n    }\n\n    this._basenameName = this.data.name;\n    return (this._basename = pathFx.basename(this.data.name));\n  }\n\n  /**\n   * The full path of the directory\n   */\n  get path(): string {\n    return getPath(this);\n  }\n}\n\nexport class Prompt<Meta = {}> extends Leaf<FileTreeData<Meta>> {\n  readonly $$type = \"prompt\";\n  /**\n   * The parent directory of this directory\n   */\n  get parent(): Dir<Meta> | null {\n    return this.parentId === -1\n      ? null\n      : (nodesById[this.parentId] as Dir<Meta>);\n  }\n\n  get basename() {\n    return \"\";\n  }\n\n  /**\n   * The full path of the prompt\n   */\n  get path(): string {\n    return getPath(this);\n  }\n}\n\nfunction getPath(node: FileTreeNode) {\n  if (node.parent) {\n    const parentPath = node.parent.path;\n    const hasTrailingSlash = parentPath[parentPath.length - 1] === pathFx.SEP;\n    const sep =\n      hasTrailingSlash || parentPath === \"\" || node.basename === \"\"\n        ? \"\"\n        : pathFx.SEP;\n    return parentPath + sep + node.basename;\n  }\n\n  return pathFx.normalize(node.data.name);\n}\n\n/**\n * A sort comparator for sorting path names\n *\n * @param a - A tree node\n * @param b - A tree node to compare against `a`\n */\nexport function defaultComparator(a: FileTreeNode, b: FileTreeNode) {\n  if (a.constructor === b.constructor) {\n    return a.basename.localeCompare(b.basename);\n  }\n\n  if (isPrompt(a)) {\n    return -1;\n  } else if (isPrompt(b)) {\n    return 1;\n  } else if (isDir(a)) {\n    return -1;\n  } else if (isDir(b)) {\n    return 1;\n  }\n\n  return 0;\n}\n\n/**\n * Returns `true` if the given node is a prompt\n *\n * @param treeNode - A tree node\n */\nexport function isPrompt<Meta>(\n  treeNode: FileTreeNode<Meta>\n): treeNode is Prompt<Meta> {\n  return treeNode.constructor === Prompt;\n}\n\n/**\n * Returns `true` if the given node is a file\n *\n * @param treeNode - A tree node\n */\nexport function isFile<Meta>(\n  treeNode: FileTreeNode<Meta>\n): treeNode is File<Meta> {\n  return treeNode.constructor === File;\n}\n\n/**\n * Returns `true` if the given node is a directory\n *\n * @param treeNode - A tree node\n */\nexport function isDir<Meta>(\n  treeNode: FileTreeNode<Meta>\n): treeNode is Dir<Meta> {\n  return treeNode.constructor === Dir;\n}\n\nexport type FileTreeNode<Meta = {}> = File<Meta> | Dir<Meta> | Prompt<Meta>;\n\nexport type FileTreeData<Meta = {}> = {\n  name: string;\n  meta?: Meta;\n};\n\nexport type FileTreeFactory<Meta = {}> = {\n  /**\n   * Create a file node that can be inserted into the tree.\n   *\n   * @param data - The data to create a file with\n   */\n  createFile(data: FileTreeData<Meta>): File<Meta>;\n  /**\n   * Create a directory node that can be inserted into the tree.\n   *\n   * @param data - The data to create a directory with\n   * @param expanded - Should the directory be expanded by default?\n   */\n  createDir(data: FileTreeData<Meta>, expanded?: boolean): Dir<Meta>;\n  /**\n   * Create a prompt node that can be inserted into the tree.\n   */\n  createPrompt(): Prompt<Meta>;\n};\n\nexport type GetNodes<Meta> = {\n  /**\n   * Get the nodes for a given directory\n   *\n   * @param parent - The parent directory to get the nodes for\n   * @param factory - A factory to create nodes (file/dir) with\n   */\n  (parent: Dir<Meta>, factory: Omit<FileTreeFactory<Meta>, \"createPrompt\">):\n    | Promise<FileTreeNode<Meta>[]>\n    | FileTreeNode<Meta>[];\n};\n\nexport type FileTreeConfig<Meta> = {\n  /**\n   * A function that compares two nodes for sorting.\n   */\n  comparator?: FileTree[\"comparator\"];\n  /**\n   * The root node data\n   */\n  root?: Omit<FileTreeData<Meta>, \"type\">;\n  /**\n   * Restore the tree from a snapshot\n   */\n  restoreFromSnapshot?: FileTreeSnapshot;\n};\n","import memoizeOne from \"@essentials/memoize-one\";\nimport * as React from \"react\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim\";\nimport type { Subject } from \"./tree/subject\";\nimport { mergeProps as mergeProps_ } from \"./utils\";\n\n/**\n * A hook that observes to plugins and retrieves props that should be applied\n * to a given node. An example of a plugin wouuld be the `useTraits()` hook.\n *\n * @param nodeId - The node ID used to retrieve props from a plugin\n * @param plugins - A list of file tree plugins\n * @example\n * ```ts\n * const traits = useTraits(fileTree)\n * const props = useNodePlugins(fileTree.visibleNodes[0], [traits])\n * return <div {...props}>...</div>\n * ```\n */\nexport function useNodePlugins(\n  nodeId: number,\n  plugins: NodePlugin[] = []\n): React.HTMLAttributes<HTMLElement> {\n  const subject = createSubject(plugins);\n  const mergeProps = React.useRef(\n    memoizeOne(mergeProps_, (a, b) => shallowEqualArray(a[0], b[0]))\n  ).current;\n  const storedPlugins = React.useRef(plugins);\n\n  React.useEffect(() => {\n    storedPlugins.current = plugins;\n  });\n\n  const getSnapshot = React.useCallback(() => {\n    const plugins = storedPlugins.current;\n    const length = plugins.length;\n    const props: React.HTMLAttributes<HTMLElement>[] = new Array(length);\n    for (let i = 0; i < length; i++) props[i] = plugins[i].getProps(nodeId);\n    return mergeProps(props);\n  }, [mergeProps, nodeId]);\n\n  return useSyncExternalStore(subject, getSnapshot, getSnapshot);\n}\n\nconst createSubject = memoizeOne((plugins: NodePlugin[]) => {\n  return function subject(onStoreChange: () => void) {\n    const numPlugins = plugins.length;\n    const unsubs: (() => void)[] = new Array(numPlugins);\n    let i = 0;\n    for (; i < numPlugins; i++)\n      unsubs[i] = plugins[i].didChange.observe(onStoreChange);\n    return () => {\n      for (i = 0; i < unsubs.length; i++) unsubs[i]();\n    };\n  };\n}, shallowEqualArray);\n\nfunction shallowEqualArray(a: any[], b: any[]) {\n  if (a === b) return true;\n  if (a.length !== b.length) return false;\n  for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;\n  return true;\n}\n\nexport type NodePlugin<T = unknown> = {\n  /**\n   * A subject that the `useNodePlugins()` hook will observe to.\n   */\n  didChange: Subject<T>;\n  /**\n   * A function that returns React props based on a node ID.\n   *\n   * @param nodeId - The ID of a node in the file tree.\n   */\n  getProps(nodeId: number): React.HTMLAttributes<HTMLElement>;\n};\n","import * as React from \"react\";\nimport { isDir, isFile } from \"./file-tree\";\nimport type { FileTree, FileTreeNode } from \"./file-tree\";\nimport { subject } from \"./tree/subject\";\nimport type { NodePlugin } from \"./use-node-plugins\";\nimport { useNodePlugins } from \"./use-node-plugins\";\nimport { retryWithBackoff } from \"./utils\";\n\n/**\n * A React component that renders a node in a file tree with plugins. The\n * `<Node>` component uses this under the hood.\n *\n * @param props - Node props\n */\nexport function Node<Meta>(props: NodeProps<Meta>) {\n  const elementProps = useNodePlugins(props.node.id, [\n    ...(props.plugins ?? empty),\n    useNode(props.tree, props),\n  ]);\n\n  return React.createElement(props.as ?? \"div\", elementProps, props.children);\n}\n\n/**\n * A plugin that creates and memoizes node-specific props.\n *\n * @param fileTree - A file tree\n * @param config - Props to generate exploration node-specific props from\n */\nexport function useNode<Meta>(\n  fileTree: FileTree<Meta>,\n  config: UseNodeConfig<Meta>\n) {\n  const { node, index, style } = config;\n  const type = isDir(node) ? \"dir\" : isFile(node) ? \"file\" : \"prompt\";\n  const expanded = isDir(node) ? node.expanded : undefined;\n  const { id, depth } = node;\n  const props = React.useMemo<React.HTMLAttributes<HTMLElement>>(() => {\n    return {\n      role: \"button\",\n      style,\n      \"data-exploration-id\": id,\n      \"data-exploration-index\": index,\n      \"data-exploration-depth\": depth,\n      \"data-exploration-type\": type,\n      \"data-exploration-expanded\": expanded,\n      onClick(event) {\n        event.currentTarget.focus();\n\n        if (\n          event.metaKey ||\n          event.shiftKey ||\n          event.altKey ||\n          event.ctrlKey ||\n          event.button === 2\n        ) {\n          return;\n        }\n\n        if (isDir(node)) {\n          if (expanded) {\n            fileTree.collapse(node);\n          } else {\n            retryWithBackoff(() => fileTree.expand(node), {\n              shouldRetry() {\n                return node.expanded && !fileTree.isExpanded(node);\n              },\n            }).catch(() => {});\n          }\n        }\n      },\n    };\n  }, [index, depth, expanded, style, type, node, fileTree, id]);\n\n  return {\n    didChange: noopSubject,\n    getProps() {\n      return props;\n    },\n  };\n}\n\nconst empty: [] = [];\nconst noopSubject = subject(0);\n\nexport interface NodeProps<Meta> {\n  /**\n   * Render the node as this component\n   *\n   * @default \"div\"\n   */\n  as?: React.ComponentType<React.HTMLAttributes<HTMLElement>>;\n  /**\n   *  A file tree node\n   */\n  node: FileTreeNode<Meta>;\n  /**\n   * The index of the node within the file tree list of visible nodes\n   */\n  index: number;\n  /**\n   * The file tree that contains the node\n   */\n  tree: FileTree<Meta>;\n  /**\n   * A list of plugins to apply to the node. For example `useTraits()`.\n   */\n  plugins?: NodePlugin[];\n  /**\n   * Styles to apply to the `<div>` element\n   */\n  style: React.CSSProperties;\n  /**\n   * Children to render within the node\n   */\n  children: React.ReactNode;\n}\n\nexport type UseNodeConfig<Meta> = Pick<\n  NodeProps<Meta>,\n  \"node\" | \"index\" | \"style\"\n>;\n","import * as React from \"react\";\nimport type { Observer, Subject } from \"./tree/subject\";\n\n/**\n * A hook for observing changes to the value of a subject.\n *\n * @param subject - A subject to observe\n * @param observer - A callback that is invoked when the subject changes\n */\nexport function useObserver<T>(subject: Subject<T>, observer: Observer<T>) {\n  const storedObserver = React.useRef(observer);\n\n  React.useEffect(() => {\n    storedObserver.current = observer;\n  });\n\n  React.useEffect(() => {\n    let didUnmount = false;\n    let cleanup: void | (() => void);\n\n    const unobserve = subject.observe((value) => {\n      if (didUnmount) return;\n      cleanup?.();\n      cleanup = storedObserver.current(value);\n    });\n\n    return () => {\n      didUnmount = true;\n      cleanup?.();\n      unobserve();\n    };\n  }, [subject]);\n}\n","import * as React from \"react\";\nimport trieMemoize from \"trie-memoize\";\nimport type { Dir, FileTree, FileTreeNode } from \"./file-tree\";\nimport { isDir } from \"./file-tree\";\nimport type { Subject } from \"./tree/subject\";\nimport { pureSubject } from \"./tree/subject\";\nimport type { WindowRef } from \"./types\";\nimport { useObserver } from \"./use-observer\";\nimport { retryWithBackoff, shallowEqual } from \"./utils\";\n\n/**\n * A plugin hook for adding drag and drop to the file tree.\n *\n * @param fileTree - A file tree\n * @param config - Configuration options\n * @param config.windowRef - A React ref created by useRef() or an HTML element for the\n *   container viewport you're rendering the list inside of.\n * @param config.dragOverExpandTimeout - Timeout for expanding a directory when a draggable\n *   element enters it.\n */\nexport function useDnd<Meta>(\n  fileTree: FileTree<Meta>,\n  config: UseDndConfig\n): UseDndPlugin<Meta> {\n  const storedConfig = React.useRef(config);\n  const dnd = createDnd(fileTree);\n  const storedTimeout = React.useRef<{\n    id: number;\n    timeout: ReturnType<typeof setTimeout> | null;\n  }>({ id: -1, timeout: null });\n  const storedDir = React.useRef<Dir | null>(null);\n\n  React.useEffect(() => {\n    storedConfig.current = config;\n  });\n\n  useObserver(dnd, (event) => {\n    if (!event) return;\n\n    if (event.type === \"enter\") {\n      storedTimeout.current.timeout &&\n        clearTimeout(storedTimeout.current.timeout);\n      storedTimeout.current.id = event.dir.id;\n      storedDir.current = event.dir;\n\n      storedTimeout.current.timeout = setTimeout(() => {\n        if (!event.dir.expanded) {\n          retryWithBackoff(\n            () =>\n              fileTree.expand(event.dir).then(() => {\n                if (event.dir === storedDir.current) {\n                  dnd.setState({ ...event, type: \"expanded\" });\n                }\n              }),\n            {\n              shouldRetry() {\n                return (\n                  event.dir === storedDir.current &&\n                  !fileTree.isExpanded(event.dir)\n                );\n              },\n            }\n          ).catch(() => {});\n        }\n      }, storedConfig.current.dragOverExpandTimeout ?? DEFAULT_DRAG_OVER_EXPAND_TIMEOUT);\n    } else if (\n      event.type === \"end\" ||\n      (event.type === \"leave\" && storedTimeout.current.id === event.dir.id)\n    ) {\n      storedDir.current = null;\n      storedTimeout.current.timeout &&\n        clearTimeout(storedTimeout.current.timeout);\n    } else if (event.type === \"drop\") {\n      storedDir.current = null;\n      storedTimeout.current.timeout &&\n        clearTimeout(storedTimeout.current.timeout);\n    }\n  });\n\n  React.useEffect(() => {\n    const { windowRef } = storedConfig.current;\n    const windowEl =\n      windowRef && \"current\" in windowRef ? windowRef.current : windowRef;\n\n    if (windowEl) {\n      const handlers = createProps(dnd, fileTree.root);\n\n      const isCurrentTarget = (event: Event) => {\n        return (\n          event.currentTarget instanceof HTMLElement &&\n          (event.currentTarget === event.target ||\n            event.currentTarget.firstChild === event.target)\n        );\n      };\n\n      const handleDragEnter = (event: Event) => {\n        if (isCurrentTarget(event)) {\n          // @ts-expect-error: technically incompatible types but that is ok\n          handlers.onDragEnter(event);\n        }\n      };\n      const handleDragOver = (event: Event) => {\n        if (isCurrentTarget(event)) {\n          // @ts-expect-error: technically incompatible types but that is ok\n          handlers.onDragOver(event);\n        }\n      };\n      const handleDragLeave = (event: Event) => {\n        if (isCurrentTarget(event)) {\n          // @ts-expect-error: technically incompatible types but that is ok\n          handlers.onDragLeave(event);\n        }\n      };\n      const handleDrop = (event: Event) => {\n        if (isCurrentTarget(event)) {\n          // @ts-expect-error: technically incompatible types but that is ok\n          handlers.onDrop(event);\n        }\n      };\n      windowEl.addEventListener(\"dragenter\", handleDragEnter);\n      windowEl.addEventListener(\"dragover\", handleDragOver);\n      windowEl.addEventListener(\"dragleave\", handleDragLeave);\n      windowEl.addEventListener(\"drop\", handleDrop);\n\n      return () => {\n        windowEl.removeEventListener(\"dragenter\", handleDragEnter);\n        windowEl.removeEventListener(\"dragover\", handleDragOver);\n        windowEl.removeEventListener(\"dragleave\", handleDragLeave);\n        windowEl.removeEventListener(\"drop\", handleDrop);\n      };\n    }\n  }, [dnd, fileTree.root]);\n\n  return {\n    didChange: dnd,\n\n    getProps(nodeId) {\n      const node = fileTree.getById(nodeId);\n      if (!node) return empty;\n      return createProps(dnd, node);\n    },\n  };\n}\n\nconst DEFAULT_DRAG_OVER_EXPAND_TIMEOUT = 400;\nconst empty = {};\n\nconst createProps = trieMemoize(\n  [WeakMap, WeakMap],\n  <Meta>(\n    dnd: Subject<DndEvent<Meta> | null>,\n    node: FileTreeNode<Meta>\n  ): DndProps => ({\n    draggable: true,\n\n    onDragStart() {\n      dnd.setState({ type: \"start\", node });\n    },\n\n    onDragEnd() {\n      dnd.setState({ type: \"end\", node });\n    },\n\n    onDragEnter() {\n      const dir = isDir(node) ? node : node.parent;\n      const state = dnd.getState();\n\n      if (dir && state?.node) {\n        dnd.setState({ type: \"enter\", node: state.node, dir });\n      }\n    },\n\n    onDragOver(event) {\n      event.preventDefault();\n    },\n\n    onDragLeave() {\n      const dir = isDir(node) ? node : node.parent;\n      const state = dnd.getState();\n\n      if (dir && state && state.type === \"enter\" && state.node) {\n        dnd.setState({ type: \"leave\", node: state.node, dir });\n      }\n    },\n\n    onDrop() {\n      const dir = isDir(node) ? node : node.parent;\n      const state = dnd.getState();\n\n      if (dir && state?.node) {\n        dnd.setState({ type: \"drop\", node: state.node, dir });\n      }\n    },\n  })\n);\n\nconst createDnd = trieMemoize([WeakMap], <Meta>(fileTree: FileTree<Meta>) => {\n  return pureSubject<DndEvent<Meta> | null>(null, shallowEqual);\n});\n\nexport type DndEvent<Meta> =\n  | {\n      type: \"start\";\n      /**\n       * The node that is being dragged\n       */\n      node: FileTreeNode<Meta>;\n    }\n  | {\n      type: \"end\";\n      /**\n       * The node that is being dragged\n       */\n      node: FileTreeNode<Meta>;\n    }\n  | {\n      type: \"enter\";\n      /**\n       * The node that is being dragged\n       */\n      node: FileTreeNode<Meta>;\n      /**\n       * The directory that the node is being dragged over\n       */\n      dir: Dir<Meta>;\n    }\n  | {\n      type: \"expanded\";\n      /**\n       * The node that is being dragged\n       */\n      node: FileTreeNode<Meta>;\n      /**\n       * The directory that the node is being dragged over\n       */\n      dir: Dir<Meta>;\n    }\n  | {\n      type: \"leave\";\n      /**\n       * The node that is being dragged\n       */\n      node: FileTreeNode<Meta>;\n      /**\n       * The directory that the node was being dragged over\n       */\n      dir: Dir<Meta>;\n    }\n  | {\n      type: \"drop\";\n      /**\n       * The node that is being dragged\n       */\n      node: FileTreeNode<Meta>;\n      /**\n       * The directory that the node is being dragged over\n       */\n      dir: Dir<Meta>;\n    };\n\nexport interface DndProps {\n  draggable: true;\n  onDragStart: React.MouseEventHandler<HTMLElement>;\n  onDragEnd: React.MouseEventHandler<HTMLElement>;\n  onDragOver: React.MouseEventHandler<HTMLElement>;\n  onDragEnter: React.MouseEventHandler<HTMLElement>;\n  onDragLeave: React.MouseEventHandler<HTMLElement>;\n  onDrop: React.MouseEventHandler<HTMLElement>;\n}\n\nexport interface UseDndConfig {\n  /**\n   * Timeout for expanding a directory when a draggable element enters it.\n   */\n  dragOverExpandTimeout?: number;\n  /**\n   * A React ref created by useRef() or an HTML element for the container viewport\n   * you're rendering the list inside of.\n   */\n  windowRef: WindowRef;\n}\n\nexport interface UseDndPlugin<Meta> {\n  /**\n   * A subject that emits drag 'n drop events.\n   */\n  didChange: Subject<DndEvent<Meta> | null>;\n  /**\n   * Get the drag 'n drop props for a given node ID.\n   */\n  getProps: (nodeId: number) => DndProps | React.HTMLAttributes<HTMLElement>;\n}\n","import { useSyncExternalStore } from \"use-sync-external-store/shim\";\nimport type { FileTree } from \"./file-tree\";\n\n/**\n * A hook that observes to updates to the file tree and returns the nodes that\n * are currently visible in the file tree.\n *\n * @param fileTree - A file tree\n * @example\n * ```tsx\n * const visibleNodes = useVisibleNodes(fileTree)\n * return visibleNodes.map((node) => <div className={`depth-${node.depth}`}>{node.basename}</div>)\n * ```\n */\nexport function useVisibleNodes<Meta>(fileTree: FileTree<Meta>) {\n  return (\n    useSyncExternalStore(\n      fileTree.flatView.observe,\n      fileTree.getSnapshot,\n      fileTree.getSnapshot\n    ) ?? empty\n  );\n}\n\nconst empty: number[] = [];\n","import * as React from \"react\";\nimport type { FileTree, FileTreeNode } from \"./file-tree\";\nimport { useDeferredValue } from \"./use-deferred-value\";\nimport { useVisibleNodes } from \"./use-visible-nodes\";\n\n/**\n * A hook that returns filtered visible nodes based on a filter function.\n *\n * @param fileTree - The file tree to use.\n * @param filter - A _stable_ callback that returns `true` if the node should be visible.\n *   This needs to be memoized or hoisted to the top level to ensure the filtered nodes\n *   only get re-generated when the filter changes or the file tree's visible nodes change.\n */\nexport function useFilter<Meta>(\n  fileTree: FileTree<Meta>,\n  filter: ((node: FileTreeNode<Meta>, i: number) => boolean) | null\n) {\n  const visibleNodes = useVisibleNodes(fileTree);\n\n  const value = React.useMemo(() => {\n    if (filter) {\n      const filteredNodes = [];\n\n      for (let i = 0; i < visibleNodes.length; i++) {\n        const nodeId = visibleNodes[i];\n        const node = fileTree.getById(nodeId);\n\n        if (node && filter(node, i)) {\n          filteredNodes.push(nodeId);\n        }\n      }\n\n      return filteredNodes;\n    }\n\n    return visibleNodes;\n  }, [fileTree, visibleNodes, filter]);\n\n  return useDeferredValue(value);\n}\n","import { useHotkeys as useHotkeys_ } from \"@react-hook/hotkey\";\nimport type { FileTree } from \"./file-tree\";\nimport { isDir } from \"./file-tree\";\nimport type { WindowRef } from \"./types\";\nimport type { useRovingFocus } from \"./use-roving-focus\";\nimport type { useSelections } from \"./use-selections\";\nimport { useVisibleNodes } from \"./use-visible-nodes\";\nimport { retryWithBackoff } from \"./utils\";\n\n/**\n * A hook for adding standard hotkeys to the file tree.\n *\n * @param fileTree - A file tree\n * @param config - Configuration options\n */\nexport function useHotkeys(fileTree: FileTree, config: UseHotkeysConfig) {\n  const {\n    nodes,\n    windowRef,\n    rovingFocus,\n    selections,\n    querySelectorPattern = `[data-exploration-index=\"{index}\"]`,\n  } = config;\n  const visibleNodes_ = useVisibleNodes(fileTree);\n  const visibleNodes = nodes ?? visibleNodes_;\n\n  function getSelectedId() {\n    const rovingId = rovingFocus.didChange.getState();\n    return rovingId > -1 ? rovingId : selections.tail ?? -1;\n  }\n\n  function getSelectedIndex() {\n    return visibleNodes.indexOf(getSelectedId());\n  }\n\n  // @ts-expect-error: `window` isn't explicitly allowed but it works\n  useHotkeys_(windowRef, [\n    [\n      \"up\",\n      (event) => {\n        if (\n          event.target instanceof HTMLInputElement ||\n          event.target instanceof HTMLTextAreaElement\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const selectedIndex = getSelectedIndex();\n        const nextSelector = querySelectorPattern.replace(\n          \"{index}\",\n          `${Math.max(selectedIndex - 1, 0)}`\n        );\n\n        const element = document.querySelector(nextSelector);\n\n        if (element instanceof HTMLElement) {\n          element.focus();\n        }\n      },\n    ],\n\n    [\n      \"down\",\n      (event) => {\n        if (\n          event.target instanceof HTMLInputElement ||\n          event.target instanceof HTMLTextAreaElement\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const selectedIndex = getSelectedIndex();\n        const nextSelector = querySelectorPattern.replace(\n          \"{index}\",\n          `${Math.min(selectedIndex + 1, visibleNodes.length)}`\n        );\n\n        const element = document.querySelector(nextSelector);\n\n        if (element instanceof HTMLElement) {\n          element.focus();\n        }\n      },\n    ],\n\n    [\n      \"right\",\n      async (event) => {\n        if (\n          event.target instanceof HTMLInputElement ||\n          event.target instanceof HTMLTextAreaElement\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const nodeId = getSelectedId();\n        const selectedIndex = getSelectedIndex();\n        const node = fileTree.getById(nodeId);\n\n        if (node && isDir(node)) {\n          if (!fileTree.isExpanded(node)) {\n            await fileTree.expand(node);\n          } else if (fileTree.isVisible(node) && node.nodes?.length) {\n            const element = document.querySelector(\n              querySelectorPattern.replace(\n                \"{index}\",\n                `${Math.min(selectedIndex + 1, visibleNodes.length)}`\n              )\n            );\n\n            if (element instanceof HTMLElement) {\n              element.focus();\n            }\n          }\n        }\n      },\n    ],\n\n    [\n      \"left\",\n      (event) => {\n        if (\n          event.target instanceof HTMLInputElement ||\n          event.target instanceof HTMLTextAreaElement\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const nodeId = getSelectedId();\n        const node = fileTree.getById(nodeId);\n\n        if (node && isDir(node)) {\n          if (node.expanded) {\n            fileTree.collapse(node);\n            return;\n          }\n        }\n\n        if (node && node.parent) {\n          const parentIndex = visibleNodes.indexOf(node.parent.id);\n          const element = document.querySelector(\n            querySelectorPattern.replace(\"{index}\", parentIndex + \"\")\n          );\n\n          if (element instanceof HTMLElement) {\n            element.focus();\n          }\n        }\n      },\n    ],\n\n    [\n      \"space\",\n      (event) => {\n        if (\n          event.target instanceof HTMLInputElement ||\n          event.target instanceof HTMLTextAreaElement\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const nodeId = getSelectedId();\n        const selectedIndex = getSelectedIndex();\n\n        if (selectedIndex > -1) {\n          const element = document.querySelector(\n            querySelectorPattern.replace(\"{index}\", selectedIndex + \"\")\n          );\n\n          if (element instanceof HTMLElement) {\n            element.focus();\n          }\n\n          const node = fileTree.getById(nodeId);\n\n          if (node) {\n            if (isDir(node)) {\n              if (node.expanded) {\n                fileTree.collapse(node);\n              } else {\n                retryWithBackoff(() => fileTree.expand(node), {\n                  shouldRetry() {\n                    return node.expanded && !fileTree.isExpanded(node);\n                  },\n                }).catch(() => {});\n              }\n            } else {\n              selections.clear();\n              selections.select(nodeId);\n            }\n          }\n        }\n      },\n    ],\n\n    [\n      \"home\",\n      (event) => {\n        if (\n          event.target instanceof HTMLInputElement ||\n          event.target instanceof HTMLTextAreaElement\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const element = document.querySelector(\n          querySelectorPattern.replace(\"{index}\", \"0\")\n        );\n\n        if (element instanceof HTMLElement) {\n          element.focus();\n        }\n      },\n    ],\n\n    [\n      \"end\",\n      (event) => {\n        if (\n          event.target instanceof HTMLInputElement ||\n          event.target instanceof HTMLTextAreaElement\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const element = document.querySelector(\n          querySelectorPattern.replace(\"{index}\", visibleNodes.length - 1 + \"\")\n        );\n\n        if (element instanceof HTMLElement) {\n          element.focus();\n        }\n      },\n    ],\n\n    [\n      \"escape\",\n      (event) => {\n        if (\n          event.target instanceof HTMLInputElement ||\n          event.target instanceof HTMLTextAreaElement\n        ) {\n          return;\n        }\n\n        event.preventDefault();\n        const rovingId = rovingFocus.didChange.getState();\n        const selectedIndex = visibleNodes.indexOf(rovingId);\n\n        if (rovingId > -1) {\n          rovingFocus.didChange.setState(-1);\n        }\n\n        selections.clear();\n\n        if (selectedIndex > -1) {\n          const element = document.querySelector(\n            querySelectorPattern.replace(\"{index}\", selectedIndex + \"\")\n          );\n\n          if (element instanceof HTMLElement) {\n            element.blur();\n\n            if (windowRef && \"current\" in windowRef) {\n              windowRef.current?.focus();\n            } else if (windowRef) {\n              windowRef.focus();\n            }\n          }\n        }\n      },\n    ],\n  ]);\n}\n\nexport interface UseHotkeysConfig {\n  /**\n   * When using a hook like `useFilter` you can supply the filtered list of\n   * nodes to this option. By default, `useVirtualize()` uses the nodes returned\n   * by `useVisibleNodes()`\n   */\n  nodes?: number[];\n  /**\n   * A React ref created by useRef() or an HTML element for the container viewport\n   * you're rendering the list inside of.\n   */\n  windowRef: WindowRef;\n  /**\n   * The returned value of the `useRovingFocus()` plugin\n   */\n  rovingFocus: ReturnType<typeof useRovingFocus>;\n  /**\n   * The returned value of the `useSelections()` plugin\n   */\n  selections: ReturnType<typeof useSelections>;\n  /**\n   * A pattern to use for selecting the elements in the list. Must contain an\n   * `{index}` placeholder for the index of the element to select.\n   */\n  querySelectorPattern?: string;\n}\n","import type { FileTree } from \"./file-tree\";\nimport { isDir } from \"./file-tree\";\nimport type { FileTreeSnapshot } from \"./types\";\nimport { useObserver } from \"./use-observer\";\n\n/**\n * Take a snapshot of the expanded and buried directories of a file tree.\n * This snapshot can be used to restore the expanded/collapsed state of the\n * file tree when you initially load it.\n *\n * @param fileTree - A file tree\n * @param observer - A callback that handles the file tree snapshot\n */\nexport function useFileTreeSnapshot<Meta>(\n  fileTree: FileTree<Meta>,\n  observer: (state: FileTreeSnapshot) => Promise<void> | void\n) {\n  useObserver(fileTree.flatView, () => {\n    const expandedPaths: string[] = [];\n    const nodeIds = [...fileTree.visibleNodes];\n    const buriedIds: number[] = [];\n    let nodeId: number | undefined;\n\n    while ((nodeId = nodeIds.pop())) {\n      const node = fileTree.getById(nodeId);\n\n      if (node && isDir(node)) {\n        if (node.expanded) {\n          expandedPaths.push(node.path);\n        } else if (node.nodes) {\n          buriedIds.push(...node.nodes);\n        }\n      }\n    }\n\n    const buriedPaths: string[] = [];\n\n    while ((nodeId = buriedIds.pop())) {\n      const node = fileTree.getById(nodeId);\n\n      if (!node) continue;\n      if (isDir(node)) {\n        if (node.expanded) {\n          buriedPaths.push(node.path);\n        }\n\n        if (node.nodes) {\n          buriedIds.push(...node.nodes);\n        }\n      }\n    }\n\n    observer({ expandedPaths, buriedPaths, version: SNAPSHOT_VERSION })?.catch(\n      () => {}\n    );\n  });\n}\n\nconst SNAPSHOT_VERSION = 1;\n","import * as React from \"react\";\nimport trieMemoize from \"trie-memoize\";\nimport type { FileTree } from \"./file-tree\";\nimport { SubjectMap } from \"./observable-data\";\nimport type { Subject } from \"./tree/subject\";\n\n/**\n * A hook that allows you to arbitrarily apply traits/decorations to nodes in the file\n * tree. For example, if you wanted to add a class name to a node in the tree if it were\n * selected, focused, et. al. you could use this hook to do that. Another example would\n * be the `M` modified decorations in VSCode.\n *\n * @param fileTree - A file tree\n * @param traits - The list of available traits that can be applied to nodes\n */\nexport function useTraits<Trait extends string>(\n  fileTree: FileTree,\n  traits: Trait[]\n): UseTraitsPlugin<Trait> {\n  const storedTraits = React.useRef(traits);\n  const traitsMap = createTraitsMap(fileTree);\n\n  React.useEffect(() => {\n    storedTraits.current = traits;\n  });\n\n  return {\n    didChange: traitsMap.didChange,\n    getProps(nodeId) {\n      let className = \"\";\n\n      for (const entry of traitsMap) {\n        if (entry[1].has(nodeId)) {\n          className += entry[0] + \" \";\n        }\n      }\n\n      return createProps(className);\n    },\n\n    add(trait, ...nodeIds) {\n      const traitSet = traitsMap.get(trait) ?? new Set<number>();\n\n      for (let i = 0; i < nodeIds.length; i++) {\n        const nodeId = nodeIds[i];\n        traitSet.add(nodeId);\n      }\n\n      traitsMap.set(trait, traitSet);\n    },\n\n    set(trait, nodeIds) {\n      const traitSet = traitsMap.get(trait) ?? new Set<number>();\n\n      if (traitSet) {\n        traitSet.clear();\n      }\n\n      for (let i = 0; i < nodeIds.length; i++) {\n        traitSet.add(nodeIds[i]);\n      }\n\n      traitsMap.set(trait, traitSet);\n    },\n\n    delete(trait, nodeId) {\n      const traitSet = traitsMap.get(trait) ?? new Set<number>();\n\n      if (traitSet) {\n        traitSet.delete(nodeId);\n      }\n\n      traitsMap.set(trait, traitSet);\n    },\n\n    clear(trait) {\n      const traitSet = traitsMap.get(trait) ?? new Set<number>();\n      traitSet.clear();\n      traitsMap.set(trait, traitSet);\n    },\n\n    clearAll() {\n      for (const trait of storedTraits.current) {\n        const traitSet = traitsMap.get(trait) ?? new Set<number>();\n        traitSet.clear();\n        traitsMap.set(trait, traitSet);\n      }\n    },\n\n    clearNode(nodeId) {\n      for (const trait of storedTraits.current) {\n        const traitSet = traitsMap.get(trait) ?? new Set<number>();\n        traitSet.delete(nodeId);\n        traitsMap.set(trait, traitSet);\n      }\n    },\n  };\n}\n\nconst createProps = trieMemoize([Map], (className: string): TraitsProps => {\n  return { className: className.slice(0, -1) };\n});\n\nconst createTraitsMap = trieMemoize(\n  [WeakMap],\n  (fileTree: FileTree) => new SubjectMap<string, Set<number>>()\n);\n\nexport interface TraitsProps {\n  className?: string;\n}\n\nexport interface UseTraitsPlugin<Trait> {\n  /**\n   * A subject that you can use to observe to changes to traits.\n   */\n  didChange: Subject<Map<string, Set<number>>>;\n  /**\n   * Get the React props for a given node ID.\n   *\n   * @param nodeId - A node ID\n   */\n  getProps(nodeId: number): TraitsProps;\n  /**\n   * Adds a trait to given node IDs\n   *\n   * @param trait - The trait to apply to the given node IDs\n   * @param nodeIds - Node IDs to add the traits to\n   */\n  add(trait: Extract<Trait, string>, ...nodeIds: number[]): void;\n  /**\n   * Sets node IDs to a given trait. This is different from add in\n   * that it replaces any exist node IDs assigned to the trait.\n   *\n   * @param trait - The trait to apply to the given node IDs\n   * @param nodeIds - Node IDs to add the traits to\n   */\n  set(trait: Extract<Trait, string>, nodeIds: number[]): void;\n  /**\n   * Deletes a node ID from a given trait\n   *\n   * @param trait - The trait\n   * @param nodeId - The node ID to delete a trait for\n   */\n  delete(trait: Extract<Trait, string>, nodeId: number): void;\n  /**\n   * Clears all of the node IDs assigned to a given trait\n   *\n   * @param trait - The trait\n   */\n  clear(trait: Extract<Trait, string>): void;\n  /**\n   * Clears all of the node IDs assigned to all traits\n   */\n  clearAll(): void;\n  /**\n   * Clears the traits assigned to a given node ID\n   *\n   * @param nodeId - A node ID\n   */\n  clearNode(nodeId: number): void;\n}\n","import type * as React from \"react\";\nimport trieMemoize from \"trie-memoize\";\nimport type { FileTree } from \"./file-tree\";\nimport type { Subject } from \"./tree/subject\";\nimport { subject } from \"./tree/subject\";\n\n/**\n * A plugin hook for adding roving focus to file tree nodes.\n *\n * @param fileTree - A file tree\n */\nexport function useRovingFocus<Meta>(\n  fileTree: FileTree<Meta>\n): UseRovingFocusPlugin {\n  const focusedNodeId = createFocusedNodeId(fileTree);\n\n  return {\n    didChange: focusedNodeId,\n\n    getProps(nodeId) {\n      return createProps(\n        focusedNodeId,\n        nodeId,\n        nodeId === focusedNodeId.getState()\n      );\n    },\n  };\n}\n\nconst createProps = trieMemoize(\n  [WeakMap, Map, Map],\n  (\n    focusedNodeId: Subject<number>,\n    nodeId: number,\n    focused: boolean\n  ): RovingFocusProps => {\n    return {\n      tabIndex: focused ? 0 : -1,\n\n      onFocus() {\n        focusedNodeId.setState(nodeId);\n      },\n\n      onBlur() {\n        if (focused) {\n          focusedNodeId.setState(-1);\n        }\n      },\n    };\n  }\n);\n\nconst createFocusedNodeId = trieMemoize(\n  [WeakMap],\n  <Meta>(fileTree: FileTree<Meta>) => subject(-1)\n);\n\nexport interface RovingFocusProps {\n  tabIndex: number;\n  onFocus(e: React.FocusEvent<HTMLElement>): void;\n  onBlur(e: React.FocusEvent<HTMLElement>): void;\n}\n\nexport interface UseRovingFocusPlugin {\n  /**\n   * A subject that you can use to observe to changes to the focused node.\n   */\n  didChange: Subject<number>;\n  /**\n   * Get the React props for a given node ID.\n   *\n   * @param nodeId - A node ID\n   */\n  getProps: (nodeId: number) => RovingFocusProps;\n}\n","import * as React from \"react\";\nimport trieMemoize from \"trie-memoize\";\nimport type { FileTree } from \"./file-tree\";\nimport { SubjectSet } from \"./observable-data\";\nimport { nodesById } from \"./tree/nodes-by-id\";\nimport type { Subject } from \"./tree/subject\";\nimport { useVisibleNodes } from \"./use-visible-nodes\";\n\n/**\n * A hook for adding select and multi-select to the file tree.\n *\n * @param fileTree - A file tree\n * @param nodes - When using a hook like `useFilter` you can supply the filtered list of\n *   nodes to this option. By default, `useVirtualize()` uses the nodes returned by\n *   `useVisibleNodes()`\n */\nexport function useSelections<Meta>(\n  fileTree: FileTree<Meta>,\n  nodes?: number[]\n): UseSelectionsPlugin {\n  const visibleNodes_ = useVisibleNodes(fileTree);\n  const visibleNodes = nodes ?? visibleNodes_;\n  const prevSelectionsSet = React.useRef<SubjectRange<number> | null>(null);\n  const selectionsSet = createSelectionsSet(fileTree, nodes ?? emptyArray);\n\n  React.useEffect(() => {\n    if (prevSelectionsSet.current) {\n      for (const nodeId of prevSelectionsSet.current) {\n        selectionsSet.add(nodeId);\n      }\n    }\n\n    prevSelectionsSet.current = selectionsSet;\n  }, [selectionsSet]);\n\n  return {\n    didChange: selectionsSet.didChange,\n\n    get head() {\n      return selectionsSet.head;\n    },\n\n    get tail() {\n      return selectionsSet.tail;\n    },\n\n    getProps(nodeId: number) {\n      return createProps(selectionsSet, visibleNodes, nodeId);\n    },\n\n    select(...nodeIds: number[]) {\n      for (const nodeId of nodeIds) {\n        selectionsSet.add(nodeId);\n      }\n    },\n\n    deselect(...nodeIds: number[]) {\n      for (const nodeId of nodeIds) {\n        selectionsSet.delete(nodeId);\n      }\n    },\n\n    clear() {\n      selectionsSet.clear();\n    },\n\n    narrow: function* () {\n      // Remove child nodes from selections if their parent is already selected\n      for (const nodeId of selectionsSet) {\n        const node = nodesById[nodeId];\n\n        if (node) {\n          let parentId = node.parentId;\n\n          while (parentId > -1) {\n            if (selectionsSet.has(parentId)) {\n              break;\n            }\n\n            const parentNode = nodesById[parentId];\n\n            if (!parentNode) {\n              break;\n            }\n\n            parentId = parentNode.parentId;\n          }\n\n          if (parentId === -1) {\n            yield nodeId;\n          }\n        }\n      }\n    },\n  };\n}\n\nconst emptyArray: number[] = [];\n\nconst createProps = trieMemoize(\n  [WeakMap, WeakMap, Map],\n  (\n    selectionsSet: SubjectRange<number>,\n    visibleNodes: number[],\n    nodeId: number\n  ): SelectionsProps => {\n    return {\n      onClick(event) {\n        if (!visibleNodes) {\n          return;\n        }\n\n        if (event.shiftKey) {\n          const { head, tail } = selectionsSet;\n          const headIndex = !head ? -1 : visibleNodes.indexOf(head);\n          const tailIndex = !tail ? -1 : visibleNodes.indexOf(tail);\n          const nodeIndex = visibleNodes.indexOf(nodeId);\n          const direction = tailIndex > nodeIndex ? -1 : 1;\n\n          // Select range\n          let selectStart = tailIndex;\n          let selectEnd = nodeIndex;\n\n          if (direction === 1) {\n            selectStart = tailIndex;\n          } else {\n            selectStart = nodeIndex;\n            selectEnd = tailIndex;\n          }\n\n          if (selectStart > -1 && selectEnd > -1) {\n            for (let i = selectStart; i <= selectEnd; i++) {\n              const node = visibleNodes[i];\n              selectionsSet.add(node);\n            }\n          }\n\n          // Deselect range\n          let deselectStart = -1;\n          let deselectEnd = -1;\n\n          if (direction === 1 && headIndex > tailIndex) {\n            deselectStart = tailIndex;\n            deselectEnd = Math.min(headIndex, nodeIndex) - 1;\n          } else if (direction === -1 && headIndex < tailIndex) {\n            deselectStart = Math.max(headIndex, nodeIndex) + 1;\n            deselectEnd = tailIndex;\n          }\n\n          if (deselectStart > -1 && deselectEnd > -1) {\n            for (let i = deselectStart; i <= deselectEnd; i++) {\n              const node = visibleNodes[i];\n              selectionsSet.delete(node);\n            }\n          }\n\n          if (selectionsSet.head === null) {\n            selectionsSet.head = nodeId;\n          }\n        } else if (event.metaKey) {\n          if (selectionsSet.has(nodeId)) {\n            selectionsSet.delete(nodeId);\n          } else {\n            selectionsSet.add(nodeId);\n          }\n\n          selectionsSet.head = nodeId;\n        } else {\n          selectionsSet.clear();\n          selectionsSet.add(nodeId);\n          selectionsSet.head = nodeId;\n        }\n\n        selectionsSet.tail = nodeId;\n      },\n    };\n  }\n);\n\nconst createSelectionsSet = trieMemoize(\n  [WeakMap, WeakMap],\n  <Meta>(fileTree: FileTree<Meta>, visibleNodes: number[]) =>\n    new SubjectRange<number>()\n);\n\nclass SubjectRange<T> extends SubjectSet<T> {\n  head: T | null = null;\n  tail: T | null = null;\n\n  add(value: T) {\n    super.add(value);\n\n    if (this.head === null) {\n      this.head = value;\n    }\n\n    this.tail = value;\n    return this;\n  }\n\n  delete(value: T) {\n    const deleted = super.delete(value);\n    return deleted;\n  }\n\n  clear() {\n    super.clear();\n    this.head = null;\n    this.tail = null;\n    return this;\n  }\n}\n\nexport interface SelectionsProps {\n  onClick: React.MouseEventHandler<HTMLElement>;\n}\n\nexport interface UseSelectionsPlugin {\n  /**\n   * A subject that you can use to observe to changes to selections.\n   */\n  didChange: Subject<Set<number>>;\n  /**\n   * Get the React props for a given node ID.\n   *\n   * @param nodeId - A node ID\n   */\n  getProps(nodeId: number): SelectionsProps;\n  /**\n   * The head of the selections list\n   */\n  get head(): number | null;\n  /**\n   * The tail of the selections list\n   */\n  get tail(): number | null;\n  /**\n   * Select given node ids\n   *\n   * @param nodeIds - Node IDs\n   */\n  select(...nodeIds: number[]): void;\n  /**\n   * Deselect given node ids\n   *\n   * @param nodeIds - Node IDs\n   */\n  deselect(...nodeIds: number[]): void;\n  /**\n   * Clear all of the selections\n   */\n  clear(): void;\n  /**\n   * A utility function that yields nodes from a set of selections if they\n   * don't have a parent node in the set.\n   *\n   * @yields {number} - A node id\n   */\n  narrow(): Generator<number, void, unknown>;\n}\n","import * as React from \"react\";\n\nexport function useResizeObserver<\n  T extends HTMLElement,\n  R extends typeof ResizeObserver\n>(\n  target: React.RefObject<T> | T | null,\n  callback: UseResizeObserverCallback,\n  options?: { ResizeObserver: R }\n) {\n  const resizeObserver = getResizeObserver(\n    options?.ResizeObserver ??\n      (typeof window !== \"undefined\" ? window.ResizeObserver : false)\n  );\n  const storedCallback = React.useRef(callback);\n\n  React.useEffect(() => {\n    storedCallback.current = callback;\n  });\n\n  React.useEffect(() => {\n    let didUnobserve = false;\n    const targetEl = target && \"current\" in target ? target.current : target;\n    if (!targetEl) return () => {};\n\n    function cb(entry: ResizeObserverEntry, observer: ResizeObserver) {\n      if (didUnobserve) return;\n      storedCallback.current(entry, observer);\n    }\n\n    resizeObserver?.observe(targetEl, cb);\n\n    return () => {\n      didUnobserve = true;\n      resizeObserver?.unobserve(targetEl, cb);\n    };\n  }, [target, resizeObserver]);\n}\n\nfunction createResizeObserver<R extends typeof ResizeObserver>(\n  ResizeObserver: R | false\n) {\n  if (!ResizeObserver) return;\n\n  const callbacks: Map<Element, Array<UseResizeObserverCallback>> = new Map();\n  const observer = new ResizeObserver((entries, obs) => {\n    for (let i = 0; i < entries.length; i++) {\n      const cbs = callbacks.get(entries[i].target);\n      cbs?.forEach((cb) => cb(entries[i], obs));\n    }\n  });\n\n  return {\n    observer,\n    observe(target: HTMLElement, callback: UseResizeObserverCallback) {\n      observer.observe(target);\n      const cbs = callbacks.get(target) ?? [];\n      cbs.push(callback);\n      callbacks.set(target, cbs);\n    },\n    unobserve(target: HTMLElement, callback: UseResizeObserverCallback) {\n      const cbs = callbacks.get(target) ?? [];\n      if (cbs.length === 1) {\n        observer.unobserve(target);\n        callbacks.delete(target);\n        return;\n      }\n      const cbIndex = cbs.indexOf(callback);\n      if (cbIndex !== -1) cbs.splice(cbIndex, 1);\n      callbacks.set(target, cbs);\n    },\n  };\n}\n\nlet _resizeObserver: ReturnType<typeof createResizeObserver>;\n\nconst getResizeObserver = <R extends typeof ResizeObserver>(\n  resizeObserver: R | false\n) =>\n  !_resizeObserver\n    ? (_resizeObserver = createResizeObserver(resizeObserver))\n    : _resizeObserver;\n\nexport type UseResizeObserverCallback = (\n  entry: ResizeObserverEntry,\n  observer: ResizeObserver\n) => void;\n","import * as React from \"react\";\n\nexport const useTransition: () => [boolean, typeof React.startTransition] =\n  typeof React.useTransition === \"function\"\n    ? React.useTransition\n    : () => [false, (fn) => fn()];\n","import {\n  clearRequestTimeout,\n  requestTimeout,\n} from \"@essentials/request-timeout\";\nimport * as React from \"react\";\nimport trieMemoize from \"trie-memoize\";\nimport { useSyncExternalStore } from \"use-sync-external-store/shim\";\nimport type { FileTree, FileTreeNode } from \"./file-tree\";\nimport type { WindowRef } from \"./types\";\nimport { useResizeObserver } from \"./use-resize-observer\";\nimport { useTransition } from \"./use-transition\";\nimport { useVisibleNodes } from \"./use-visible-nodes\";\nimport { throttle } from \"./utils\";\n\n/**\n * A hook similar to `react-window`'s [`FixesSizeList`](https://react-window.vercel.app/#/examples/list/fixed-size)\n * component. It allows you to render only enough components to fill a viewport, solving\n * some important performance bottlenecks when rendering large lists.\n *\n * @param fileTree - The file tree to virtualize.\n * @param config - Configuration options\n */\nexport function useVirtualize<Meta>(\n  fileTree: FileTree<Meta>,\n  config: UseVirtualizeConfig\n): UseVirtualizeResult<Meta> {\n  const {\n    windowRef,\n    nodes,\n    nodeHeight,\n    nodeGap = 0,\n    overscanBy = 2,\n    ResizeObserver,\n  } = config;\n  const _visibleNodes = useVisibleNodes(fileTree);\n  const visibleNodes = nodes ?? _visibleNodes;\n  const scrollPosition = useScrollPosition(windowRef);\n  const height = useHeight(windowRef, ResizeObserver);\n  const scrollHeight = (nodeHeight + nodeGap) * visibleNodes.length - nodeGap;\n\n  return {\n    scrollTop: scrollPosition.scrollTop,\n    isScrolling: scrollPosition.isScrolling,\n\n    scrollTo(scrollTop, config = {}) {\n      const windowEl =\n        windowRef && \"current\" in windowRef ? windowRef.current : windowRef;\n\n      if (windowEl) {\n        windowEl.scrollTo({ top: scrollTop, behavior: config.behavior });\n      }\n    },\n\n    scrollToNode(nodeId, config = {}) {\n      const index = visibleNodes.indexOf(nodeId) ?? -1;\n\n      if (index > -1) {\n        // eslint-disable-next-line prefer-const\n        let { behavior = \"auto\", align = \"start\" } = config;\n        const lastNodeOffset = Math.max(\n          0,\n          visibleNodes.length * nodeHeight - height\n        );\n        const nodeOffset = index * (nodeHeight + nodeGap);\n        const minOffset = Math.max(\n          0,\n          nodeOffset - (height + (nodeHeight + nodeGap))\n        );\n        const maxOffset = Math.min(nodeOffset, lastNodeOffset);\n        const windowEl =\n          windowRef && \"current\" in windowRef ? windowRef.current : windowRef;\n        // use \"start\" alignment by default\n        let top: number = maxOffset;\n\n        if (align === \"smart\") {\n          if (\n            scrollPosition.scrollTop >= minOffset - height &&\n            scrollPosition.scrollTop <= maxOffset + height\n          ) {\n            align = \"auto\";\n          } else {\n            align = \"center\";\n          }\n        }\n\n        if (align === \"end\") {\n          top = minOffset;\n        } else if (align === \"center\") {\n          top = Math.round(minOffset + (maxOffset - minOffset) / 2);\n\n          if (top < Math.ceil(height / 2)) {\n            top = 0; // near the beginning\n          } else if (top > lastNodeOffset + Math.floor(height / 2)) {\n            top = lastNodeOffset; // near the end\n          }\n        } else if (align === \"auto\") {\n          top = maxOffset;\n\n          if (\n            scrollPosition.scrollTop >= minOffset &&\n            scrollPosition.scrollTop <= maxOffset\n          ) {\n            top = scrollPosition.scrollTop;\n          } else if (scrollPosition.scrollTop < minOffset) {\n            top = minOffset;\n          }\n        }\n\n        if (top !== scrollPosition.scrollTop) {\n          windowEl?.scrollTo({ top, behavior });\n        }\n      }\n    },\n\n    props: {\n      tabIndex: 0,\n      style: {\n        position: \"relative\",\n        width: \"100%\",\n        height: Math.max(Math.ceil(scrollHeight), height),\n        contain: \"strict\",\n        userSelect: \"none\",\n        pointerEvents: scrollPosition.isScrolling ? \"none\" : undefined,\n      },\n    },\n\n    map(render) {\n      const totalNodeHeight = nodeHeight + nodeGap;\n      const overscan = height * overscanBy;\n\n      let index = Math.floor(\n        Math.max(0, scrollPosition.scrollTop - overscan / 2) / totalNodeHeight\n      );\n      const stopIndex = Math.min(\n        visibleNodes.length,\n        Math.ceil((scrollPosition.scrollTop + overscan) / totalNodeHeight)\n      );\n      const start = index;\n      const children: React.ReactElement[] = new Array(\n        Math.max(stopIndex - index, 0)\n      );\n\n      for (; index < stopIndex; index++) {\n        const nodeId = visibleNodes[index];\n        const node = fileTree.getById(nodeId);\n        if (!node) continue;\n\n        children[index - start] = render({\n          key: nodeId,\n          index,\n          node,\n          tree: fileTree,\n          style: createStyle(nodeHeight, nodeGap * index + index * nodeHeight),\n        });\n      }\n\n      return children;\n    },\n  };\n}\n\nconst createStyle = trieMemoize(\n  [Map, Map],\n  (height: number, top: number): React.CSSProperties => ({\n    position: \"absolute\",\n    contain: \"strict\",\n    userSelect: \"none\",\n    width: \"100%\",\n    left: 0,\n    height,\n    top,\n  })\n);\n\nexport function useHeight(windowRef: WindowRef, ResizeObserver: any) {\n  const [, startTransition] = useTransition();\n  const getWindowHeight = () => {\n    const windowEl =\n      windowRef && \"current\" in windowRef ? windowRef.current : windowRef;\n\n    if (typeof window !== \"undefined\" && windowEl instanceof HTMLElement) {\n      const computedStyle = getComputedStyle(windowEl);\n      return (\n        windowEl.clientHeight -\n        parseFloat(computedStyle.paddingTop) -\n        parseFloat(computedStyle.paddingBottom)\n      );\n    }\n\n    return 0;\n  };\n  const [height, setHeight] = React.useState(getWindowHeight);\n\n  useResizeObserver(\n    // @ts-expect-error\n    typeof window === \"undefined\" ||\n      (typeof window !== \"undefined\" && windowRef === window)\n      ? null\n      : windowRef,\n    () => {\n      startTransition(() => {\n        setHeight(getWindowHeight());\n      });\n    },\n    { ResizeObserver }\n  );\n\n  return useGlobalWindowHeight(windowRef) ?? height;\n}\n\nexport function useGlobalWindowHeight(windowRef: WindowRef) {\n  return useSyncExternalStore(\n    (callback) => {\n      callback = throttle(callback, 12, true);\n      if (typeof window !== \"undefined\" && windowRef instanceof Window) {\n        window.addEventListener(\"resize\", callback);\n        window.addEventListener(\"orientationchange\", callback);\n\n        return () => {\n          window.removeEventListener(\"resize\", callback);\n          window.removeEventListener(\"orientationchange\", callback);\n        };\n      }\n\n      return () => {};\n    },\n    () => {\n      if (typeof window !== \"undefined\" && windowRef === window) {\n        return window.innerHeight;\n      }\n\n      return null;\n    },\n    () => {\n      if (typeof window !== \"undefined\" && windowRef === window) {\n        return window.innerHeight;\n      }\n\n      return null;\n    }\n  );\n}\n\nexport function useScrollPosition(\n  windowRef: WindowRef,\n  { offset = 0 }: UseScrollPosition = {}\n): { scrollTop: number; isScrolling: boolean } {\n  const [isScrolling, setIsScrolling] = React.useState(false);\n  const getSnapshot = () => {\n    const current =\n      windowRef && \"current\" in windowRef ? windowRef.current : windowRef;\n\n    if (typeof window !== \"undefined\") {\n      return !current\n        ? 0\n        : \"scrollTop\" in current\n        ? current.scrollTop\n        : current.scrollY;\n    }\n\n    return 0;\n  };\n  const scrollTop = useSyncExternalStore(\n    (callback) => {\n      const current =\n        windowRef && \"current\" in windowRef ? windowRef.current : windowRef;\n      callback = throttle(callback, 15, true);\n\n      if (current) {\n        current.addEventListener(\"scroll\", callback);\n\n        return () => {\n          window.removeEventListener(\"scroll\", callback);\n        };\n      }\n\n      return () => {};\n    },\n    getSnapshot,\n    getSnapshot\n  );\n\n  React.useEffect(() => {\n    let didUnmount = false;\n\n    const to = requestTimeout(() => {\n      if (didUnmount) return;\n      // This is here to prevent premature bail outs while maintaining high resolution\n      // unsets. Without it there will always be a lot of unnecessary DOM writes to style.\n      setIsScrolling(false);\n    }, 1000 / 8);\n\n    setIsScrolling(true);\n\n    return () => {\n      didUnmount = true;\n      to && clearRequestTimeout(to);\n    };\n  }, [scrollTop]);\n\n  return { scrollTop: Math.max(0, scrollTop - offset), isScrolling };\n}\n\nexport interface UseScrollPosition {\n  offset?: number;\n}\n\nexport interface UseVirtualizeConfig {\n  /**\n   * The fixed height (in px) of each node in your list.\n   */\n  nodeHeight: number;\n  /**\n   * Optionally set a gap (in px) between each node in your list.\n   */\n  nodeGap?: number;\n  /**\n   * When using a hook like `useFilter` you can supply the filtered list of\n   * nodes to this option. By default, `useVirtualize()` uses the nodes returned\n   * by `useVisibleNodes()`\n   */\n  nodes?: number[];\n  /**\n   * This number is used for determining the number of nodes outside of the visible\n   * window to render. The default value is 2 which means \"render 2 windows worth (2 * height)\n   * of content before and after the items in the visible window\". A value of 3 would be\n   * 3 windows worth of grid cells, so it's a linear relationship. Overscanning is important\n   * for preventing tearing when scrolling through items in the grid, but setting too high of\n   * a value may create too much work for React to handle, so it's best that you tune this\n   * value accordingly.\n   *\n   * @default 2\n   */\n  overscanBy?: number;\n  /**\n   * A React ref created by useRef() or an HTML element for the container viewport\n   * you're rendering the list inside of.\n   */\n  windowRef: WindowRef;\n  /**\n   * This hook uses a [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver)\n   * for tracking the size of the viewport. If you need to polyfill ResizeObserver you can provide\n   * that polyfill here. By default, we use the `ResizeObserver` from the `window` global.\n   */\n  ResizeObserver?: ResizeObserver;\n}\n\nexport type ScrollToNodeConfig = {\n  /**\n   * The scrolling behavior\n   */\n  behavior?: \"smooth\" | \"auto\";\n  /**\n   * By default, the list will scroll as little as possible to ensure the item is\n   * visible. You can control the alignment of the item though by specifying a\n   * second alignment parameter.\n   * - `auto` - Scroll as little as possible to ensure the item is visible. (If the item\n   *     is already visible, it won't scroll at all.)\n   * - `smart` - If the item is already visible, don't scroll at all. If it is less than\n   *      one viewport away, scroll as little as possible so that it becomes visible. If\n   *      it is more than one viewport away, scroll so that it is centered within the list.\n   * - `center` - Center align the item within the list.\n   * - `end` - Align the item to the end of the list (the bottom for vertical lists or the\n   *      right for horizontal lists).\n   * - `start` - Align the item to the beginning of the list (the top for vertical lists or\n   *      the left for horizontal lists).\n   *\n   * @default \"auto\"\n   */\n  align?: \"auto\" | \"smart\" | \"center\" | \"start\" | \"end\";\n};\n\nexport interface UseVirtualizeResult<Meta> {\n  /**\n   * The current scroll position of the viewport\n   */\n  scrollTop: number;\n  /**\n   * `true` if the viewport is currently scrolling\n   */\n  isScrolling: boolean;\n  /**\n   * Scroll to the viewport a given position\n   *\n   * @param scrollTop - The new scroll position\n   * @param config - Configuration options\n   */\n  scrollTo(\n    scrollTop: number,\n    config?: Pick<ScrollToNodeConfig, \"behavior\">\n  ): void;\n  /**\n   * Scroll to a given node by its ID\n   *\n   * @param nodeId - The node ID to scroll to\n   * @param config - Configuration options\n   */\n  scrollToNode(nodeId: number, config?: ScrollToNodeConfig): void;\n  /**\n   * Props that should be applied to the container you're mapping your virtualized\n   * nodes into.\n   *\n   * @example\n   * ```tsx\n   * const windowRef = React.useRef(null)\n   * const virtualize = useVirtualize(fileTree, {windowRef, nodeHeight: 24})\n   * return (\n   *   <div ref={windowRef} className='file-tree'>\n   *     <div className='file-tree-container' {...virtualize.props}>\n   *      {virtualize.map(props => <Node {...props}/>)}\n   *     </div>\n   *   </div>\n   * )\n   * ```\n   */\n  props: VirtualizeContainerProps;\n  /**\n   * Calls a defined render function on each node and returns an array that\n   * contains the resulting React elements.\n   *\n   * @param render - A callback that renders a node.\n   * @example\n   * ```tsx\n   * const windowRef = React.useRef(null)\n   * const virtualize = useVirtualize(fileTree, {windowRef, nodeHeight: 24})\n   * return (\n   *   <div ref={windowRef} className='file-tree'>\n   *     <div className='file-tree-container' {...virtualize.props}>\n   *      {virtualize.map(props => <Node {...props}/>)}\n   *     </div>\n   *   </div>\n   * )\n   * ```\n   */\n  map(\n    render: (config: VirtualizeRenderProps<Meta>) => React.ReactElement\n  ): React.ReactElement[];\n}\n\nexport interface VirtualizeRenderProps<Meta> {\n  /**\n   * A stable key as required by React elements that are included in arrays\n   */\n  key: number;\n  /**\n   * The index of the node within the list of visible nodes\n   */\n  index: number;\n  /**\n   * A file tree node\n   */\n  node: FileTreeNode<Meta>;\n  /**\n   * The file tree that contains the node\n   */\n  tree: FileTree<Meta>;\n  /**\n   * Styles that need to be applied to the node element\n   */\n  style: React.CSSProperties;\n}\n\nexport interface VirtualizeContainerProps {\n  tabIndex: number;\n  style: React.CSSProperties;\n}\n","import type { Node } from \"./branch\";\n\nexport const nodesById: Node[] = new Array(1000);\n","import type { Branch } from \"./branch\";\nimport { nodesById } from \"./nodes-by-id\";\n\nexport class Leaf<NodeData = {}> {\n  /**\n   * The unique ID of the node\n   */\n  public readonly id = nextId();\n  /**\n   * The ID of the parent node\n   */\n  public parentId = -1;\n\n  constructor(\n    /**\n     * The parent node\n     */\n    parent: Branch<NodeData> | null,\n    /**\n     * The data for this node\n     */\n    public data: NodeData\n  ) {\n    this.parentId = parent === null ? -1 : parent.id;\n  }\n\n  /**\n   * The parent node\n   */\n  get parent(): Branch<NodeData> | null {\n    return this.parentId === -1\n      ? null\n      : (nodesById[this.parentId] as Branch<NodeData>);\n  }\n\n  /**\n   * The depth of the node in the tree\n   */\n  get depth(): number {\n    if (this.parentId === -1) {\n      return 0;\n    }\n\n    return nodesById[this.parentId].depth + 1;\n  }\n}\n\nconst nextId = (() => {\n  let id = 0;\n  return () => id++;\n})();\n","import { Leaf } from \"./leaf\";\nimport { nodesById } from \"./nodes-by-id\";\n\nexport class Branch<NodeData = {}> extends Leaf<NodeData> {\n  /**\n   * The child node IDs of this branch\n   */\n  public nodes?: number[];\n  /**\n   * A flag indicating the \"intended\" expansion status of this branch. If this is `true`, the branch\n   * is either already expanded OR is about to be expanded. Explained below.\n   *\n   * This value represents the \"intended\" expansion state not the \"actual\" expansion state. When\n   * `Tree#expand` is called, the value of this will be immediately become `true`, however because\n   * the child nodes of the branch in question might need to be loaded, the actual expansion won't\n   * take effect until the children are loaded. So in that interim time while children are loading,\n   * the branch isn't truly expanded even if the value is `true`.\n   *\n   * Depending on your use case you might want to rely on `Tree#isExpanded` for a \"real-time\" status.\n   */\n  public expanded: boolean;\n\n  constructor(\n    /**\n     * The parent node\n     */\n    parent: Branch<NodeData> | null,\n    /**\n     * The data for this node\n     */\n    data: NodeData,\n    /**\n     * Is the branch expanded?\n     */\n    expanded = false\n  ) {\n    super(parent, data);\n    this.expanded = expanded;\n  }\n\n  /**\n   * Returns `true` if the node is a child of this branch, regardless of\n   * depth.\n   *\n   * @param node - A tree node\n   */\n  contains(node: Node<NodeData>): boolean {\n    while (node.parentId > -1) {\n      if (node.parentId === this.id) return true;\n      node = nodesById[node.parentId] as Branch<NodeData>;\n    }\n\n    return false;\n  }\n}\n\nexport type Node<NodeData = {}> = Leaf<NodeData> | Branch<NodeData>;\n","import type { Subject } from \"./tree/subject\";\nimport { subject } from \"./tree/subject\";\n\nexport class SubjectSet<T> extends Set<T> {\n  didChange: Subject<Set<T>>;\n\n  constructor(initialValue?: T[]) {\n    super(initialValue);\n    this.didChange = subject(new Set(this));\n  }\n\n  add(value: T) {\n    super.add(value);\n    this.didChange.setState(new Set(this));\n    return this;\n  }\n\n  delete(value: T) {\n    const deleted = super.delete(value);\n    this.didChange.setState(new Set(this));\n    return deleted;\n  }\n\n  clear() {\n    super.clear();\n    this.didChange.setState(new Set(this));\n    return this;\n  }\n}\n\nexport class SubjectMap<K, V> extends Map<K, V> {\n  didChange: Subject<Map<K, V>>;\n\n  constructor(initialValue?: [K, V][]) {\n    super(initialValue);\n    this.didChange = subject(new Map(this));\n  }\n\n  set(key: K, value: V) {\n    super.set(key, value);\n    this.didChange.setState(new Map(this));\n    return this;\n  }\n\n  delete(key: K) {\n    const deleted = super.delete(key);\n    this.didChange.setState(new Map(this));\n    return deleted;\n  }\n\n  clear() {\n    super.clear();\n    this.didChange.setState(new Map(this));\n    return this;\n  }\n}\n","import {\n  clearRequestTimeout,\n  requestTimeout,\n} from \"@essentials/request-timeout\";\nimport * as React from \"react\";\n\nexport const useDeferredValue: <T>(\n  value: T,\n  options?: {\n    timeoutMs: number;\n  }\n) => T =\n  typeof React.useDeferredValue === \"function\"\n    ? (React.useDeferredValue as any)\n    : useThrottle;\n\nexport function useThrottle<T>(\n  value: T,\n  options: { timeoutMs: number } = { timeoutMs: 200 }\n) {\n  const [state, setState] = React.useState<T>(value);\n  const lastInvocation = React.useRef<number>(0);\n  const waitedFor = React.useRef<number>(0);\n\n  React.useEffect(() => {\n    let didUnmount = false;\n    const now = performance.now();\n    waitedFor.current +=\n      now - (lastInvocation.current === 0 ? now : lastInvocation.current);\n    lastInvocation.current = now;\n\n    const timeout = requestTimeout(() => {\n      if (!didUnmount) {\n        setState(value);\n        waitedFor.current = 0;\n        lastInvocation.current = 0;\n      }\n    }, Math.max(options.timeoutMs - waitedFor.current, 0));\n\n    return () => {\n      didUnmount = true;\n      clearRequestTimeout(timeout);\n    };\n  }, [value, options.timeoutMs]);\n\n  return state;\n}\n"],"names":["isRelative","path","join","composed","_len","arguments","length","paths","Array","_key","hasLeadingSlash","lastPath","hasTrailingSlash","i","parts","split","j","part","pop","push","unshift","_path$match","match","SEP_NEGATE_RE","normalize","basename","frags","lastIndex","removeTrailingSlashes","replace","TRAILING_SEP_RE","mergeProps","args","_args$","result","_extends","style","props","key","a","b","charCodeAt","Object","assign","clsx","chain","callbacks","_key2","callback","throttle","fps","leading","trailingTimeout","ms","prev","clearTrailing","clearRequestTimeout","rightNow","performance","now","call","apply","current","delta","requestTimeout","shallowEqual","objA","objB","retryWithBackoff","_x","_x2","_retryWithBackoff","this","promiseFn","config","maxRetries","initialDelay","delayMultiple","shouldRetry","err","Promise","resolve","setTimeout","subject","initialState","observers","Set","state","setState","nextState","listener","getState","observe","observer","add","delete","unobserve","next","prevArgs","_ref3","_ref6","createDraft","nodes","draft","Proxy","set","target","index","value","parseInt","draftResult","modified","getOwnPropertyNames","prototype","forEach","prop","defineProperty","isBranch","node","Branch","createFileTree","getNodes","comparator","defaultComparator","root","restoreFromSnapshot","FileTree","parent","_asyncToGenerator","createFile","data","File","createDir","expanded","id","name","pathFx","Dir","expandedPaths","includes","buriedPaths","getPath","parentPath","constructor","localeCompare","isPrompt","isDir","treeNode","Prompt","isFile","shallowEqualArray","useNodePlugins","nodeId","plugins","createSubject","React","useRef","memoizeOne","mergeProps_","_ref","storedPlugins","useEffect","getSnapshot","useCallback","getProps","useSyncExternalStore","Node","_props$plugins","_props$as","elementProps","empty","useNode","tree","__reactCreateElement__","as","children","_ref2","fileTree","expand","type","undefined","depth","useMemo","role","onClick","event","currentTarget","focus","metaKey","shiftKey","altKey","ctrlKey","button","collapse","isExpanded","catch","didChange","noopSubject","useObserver","storedObserver","cleanup","didUnmount","_cleanup","_cleanup2","_ref5","HTMLElement","firstChild","useDnd","storedConfig","dnd","createDnd","storedTimeout","timeout","storedDir","dir","then","_storedConfig$current","clearTimeout","dragOverExpandTimeout","DEFAULT_DRAG_OVER_EXPAND_TIMEOUT","windowRef","windowEl","handlers","createProps","isCurrentTarget","handleDragEnter","onDragEnter","handleDragOver","onDragOver","handleDragLeave","onDragLeave","handleDrop","onDrop","addEventListener","removeEventListener","getById","useVisibleNodes","_useSyncExternalStore","flatView","useFilter","filter","visibleNodes","filteredNodes","useDeferredValue","_ref4","useHotkeys","getSelectedId","_selections$tail","rovingId","rovingFocus","selections","tail","getSelectedIndex","indexOf","HTMLInputElement","HTMLTextAreaElement","preventDefault","_node$nodes","selectedIndex","isVisible","element","document","querySelector","querySelectorPattern","Math","min","visibleNodes_","useHotkeys_","nextSelector","max","parentIndex","clear","select","_windowRef$current","blur","useFileTreeSnapshot","_observer","nodeIds","buriedIds","version","SNAPSHOT_VERSION","useTraits","traits","storedTraits","traitsMap","createTraitsMap","className","entry","has","trait","_traitsMap$get","traitSet","get","_traitsMap$get2","_traitsMap$get3","_traitsMap$get4","clearAll","_traitsMap$get5","clearNode","_traitsMap$get6","useRovingFocus","focusedNodeId","createFocusedNodeId","useSelections","prevSelectionsSet","selectionsSet","createSelectionsSet","emptyArray","head","deselect","_len2","narrow","nodesById","parentId","parentNode","fn","useVirtualize","nodeHeight","nodeGap","overscanBy","ResizeObserver","_visibleNodes","scrollPosition","offset","isScrolling","setIsScrolling","useState","window","scrollTop","scrollY","to","useScrollPosition","height","setHeight","getWindowHeight","_useGlobalWindowHeigh","options","_options$ResizeObserv","resizeObserver","storedCallback","startTransition","useTransition","computedStyle","getComputedStyle","clientHeight","parseFloat","paddingTop","paddingBottom","getResizeObserver","cb","didUnobserve","targetEl","Window","innerHeight","useGlobalWindowHeight","useHeight","scrollHeight","scrollTo","top","behavior","scrollToNode","_visibleNodes$indexOf","align","lastNodeOffset","nodeOffset","minOffset","maxOffset","round","ceil","floor","tabIndex","position","width","contain","userSelect","pointerEvents","map","render","totalNodeHeight","overscan","stopIndex","start","createStyle","from","Error","fromFrags","toFrags","hasTrailingSep","remainder","fill","concat","slice","pathFrags","contPathFrags","every","fragment","lastIndexOf","hasLeadingSep","Leaf","nextId","super","contains","loadingBranches","Map","createVisibleNodes","reverse","ensureLoaded","branch","_this","loadNodes","_this2","ensureVisible","recursive","isVisibilitySkippable","all","invalidate","_produce","produceFn","_branch$nodes","_produceFn","insert","insertionIndex","splice","Infinity","revert","_branch$nodes2","setNodes","remove","nodeToRemove","_nodeToRemove$parent","nodeToRemoveParent","found","nextNodes","move","_this3","_node$parent","initialParent","p","_ref7","_this4","_loop","_ref8","promise","finally","sort","dispose","getByPath","walk","visitor","produce","context","createPrompt","newFile","inDir","withData","file","newDir","newPrompt","prompt","rename","newName","$$type","_basenameName","_basename","onStoreChange","numPlugins","unsubs","SubjectSet","initialValue","deleted","SubjectMap","_resizeObserver","trieMemoize","WeakMap","draggable","onDragStart","onDragEnd","areEqual","pureSubject","timeoutMs","lastInvocation","waitedFor","focused","onFocus","onBlur","headIndex","tailIndex","nodeIndex","direction","selectStart","selectEnd","deselectStart","deselectEnd","SubjectRange","entries","obs","cbs","_callbacks$get","_callbacks$get2","cbIndex","createResizeObserver","left"],"mappings":"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"}