{"version":3,"file":"templateEditor.dom.mjs","names":[],"sources":["../../../../package/common/templateEditor/templateEditor.dom.ts"],"sourcesContent":["import type React from 'react';\nimport type { TemplateEditorLabels, TemplateEditorToken } from './templateEditor.types';\nimport { parseTemplate, tokenLabel, tokenLength, tokenSpans } from './templateEditor.utils';\n\n/** Everything the DOM helpers need to turn a token id into a chip element. */\nexport interface TemplateChipContext {\n  prefix: string;\n  suffix: string;\n  tokenIndex: Map<string, TemplateEditorToken>;\n  /** From `buildChipLabels`. A token missing here is labelled with `tokenLabel`. */\n  chipLabels?: Map<string, string>;\n  labels: Pick<Required<TemplateEditorLabels>, 'removeToken' | 'unknownToken' | 'unknownTokenTitle'>;\n  /** Show each token's `sample`, where it has one, in place of its label. */\n  preview?: boolean;\n  chipClassName?: string;\n  /** Added to a chip whose token is in `tokenIndex`; `unknownChipClassName` replaces it otherwise. */\n  knownChipClassName?: string;\n  unknownChipClassName?: string;\n  /** Added to a chip showing its sample. */\n  previewChipClassName?: string;\n  chipStyle?: React.CSSProperties;\n  /** Render a remove button inside each chip. Off while the field is read-only or disabled. */\n  showRemove?: boolean;\n  removeClassName?: string;\n  removeStyle?: React.CSSProperties;\n}\n\n/** Where a boundary in the serialized string lands in the DOM. */\ninterface BoundaryPoint {\n  node: Node;\n  offset: number;\n}\n\n/** Which side of a chip a snapped selection endpoint should end up on. */\ntype SnapPreference = 'before' | 'after';\n\n// Deliberately not a type predicate: narrowing an `HTMLElement` to `HTMLElement`\n// leaves every `else` branch typed `never`, which every caller here has one of.\nexport function isChip(node: Node | null | undefined): boolean {\n  return !!node && node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).dataset?.chip !== undefined;\n}\n\nconst SPACER_TEXT = '\\uFEFF';\n\n/**\n * A zero-width text holder in front of a chip that starts a line. Without one,\n * the only position before such a chip is the end of the text before it, after\n * its newline, and no engine handles that: Chrome draws no caret there and types\n * after the chip, WebKit types before the newline, Firefox draws the caret on the\n * line above. Slate and ProseMirror carry a spacer for the same reason. It never\n * serializes, and text typed into it is moved out by `normalizeEditable`.\n */\nexport function isSpacer(node: Node | null | undefined): boolean {\n  return !!node && node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).dataset?.spacer !== undefined;\n}\n\nfunction endsLine(node: Node | null): boolean {\n  return !!node && node.nodeType === Node.TEXT_NODE && (node as Text).data.endsWith('\\n');\n}\n\n/** Puts a spacer in front of every chip that starts a line, and removes any that no longer does. Returns whether anything changed. */\nexport function syncSpacers(root: HTMLElement): boolean {\n  let changed = false;\n  Array.from(root.childNodes).forEach((node) => {\n    if (isSpacer(node) && !(isChip(node.nextSibling) && endsLine(node.previousSibling))) {\n      node.parentNode?.removeChild(node);\n      changed = true;\n    }\n  });\n  Array.from(root.childNodes).forEach((node) => {\n    if (!isChip(node) || !endsLine(node.previousSibling)) return;\n    const spacer = root.ownerDocument.createElement('span');\n    spacer.dataset.spacer = '';\n    spacer.textContent = SPACER_TEXT;\n    node.parentNode?.insertBefore(spacer, node);\n    changed = true;\n  });\n  return changed;\n}\n\n/**\n * A `<br>` that exists only so the caret has somewhere to go, and that must not\n * serialize to a newline. Ours are tagged; a browser-inserted trailing `<br>` is\n * treated the same way, since the canonical DOM never contains a real `<br>`\n * (line breaks are literal `\\n` characters under `white-space: pre-wrap`).\n */\nexport function isBogusBr(node: Node | null | undefined): boolean {\n  if (!node || node.nodeName !== 'BR') return false;\n  return (node as HTMLElement).dataset?.bogus !== undefined || node.parentNode?.lastChild === node;\n}\n\n/** The nearest enclosing chip of a node, or `null` when it isn't inside one. */\nexport function closestChip(root: HTMLElement, node: Node | null): HTMLElement | null {\n  let current: Node | null = node;\n  while (current && current !== root) {\n    if (isChip(current)) return current as HTMLElement;\n    current = current.parentNode;\n  }\n  return null;\n}\n\nfunction nameOf(id: string, token: TemplateEditorToken, ctx: TemplateChipContext): string {\n  return ctx.chipLabels?.get(id) ?? tokenLabel(token);\n}\n\nexport function chipLabelFor(id: string, ctx: TemplateChipContext): string {\n  const token = ctx.tokenIndex.get(id);\n  if (!token) return ctx.labels.unknownToken(id);\n  return ctx.preview && token.sample ? token.sample : nameOf(id, token, ctx);\n}\n\n/** The chip's own label node, which is what the repair sweep compares against. */\nfunction labelElementOf(chip: HTMLElement): HTMLElement | null {\n  return chip.querySelector<HTMLElement>('[data-chip-label]');\n}\n\nfunction createRemoveElement(label: string, ctx: TemplateChipContext, doc: Document): HTMLElement {\n  const el = doc.createElement('span');\n  el.dataset.chipRemove = '';\n  // Exposed as a button but never in the tab order: Tab belongs to the text\n  // caret here, and keyboard users delete a chip by arrowing onto it and\n  // pressing Backspace. This is the pointer and touch affordance for that.\n  el.setAttribute('role', 'button');\n  el.setAttribute('aria-label', ctx.labels.removeToken(label));\n  el.setAttribute('contenteditable', 'false');\n  el.draggable = false;\n  el.textContent = '×';\n  if (ctx.removeClassName) el.className = ctx.removeClassName;\n  if (ctx.removeStyle) Object.assign(el.style, ctx.removeStyle);\n  return el;\n}\n\n/**\n * Builds one inline chip. `data-label` records the text that was rendered, so\n * `normalizeEditable` can tell a chip the user broke into apart from a chip\n * whose label merely went stale after `tokenGroups` changed.\n */\nexport function createChipElement(id: string, ctx: TemplateChipContext, doc: Document = document): HTMLElement {\n  const el = doc.createElement('span');\n  const token = ctx.tokenIndex.get(id);\n  const label = chipLabelFor(id, ctx);\n  const showsSample = !!(ctx.preview && token?.sample);\n\n  el.dataset.chip = '';\n  el.dataset.token = id;\n  el.dataset.label = label;\n  if (!token) el.dataset.unknown = 'true';\n  // Set as an attribute, not via the IDL property: the property is unimplemented\n  // in jsdom, so the attribute form is the only one that survives into tests.\n  el.setAttribute('contenteditable', 'false');\n  el.draggable = true;\n  el.spellcheck = false;\n  el.className = [\n    ctx.chipClassName,\n    token ? ctx.knownChipClassName : ctx.unknownChipClassName,\n    showsSample && ctx.previewChipClassName,\n  ]\n    .filter(Boolean)\n    .join(' ');\n  if (ctx.chipStyle) Object.assign(el.style, ctx.chipStyle);\n\n  // The label lives in its own span rather than being the chip's whole text\n  // content, so the remove button can sit beside it without the repair sweep in\n  // `normalizeEditable` mistaking the button for the user having edited the label.\n  const labelEl = doc.createElement('span');\n  labelEl.dataset.chipLabel = '';\n  labelEl.textContent = label;\n  el.appendChild(labelEl);\n\n  if (ctx.showRemove) el.appendChild(createRemoveElement(label, ctx, doc));\n\n  if (!token) el.title = ctx.labels.unknownTokenTitle(id);\n  else if (showsSample) el.title = nameOf(id, token, ctx);\n  return el;\n}\n\n/**\n * Flags the chips a selection covers, for the stylesheet to draw: no engine paints a selection\n * across an atomic chip the same way, and Chromium does not paint it at all. `null` clears them.\n */\nexport function markSelectedChips(\n  root: HTMLElement,\n  selection: { start: number; end: number } | null,\n  prefix: string,\n  suffix: string,\n): void {\n  const selected = new Set(\n    selection && selection.start !== selection.end\n      ? chipsWithin(root, selection.start, selection.end, prefix, suffix)\n      : [],\n  );\n  root\n    .querySelectorAll<HTMLElement>('[data-chip]')\n    .forEach((chip) => chip.toggleAttribute('data-selected', selected.has(chip)));\n}\n\n/** The chips whose tokens lie within serialized-string offsets, e.g. the ones an insertion just placed. */\nexport function chipsWithin(\n  root: HTMLElement,\n  start: number,\n  end: number,\n  prefix: string,\n  suffix: string,\n): HTMLElement[] {\n  // Chips are in the DOM in the order their tokens are in the value.\n  const chips = root.querySelectorAll<HTMLElement>('[data-chip]');\n  return tokenSpans(domToValue(root, prefix, suffix), prefix, suffix).flatMap((span, index) =>\n    span.start >= start && span.end <= end && chips[index] ? [chips[index]] : [],\n  );\n}\n\n/**\n * Serializes a DOM subtree back to the template string. Recursive, so a\n * transient element the browser injected between a mutation and the next\n * `normalizeEditable` still serializes to the right text.\n */\nexport function serializeFragment(node: Node, prefix: string, suffix: string): string {\n  let out = '';\n  node.childNodes.forEach((child) => {\n    if (child.nodeType === Node.TEXT_NODE) {\n      out += (child as Text).data;\n      return;\n    }\n    if (child.nodeType !== Node.ELEMENT_NODE) return;\n    const el = child as HTMLElement;\n    if (isChip(el)) {\n      out += prefix + (el.dataset.token ?? '') + suffix;\n      return;\n    }\n    if (el.nodeName === 'BR') {\n      if (!isBogusBr(el)) out += '\\n';\n      return;\n    }\n    if (isSpacer(el)) {\n      out += (el.textContent ?? '').split(SPACER_TEXT).join('');\n      return;\n    }\n    out += serializeFragment(el, prefix, suffix);\n  });\n  return out;\n}\n\nexport function domToValue(root: HTMLElement, prefix: string, suffix: string): string {\n  return serializeFragment(root, prefix, suffix);\n}\n\n/** Guarantees the last child is a caret parking spot, so a trailing newline, a trailing chip, and an empty field are all caretable. */\nexport function ensureTrailingBr(root: HTMLElement): void {\n  const doc = root.ownerDocument;\n  const last = root.lastChild;\n  if (last && last.nodeName === 'BR') {\n    (last as HTMLElement).dataset.bogus = 'true';\n    return;\n  }\n  const br = doc.createElement('br');\n  br.dataset.bogus = 'true';\n  root.appendChild(br);\n}\n\n/** Replaces the editable's entire content with the rendering of `value`. */\nexport function renderValue(root: HTMLElement, value: string, ctx: TemplateChipContext): void {\n  const doc = root.ownerDocument;\n  const nodes = parseTemplate(value, ctx.prefix, ctx.suffix).map((segment) =>\n    segment.type === 'text'\n      ? (doc.createTextNode(segment.text) as Node)\n      : (createChipElement(segment.id, ctx, doc) as Node),\n  );\n  root.replaceChildren(...nodes);\n  syncSpacers(root);\n  ensureTrailingBr(root);\n}\n\n/**\n * Brings every placed chip in line with a changed context, e.g. a label once\n * `tokenGroups` load or the remove button once `readOnly` toggles, without\n * touching text nodes. The chip node itself is kept and only its attributes and\n * children are swapped: replacing the node would move a caret sitting right\n * after the chip to right before it.\n */\nexport function refreshChips(root: HTMLElement, ctx: TemplateChipContext): void {\n  root.querySelectorAll<HTMLElement>('[data-chip]').forEach((chip) => {\n    const fresh = createChipElement(chip.dataset.token ?? '', ctx, root.ownerDocument);\n    // State the editable keeps on a placed chip, which a freshly built one does not have.\n    ['data-dragging', 'data-selected'].forEach((name) => {\n      const state = chip.getAttribute(name);\n      if (state !== null) fresh.setAttribute(name, state);\n    });\n    if (fresh.isEqualNode(chip)) return;\n    Array.from(chip.attributes).forEach((attribute) => chip.removeAttribute(attribute.name));\n    Array.from(fresh.attributes).forEach((attribute) => chip.setAttribute(attribute.name, attribute.value));\n    chip.replaceChildren(...Array.from(fresh.childNodes));\n  });\n}\n\nlet morphCount = 0;\n\nfunction textHeight(root: HTMLElement): number {\n  const range = root.ownerDocument.createRange();\n  range.selectNodeContents(root);\n  return typeof range.getBoundingClientRect === 'function' ? range.getBoundingClientRect().height : 0;\n}\n\n/**\n * Runs `update`, which changes what the chips show, as a view transition in which each chip\n * morphs from its old box into its new one. Where the engine has no view transitions, or none\n * that take a class to style them by, or the swap changes how many lines the text takes, `update`\n * simply takes effect.\n */\nexport function morphChips(root: HTMLElement, transitionClass: string, update: () => void): void {\n  const doc = root.ownerDocument;\n  if (!doc.startViewTransition || !doc.defaultView?.CSS?.supports('view-transition-class', 'a')) {\n    update();\n    return;\n  }\n  // A named element is drawn above the whole page for the transition, so a chip scrolled out of\n  // the field would show outside it. Those cross-fade with the rest of the page instead.\n  const box = root.getBoundingClientRect();\n  const chips = Array.from(root.querySelectorAll<HTMLElement>('[data-chip]')).filter((chip) => {\n    const rect = chip.getBoundingClientRect();\n    return rect.top >= box.top && rect.bottom <= box.bottom && rect.left >= box.left && rect.right <= box.right;\n  });\n  morphCount += 1;\n  const run = morphCount;\n  const nameOfChip = (index: number) => `template-editor-chip-${run}-${index}`;\n  const name = () =>\n    chips.forEach((chip, index) => {\n      chip.style.setProperty('view-transition-name', nameOfChip(index));\n      chip.style.setProperty('view-transition-class', transitionClass);\n    });\n  const unname = () =>\n    chips.forEach((chip, index) => {\n      // A toggle pressed again mid-transition has named the chip for its own.\n      if (chip.style.getPropertyValue('view-transition-name') !== nameOfChip(index)) return;\n      chip.style.removeProperty('view-transition-name');\n      chip.style.removeProperty('view-transition-class');\n      if (!chip.getAttribute('style')) chip.removeAttribute('style');\n    });\n\n  name();\n  const height = textHeight(root);\n  const halfLine = parseFloat(doc.defaultView.getComputedStyle(root).fontSize) / 2;\n  const transition = doc.startViewTransition(() => {\n    update();\n    // Only chips morph; text cross-fades, so a swap that changes how many lines the text takes\n    // showed every line after the change twice. That one happens at once instead.\n    if (Math.abs(textHeight(root) - height) > halfLine) transition.skipTransition();\n    // `update` rebuilds the chips' attributes, and the names with them.\n    name();\n  });\n  // Rejects when the transition is skipped, which is a swap without the morph rather than an error.\n  transition.ready.catch(() => {});\n  transition.finished.then(unname, unname);\n}\n\n/**\n * Converts any complete `prefix…suffix` run sitting in a text node into a chip.\n * This is what makes typing a placeholder out by hand work, and it is the\n * graceful degradation for the autocomplete popup.\n */\nexport function autoTokenize(root: HTMLElement, ctx: TemplateChipContext): boolean {\n  const doc = root.ownerDocument;\n  let changed = false;\n  Array.from(root.childNodes).forEach((node) => {\n    if (node.nodeType !== Node.TEXT_NODE) return;\n    const segments = parseTemplate((node as Text).data, ctx.prefix, ctx.suffix);\n    if (!segments.some((segment) => segment.type === 'token')) return;\n    const fragment = doc.createDocumentFragment();\n    segments.forEach((segment) => {\n      fragment.appendChild(\n        segment.type === 'text' ? doc.createTextNode(segment.text) : createChipElement(segment.id, ctx, doc),\n      );\n    });\n    node.parentNode?.replaceChild(fragment, node);\n    changed = true;\n  });\n  return changed;\n}\n\nfunction isBlockElement(el: HTMLElement): boolean {\n  return ['DIV', 'P', 'LI', 'TR', 'SECTION', 'ARTICLE', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(el.nodeName);\n}\n\n/** Whether only empty text nodes follow, i.e. this node is last once the sweep has cleaned up. */\nfunction isLastMeaningful(node: Node): boolean {\n  let next = node.nextSibling;\n  while (next) {\n    if (!(next.nodeType === Node.TEXT_NODE && (next as Text).data === '')) return false;\n    next = next.nextSibling;\n  }\n  return true;\n}\n\n/**\n * Repairs the editable back to its invariants: a flat list of text nodes and\n * chips, ending in a bogus `<br>`. Browsers inject wrappers on paste, drop, and\n * on any editing command we failed to intercept, so this runs before every\n * serialization. Returns whether anything changed, so the caller knows to\n * restore the caret.\n */\nexport function normalizeEditable(root: HTMLElement, ctx: TemplateChipContext): boolean {\n  const doc = root.ownerDocument;\n  let changed = false;\n\n  const visit = (parent: Node): void => {\n    Array.from(parent.childNodes).forEach((node) => {\n      if (node.nodeType === Node.TEXT_NODE) {\n        if ((node as Text).data === '') {\n          node.parentNode?.removeChild(node);\n          changed = true;\n        }\n        return;\n      }\n      if (node.nodeType !== Node.ELEMENT_NODE) {\n        node.parentNode?.removeChild(node);\n        changed = true;\n        return;\n      }\n      const el = node as HTMLElement;\n\n      if (isChip(el)) {\n        // A chip whose label no longer matches what we rendered was edited into\n        // by the user; there is no sane partial state, so it goes. Compared\n        // against the label node specifically, so the remove button's own text\n        // never reads as an edit.\n        const labelEl = labelElementOf(el);\n        if (!labelEl || labelEl.textContent !== (el.dataset.label ?? '')) {\n          el.remove();\n          changed = true;\n        }\n        return;\n      }\n\n      if (isSpacer(el)) {\n        if (el.textContent === SPACER_TEXT) return;\n        // Typed into: what was typed is ordinary text. `syncSpacers` puts a\n        // fresh spacer back if the chip still starts its line.\n        el.replaceWith(doc.createTextNode((el.textContent ?? '').split(SPACER_TEXT).join('')));\n        changed = true;\n        return;\n      }\n\n      if (el.nodeName === 'BR') {\n        // Only the very last `<br>` is the caret parking spot. One left mid-document\n        // would render a line break while serializing to nothing, so it becomes a\n        // real newline instead.\n        if (parent === root && isLastMeaningful(el)) return;\n        el.replaceWith(doc.createTextNode('\\n'));\n        changed = true;\n        return;\n      }\n\n      visit(el);\n      const fragment = doc.createDocumentFragment();\n      if (isBlockElement(el) && el.previousSibling) fragment.appendChild(doc.createTextNode('\\n'));\n      while (el.firstChild) fragment.appendChild(el.firstChild);\n      el.replaceWith(fragment);\n      changed = true;\n    });\n  };\n\n  visit(root);\n  if (autoTokenize(root, ctx)) changed = true;\n\n  const before = root.childNodes.length;\n  root.normalize();\n  if (root.childNodes.length !== before) changed = true;\n\n  if (syncSpacers(root)) changed = true;\n  if (!root.lastChild || root.lastChild.nodeName !== 'BR') changed = true;\n  ensureTrailingBr(root);\n  return changed;\n}\n\n/**\n * Moves a selection endpoint that a browser placed inside a chip out to one of\n * the chip's edges, so all offset arithmetic happens between atomic units.\n */\nexport function snapOutOfChip(\n  root: HTMLElement,\n  node: Node,\n  offset: number,\n  prefer: SnapPreference = 'after',\n): BoundaryPoint {\n  const chip = closestChip(root, node);\n  if (!chip || !chip.parentNode) return { node, offset };\n  const parent = chip.parentNode;\n  const index = Array.prototype.indexOf.call(parent.childNodes, chip);\n  const after = node === chip ? offset > 0 : prefer === 'after';\n  return { node: parent, offset: after ? index + 1 : index };\n}\n\n/** The serialized-string offset of a DOM boundary point. */\nexport function offsetOfPoint(root: HTMLElement, node: Node, offset: number, prefix: string, suffix: string): number {\n  const probe = root.ownerDocument.createRange();\n  probe.setStart(root, 0);\n  probe.setEnd(node, offset);\n  // Serializing a clone of the span reuses the exact walker `domToValue` uses,\n  // so caret offsets and value offsets cannot drift apart.\n  return serializeFragment(probe.cloneContents(), prefix, suffix).length;\n}\n\nfunction selectionOf(root: HTMLElement): Selection | null {\n  return root.ownerDocument.getSelection();\n}\n\n/** The current selection as `[start, end]` offsets into the serialized string, with any chip endpoints expanded to whole chips. */\nexport function getSelectionOffsets(\n  root: HTMLElement,\n  prefix: string,\n  suffix: string,\n): { start: number; end: number } | null {\n  const selection = selectionOf(root);\n  if (!selection || selection.rangeCount === 0) return null;\n  const range = selection.getRangeAt(0);\n  if (!root.contains(range.startContainer) || !root.contains(range.endContainer)) return null;\n\n  const startPoint = snapOutOfChip(root, range.startContainer, range.startOffset, range.collapsed ? 'after' : 'before');\n  const endPoint = snapOutOfChip(root, range.endContainer, range.endOffset, 'after');\n  const start = offsetOfPoint(root, startPoint.node, startPoint.offset, prefix, suffix);\n  const end = offsetOfPoint(root, endPoint.node, endPoint.offset, prefix, suffix);\n  return start <= end ? { start, end } : { start: end, end: start };\n}\n\n/** The caret position as a serialized-string offset, or `null` when the selection isn't in this editable. */\nexport function getCaretOffset(root: HTMLElement, prefix: string, suffix: string): number | null {\n  return getSelectionOffsets(root, prefix, suffix)?.start ?? null;\n}\n\n/** Resolves a serialized-string offset back to a DOM boundary point. */\nfunction locate(root: HTMLElement, target: number, prefix: string, suffix: string): BoundaryPoint {\n  const children = Array.from(root.childNodes);\n  let remaining = Math.max(0, target);\n\n  for (let index = 0; index < children.length; index += 1) {\n    const node = children[index];\n    if (node.nodeType === Node.TEXT_NODE) {\n      const length = (node as Text).data.length;\n      // The end of a line's text is also the start of the next line, where a\n      // spacer, when there is one, is the position that works.\n      if (remaining < length || (remaining === length && !isSpacer(node.nextSibling)))\n        return { node, offset: remaining };\n      remaining -= length;\n      continue;\n    }\n    if (node.nodeType !== Node.ELEMENT_NODE) continue;\n    const el = node as HTMLElement;\n    if (isBogusBr(el)) continue;\n    if (isSpacer(el)) {\n      if (remaining === 0 && el.firstChild) return { node: el.firstChild, offset: (el.firstChild as Text).length };\n      continue;\n    }\n\n    const length = isChip(el)\n      ? tokenLength(el.dataset.token ?? '', prefix, suffix)\n      : el.nodeName === 'BR'\n        ? 1\n        : (el.textContent?.length ?? 0);\n\n    // Never land inside an atomic node: snap to whichever edge is nearer.\n    if (remaining < length) return { node: root, offset: remaining === 0 ? index : index + 1 };\n    remaining -= length;\n  }\n\n  const last = root.lastChild;\n  if (last && isBogusBr(last)) return { node: root, offset: children.length - 1 };\n  return { node: root, offset: children.length };\n}\n\n/** Places the caret (or a range) at serialized-string offsets. */\nexport function setSelectionOffsets(\n  root: HTMLElement,\n  start: number,\n  end: number,\n  prefix: string,\n  suffix: string,\n): void {\n  const doc = root.ownerDocument;\n  const range = doc.createRange();\n  const from = locate(root, start, prefix, suffix);\n  const to = start === end ? from : locate(root, end, prefix, suffix);\n  range.setStart(from.node, from.offset);\n  range.setEnd(to.node, to.offset);\n  const selection = selectionOf(root);\n  selection?.removeAllRanges();\n  selection?.addRange(range);\n}\n\n/**\n * Resolves viewport coordinates to a caret range, across both the standard API\n * and the WebKit-prefixed one. Returns `null` where neither exists, which is\n * both older Safari and jsdom, so every caller needs a fallback.\n */\nexport function caretFromPoint(doc: Document, x: number, y: number): Range | null {\n  const api = doc as Document & {\n    caretPositionFromPoint?: (x: number, y: number) => { offsetNode: Node; offset: number } | null;\n    caretRangeFromPoint?: (x: number, y: number) => Range | null;\n  };\n  if (typeof api.caretPositionFromPoint === 'function') {\n    const position = api.caretPositionFromPoint(x, y);\n    if (!position) return null;\n    const range = doc.createRange();\n    range.setStart(position.offsetNode, position.offset);\n    range.collapse(true);\n    return range;\n  }\n  if (typeof api.caretRangeFromPoint === 'function') return api.caretRangeFromPoint(x, y);\n  return null;\n}\n\nfunction isRtl(root: HTMLElement): boolean {\n  const view = root.ownerDocument.defaultView;\n  return !!view && view.getComputedStyle(root).direction === 'rtl';\n}\n\n/**\n * The serialized-string offset under a pointer, used for drops. A point inside\n * a chip snaps to the nearer edge, which is the far edge in RTL.\n */\nexport function offsetFromPoint(\n  root: HTMLElement,\n  x: number,\n  y: number,\n  prefix: string,\n  suffix: string,\n): number | null {\n  const range = caretFromPoint(root.ownerDocument, x, y);\n  if (!range || !root.contains(range.startContainer)) return null;\n\n  let node: Node = range.startContainer;\n  let offset = range.startOffset;\n  const chip = closestChip(root, node);\n  if (chip?.parentNode) {\n    const index = Array.prototype.indexOf.call(chip.parentNode.childNodes, chip);\n    node = chip.parentNode;\n    offset = isAfterChip(root, chip, x, y) ? index + 1 : index;\n  }\n  return offsetOfPoint(root, node, offset, prefix, suffix);\n}\n\n/**\n * Whether a pointer over a chip is nearer its far edge, which is its left edge in RTL. A sample in\n * the preview wraps, so this is measured along its lines: across its box, a click on the start of\n * its last line counted as before it.\n */\nexport function isAfterChip(root: HTMLElement, chip: HTMLElement, x: number, y: number): boolean {\n  const fragments = Array.from(chip.getClientRects()).filter((rect) => rect.width > 0);\n  const lines = fragments.length > 1 ? fragments : [chip.getBoundingClientRect()];\n  const distance = (line: DOMRect) => Math.max(line.top - y, y - line.bottom, 0);\n  const hit = lines.reduce((nearest, line, index) => (distance(line) < distance(lines[nearest]) ? index : nearest), 0);\n  const line = lines[hit];\n  const into = Math.min(Math.max(isRtl(root) ? line.right - x : x - line.left, 0), line.width);\n  const before = lines.slice(0, hit).reduce((sum, { width }) => sum + width, 0);\n  const total = lines.reduce((sum, { width }) => sum + width, 0);\n  return before + into > total / 2;\n}\n\n/** A zero-width caret at a box's near or far edge, which in RTL are its right and left. */\nfunction caretAtEdge(root: HTMLElement, rect: DOMRect | undefined, far: boolean): DOMRect | null {\n  return rect ? new DOMRect(far !== isRtl(root) ? rect.right : rect.left, rect.top, 0, rect.height) : null;\n}\n\n/**\n * Where a caret is drawn when the engines' own rect for it is missing or wrong, taken from what it\n * sits against. After a chip ending a line and at the start of a line, Chromium reported no rect,\n * and Firefox put a line start at the end of the line before; in front of the trailing `<br>`, so in\n * an empty field or on a last empty line, all three reported none.\n */\nfunction caretRectBeside(root: HTMLElement, { node, offset }: BoundaryPoint): DOMRect | null {\n  const text = node.nodeType === Node.TEXT_NODE ? (node as Text).data : null;\n\n  const before = text === null ? node.childNodes[offset - 1] : offset === 0 ? node.previousSibling : null;\n  if (isChip(before)) {\n    const rects = (before as HTMLElement).getClientRects();\n    return caretAtEdge(root, rects[rects.length - 1], true);\n  }\n\n  const range = root.ownerDocument.createRange();\n  const measure = () =>\n    typeof range.getClientRects === 'function' ? caretAtEdge(root, range.getClientRects()[0], false) : null;\n  if (text !== null) {\n    if (offset === 0 || text[offset - 1] !== '\\n') return null;\n    if (offset < text.length) {\n      range.setStart(node, offset);\n      range.setEnd(node, offset + 1);\n      return measure();\n    }\n  }\n  const next = text === null ? node.childNodes[offset] : node.nextSibling;\n  if (!next || !isBogusBr(next)) return null;\n  range.selectNode(next);\n  return measure();\n}\n\n/**\n * A caret after a character, at that character's far edge. Only a fallback, for where Chromium\n * reports no rect of its own: after a space that ends a line.\n */\nfunction caretRectAfterCharacter(root: HTMLElement, { node, offset }: BoundaryPoint): DOMRect | null {\n  if (node.nodeType !== Node.TEXT_NODE || offset === 0) return null;\n  const range = root.ownerDocument.createRange();\n  range.setStart(node, offset - 1);\n  range.setEnd(node, offset);\n  const rects = typeof range.getClientRects === 'function' ? range.getClientRects() : null;\n  return caretAtEdge(root, rects?.[rects.length - 1], true);\n}\n\n/** The client rect of a serialized-string range, used to place the autocomplete anchor and the drop caret. */\nexport function rectOfOffsets(\n  root: HTMLElement,\n  start: number,\n  end: number,\n  prefix: string,\n  suffix: string,\n): DOMRect | null {\n  const doc = root.ownerDocument;\n  const range = doc.createRange();\n  const from = locate(root, start, prefix, suffix);\n  const to = start === end ? from : locate(root, end, prefix, suffix);\n  const beside = start === end ? caretRectBeside(root, from) : null;\n  if (beside) return beside;\n  range.setStart(from.node, from.offset);\n  range.setEnd(to.node, to.offset);\n  // Range geometry is layout, which jsdom has none of: both methods can be\n  // missing entirely. Every caller treats `null` as \"no position known\".\n  const rects = typeof range.getClientRects === 'function' ? range.getClientRects() : null;\n  // The last rect of a wrapped range is the one nearest the caret; a collapsed\n  // range often reports no rects at all, in which case the bounding box (which\n  // browsers still fill in from the containing text) is the better guess.\n  if (rects && rects.length > 0) return rects[rects.length - 1];\n  if (typeof range.getBoundingClientRect !== 'function') return null;\n  const bounding = range.getBoundingClientRect();\n  if (bounding.width || bounding.height || bounding.top || bounding.left) return bounding;\n  return start === end ? caretRectAfterCharacter(root, from) : null;\n}\n\n/**\n * Scrolls the editable so the offset is visible, if it isn't already. Needed\n * because none of the ways this component moves the caret scroll on their own:\n * assigning a selection never scrolls, and `focus()` scrolls to wherever the\n * caret was *before* the content was rebuilt.\n */\nexport function scrollOffsetIntoView(\n  root: HTMLElement,\n  offset: number,\n  prefix: string,\n  suffix: string,\n  margin = 8,\n): void {\n  // A collapsed range reports no rect in some engines, so fall back to the one\n  // character before the caret, which occupies the same line.\n  const rect =\n    rectOfOffsets(root, offset, offset, prefix, suffix) ??\n    rectOfOffsets(root, Math.max(0, offset - 1), offset, prefix, suffix);\n  if (!rect) return;\n  const host = root.getBoundingClientRect();\n  if (rect.top < host.top + margin) {\n    root.scrollTop -= host.top + margin - rect.top;\n  } else if (rect.bottom > host.bottom - margin) {\n    root.scrollTop += rect.bottom - (host.bottom - margin);\n  }\n}\n\n/** True when the editable, or anything inside it, currently holds focus. */\nexport function hasFocusWithin(root: HTMLElement): boolean {\n  const active = root.ownerDocument.activeElement;\n  return active === root || (!!active && root.contains(active));\n}\n"],"mappings":"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"}