@pierre/diffs 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -67,13 +67,13 @@ var LineSelectionManager = class {
67
67
  attachEventListeners() {
68
68
  if (this.pre == null) return;
69
69
  this.removeEventListeners();
70
- this.pre.addEventListener("mousedown", this.handleMouseDown);
70
+ this.pre.addEventListener("pointerdown", this.handleMouseDown);
71
71
  }
72
72
  removeEventListeners() {
73
73
  if (this.pre == null) return;
74
- this.pre.removeEventListener("mousedown", this.handleMouseDown);
75
- document.removeEventListener("mousemove", this.handleMouseMove);
76
- document.removeEventListener("mouseup", this.handleMouseUp);
74
+ this.pre.removeEventListener("pointerdown", this.handleMouseDown);
75
+ document.removeEventListener("pointermove", this.handleMouseMove);
76
+ document.removeEventListener("pointerup", this.handleMouseUp);
77
77
  }
78
78
  handleMouseDown = (event) => {
79
79
  const mouseEventData = event.button === 0 ? this.getMouseEventDataForPath(event.composedPath(), "click") : void 0;
@@ -105,8 +105,8 @@ var LineSelectionManager = class {
105
105
  this.updateSelection(lineNumber, eventSide);
106
106
  this.notifySelectionStart(this.selectedRange);
107
107
  }
108
- document.addEventListener("mousemove", this.handleMouseMove);
109
- document.addEventListener("mouseup", this.handleMouseUp);
108
+ document.addEventListener("pointermove", this.handleMouseMove);
109
+ document.addEventListener("pointerup", this.handleMouseUp);
110
110
  };
111
111
  handleMouseMove = (event) => {
112
112
  const mouseEventData = this.getMouseEventDataForPath(event.composedPath(), "move");
@@ -116,8 +116,8 @@ var LineSelectionManager = class {
116
116
  };
117
117
  handleMouseUp = () => {
118
118
  this.anchor = void 0;
119
- document.removeEventListener("mousemove", this.handleMouseMove);
120
- document.removeEventListener("mouseup", this.handleMouseUp);
119
+ document.removeEventListener("pointermove", this.handleMouseMove);
120
+ document.removeEventListener("pointerup", this.handleMouseUp);
121
121
  this.notifySelectionEnd(this.selectedRange);
122
122
  this.notifySelectionChange();
123
123
  };
@@ -1 +1 @@
1
- {"version":3,"file":"LineSelectionManager.js","names":["options: LineSelectionOptions","lineNumber: number | undefined","lineIndex: number | undefined","eventSide: AnnotationSide | undefined"],"sources":["../../src/managers/LineSelectionManager.ts"],"sourcesContent":["import type { AnnotationSide } from '../types';\nimport { areSelectionsEqual } from '../utils/areSelectionsEqual';\n\nexport type SelectionSide = AnnotationSide;\n\nexport interface SelectedLineRange {\n start: number;\n side?: SelectionSide;\n end: number;\n endSide?: SelectionSide;\n}\n\nexport interface LineSelectionOptions {\n enableLineSelection?: boolean;\n onLineSelected?: (range: SelectedLineRange | null) => void;\n onLineSelectionStart?: (range: SelectedLineRange | null) => void;\n onLineSelectionEnd?: (range: SelectedLineRange | null) => void;\n}\n\ninterface MouseInfo {\n lineNumber: number;\n eventSide: AnnotationSide;\n lineIndex: number;\n}\n\n/**\n * Manages line selection state and interactions for code/diff viewers.\n * Handles:\n * - Click and drag selection\n * - Shift-click to extend selection\n * - DOM attribute updates (data-selected-line)\n */\nexport class LineSelectionManager {\n private pre: HTMLPreElement | undefined;\n private selectedRange: SelectedLineRange | null = null;\n private renderedSelectionRange: SelectedLineRange | null | undefined;\n private anchor: { line: number; side: SelectionSide } | undefined;\n private _queuedRender: number | undefined;\n\n constructor(private options: LineSelectionOptions = {}) {}\n\n setOptions(options: LineSelectionOptions): void {\n this.options = { ...this.options, ...options };\n this.removeEventListeners();\n if (this.options.enableLineSelection === true) {\n this.attachEventListeners();\n }\n }\n\n cleanUp(): void {\n this.removeEventListeners();\n if (this._queuedRender != null) {\n cancelAnimationFrame(this._queuedRender);\n this._queuedRender = undefined;\n }\n if (this.pre != null) {\n delete this.pre.dataset.interactiveLineNumbers;\n }\n this.pre = undefined;\n }\n\n setup(pre: HTMLPreElement): void {\n // Assume we are always dirty after a setup...\n this.setDirty();\n if (this.pre !== pre) {\n this.cleanUp();\n }\n this.pre = pre;\n const { enableLineSelection = false } = this.options;\n if (enableLineSelection) {\n this.pre.dataset.interactiveLineNumbers = '';\n this.attachEventListeners();\n } else {\n this.removeEventListeners();\n delete this.pre.dataset.interactiveLineNumbers;\n }\n\n this.setSelection(this.selectedRange);\n }\n\n setDirty(): void {\n this.renderedSelectionRange = undefined;\n }\n\n isDirty(): boolean {\n return this.renderedSelectionRange === undefined;\n }\n\n setSelection(range: SelectedLineRange | null): void {\n const isRangeChange = !(\n range === this.selectedRange ||\n areSelectionsEqual(range ?? undefined, this.selectedRange ?? undefined)\n );\n if (!this.isDirty() && !isRangeChange) return;\n this.selectedRange = range;\n this.renderSelection();\n if (isRangeChange) {\n this.notifySelectionChange();\n }\n }\n\n getSelection(): SelectedLineRange | null {\n return this.selectedRange;\n }\n\n private attachEventListeners(): void {\n if (this.pre == null) return;\n // Lets run a cleanup, just in case\n this.removeEventListeners();\n this.pre.addEventListener('mousedown', this.handleMouseDown);\n }\n\n private removeEventListeners(): void {\n if (this.pre == null) return;\n this.pre.removeEventListener('mousedown', this.handleMouseDown);\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n }\n\n private handleMouseDown = (event: MouseEvent): void => {\n // Only handle left mouse button\n const mouseEventData =\n event.button === 0\n ? this.getMouseEventDataForPath(event.composedPath(), 'click')\n : undefined;\n if (mouseEventData == null) {\n return;\n }\n event.preventDefault();\n const { lineNumber, eventSide, lineIndex } = mouseEventData;\n if (event.shiftKey && this.selectedRange != null) {\n const range = this.deriveRowRangeFromDOM(\n this.selectedRange,\n this.pre?.dataset.type === 'split'\n );\n if (range == null) return;\n const useStart =\n range.start <= range.end\n ? lineIndex >= range.start\n : lineIndex <= range.end;\n this.anchor = {\n line: useStart ? this.selectedRange.start : this.selectedRange.end,\n side:\n (useStart\n ? this.selectedRange.side\n : (this.selectedRange.endSide ?? this.selectedRange.side)) ??\n 'additions',\n };\n this.updateSelection(lineNumber, eventSide);\n this.notifySelectionStart(this.selectedRange);\n } else {\n // Check if clicking on already selected single line to unselect\n if (\n this.selectedRange?.start === lineNumber &&\n this.selectedRange?.end === lineNumber\n ) {\n this.updateSelection(null);\n this.notifySelectionEnd(null);\n this.notifySelectionChange();\n return;\n }\n this.selectedRange = null;\n this.anchor = { line: lineNumber, side: eventSide };\n this.updateSelection(lineNumber, eventSide);\n this.notifySelectionStart(this.selectedRange);\n }\n\n document.addEventListener('mousemove', this.handleMouseMove);\n document.addEventListener('mouseup', this.handleMouseUp);\n };\n\n private handleMouseMove = (event: MouseEvent): void => {\n const mouseEventData = this.getMouseEventDataForPath(\n event.composedPath(),\n 'move'\n );\n if (mouseEventData == null || this.anchor == null) return;\n const { lineNumber, eventSide } = mouseEventData;\n this.updateSelection(lineNumber, eventSide);\n };\n\n private handleMouseUp = (): void => {\n this.anchor = undefined;\n document.removeEventListener('mousemove', this.handleMouseMove);\n document.removeEventListener('mouseup', this.handleMouseUp);\n this.notifySelectionEnd(this.selectedRange);\n this.notifySelectionChange();\n };\n\n private updateSelection(currentLine: null): void;\n private updateSelection(currentLine: number, side: AnnotationSide): void;\n private updateSelection(\n currentLine: number | null,\n side?: AnnotationSide\n ): void {\n if (currentLine == null) {\n this.selectedRange = null;\n } else {\n const anchorSide = this.anchor?.side ?? side;\n const anchorLine = this.anchor?.line ?? currentLine;\n this.selectedRange = {\n start: anchorLine,\n end: currentLine,\n side: anchorSide,\n endSide: anchorSide !== side ? side : undefined,\n };\n }\n this._queuedRender ??= requestAnimationFrame(this.renderSelection);\n }\n\n private renderSelection = (): void => {\n if (this._queuedRender != null) {\n cancelAnimationFrame(this._queuedRender);\n this._queuedRender = undefined;\n }\n if (\n this.pre == null ||\n this.renderedSelectionRange === this.selectedRange\n ) {\n return;\n }\n\n // First clear existing selections, maybe we\n // can cache this to better avoid this query?\n const allSelected = this.pre.querySelectorAll('[data-selected-line]');\n for (const element of allSelected) {\n element.removeAttribute('data-selected-line');\n }\n\n this.renderedSelectionRange = this.selectedRange;\n if (this.selectedRange == null) {\n return;\n }\n\n const codeElements = this.pre.querySelectorAll('[data-code]');\n if (codeElements.length === 0) return;\n if (codeElements.length > 2) {\n console.error(codeElements);\n throw new Error(\n 'LineSelectionManager.applySelectionToDOM: Somehow there are more than 2 code elements...'\n );\n }\n const split = this.pre.dataset.type === 'split';\n const rowRange = this.deriveRowRangeFromDOM(this.selectedRange, split);\n if (rowRange == null) {\n console.error({ rowRange, selectedRange: this.selectedRange });\n throw new Error(\n 'LineSelectionManager.renderSelection: No valid rowRange'\n );\n }\n const isSingle = rowRange.start === rowRange.end;\n const first = Math.min(rowRange.start, rowRange.end);\n const last = Math.max(rowRange.start, rowRange.end);\n for (const code of codeElements) {\n for (const element of code.children) {\n if (!(element instanceof HTMLElement)) continue;\n const lineIndex = this.getLineIndex(element, split);\n if ((lineIndex ?? 0) > last) break;\n if (lineIndex == null || lineIndex < first) continue;\n let attributeValue = isSingle\n ? 'single'\n : lineIndex === first\n ? 'first'\n : lineIndex === last\n ? 'last'\n : '';\n element.setAttribute('data-selected-line', attributeValue);\n // If we have a line annotation following our selected line, we should\n // mark it as selected as well\n if (\n element.nextSibling instanceof HTMLElement &&\n element.nextSibling.hasAttribute('data-line-annotation')\n ) {\n // Depending on the line's attribute value, lets go ahead and correct\n // it when adding in the annotation row\n if (isSingle) {\n // Single technically becomes 2 selected lines\n attributeValue = 'last';\n element.setAttribute('data-selected-line', 'first');\n } else if (lineIndex === first) {\n // We don't want apply 'first' to the line annotation\n attributeValue = '';\n } else if (lineIndex === last) {\n // the annotation will become the last selected line and therefore\n // our existing line should no longer be last\n element.setAttribute('data-selected-line', '');\n }\n element.nextSibling.setAttribute(\n 'data-selected-line',\n attributeValue\n );\n }\n }\n }\n };\n\n private deriveRowRangeFromDOM(\n range: SelectedLineRange,\n split: boolean\n ): { start: number; end: number } | undefined {\n if (range == null) return undefined;\n const start = this.findRowIndexForLineNumber(\n range.start,\n range.side,\n split\n );\n const end =\n range.end === range.start &&\n (range.endSide == null || range.endSide === range.side)\n ? start\n : this.findRowIndexForLineNumber(\n range.end,\n range.endSide ?? range.side,\n split\n );\n return start != null && end != null ? { start, end } : undefined;\n }\n\n private findRowIndexForLineNumber(\n lineNumber: number,\n targetSide: SelectionSide = 'additions',\n split: boolean\n ): number | undefined {\n if (this.pre == null) return undefined;\n const elements = Array.from(\n this.pre.querySelectorAll(`[data-line=\"${lineNumber}\"]`)\n );\n // Given how unified diffs can order things, we need to always process\n // `[data-line]` elements before `[data-alt-line]`\n elements.push(\n ...Array.from(\n this.pre.querySelectorAll(`[data-alt-line=\"${lineNumber}\"]`)\n )\n );\n if (elements.length === 0) return undefined;\n\n for (const element of elements) {\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n const side = this.getLineSideFromElement(element);\n if (side === targetSide) {\n return this.getLineIndex(element, split);\n } else if (parseInt(element.dataset.altLine ?? '') === lineNumber) {\n return this.getLineIndex(element, split);\n }\n }\n console.error(\n 'LineSelectionManager.findRowIndexForLineNumber: Invalid selection',\n lineNumber,\n targetSide\n );\n return undefined;\n }\n\n private notifySelectionChange(): void {\n const { onLineSelected } = this.options;\n if (onLineSelected == null) return;\n\n onLineSelected(this.selectedRange ?? null);\n }\n\n private notifySelectionStart(range: SelectedLineRange | null): void {\n const { onLineSelectionStart } = this.options;\n if (onLineSelectionStart == null) return;\n onLineSelectionStart(range);\n }\n\n private notifySelectionEnd(range: SelectedLineRange | null): void {\n const { onLineSelectionEnd } = this.options;\n if (onLineSelectionEnd == null) return;\n onLineSelectionEnd(range);\n }\n\n private getMouseEventDataForPath(\n path: (EventTarget | undefined)[],\n eventType: 'click' | 'move'\n ): MouseInfo | undefined {\n let lineNumber: number | undefined;\n let lineIndex: number | undefined;\n let isNumberColumn = false;\n let eventSide: AnnotationSide | undefined;\n for (const element of path) {\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n if (element.hasAttribute('data-column-number')) {\n isNumberColumn = true;\n continue;\n }\n if (element.hasAttribute('data-line')) {\n lineNumber = this.getLineNumber(element);\n lineIndex = this.getLineIndex(\n element,\n this.pre?.dataset.type === 'split'\n );\n if (element.dataset.lineType === 'change-deletion') {\n eventSide = 'deletions';\n } else if (element.dataset.lineType === 'change-additions') {\n eventSide = 'additions';\n }\n // if we can't pull out an index or line number, we can't do anything.\n if (lineIndex == null || lineNumber == null) {\n lineIndex = undefined;\n lineNumber = undefined;\n break;\n }\n // If we already have an eventSide, we done computin\n if (eventSide != null) {\n break;\n } else {\n // context type lines will need to be discovered higher up\n // at the data-code level\n }\n continue;\n }\n if (element.hasAttribute('data-code')) {\n eventSide ??= element.hasAttribute('data-deletions')\n ? 'deletions'\n : // context in unified style are assumed to be additions based on\n // their line numbers\n 'additions';\n // If we got to the code element, we def done, son\n break;\n }\n }\n if (\n (eventType === 'click' && !isNumberColumn) ||\n lineIndex == null ||\n lineNumber == null\n ) {\n return undefined;\n }\n return {\n lineIndex,\n lineNumber,\n // Normally this shouldn't hit unless we broke early for whatever reason,\n // but for types lets ensure it's additions if undefined\n eventSide: eventSide ?? 'additions',\n };\n }\n\n private getLineNumber(element: HTMLElement): number | undefined {\n const lineNumber = parseInt(element.dataset.line ?? '', 10);\n return !Number.isNaN(lineNumber) ? lineNumber : undefined;\n }\n\n private getLineIndex(\n element: HTMLElement,\n split: boolean\n ): number | undefined {\n const lineIndexes = (element.dataset.lineIndex ?? '')\n .split(',')\n .map((value) => parseInt(value))\n .filter((value) => !Number.isNaN(value));\n\n if (split && lineIndexes.length === 2) {\n return lineIndexes[1];\n } else if (!split) {\n return lineIndexes[0];\n }\n return undefined;\n }\n\n private getLineSideFromElement(element: HTMLElement): SelectionSide {\n if (element.dataset.lineType === 'change-deletion') {\n return 'deletions';\n }\n if (element.dataset.lineType === 'change-addition') {\n return 'additions';\n }\n const parent = element.closest('[data-code]');\n if (!(parent instanceof HTMLElement)) {\n return 'additions';\n }\n return parent.hasAttribute('data-deletions') ? 'deletions' : 'additions';\n }\n}\n\nexport function pluckLineSelectionOptions({\n enableLineSelection,\n onLineSelected,\n onLineSelectionStart,\n onLineSelectionEnd,\n}: LineSelectionOptions): LineSelectionOptions {\n return {\n enableLineSelection,\n onLineSelected,\n onLineSelectionStart,\n onLineSelectionEnd,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"LineSelectionManager.js","names":["options: LineSelectionOptions","lineNumber: number | undefined","lineIndex: number | undefined","eventSide: AnnotationSide | undefined"],"sources":["../../src/managers/LineSelectionManager.ts"],"sourcesContent":["import type { AnnotationSide } from '../types';\nimport { areSelectionsEqual } from '../utils/areSelectionsEqual';\n\nexport type SelectionSide = AnnotationSide;\n\nexport interface SelectedLineRange {\n start: number;\n side?: SelectionSide;\n end: number;\n endSide?: SelectionSide;\n}\n\nexport interface LineSelectionOptions {\n enableLineSelection?: boolean;\n onLineSelected?: (range: SelectedLineRange | null) => void;\n onLineSelectionStart?: (range: SelectedLineRange | null) => void;\n onLineSelectionEnd?: (range: SelectedLineRange | null) => void;\n}\n\ninterface MouseInfo {\n lineNumber: number;\n eventSide: AnnotationSide;\n lineIndex: number;\n}\n\n/**\n * Manages line selection state and interactions for code/diff viewers.\n * Handles:\n * - Click and drag selection\n * - Shift-click to extend selection\n * - DOM attribute updates (data-selected-line)\n */\nexport class LineSelectionManager {\n private pre: HTMLPreElement | undefined;\n private selectedRange: SelectedLineRange | null = null;\n private renderedSelectionRange: SelectedLineRange | null | undefined;\n private anchor: { line: number; side: SelectionSide } | undefined;\n private _queuedRender: number | undefined;\n\n constructor(private options: LineSelectionOptions = {}) {}\n\n setOptions(options: LineSelectionOptions): void {\n this.options = { ...this.options, ...options };\n this.removeEventListeners();\n if (this.options.enableLineSelection === true) {\n this.attachEventListeners();\n }\n }\n\n cleanUp(): void {\n this.removeEventListeners();\n if (this._queuedRender != null) {\n cancelAnimationFrame(this._queuedRender);\n this._queuedRender = undefined;\n }\n if (this.pre != null) {\n delete this.pre.dataset.interactiveLineNumbers;\n }\n this.pre = undefined;\n }\n\n setup(pre: HTMLPreElement): void {\n // Assume we are always dirty after a setup...\n this.setDirty();\n if (this.pre !== pre) {\n this.cleanUp();\n }\n this.pre = pre;\n const { enableLineSelection = false } = this.options;\n if (enableLineSelection) {\n this.pre.dataset.interactiveLineNumbers = '';\n this.attachEventListeners();\n } else {\n this.removeEventListeners();\n delete this.pre.dataset.interactiveLineNumbers;\n }\n\n this.setSelection(this.selectedRange);\n }\n\n setDirty(): void {\n this.renderedSelectionRange = undefined;\n }\n\n isDirty(): boolean {\n return this.renderedSelectionRange === undefined;\n }\n\n setSelection(range: SelectedLineRange | null): void {\n const isRangeChange = !(\n range === this.selectedRange ||\n areSelectionsEqual(range ?? undefined, this.selectedRange ?? undefined)\n );\n if (!this.isDirty() && !isRangeChange) return;\n this.selectedRange = range;\n this.renderSelection();\n if (isRangeChange) {\n this.notifySelectionChange();\n }\n }\n\n getSelection(): SelectedLineRange | null {\n return this.selectedRange;\n }\n\n private attachEventListeners(): void {\n if (this.pre == null) return;\n // Lets run a cleanup, just in case\n this.removeEventListeners();\n this.pre.addEventListener('pointerdown', this.handleMouseDown);\n }\n\n private removeEventListeners(): void {\n if (this.pre == null) return;\n this.pre.removeEventListener('pointerdown', this.handleMouseDown);\n document.removeEventListener('pointermove', this.handleMouseMove);\n document.removeEventListener('pointerup', this.handleMouseUp);\n }\n\n private handleMouseDown = (event: PointerEvent): void => {\n // Only handle left mouse button\n const mouseEventData =\n event.button === 0\n ? this.getMouseEventDataForPath(event.composedPath(), 'click')\n : undefined;\n if (mouseEventData == null) {\n return;\n }\n event.preventDefault();\n const { lineNumber, eventSide, lineIndex } = mouseEventData;\n if (event.shiftKey && this.selectedRange != null) {\n const range = this.deriveRowRangeFromDOM(\n this.selectedRange,\n this.pre?.dataset.type === 'split'\n );\n if (range == null) return;\n const useStart =\n range.start <= range.end\n ? lineIndex >= range.start\n : lineIndex <= range.end;\n this.anchor = {\n line: useStart ? this.selectedRange.start : this.selectedRange.end,\n side:\n (useStart\n ? this.selectedRange.side\n : (this.selectedRange.endSide ?? this.selectedRange.side)) ??\n 'additions',\n };\n this.updateSelection(lineNumber, eventSide);\n this.notifySelectionStart(this.selectedRange);\n } else {\n // Check if clicking on already selected single line to unselect\n if (\n this.selectedRange?.start === lineNumber &&\n this.selectedRange?.end === lineNumber\n ) {\n this.updateSelection(null);\n this.notifySelectionEnd(null);\n this.notifySelectionChange();\n return;\n }\n this.selectedRange = null;\n this.anchor = { line: lineNumber, side: eventSide };\n this.updateSelection(lineNumber, eventSide);\n this.notifySelectionStart(this.selectedRange);\n }\n\n document.addEventListener('pointermove', this.handleMouseMove);\n document.addEventListener('pointerup', this.handleMouseUp);\n };\n\n private handleMouseMove = (event: PointerEvent): void => {\n const mouseEventData = this.getMouseEventDataForPath(\n event.composedPath(),\n 'move'\n );\n if (mouseEventData == null || this.anchor == null) return;\n const { lineNumber, eventSide } = mouseEventData;\n this.updateSelection(lineNumber, eventSide);\n };\n\n private handleMouseUp = (): void => {\n this.anchor = undefined;\n document.removeEventListener('pointermove', this.handleMouseMove);\n document.removeEventListener('pointerup', this.handleMouseUp);\n this.notifySelectionEnd(this.selectedRange);\n this.notifySelectionChange();\n };\n\n private updateSelection(currentLine: null): void;\n private updateSelection(currentLine: number, side: AnnotationSide): void;\n private updateSelection(\n currentLine: number | null,\n side?: AnnotationSide\n ): void {\n if (currentLine == null) {\n this.selectedRange = null;\n } else {\n const anchorSide = this.anchor?.side ?? side;\n const anchorLine = this.anchor?.line ?? currentLine;\n this.selectedRange = {\n start: anchorLine,\n end: currentLine,\n side: anchorSide,\n endSide: anchorSide !== side ? side : undefined,\n };\n }\n this._queuedRender ??= requestAnimationFrame(this.renderSelection);\n }\n\n private renderSelection = (): void => {\n if (this._queuedRender != null) {\n cancelAnimationFrame(this._queuedRender);\n this._queuedRender = undefined;\n }\n if (\n this.pre == null ||\n this.renderedSelectionRange === this.selectedRange\n ) {\n return;\n }\n\n // First clear existing selections, maybe we\n // can cache this to better avoid this query?\n const allSelected = this.pre.querySelectorAll('[data-selected-line]');\n for (const element of allSelected) {\n element.removeAttribute('data-selected-line');\n }\n\n this.renderedSelectionRange = this.selectedRange;\n if (this.selectedRange == null) {\n return;\n }\n\n const codeElements = this.pre.querySelectorAll('[data-code]');\n if (codeElements.length === 0) return;\n if (codeElements.length > 2) {\n console.error(codeElements);\n throw new Error(\n 'LineSelectionManager.applySelectionToDOM: Somehow there are more than 2 code elements...'\n );\n }\n const split = this.pre.dataset.type === 'split';\n const rowRange = this.deriveRowRangeFromDOM(this.selectedRange, split);\n if (rowRange == null) {\n console.error({ rowRange, selectedRange: this.selectedRange });\n throw new Error(\n 'LineSelectionManager.renderSelection: No valid rowRange'\n );\n }\n const isSingle = rowRange.start === rowRange.end;\n const first = Math.min(rowRange.start, rowRange.end);\n const last = Math.max(rowRange.start, rowRange.end);\n for (const code of codeElements) {\n for (const element of code.children) {\n if (!(element instanceof HTMLElement)) continue;\n const lineIndex = this.getLineIndex(element, split);\n if ((lineIndex ?? 0) > last) break;\n if (lineIndex == null || lineIndex < first) continue;\n let attributeValue = isSingle\n ? 'single'\n : lineIndex === first\n ? 'first'\n : lineIndex === last\n ? 'last'\n : '';\n element.setAttribute('data-selected-line', attributeValue);\n // If we have a line annotation following our selected line, we should\n // mark it as selected as well\n if (\n element.nextSibling instanceof HTMLElement &&\n element.nextSibling.hasAttribute('data-line-annotation')\n ) {\n // Depending on the line's attribute value, lets go ahead and correct\n // it when adding in the annotation row\n if (isSingle) {\n // Single technically becomes 2 selected lines\n attributeValue = 'last';\n element.setAttribute('data-selected-line', 'first');\n } else if (lineIndex === first) {\n // We don't want apply 'first' to the line annotation\n attributeValue = '';\n } else if (lineIndex === last) {\n // the annotation will become the last selected line and therefore\n // our existing line should no longer be last\n element.setAttribute('data-selected-line', '');\n }\n element.nextSibling.setAttribute(\n 'data-selected-line',\n attributeValue\n );\n }\n }\n }\n };\n\n private deriveRowRangeFromDOM(\n range: SelectedLineRange,\n split: boolean\n ): { start: number; end: number } | undefined {\n if (range == null) return undefined;\n const start = this.findRowIndexForLineNumber(\n range.start,\n range.side,\n split\n );\n const end =\n range.end === range.start &&\n (range.endSide == null || range.endSide === range.side)\n ? start\n : this.findRowIndexForLineNumber(\n range.end,\n range.endSide ?? range.side,\n split\n );\n return start != null && end != null ? { start, end } : undefined;\n }\n\n private findRowIndexForLineNumber(\n lineNumber: number,\n targetSide: SelectionSide = 'additions',\n split: boolean\n ): number | undefined {\n if (this.pre == null) return undefined;\n const elements = Array.from(\n this.pre.querySelectorAll(`[data-line=\"${lineNumber}\"]`)\n );\n // Given how unified diffs can order things, we need to always process\n // `[data-line]` elements before `[data-alt-line]`\n elements.push(\n ...Array.from(\n this.pre.querySelectorAll(`[data-alt-line=\"${lineNumber}\"]`)\n )\n );\n if (elements.length === 0) return undefined;\n\n for (const element of elements) {\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n const side = this.getLineSideFromElement(element);\n if (side === targetSide) {\n return this.getLineIndex(element, split);\n } else if (parseInt(element.dataset.altLine ?? '') === lineNumber) {\n return this.getLineIndex(element, split);\n }\n }\n console.error(\n 'LineSelectionManager.findRowIndexForLineNumber: Invalid selection',\n lineNumber,\n targetSide\n );\n return undefined;\n }\n\n private notifySelectionChange(): void {\n const { onLineSelected } = this.options;\n if (onLineSelected == null) return;\n\n onLineSelected(this.selectedRange ?? null);\n }\n\n private notifySelectionStart(range: SelectedLineRange | null): void {\n const { onLineSelectionStart } = this.options;\n if (onLineSelectionStart == null) return;\n onLineSelectionStart(range);\n }\n\n private notifySelectionEnd(range: SelectedLineRange | null): void {\n const { onLineSelectionEnd } = this.options;\n if (onLineSelectionEnd == null) return;\n onLineSelectionEnd(range);\n }\n\n private getMouseEventDataForPath(\n path: (EventTarget | undefined)[],\n eventType: 'click' | 'move'\n ): MouseInfo | undefined {\n let lineNumber: number | undefined;\n let lineIndex: number | undefined;\n let isNumberColumn = false;\n let eventSide: AnnotationSide | undefined;\n for (const element of path) {\n if (!(element instanceof HTMLElement)) {\n continue;\n }\n if (element.hasAttribute('data-column-number')) {\n isNumberColumn = true;\n continue;\n }\n if (element.hasAttribute('data-line')) {\n lineNumber = this.getLineNumber(element);\n lineIndex = this.getLineIndex(\n element,\n this.pre?.dataset.type === 'split'\n );\n if (element.dataset.lineType === 'change-deletion') {\n eventSide = 'deletions';\n } else if (element.dataset.lineType === 'change-additions') {\n eventSide = 'additions';\n }\n // if we can't pull out an index or line number, we can't do anything.\n if (lineIndex == null || lineNumber == null) {\n lineIndex = undefined;\n lineNumber = undefined;\n break;\n }\n // If we already have an eventSide, we done computin\n if (eventSide != null) {\n break;\n } else {\n // context type lines will need to be discovered higher up\n // at the data-code level\n }\n continue;\n }\n if (element.hasAttribute('data-code')) {\n eventSide ??= element.hasAttribute('data-deletions')\n ? 'deletions'\n : // context in unified style are assumed to be additions based on\n // their line numbers\n 'additions';\n // If we got to the code element, we def done, son\n break;\n }\n }\n if (\n (eventType === 'click' && !isNumberColumn) ||\n lineIndex == null ||\n lineNumber == null\n ) {\n return undefined;\n }\n return {\n lineIndex,\n lineNumber,\n // Normally this shouldn't hit unless we broke early for whatever reason,\n // but for types lets ensure it's additions if undefined\n eventSide: eventSide ?? 'additions',\n };\n }\n\n private getLineNumber(element: HTMLElement): number | undefined {\n const lineNumber = parseInt(element.dataset.line ?? '', 10);\n return !Number.isNaN(lineNumber) ? lineNumber : undefined;\n }\n\n private getLineIndex(\n element: HTMLElement,\n split: boolean\n ): number | undefined {\n const lineIndexes = (element.dataset.lineIndex ?? '')\n .split(',')\n .map((value) => parseInt(value))\n .filter((value) => !Number.isNaN(value));\n\n if (split && lineIndexes.length === 2) {\n return lineIndexes[1];\n } else if (!split) {\n return lineIndexes[0];\n }\n return undefined;\n }\n\n private getLineSideFromElement(element: HTMLElement): SelectionSide {\n if (element.dataset.lineType === 'change-deletion') {\n return 'deletions';\n }\n if (element.dataset.lineType === 'change-addition') {\n return 'additions';\n }\n const parent = element.closest('[data-code]');\n if (!(parent instanceof HTMLElement)) {\n return 'additions';\n }\n return parent.hasAttribute('data-deletions') ? 'deletions' : 'additions';\n }\n}\n\nexport function pluckLineSelectionOptions({\n enableLineSelection,\n onLineSelected,\n onLineSelectionStart,\n onLineSelectionEnd,\n}: LineSelectionOptions): LineSelectionOptions {\n return {\n enableLineSelection,\n onLineSelected,\n onLineSelectionStart,\n onLineSelectionEnd,\n };\n}\n"],"mappings":";;;;;;;;;;AAgCA,IAAa,uBAAb,MAAkC;CAChC,AAAQ;CACR,AAAQ,gBAA0C;CAClD,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YAAY,AAAQA,UAAgC,EAAE,EAAE;EAApC;;CAEpB,WAAW,SAAqC;AAC9C,OAAK,UAAU;GAAE,GAAG,KAAK;GAAS,GAAG;GAAS;AAC9C,OAAK,sBAAsB;AAC3B,MAAI,KAAK,QAAQ,wBAAwB,KACvC,MAAK,sBAAsB;;CAI/B,UAAgB;AACd,OAAK,sBAAsB;AAC3B,MAAI,KAAK,iBAAiB,MAAM;AAC9B,wBAAqB,KAAK,cAAc;AACxC,QAAK,gBAAgB;;AAEvB,MAAI,KAAK,OAAO,KACd,QAAO,KAAK,IAAI,QAAQ;AAE1B,OAAK,MAAM;;CAGb,MAAM,KAA2B;AAE/B,OAAK,UAAU;AACf,MAAI,KAAK,QAAQ,IACf,MAAK,SAAS;AAEhB,OAAK,MAAM;EACX,MAAM,EAAE,sBAAsB,UAAU,KAAK;AAC7C,MAAI,qBAAqB;AACvB,QAAK,IAAI,QAAQ,yBAAyB;AAC1C,QAAK,sBAAsB;SACtB;AACL,QAAK,sBAAsB;AAC3B,UAAO,KAAK,IAAI,QAAQ;;AAG1B,OAAK,aAAa,KAAK,cAAc;;CAGvC,WAAiB;AACf,OAAK,yBAAyB;;CAGhC,UAAmB;AACjB,SAAO,KAAK,2BAA2B;;CAGzC,aAAa,OAAuC;EAClD,MAAM,gBAAgB,EACpB,UAAU,KAAK,iBACf,mBAAmB,SAAS,QAAW,KAAK,iBAAiB,OAAU;AAEzE,MAAI,CAAC,KAAK,SAAS,IAAI,CAAC,cAAe;AACvC,OAAK,gBAAgB;AACrB,OAAK,iBAAiB;AACtB,MAAI,cACF,MAAK,uBAAuB;;CAIhC,eAAyC;AACvC,SAAO,KAAK;;CAGd,AAAQ,uBAA6B;AACnC,MAAI,KAAK,OAAO,KAAM;AAEtB,OAAK,sBAAsB;AAC3B,OAAK,IAAI,iBAAiB,eAAe,KAAK,gBAAgB;;CAGhE,AAAQ,uBAA6B;AACnC,MAAI,KAAK,OAAO,KAAM;AACtB,OAAK,IAAI,oBAAoB,eAAe,KAAK,gBAAgB;AACjE,WAAS,oBAAoB,eAAe,KAAK,gBAAgB;AACjE,WAAS,oBAAoB,aAAa,KAAK,cAAc;;CAG/D,AAAQ,mBAAmB,UAA8B;EAEvD,MAAM,iBACJ,MAAM,WAAW,IACb,KAAK,yBAAyB,MAAM,cAAc,EAAE,QAAQ,GAC5D;AACN,MAAI,kBAAkB,KACpB;AAEF,QAAM,gBAAgB;EACtB,MAAM,EAAE,YAAY,WAAW,cAAc;AAC7C,MAAI,MAAM,YAAY,KAAK,iBAAiB,MAAM;GAChD,MAAM,QAAQ,KAAK,sBACjB,KAAK,eACL,KAAK,KAAK,QAAQ,SAAS,QAC5B;AACD,OAAI,SAAS,KAAM;GACnB,MAAM,WACJ,MAAM,SAAS,MAAM,MACjB,aAAa,MAAM,QACnB,aAAa,MAAM;AACzB,QAAK,SAAS;IACZ,MAAM,WAAW,KAAK,cAAc,QAAQ,KAAK,cAAc;IAC/D,OACG,WACG,KAAK,cAAc,OAClB,KAAK,cAAc,WAAW,KAAK,cAAc,SACtD;IACH;AACD,QAAK,gBAAgB,YAAY,UAAU;AAC3C,QAAK,qBAAqB,KAAK,cAAc;SACxC;AAEL,OACE,KAAK,eAAe,UAAU,cAC9B,KAAK,eAAe,QAAQ,YAC5B;AACA,SAAK,gBAAgB,KAAK;AAC1B,SAAK,mBAAmB,KAAK;AAC7B,SAAK,uBAAuB;AAC5B;;AAEF,QAAK,gBAAgB;AACrB,QAAK,SAAS;IAAE,MAAM;IAAY,MAAM;IAAW;AACnD,QAAK,gBAAgB,YAAY,UAAU;AAC3C,QAAK,qBAAqB,KAAK,cAAc;;AAG/C,WAAS,iBAAiB,eAAe,KAAK,gBAAgB;AAC9D,WAAS,iBAAiB,aAAa,KAAK,cAAc;;CAG5D,AAAQ,mBAAmB,UAA8B;EACvD,MAAM,iBAAiB,KAAK,yBAC1B,MAAM,cAAc,EACpB,OACD;AACD,MAAI,kBAAkB,QAAQ,KAAK,UAAU,KAAM;EACnD,MAAM,EAAE,YAAY,cAAc;AAClC,OAAK,gBAAgB,YAAY,UAAU;;CAG7C,AAAQ,sBAA4B;AAClC,OAAK,SAAS;AACd,WAAS,oBAAoB,eAAe,KAAK,gBAAgB;AACjE,WAAS,oBAAoB,aAAa,KAAK,cAAc;AAC7D,OAAK,mBAAmB,KAAK,cAAc;AAC3C,OAAK,uBAAuB;;CAK9B,AAAQ,gBACN,aACA,MACM;AACN,MAAI,eAAe,KACjB,MAAK,gBAAgB;OAChB;GACL,MAAM,aAAa,KAAK,QAAQ,QAAQ;AAExC,QAAK,gBAAgB;IACnB,OAFiB,KAAK,QAAQ,QAAQ;IAGtC,KAAK;IACL,MAAM;IACN,SAAS,eAAe,OAAO,OAAO;IACvC;;AAEH,OAAK,kBAAkB,sBAAsB,KAAK,gBAAgB;;CAGpE,AAAQ,wBAA8B;AACpC,MAAI,KAAK,iBAAiB,MAAM;AAC9B,wBAAqB,KAAK,cAAc;AACxC,QAAK,gBAAgB;;AAEvB,MACE,KAAK,OAAO,QACZ,KAAK,2BAA2B,KAAK,cAErC;EAKF,MAAM,cAAc,KAAK,IAAI,iBAAiB,uBAAuB;AACrE,OAAK,MAAM,WAAW,YACpB,SAAQ,gBAAgB,qBAAqB;AAG/C,OAAK,yBAAyB,KAAK;AACnC,MAAI,KAAK,iBAAiB,KACxB;EAGF,MAAM,eAAe,KAAK,IAAI,iBAAiB,cAAc;AAC7D,MAAI,aAAa,WAAW,EAAG;AAC/B,MAAI,aAAa,SAAS,GAAG;AAC3B,WAAQ,MAAM,aAAa;AAC3B,SAAM,IAAI,MACR,2FACD;;EAEH,MAAM,QAAQ,KAAK,IAAI,QAAQ,SAAS;EACxC,MAAM,WAAW,KAAK,sBAAsB,KAAK,eAAe,MAAM;AACtE,MAAI,YAAY,MAAM;AACpB,WAAQ,MAAM;IAAE;IAAU,eAAe,KAAK;IAAe,CAAC;AAC9D,SAAM,IAAI,MACR,0DACD;;EAEH,MAAM,WAAW,SAAS,UAAU,SAAS;EAC7C,MAAM,QAAQ,KAAK,IAAI,SAAS,OAAO,SAAS,IAAI;EACpD,MAAM,OAAO,KAAK,IAAI,SAAS,OAAO,SAAS,IAAI;AACnD,OAAK,MAAM,QAAQ,aACjB,MAAK,MAAM,WAAW,KAAK,UAAU;AACnC,OAAI,EAAE,mBAAmB,aAAc;GACvC,MAAM,YAAY,KAAK,aAAa,SAAS,MAAM;AACnD,QAAK,aAAa,KAAK,KAAM;AAC7B,OAAI,aAAa,QAAQ,YAAY,MAAO;GAC5C,IAAI,iBAAiB,WACjB,WACA,cAAc,QACZ,UACA,cAAc,OACZ,SACA;AACR,WAAQ,aAAa,sBAAsB,eAAe;AAG1D,OACE,QAAQ,uBAAuB,eAC/B,QAAQ,YAAY,aAAa,uBAAuB,EACxD;AAGA,QAAI,UAAU;AAEZ,sBAAiB;AACjB,aAAQ,aAAa,sBAAsB,QAAQ;eAC1C,cAAc,MAEvB,kBAAiB;aACR,cAAc,KAGvB,SAAQ,aAAa,sBAAsB,GAAG;AAEhD,YAAQ,YAAY,aAClB,sBACA,eACD;;;;CAMT,AAAQ,sBACN,OACA,OAC4C;AAC5C,MAAI,SAAS,KAAM,QAAO;EAC1B,MAAM,QAAQ,KAAK,0BACjB,MAAM,OACN,MAAM,MACN,MACD;EACD,MAAM,MACJ,MAAM,QAAQ,MAAM,UACnB,MAAM,WAAW,QAAQ,MAAM,YAAY,MAAM,QAC9C,QACA,KAAK,0BACH,MAAM,KACN,MAAM,WAAW,MAAM,MACvB,MACD;AACP,SAAO,SAAS,QAAQ,OAAO,OAAO;GAAE;GAAO;GAAK,GAAG;;CAGzD,AAAQ,0BACN,YACA,aAA4B,aAC5B,OACoB;AACpB,MAAI,KAAK,OAAO,KAAM,QAAO;EAC7B,MAAM,WAAW,MAAM,KACrB,KAAK,IAAI,iBAAiB,eAAe,WAAW,IAAI,CACzD;AAGD,WAAS,KACP,GAAG,MAAM,KACP,KAAK,IAAI,iBAAiB,mBAAmB,WAAW,IAAI,CAC7D,CACF;AACD,MAAI,SAAS,WAAW,EAAG,QAAO;AAElC,OAAK,MAAM,WAAW,UAAU;AAC9B,OAAI,EAAE,mBAAmB,aACvB;AAGF,OADa,KAAK,uBAAuB,QAAQ,KACpC,WACX,QAAO,KAAK,aAAa,SAAS,MAAM;YAC/B,SAAS,QAAQ,QAAQ,WAAW,GAAG,KAAK,WACrD,QAAO,KAAK,aAAa,SAAS,MAAM;;AAG5C,UAAQ,MACN,qEACA,YACA,WACD;;CAIH,AAAQ,wBAA8B;EACpC,MAAM,EAAE,mBAAmB,KAAK;AAChC,MAAI,kBAAkB,KAAM;AAE5B,iBAAe,KAAK,iBAAiB,KAAK;;CAG5C,AAAQ,qBAAqB,OAAuC;EAClE,MAAM,EAAE,yBAAyB,KAAK;AACtC,MAAI,wBAAwB,KAAM;AAClC,uBAAqB,MAAM;;CAG7B,AAAQ,mBAAmB,OAAuC;EAChE,MAAM,EAAE,uBAAuB,KAAK;AACpC,MAAI,sBAAsB,KAAM;AAChC,qBAAmB,MAAM;;CAG3B,AAAQ,yBACN,MACA,WACuB;EACvB,IAAIC;EACJ,IAAIC;EACJ,IAAI,iBAAiB;EACrB,IAAIC;AACJ,OAAK,MAAM,WAAW,MAAM;AAC1B,OAAI,EAAE,mBAAmB,aACvB;AAEF,OAAI,QAAQ,aAAa,qBAAqB,EAAE;AAC9C,qBAAiB;AACjB;;AAEF,OAAI,QAAQ,aAAa,YAAY,EAAE;AACrC,iBAAa,KAAK,cAAc,QAAQ;AACxC,gBAAY,KAAK,aACf,SACA,KAAK,KAAK,QAAQ,SAAS,QAC5B;AACD,QAAI,QAAQ,QAAQ,aAAa,kBAC/B,aAAY;aACH,QAAQ,QAAQ,aAAa,mBACtC,aAAY;AAGd,QAAI,aAAa,QAAQ,cAAc,MAAM;AAC3C,iBAAY;AACZ,kBAAa;AACb;;AAGF,QAAI,aAAa,KACf;AAKF;;AAEF,OAAI,QAAQ,aAAa,YAAY,EAAE;AACrC,kBAAc,QAAQ,aAAa,iBAAiB,GAChD,cAGA;AAEJ;;;AAGJ,MACG,cAAc,WAAW,CAAC,kBAC3B,aAAa,QACb,cAAc,KAEd;AAEF,SAAO;GACL;GACA;GAGA,WAAW,aAAa;GACzB;;CAGH,AAAQ,cAAc,SAA0C;EAC9D,MAAM,aAAa,SAAS,QAAQ,QAAQ,QAAQ,IAAI,GAAG;AAC3D,SAAO,CAAC,OAAO,MAAM,WAAW,GAAG,aAAa;;CAGlD,AAAQ,aACN,SACA,OACoB;EACpB,MAAM,eAAe,QAAQ,QAAQ,aAAa,IAC/C,MAAM,IAAI,CACV,KAAK,UAAU,SAAS,MAAM,CAAC,CAC/B,QAAQ,UAAU,CAAC,OAAO,MAAM,MAAM,CAAC;AAE1C,MAAI,SAAS,YAAY,WAAW,EAClC,QAAO,YAAY;WACV,CAAC,MACV,QAAO,YAAY;;CAKvB,AAAQ,uBAAuB,SAAqC;AAClE,MAAI,QAAQ,QAAQ,aAAa,kBAC/B,QAAO;AAET,MAAI,QAAQ,QAAQ,aAAa,kBAC/B,QAAO;EAET,MAAM,SAAS,QAAQ,QAAQ,cAAc;AAC7C,MAAI,EAAE,kBAAkB,aACtB,QAAO;AAET,SAAO,OAAO,aAAa,iBAAiB,GAAG,cAAc;;;AAIjE,SAAgB,0BAA0B,EACxC,qBACA,gBACA,sBACA,sBAC6C;AAC7C,QAAO;EACL;EACA;EACA;EACA;EACD"}
@@ -7,13 +7,13 @@ interface OnLineClickProps extends LineEventBaseProps {
7
7
  event: PointerEvent;
8
8
  }
9
9
  interface OnLineEnterLeaveProps extends LineEventBaseProps {
10
- event: MouseEvent;
10
+ event: PointerEvent;
11
11
  }
12
12
  interface OnDiffLineClickProps extends DiffLineEventBaseProps {
13
13
  event: PointerEvent;
14
14
  }
15
15
  interface OnDiffLineEnterLeaveProps extends DiffLineEventBaseProps {
16
- event: MouseEvent;
16
+ event: PointerEvent;
17
17
  }
18
18
  type EventClickProps<TMode extends MouseEventManagerMode> = TMode extends "file" ? OnLineClickProps : OnDiffLineClickProps;
19
19
  type MouseEventEnterLeaveProps<TMode extends MouseEventManagerMode> = TMode extends "file" ? OnLineEnterLeaveProps : OnDiffLineEnterLeaveProps;
@@ -45,9 +45,9 @@ declare class MouseEventManager<TMode extends MouseEventManagerMode> {
45
45
  cleanUp(): void;
46
46
  setup(pre: HTMLPreElement): void;
47
47
  getHoveredLine: () => GetHoveredLineResult<TMode> | undefined;
48
- handleMouseClick: (event: MouseEvent) => void;
49
- handleMouseMove: (event: MouseEvent) => void;
50
- handleMouseLeave: (event: MouseEvent) => void;
48
+ handleMouseClick: (event: PointerEvent) => void;
49
+ handleMouseMove: (event: PointerEvent) => void;
50
+ handleMouseLeave: (event: PointerEvent) => void;
51
51
  private handleMouseEvent;
52
52
  private getLineData;
53
53
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MouseEventManager.d.ts","names":["mode: TMode","options: MouseEventManagerOptions<TMode>"],"sources":["../../src/managers/MouseEventManager.ts"],"sourcesContent":[],"mappings":";;;KAOY,QAAA;KAEA,qBAAA;AAFA,UAIK,gBAAA,SAAyB,kBAJ9B,CAAA;EAEZ,KAAY,EAGH,YAHG;AAEZ;AAIiB,UAAA,qBAAA,SAA8B,kBAAA,CAAA;EAI/C,KAAiB,EAHR,UAGQ;AAIjB;AAQK,UAZY,oBAAA,SAA6B,sBAYzC,CAAA;EAA8B,KAAA,EAX1B,YAW0B;;AAC/B,UATa,yBAAA,SAAkC,sBAS/C,CAAA;EACA,KAAA,EATK,UASL;;AAAA,KAFC,eAIA,CAAA,cAJ8B,qBAI9B,CAAA,GAJuD,KAIvD,SAAA,MAAA,GAHD,gBAGC,GAFD,oBAEC;KAAA,yBAAwC,CAAA,cAAA,qBAAA,CAAA,GAC3C,KAD2C,SAAA,MAAA,GACpB,qBADoB,GACI,yBADJ;AAC3C,KAYU,oBAZV,CAAA,cAY6C,qBAZ7C,CAAA,GAaA,KAbA,SAAA,MAAA,GAAA;EAAuB,UAAA,EAAA,MAAA;CAAwB,GAAA;EAAA,UAAA,EAAA,MAAA;EAYjD,IAAY,EAGsB,cAHtB;CAAmC;AAC7C,UAmCe,4BAnCf,CAAA,cAoCc,qBApCd,CAAA,CAAA;EAEgC,kBAAA,CAAA,EAAA,OAAA;EAAA,WAAA,EAAA,KAAA,EAqCZ,eArCY,CAqCI,KArCJ,CAAA,CAAA,EAAA,OAAA;EAiClC,iBAAiB,EAAA,KAAA,EAKW,eALX,CAK2B,KAL3B,CAAA,CAAA,EAAA,OAAA;EACD,WAAA,EAAA,KAAA,EAKM,yBALN,CAKgC,KALhC,CAAA,CAAA,EAAA,OAAA;EAGsB,WAAA,EAAA,KAAA,EAGhB,yBAHgB,CAGU,KAHV,CAAA,CAAA,EAAA,OAAA;EAAhB,kBAAA,CAAA,EAIC,QAJD;;AACM,UAMX,wBANW,CAAA,cAM4B,qBAN5B,CAAA,SAOlB,4BAPkB,CAOW,KAPX,CAAA,CAAA;EACoB,YAAA,EAAA,SAAA,EAAA,MAAA,EAAA,SAAA,EAOF,mBAPE,CAAA,EAAA,OAAA;;AACA,cASnC,iBATmC,CAAA,cASH,qBATG,CAAA,CAAA;EAA1B,QAAA,IAAA;EACC,QAAA,OAAA;EAAA,QAAA,WAAA;EAGvB,QAAiB,GAAA;EAAuC,QAAA,SAAA;EACjB,WAAA,CAAA,IAAA,EAUrB,KAVqB,EAAA,OAAA,EAWlB,wBAXkB,CAWO,KAXP,CAAA;EACO,UAAA,CAAA,OAAA,EAaxB,wBAbwB,CAaC,KAbD,CAAA,CAAA,EAAA,IAAA;EADpC,OAAA,CAAA,CAAA,EAAA,IAAA;EAAA,KAAA,CAAA,GAAA,EA2BG,cA3BH,CAAA,EAAA,IAAA;EAIV,cAAa,EAAA,GAAA,GAgGU,oBAhGV,CAgG+B,KAhG/B,CAAA,GAAA,SAAA;EAAgC,gBAAA,EAAA,CAAA,KAAA,EAiHhB,UAjHgB,EAAA,GAAA,IAAA;EAM3B,eAAA,EAAA,CAAA,KAAA,EAqHU,UArHV,EAAA,GAAA,IAAA;EAC4B,gBAAA,EAAA,CAAA,KAAA,EA8HjB,UA9HiB,EAAA,GAAA,IAAA;EAAzB,QAAA,gBAAA;EAG0B,QAAA,WAAA;;AAalC,iBAsWG,sBAtWH,CAAA,cAsWwC,qBAtWxC,CAAA,CAAA;EAAA,WAAA;EAAA,iBAAA;EAAA,WAAA;EAAA,WAAA;EAAA,kBAAA;EAAA;AAAA,CAAA,EA8WR,4BA9WQ,CA8WqB,KA9WrB,CAAA,EAAA,YAAA,CAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,SAAA,EA+WmC,mBA/WnC,EAAA,GAAA,OAAA,CAAA,EAgXV,wBAhXU,CAgXe,KAhXf,CAAA"}
1
+ {"version":3,"file":"MouseEventManager.d.ts","names":["mode: TMode","options: MouseEventManagerOptions<TMode>"],"sources":["../../src/managers/MouseEventManager.ts"],"sourcesContent":[],"mappings":";;;KAOY,QAAA;KAEA,qBAAA;AAFA,UAIK,gBAAA,SAAyB,kBAJ9B,CAAA;EAEZ,KAAY,EAGH,YAHG;AAEZ;AAIiB,UAAA,qBAAA,SAA8B,kBAAA,CAAA;EAI/C,KAAiB,EAHR,YAGQ;AAIjB;AAQK,UAZY,oBAAA,SAA6B,sBAYzC,CAAA;EAA8B,KAAA,EAX1B,YAW0B;;AAC/B,UATa,yBAAA,SAAkC,sBAS/C,CAAA;EACA,KAAA,EATK,YASL;;AAAA,KAFC,eAIA,CAAA,cAJ8B,qBAI9B,CAAA,GAJuD,KAIvD,SAAA,MAAA,GAHD,gBAGC,GAFD,oBAEC;KAAA,yBAAwC,CAAA,cAAA,qBAAA,CAAA,GAC3C,KAD2C,SAAA,MAAA,GACpB,qBADoB,GACI,yBADJ;AAC3C,KAYU,oBAZV,CAAA,cAY6C,qBAZ7C,CAAA,GAaA,KAbA,SAAA,MAAA,GAAA;EAAuB,UAAA,EAAA,MAAA;CAAwB,GAAA;EAAA,UAAA,EAAA,MAAA;EAYjD,IAAY,EAGsB,cAHtB;CAAmC;AAC7C,UAmCe,4BAnCf,CAAA,cAoCc,qBApCd,CAAA,CAAA;EAEgC,kBAAA,CAAA,EAAA,OAAA;EAAA,WAAA,EAAA,KAAA,EAqCZ,eArCY,CAqCI,KArCJ,CAAA,CAAA,EAAA,OAAA;EAiClC,iBAAiB,EAAA,KAAA,EAKW,eALX,CAK2B,KAL3B,CAAA,CAAA,EAAA,OAAA;EACD,WAAA,EAAA,KAAA,EAKM,yBALN,CAKgC,KALhC,CAAA,CAAA,EAAA,OAAA;EAGsB,WAAA,EAAA,KAAA,EAGhB,yBAHgB,CAGU,KAHV,CAAA,CAAA,EAAA,OAAA;EAAhB,kBAAA,CAAA,EAIC,QAJD;;AACM,UAMX,wBANW,CAAA,cAM4B,qBAN5B,CAAA,SAOlB,4BAPkB,CAOW,KAPX,CAAA,CAAA;EACoB,YAAA,EAAA,SAAA,EAAA,MAAA,EAAA,SAAA,EAOF,mBAPE,CAAA,EAAA,OAAA;;AACA,cASnC,iBATmC,CAAA,cASH,qBATG,CAAA,CAAA;EAA1B,QAAA,IAAA;EACC,QAAA,OAAA;EAAA,QAAA,WAAA;EAGvB,QAAiB,GAAA;EAAuC,QAAA,SAAA;EACjB,WAAA,CAAA,IAAA,EAUrB,KAVqB,EAAA,OAAA,EAWlB,wBAXkB,CAWO,KAXP,CAAA;EACO,UAAA,CAAA,OAAA,EAaxB,wBAbwB,CAaC,KAbD,CAAA,CAAA,EAAA,IAAA;EADpC,OAAA,CAAA,CAAA,EAAA,IAAA;EAAA,KAAA,CAAA,GAAA,EA2BG,cA3BH,CAAA,EAAA,IAAA;EAIV,cAAa,EAAA,GAAA,GAgGU,oBAhGV,CAgG+B,KAhG/B,CAAA,GAAA,SAAA;EAAgC,gBAAA,EAAA,CAAA,KAAA,EAiHhB,YAjHgB,EAAA,GAAA,IAAA;EAM3B,eAAA,EAAA,CAAA,KAAA,EAqHU,YArHV,EAAA,GAAA,IAAA;EAC4B,gBAAA,EAAA,CAAA,KAAA,EA8HjB,YA9HiB,EAAA,GAAA,IAAA;EAAzB,QAAA,gBAAA;EAG0B,QAAA,WAAA;;AAalC,iBAsWG,sBAtWH,CAAA,cAsWwC,qBAtWxC,CAAA,CAAA;EAAA,WAAA;EAAA,iBAAA;EAAA,WAAA;EAAA,WAAA;EAAA,kBAAA;EAAA;AAAA,CAAA,EA8WR,4BA9WQ,CA8WqB,KA9WrB,CAAA,EAAA,YAAA,CAAA,EAAA,CAAA,SAAA,EAAA,MAAA,EAAA,SAAA,EA+WmC,mBA/WnC,EAAA,GAAA,OAAA,CAAA,EAgXV,wBAhXU,CAgXe,KAhXf,CAAA"}
@@ -20,8 +20,8 @@ var MouseEventManager = class {
20
20
  }
21
21
  cleanUp() {
22
22
  this.pre?.removeEventListener("click", this.handleMouseClick);
23
- this.pre?.removeEventListener("mousemove", this.handleMouseMove);
24
- this.pre?.removeEventListener("mouseout", this.handleMouseLeave);
23
+ this.pre?.removeEventListener("pointermove", this.handleMouseMove);
24
+ this.pre?.removeEventListener("pointerout", this.handleMouseLeave);
25
25
  delete this.pre?.dataset.interactiveLines;
26
26
  delete this.pre?.dataset.interactiveLineNumbers;
27
27
  this.pre = void 0;
@@ -55,10 +55,10 @@ var MouseEventManager = class {
55
55
  })());
56
56
  }
57
57
  if (onLineEnter != null || onLineLeave != null || enableHoverUtility) {
58
- pre.addEventListener("mousemove", this.handleMouseMove);
59
- debugLogIfEnabled(__debugMouseEvents, "move", "FileDiff.DEBUG.attachEventListeners: Attaching mouse move event");
60
- pre.addEventListener("mouseleave", this.handleMouseLeave);
61
- debugLogIfEnabled(__debugMouseEvents, "move", "FileDiff.DEBUG.attachEventListeners: Attaching mouse leave event");
58
+ pre.addEventListener("pointermove", this.handleMouseMove);
59
+ debugLogIfEnabled(__debugMouseEvents, "move", "FileDiff.DEBUG.attachEventListeners: Attaching pointer move event");
60
+ pre.addEventListener("pointerleave", this.handleMouseLeave);
61
+ debugLogIfEnabled(__debugMouseEvents, "move", "FileDiff.DEBUG.attachEventListeners: Attaching pointer leave event");
62
62
  }
63
63
  }
64
64
  getHoveredLine = () => {
@@ -1 +1 @@
1
- {"version":3,"file":"MouseEventManager.js","names":["mode: TMode","options: MouseEventManagerOptions<TMode>","reasons: string[]","direction: ExpansionDirections | undefined","numberElement"],"sources":["../../src/managers/MouseEventManager.ts"],"sourcesContent":["import type {\n AnnotationSide,\n DiffLineEventBaseProps,\n ExpansionDirections,\n LineEventBaseProps,\n} from '../types';\n\nexport type LogTypes = 'click' | 'move' | 'both' | 'none';\n\nexport type MouseEventManagerMode = 'file' | 'diff';\n\nexport interface OnLineClickProps extends LineEventBaseProps {\n event: PointerEvent;\n}\n\nexport interface OnLineEnterLeaveProps extends LineEventBaseProps {\n event: MouseEvent;\n}\n\nexport interface OnDiffLineClickProps extends DiffLineEventBaseProps {\n event: PointerEvent;\n}\n\nexport interface OnDiffLineEnterLeaveProps extends DiffLineEventBaseProps {\n event: MouseEvent;\n}\n\ntype HandleMouseEventProps =\n | { eventType: 'click'; event: MouseEvent }\n | { eventType: 'move'; event: MouseEvent };\n\ntype EventClickProps<TMode extends MouseEventManagerMode> = TMode extends 'file'\n ? OnLineClickProps\n : OnDiffLineClickProps;\n\ntype MouseEventEnterLeaveProps<TMode extends MouseEventManagerMode> =\n TMode extends 'file' ? OnLineEnterLeaveProps : OnDiffLineEnterLeaveProps;\n\ntype EventBaseProps<TMode extends MouseEventManagerMode> = TMode extends 'file'\n ? LineEventBaseProps\n : DiffLineEventBaseProps;\n\ninterface ExpandoEventProps {\n type: 'line-info';\n hunkIndex: number;\n direction: ExpansionDirections;\n}\n\nexport type GetHoveredLineResult<TMode extends MouseEventManagerMode> =\n TMode extends 'file'\n ? { lineNumber: number }\n : { lineNumber: number; side: AnnotationSide };\n\ntype GetLineDataResult<TMode extends MouseEventManagerMode> =\n TMode extends 'file'\n ? LineEventBaseProps | ExpandoEventProps | undefined\n : DiffLineEventBaseProps | ExpandoEventProps | undefined;\n\ntype LineEventData<TMode extends MouseEventManagerMode> = TMode extends 'file'\n ? LineEventBaseProps\n : DiffLineEventBaseProps;\n\nfunction isLineEventData<TMode extends MouseEventManagerMode>(\n data: GetLineDataResult<TMode>,\n mode: TMode\n): data is LineEventData<TMode> {\n if (data == null) return false;\n if (mode === 'file') {\n return data.type === 'line';\n } else {\n return data.type === 'diff-line';\n }\n}\n\nfunction isExpandoEventData(\n data:\n | LineEventBaseProps\n | DiffLineEventBaseProps\n | ExpandoEventProps\n | undefined\n): data is ExpandoEventProps {\n return data?.type === 'line-info';\n}\n\nexport interface MouseEventManagerBaseOptions<\n TMode extends MouseEventManagerMode,\n> {\n enableHoverUtility?: boolean;\n onLineClick?(props: EventClickProps<TMode>): unknown;\n onLineNumberClick?(props: EventClickProps<TMode>): unknown;\n onLineEnter?(props: MouseEventEnterLeaveProps<TMode>): unknown;\n onLineLeave?(props: MouseEventEnterLeaveProps<TMode>): unknown;\n __debugMouseEvents?: LogTypes;\n}\n\nexport interface MouseEventManagerOptions<TMode extends MouseEventManagerMode>\n extends MouseEventManagerBaseOptions<TMode> {\n onHunkExpand?(hunkIndex: number, direction: ExpansionDirections): unknown;\n}\n\nexport class MouseEventManager<TMode extends MouseEventManagerMode> {\n private hoveredLine: EventBaseProps<TMode> | undefined;\n private pre: HTMLPreElement | undefined;\n private hoverSlot: HTMLDivElement | undefined;\n\n constructor(\n private mode: TMode,\n private options: MouseEventManagerOptions<TMode>\n ) {}\n\n setOptions(options: MouseEventManagerOptions<TMode>): void {\n this.options = options;\n }\n\n cleanUp(): void {\n this.pre?.removeEventListener('click', this.handleMouseClick);\n this.pre?.removeEventListener('mousemove', this.handleMouseMove);\n this.pre?.removeEventListener('mouseout', this.handleMouseLeave);\n delete this.pre?.dataset.interactiveLines;\n delete this.pre?.dataset.interactiveLineNumbers;\n this.pre = undefined;\n }\n\n setup(pre: HTMLPreElement): void {\n const {\n __debugMouseEvents,\n onLineClick,\n onLineNumberClick,\n onLineEnter,\n onLineLeave,\n onHunkExpand,\n enableHoverUtility = false,\n } = this.options;\n\n this.cleanUp();\n this.pre = pre;\n\n if (enableHoverUtility && this.hoverSlot == null) {\n this.hoverSlot = document.createElement('div');\n this.hoverSlot.dataset.hoverSlot = '';\n const slotElement = document.createElement('slot');\n slotElement.name = 'hover-slot';\n this.hoverSlot.appendChild(slotElement);\n } else if (!enableHoverUtility && this.hoverSlot != null) {\n this.hoverSlot.parentNode?.removeChild(this.hoverSlot);\n this.hoverSlot = undefined;\n }\n\n if (\n onLineClick != null ||\n onLineNumberClick != null ||\n onHunkExpand != null\n ) {\n pre.addEventListener('click', this.handleMouseClick);\n if (onLineClick != null) {\n pre.dataset.interactiveLines = '';\n } else if (onLineNumberClick != null) {\n pre.dataset.interactiveLineNumbers = '';\n }\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n 'FileDiff.DEBUG.attachEventListeners: Attaching click events for:',\n (() => {\n const reasons: string[] = [];\n if (__debugMouseEvents === 'both' || __debugMouseEvents === 'click') {\n if (onLineClick != null) {\n reasons.push('onLineClick');\n }\n if (onLineNumberClick != null) {\n reasons.push('onLineNumberClick');\n }\n if (onHunkExpand != null) {\n reasons.push('expandable hunk separators');\n }\n }\n return reasons;\n })()\n );\n }\n if (onLineEnter != null || onLineLeave != null || enableHoverUtility) {\n pre.addEventListener('mousemove', this.handleMouseMove);\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.attachEventListeners: Attaching mouse move event'\n );\n pre.addEventListener('mouseleave', this.handleMouseLeave);\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.attachEventListeners: Attaching mouse leave event'\n );\n }\n }\n\n getHoveredLine = (): GetHoveredLineResult<TMode> | undefined => {\n if (this.hoveredLine != null) {\n if (this.mode === 'diff' && this.hoveredLine.type === 'diff-line') {\n return {\n lineNumber: this.hoveredLine.lineNumber,\n side: this.hoveredLine.annotationSide,\n } as GetHoveredLineResult<TMode>;\n }\n if (this.mode === 'file' && this.hoveredLine.type === 'line') {\n return {\n lineNumber: this.hoveredLine.lineNumber,\n } as GetHoveredLineResult<TMode>;\n }\n }\n return undefined;\n };\n\n handleMouseClick = (event: MouseEvent): void => {\n debugLogIfEnabled(\n this.options.__debugMouseEvents,\n 'click',\n 'FileDiff.DEBUG.handleMouseClick:',\n event\n );\n this.handleMouseEvent({ eventType: 'click', event });\n };\n\n handleMouseMove = (event: MouseEvent): void => {\n debugLogIfEnabled(\n this.options.__debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.handleMouseMove:',\n event\n );\n this.handleMouseEvent({ eventType: 'move', event });\n };\n\n handleMouseLeave = (event: MouseEvent): void => {\n const { __debugMouseEvents } = this.options;\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.handleMouseLeave: no event'\n );\n if (this.hoveredLine == null) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.handleMouseLeave: returned early, no .hoveredLine'\n );\n return;\n }\n this.hoverSlot?.parentElement?.removeChild(this.hoverSlot);\n this.options.onLineLeave?.({\n ...this.hoveredLine,\n event,\n } as MouseEventEnterLeaveProps<TMode>);\n this.hoveredLine = undefined;\n };\n\n private handleMouseEvent({ eventType, event }: HandleMouseEventProps) {\n const { __debugMouseEvents } = this.options;\n const composedPath = event.composedPath();\n debugLogIfEnabled(\n __debugMouseEvents,\n eventType,\n 'FileDiff.DEBUG.handleMouseEvent:',\n { eventType, composedPath }\n );\n const data = this.getLineData(composedPath);\n debugLogIfEnabled(\n __debugMouseEvents,\n eventType,\n 'FileDiff.DEBUG.handleMouseEvent: getLineData result:',\n data\n );\n const {\n onLineClick,\n onLineNumberClick,\n onLineEnter,\n onLineLeave,\n onHunkExpand,\n } = this.options;\n switch (eventType) {\n case 'move': {\n if (\n isLineEventData(data, this.mode) &&\n this.hoveredLine?.lineElement === data.lineElement\n ) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'move', returned early because same line\"\n );\n break;\n }\n if (this.hoveredLine != null) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'move', clearing an existing hovered line and firing onLineLeave\"\n );\n this.hoverSlot?.parentElement?.removeChild(this.hoverSlot);\n onLineLeave?.({\n ...this.hoveredLine,\n event,\n } as MouseEventEnterLeaveProps<TMode>);\n this.hoveredLine = undefined;\n }\n if (isLineEventData(data, this.mode)) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'move', setting up a new hoveredLine and firing onLineEnter\"\n );\n this.hoveredLine = data;\n if (this.hoverSlot != null) {\n data.numberElement?.appendChild(this.hoverSlot);\n }\n onLineEnter?.({\n ...this.hoveredLine,\n event,\n } as MouseEventEnterLeaveProps<TMode>);\n }\n break;\n }\n case 'click':\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', with data:\",\n data\n );\n if (data == null) break;\n if (isExpandoEventData(data) && onHunkExpand != null) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', expanding a hunk\"\n );\n onHunkExpand(data.hunkIndex, data.direction);\n break;\n }\n if (isLineEventData(data, this.mode)) {\n if (onLineNumberClick != null && data.numberColumn) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', firing 'onLineNumberClick'\"\n );\n onLineNumberClick({ ...data, event } as EventClickProps<TMode>);\n } else if (onLineClick != null) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', firing 'onLineClick'\"\n );\n onLineClick({ ...data, event } as EventClickProps<TMode>);\n } else {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', fell through, no event to fire\"\n );\n }\n }\n break;\n }\n }\n\n private getLineData(\n path: (EventTarget | undefined)[]\n ): GetLineDataResult<TMode> {\n let numberColumn = false;\n const lineElement = path.find((element) => {\n if (!(element instanceof HTMLElement)) {\n return false;\n }\n numberColumn = numberColumn || 'columnNumber' in element.dataset;\n return 'line' in element.dataset || 'expandIndex' in element.dataset;\n });\n if (!(lineElement instanceof HTMLElement)) return undefined;\n if (lineElement.dataset.expandIndex != null) {\n const hunkIndex = parseInt(lineElement.dataset.expandIndex);\n if (isNaN(hunkIndex)) {\n return undefined;\n }\n let direction: ExpansionDirections | undefined;\n for (const element of path) {\n if (element === lineElement) break;\n if (element instanceof HTMLElement) {\n direction =\n direction ??\n ('expandUp' in element.dataset ? 'up' : undefined) ??\n ('expandDown' in element.dataset ? 'down' : undefined) ??\n ('expandBoth' in element.dataset ? 'both' : undefined);\n if (direction != null) {\n break;\n }\n }\n }\n return direction != null\n ? { type: 'line-info', hunkIndex, direction }\n : undefined;\n }\n const lineNumber = parseInt(lineElement.dataset.line ?? '');\n if (isNaN(lineNumber)) return;\n const lineType = lineElement.dataset.lineType;\n if (\n lineType !== 'context' &&\n lineType !== 'context-expanded' &&\n lineType !== 'change-deletion' &&\n lineType !== 'change-addition'\n ) {\n return undefined;\n }\n\n const numberElement = (() => {\n const numberElement = lineElement.children[0];\n return numberElement instanceof HTMLElement &&\n numberElement.dataset.columnNumber != null\n ? numberElement\n : undefined;\n })();\n\n if (this.mode === 'file') {\n return {\n type: 'line',\n lineElement,\n lineNumber,\n numberElement,\n numberColumn,\n } as GetLineDataResult<TMode>;\n }\n\n const annotationSide: AnnotationSide = (() => {\n if (lineType === 'change-deletion') {\n return 'deletions';\n }\n if (lineType === 'change-addition') {\n return 'additions';\n }\n const parent = lineElement.closest('[data-code]');\n if (!(parent instanceof HTMLElement)) {\n return 'additions';\n }\n return 'deletions' in parent.dataset ? 'deletions' : 'additions';\n })();\n\n return {\n type: 'diff-line',\n annotationSide,\n lineType,\n lineElement,\n numberElement,\n lineNumber,\n numberColumn,\n } as GetLineDataResult<TMode>;\n }\n}\n\nfunction debugLogIfEnabled(\n debugLogType: LogTypes | undefined = 'none',\n logIfType: 'move' | 'click',\n ...args: unknown[]\n) {\n switch (debugLogType) {\n case 'none':\n return;\n case 'both':\n break;\n case 'click':\n if (logIfType !== 'click') {\n return;\n }\n break;\n case 'move':\n if (logIfType !== 'move') {\n return;\n }\n break;\n }\n console.log(...args);\n}\n\nexport function pluckMouseEventOptions<TMode extends MouseEventManagerMode>(\n {\n onLineClick,\n onLineNumberClick,\n onLineEnter,\n onLineLeave,\n enableHoverUtility,\n __debugMouseEvents,\n }: MouseEventManagerBaseOptions<TMode>,\n onHunkExpand?: (hunkIndex: number, direction: ExpansionDirections) => unknown\n): MouseEventManagerOptions<TMode> {\n return {\n onLineClick,\n onLineNumberClick,\n onLineEnter,\n onLineLeave,\n enableHoverUtility,\n __debugMouseEvents,\n onHunkExpand,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MouseEventManager.js","names":["mode: TMode","options: MouseEventManagerOptions<TMode>","reasons: string[]","direction: ExpansionDirections | undefined","numberElement"],"sources":["../../src/managers/MouseEventManager.ts"],"sourcesContent":["import type {\n AnnotationSide,\n DiffLineEventBaseProps,\n ExpansionDirections,\n LineEventBaseProps,\n} from '../types';\n\nexport type LogTypes = 'click' | 'move' | 'both' | 'none';\n\nexport type MouseEventManagerMode = 'file' | 'diff';\n\nexport interface OnLineClickProps extends LineEventBaseProps {\n event: PointerEvent;\n}\n\nexport interface OnLineEnterLeaveProps extends LineEventBaseProps {\n event: PointerEvent;\n}\n\nexport interface OnDiffLineClickProps extends DiffLineEventBaseProps {\n event: PointerEvent;\n}\n\nexport interface OnDiffLineEnterLeaveProps extends DiffLineEventBaseProps {\n event: PointerEvent;\n}\n\ntype HandleMouseEventProps =\n | { eventType: 'click'; event: PointerEvent }\n | { eventType: 'move'; event: PointerEvent };\n\ntype EventClickProps<TMode extends MouseEventManagerMode> = TMode extends 'file'\n ? OnLineClickProps\n : OnDiffLineClickProps;\n\ntype MouseEventEnterLeaveProps<TMode extends MouseEventManagerMode> =\n TMode extends 'file' ? OnLineEnterLeaveProps : OnDiffLineEnterLeaveProps;\n\ntype EventBaseProps<TMode extends MouseEventManagerMode> = TMode extends 'file'\n ? LineEventBaseProps\n : DiffLineEventBaseProps;\n\ninterface ExpandoEventProps {\n type: 'line-info';\n hunkIndex: number;\n direction: ExpansionDirections;\n}\n\nexport type GetHoveredLineResult<TMode extends MouseEventManagerMode> =\n TMode extends 'file'\n ? { lineNumber: number }\n : { lineNumber: number; side: AnnotationSide };\n\ntype GetLineDataResult<TMode extends MouseEventManagerMode> =\n TMode extends 'file'\n ? LineEventBaseProps | ExpandoEventProps | undefined\n : DiffLineEventBaseProps | ExpandoEventProps | undefined;\n\ntype LineEventData<TMode extends MouseEventManagerMode> = TMode extends 'file'\n ? LineEventBaseProps\n : DiffLineEventBaseProps;\n\nfunction isLineEventData<TMode extends MouseEventManagerMode>(\n data: GetLineDataResult<TMode>,\n mode: TMode\n): data is LineEventData<TMode> {\n if (data == null) return false;\n if (mode === 'file') {\n return data.type === 'line';\n } else {\n return data.type === 'diff-line';\n }\n}\n\nfunction isExpandoEventData(\n data:\n | LineEventBaseProps\n | DiffLineEventBaseProps\n | ExpandoEventProps\n | undefined\n): data is ExpandoEventProps {\n return data?.type === 'line-info';\n}\n\nexport interface MouseEventManagerBaseOptions<\n TMode extends MouseEventManagerMode,\n> {\n enableHoverUtility?: boolean;\n onLineClick?(props: EventClickProps<TMode>): unknown;\n onLineNumberClick?(props: EventClickProps<TMode>): unknown;\n onLineEnter?(props: MouseEventEnterLeaveProps<TMode>): unknown;\n onLineLeave?(props: MouseEventEnterLeaveProps<TMode>): unknown;\n __debugMouseEvents?: LogTypes;\n}\n\nexport interface MouseEventManagerOptions<TMode extends MouseEventManagerMode>\n extends MouseEventManagerBaseOptions<TMode> {\n onHunkExpand?(hunkIndex: number, direction: ExpansionDirections): unknown;\n}\n\nexport class MouseEventManager<TMode extends MouseEventManagerMode> {\n private hoveredLine: EventBaseProps<TMode> | undefined;\n private pre: HTMLPreElement | undefined;\n private hoverSlot: HTMLDivElement | undefined;\n\n constructor(\n private mode: TMode,\n private options: MouseEventManagerOptions<TMode>\n ) {}\n\n setOptions(options: MouseEventManagerOptions<TMode>): void {\n this.options = options;\n }\n\n cleanUp(): void {\n this.pre?.removeEventListener('click', this.handleMouseClick);\n this.pre?.removeEventListener('pointermove', this.handleMouseMove);\n this.pre?.removeEventListener('pointerout', this.handleMouseLeave);\n delete this.pre?.dataset.interactiveLines;\n delete this.pre?.dataset.interactiveLineNumbers;\n this.pre = undefined;\n }\n\n setup(pre: HTMLPreElement): void {\n const {\n __debugMouseEvents,\n onLineClick,\n onLineNumberClick,\n onLineEnter,\n onLineLeave,\n onHunkExpand,\n enableHoverUtility = false,\n } = this.options;\n\n this.cleanUp();\n this.pre = pre;\n\n if (enableHoverUtility && this.hoverSlot == null) {\n this.hoverSlot = document.createElement('div');\n this.hoverSlot.dataset.hoverSlot = '';\n const slotElement = document.createElement('slot');\n slotElement.name = 'hover-slot';\n this.hoverSlot.appendChild(slotElement);\n } else if (!enableHoverUtility && this.hoverSlot != null) {\n this.hoverSlot.parentNode?.removeChild(this.hoverSlot);\n this.hoverSlot = undefined;\n }\n\n if (\n onLineClick != null ||\n onLineNumberClick != null ||\n onHunkExpand != null\n ) {\n pre.addEventListener('click', this.handleMouseClick);\n if (onLineClick != null) {\n pre.dataset.interactiveLines = '';\n } else if (onLineNumberClick != null) {\n pre.dataset.interactiveLineNumbers = '';\n }\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n 'FileDiff.DEBUG.attachEventListeners: Attaching click events for:',\n (() => {\n const reasons: string[] = [];\n if (__debugMouseEvents === 'both' || __debugMouseEvents === 'click') {\n if (onLineClick != null) {\n reasons.push('onLineClick');\n }\n if (onLineNumberClick != null) {\n reasons.push('onLineNumberClick');\n }\n if (onHunkExpand != null) {\n reasons.push('expandable hunk separators');\n }\n }\n return reasons;\n })()\n );\n }\n if (onLineEnter != null || onLineLeave != null || enableHoverUtility) {\n pre.addEventListener('pointermove', this.handleMouseMove);\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.attachEventListeners: Attaching pointer move event'\n );\n pre.addEventListener('pointerleave', this.handleMouseLeave);\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.attachEventListeners: Attaching pointer leave event'\n );\n }\n }\n\n getHoveredLine = (): GetHoveredLineResult<TMode> | undefined => {\n if (this.hoveredLine != null) {\n if (this.mode === 'diff' && this.hoveredLine.type === 'diff-line') {\n return {\n lineNumber: this.hoveredLine.lineNumber,\n side: this.hoveredLine.annotationSide,\n } as GetHoveredLineResult<TMode>;\n }\n if (this.mode === 'file' && this.hoveredLine.type === 'line') {\n return {\n lineNumber: this.hoveredLine.lineNumber,\n } as GetHoveredLineResult<TMode>;\n }\n }\n return undefined;\n };\n\n handleMouseClick = (event: PointerEvent): void => {\n debugLogIfEnabled(\n this.options.__debugMouseEvents,\n 'click',\n 'FileDiff.DEBUG.handleMouseClick:',\n event\n );\n this.handleMouseEvent({ eventType: 'click', event });\n };\n\n handleMouseMove = (event: PointerEvent): void => {\n debugLogIfEnabled(\n this.options.__debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.handleMouseMove:',\n event\n );\n this.handleMouseEvent({ eventType: 'move', event });\n };\n\n handleMouseLeave = (event: PointerEvent): void => {\n const { __debugMouseEvents } = this.options;\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.handleMouseLeave: no event'\n );\n if (this.hoveredLine == null) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n 'FileDiff.DEBUG.handleMouseLeave: returned early, no .hoveredLine'\n );\n return;\n }\n this.hoverSlot?.parentElement?.removeChild(this.hoverSlot);\n this.options.onLineLeave?.({\n ...this.hoveredLine,\n event,\n } as MouseEventEnterLeaveProps<TMode>);\n this.hoveredLine = undefined;\n };\n\n private handleMouseEvent({ eventType, event }: HandleMouseEventProps) {\n const { __debugMouseEvents } = this.options;\n const composedPath = event.composedPath();\n debugLogIfEnabled(\n __debugMouseEvents,\n eventType,\n 'FileDiff.DEBUG.handleMouseEvent:',\n { eventType, composedPath }\n );\n const data = this.getLineData(composedPath);\n debugLogIfEnabled(\n __debugMouseEvents,\n eventType,\n 'FileDiff.DEBUG.handleMouseEvent: getLineData result:',\n data\n );\n const {\n onLineClick,\n onLineNumberClick,\n onLineEnter,\n onLineLeave,\n onHunkExpand,\n } = this.options;\n switch (eventType) {\n case 'move': {\n if (\n isLineEventData(data, this.mode) &&\n this.hoveredLine?.lineElement === data.lineElement\n ) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'move', returned early because same line\"\n );\n break;\n }\n if (this.hoveredLine != null) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'move', clearing an existing hovered line and firing onLineLeave\"\n );\n this.hoverSlot?.parentElement?.removeChild(this.hoverSlot);\n onLineLeave?.({\n ...this.hoveredLine,\n event,\n } as MouseEventEnterLeaveProps<TMode>);\n this.hoveredLine = undefined;\n }\n if (isLineEventData(data, this.mode)) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'move',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'move', setting up a new hoveredLine and firing onLineEnter\"\n );\n this.hoveredLine = data;\n if (this.hoverSlot != null) {\n data.numberElement?.appendChild(this.hoverSlot);\n }\n onLineEnter?.({\n ...this.hoveredLine,\n event,\n } as MouseEventEnterLeaveProps<TMode>);\n }\n break;\n }\n case 'click':\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', with data:\",\n data\n );\n if (data == null) break;\n if (isExpandoEventData(data) && onHunkExpand != null) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', expanding a hunk\"\n );\n onHunkExpand(data.hunkIndex, data.direction);\n break;\n }\n if (isLineEventData(data, this.mode)) {\n if (onLineNumberClick != null && data.numberColumn) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', firing 'onLineNumberClick'\"\n );\n onLineNumberClick({ ...data, event } as EventClickProps<TMode>);\n } else if (onLineClick != null) {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', firing 'onLineClick'\"\n );\n onLineClick({ ...data, event } as EventClickProps<TMode>);\n } else {\n debugLogIfEnabled(\n __debugMouseEvents,\n 'click',\n \"FileDiff.DEBUG.handleMouseEvent: switch, 'click', fell through, no event to fire\"\n );\n }\n }\n break;\n }\n }\n\n private getLineData(\n path: (EventTarget | undefined)[]\n ): GetLineDataResult<TMode> {\n let numberColumn = false;\n const lineElement = path.find((element) => {\n if (!(element instanceof HTMLElement)) {\n return false;\n }\n numberColumn = numberColumn || 'columnNumber' in element.dataset;\n return 'line' in element.dataset || 'expandIndex' in element.dataset;\n });\n if (!(lineElement instanceof HTMLElement)) return undefined;\n if (lineElement.dataset.expandIndex != null) {\n const hunkIndex = parseInt(lineElement.dataset.expandIndex);\n if (isNaN(hunkIndex)) {\n return undefined;\n }\n let direction: ExpansionDirections | undefined;\n for (const element of path) {\n if (element === lineElement) break;\n if (element instanceof HTMLElement) {\n direction =\n direction ??\n ('expandUp' in element.dataset ? 'up' : undefined) ??\n ('expandDown' in element.dataset ? 'down' : undefined) ??\n ('expandBoth' in element.dataset ? 'both' : undefined);\n if (direction != null) {\n break;\n }\n }\n }\n return direction != null\n ? { type: 'line-info', hunkIndex, direction }\n : undefined;\n }\n const lineNumber = parseInt(lineElement.dataset.line ?? '');\n if (isNaN(lineNumber)) return;\n const lineType = lineElement.dataset.lineType;\n if (\n lineType !== 'context' &&\n lineType !== 'context-expanded' &&\n lineType !== 'change-deletion' &&\n lineType !== 'change-addition'\n ) {\n return undefined;\n }\n\n const numberElement = (() => {\n const numberElement = lineElement.children[0];\n return numberElement instanceof HTMLElement &&\n numberElement.dataset.columnNumber != null\n ? numberElement\n : undefined;\n })();\n\n if (this.mode === 'file') {\n return {\n type: 'line',\n lineElement,\n lineNumber,\n numberElement,\n numberColumn,\n } as GetLineDataResult<TMode>;\n }\n\n const annotationSide: AnnotationSide = (() => {\n if (lineType === 'change-deletion') {\n return 'deletions';\n }\n if (lineType === 'change-addition') {\n return 'additions';\n }\n const parent = lineElement.closest('[data-code]');\n if (!(parent instanceof HTMLElement)) {\n return 'additions';\n }\n return 'deletions' in parent.dataset ? 'deletions' : 'additions';\n })();\n\n return {\n type: 'diff-line',\n annotationSide,\n lineType,\n lineElement,\n numberElement,\n lineNumber,\n numberColumn,\n } as GetLineDataResult<TMode>;\n }\n}\n\nfunction debugLogIfEnabled(\n debugLogType: LogTypes | undefined = 'none',\n logIfType: 'move' | 'click',\n ...args: unknown[]\n) {\n switch (debugLogType) {\n case 'none':\n return;\n case 'both':\n break;\n case 'click':\n if (logIfType !== 'click') {\n return;\n }\n break;\n case 'move':\n if (logIfType !== 'move') {\n return;\n }\n break;\n }\n console.log(...args);\n}\n\nexport function pluckMouseEventOptions<TMode extends MouseEventManagerMode>(\n {\n onLineClick,\n onLineNumberClick,\n onLineEnter,\n onLineLeave,\n enableHoverUtility,\n __debugMouseEvents,\n }: MouseEventManagerBaseOptions<TMode>,\n onHunkExpand?: (hunkIndex: number, direction: ExpansionDirections) => unknown\n): MouseEventManagerOptions<TMode> {\n return {\n onLineClick,\n onLineNumberClick,\n onLineEnter,\n onLineLeave,\n enableHoverUtility,\n __debugMouseEvents,\n onHunkExpand,\n };\n}\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { FileContents, FileDiffMetadata } from "../types.js";
2
+ import { CreatePatchOptionsNonabortable } from "diff";
2
3
 
3
4
  //#region src/utils/parseDiffFromFile.d.ts
4
5
 
@@ -8,7 +9,7 @@ import { FileContents, FileDiffMetadata } from "../types.js";
8
9
  * If both `oldFile` and `newFile` have a `cacheKey`, the resulting diff will
9
10
  * automatically get a combined cache key in the format `oldKey:newKey`.
10
11
  */
11
- declare function parseDiffFromFile(oldFile: FileContents, newFile: FileContents): FileDiffMetadata;
12
+ declare function parseDiffFromFile(oldFile: FileContents, newFile: FileContents, options?: CreatePatchOptionsNonabortable): FileDiffMetadata;
12
13
  //#endregion
13
14
  export { parseDiffFromFile };
14
15
  //# sourceMappingURL=parseDiffFromFile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parseDiffFromFile.d.ts","names":[],"sources":["../../src/utils/parseDiffFromFile.ts"],"sourcesContent":[],"mappings":";;;;;;AAYA;;;;AAGG,iBAHa,iBAAA,CAGb,OAAA,EAFQ,YAER,EAAA,OAAA,EADQ,YACR,CAAA,EAAA,gBAAA"}
1
+ {"version":3,"file":"parseDiffFromFile.d.ts","names":[],"sources":["../../src/utils/parseDiffFromFile.ts"],"sourcesContent":[],"mappings":";;;;;;;AAYA;;;;AAIG,iBAJa,iBAAA,CAIb,OAAA,EAHQ,YAGR,EAAA,OAAA,EAFQ,YAER,EAAA,OAAA,CAAA,EADS,8BACT,CAAA,EAAA,gBAAA"}
@@ -9,8 +9,8 @@ import { createTwoFilesPatch } from "diff";
9
9
  * If both `oldFile` and `newFile` have a `cacheKey`, the resulting diff will
10
10
  * automatically get a combined cache key in the format `oldKey:newKey`.
11
11
  */
12
- function parseDiffFromFile(oldFile, newFile) {
13
- const fileData = parsePatchFiles(createTwoFilesPatch(oldFile.name, newFile.name, oldFile.contents, newFile.contents, oldFile.header, newFile.header))[0]?.files[0];
12
+ function parseDiffFromFile(oldFile, newFile, options) {
13
+ const fileData = parsePatchFiles(createTwoFilesPatch(oldFile.name, newFile.name, oldFile.contents, newFile.contents, oldFile.header, newFile.header, options))[0]?.files[0];
14
14
  if (fileData == null) throw new Error("parseDiffFrom: FileInvalid diff -- probably need to fix something -- if the files are the same maybe?");
15
15
  fileData.oldLines = oldFile.contents.split(SPLIT_WITH_NEWLINES);
16
16
  fileData.newLines = newFile.contents.split(SPLIT_WITH_NEWLINES);
@@ -1 +1 @@
1
- {"version":3,"file":"parseDiffFromFile.js","names":[],"sources":["../../src/utils/parseDiffFromFile.ts"],"sourcesContent":["import { createTwoFilesPatch } from 'diff';\n\nimport { SPLIT_WITH_NEWLINES } from '../constants';\nimport type { FileContents, FileDiffMetadata } from '../types';\nimport { parsePatchFiles } from './parsePatchFiles';\n\n/**\n * Parses a diff from two file contents objects.\n *\n * If both `oldFile` and `newFile` have a `cacheKey`, the resulting diff will\n * automatically get a combined cache key in the format `oldKey:newKey`.\n */\nexport function parseDiffFromFile(\n oldFile: FileContents,\n newFile: FileContents\n): FileDiffMetadata {\n const patch = createTwoFilesPatch(\n oldFile.name,\n newFile.name,\n oldFile.contents,\n newFile.contents,\n oldFile.header,\n newFile.header\n );\n const fileData = parsePatchFiles(patch)[0]?.files[0];\n if (fileData == null) {\n throw new Error(\n 'parseDiffFrom: FileInvalid diff -- probably need to fix something -- if the files are the same maybe?'\n );\n }\n fileData.oldLines = oldFile.contents.split(SPLIT_WITH_NEWLINES);\n fileData.newLines = newFile.contents.split(SPLIT_WITH_NEWLINES);\n if (oldFile.cacheKey != null && newFile.cacheKey != null) {\n fileData.cacheKey = `${oldFile.cacheKey}:${newFile.cacheKey}`;\n }\n return fileData;\n}\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,kBACd,SACA,SACkB;CASlB,MAAM,WAAW,gBARH,oBACZ,QAAQ,MACR,QAAQ,MACR,QAAQ,UACR,QAAQ,UACR,QAAQ,QACR,QAAQ,OACT,CACsC,CAAC,IAAI,MAAM;AAClD,KAAI,YAAY,KACd,OAAM,IAAI,MACR,wGACD;AAEH,UAAS,WAAW,QAAQ,SAAS,MAAM,oBAAoB;AAC/D,UAAS,WAAW,QAAQ,SAAS,MAAM,oBAAoB;AAC/D,KAAI,QAAQ,YAAY,QAAQ,QAAQ,YAAY,KAClD,UAAS,WAAW,GAAG,QAAQ,SAAS,GAAG,QAAQ;AAErD,QAAO"}
1
+ {"version":3,"file":"parseDiffFromFile.js","names":[],"sources":["../../src/utils/parseDiffFromFile.ts"],"sourcesContent":["import { type CreatePatchOptionsNonabortable, createTwoFilesPatch } from 'diff';\n\nimport { SPLIT_WITH_NEWLINES } from '../constants';\nimport type { FileContents, FileDiffMetadata } from '../types';\nimport { parsePatchFiles } from './parsePatchFiles';\n\n/**\n * Parses a diff from two file contents objects.\n *\n * If both `oldFile` and `newFile` have a `cacheKey`, the resulting diff will\n * automatically get a combined cache key in the format `oldKey:newKey`.\n */\nexport function parseDiffFromFile(\n oldFile: FileContents,\n newFile: FileContents,\n options?: CreatePatchOptionsNonabortable\n): FileDiffMetadata {\n const patch = createTwoFilesPatch(\n oldFile.name,\n newFile.name,\n oldFile.contents,\n newFile.contents,\n oldFile.header,\n newFile.header,\n options\n );\n const fileData = parsePatchFiles(patch)[0]?.files[0];\n if (fileData == null) {\n throw new Error(\n 'parseDiffFrom: FileInvalid diff -- probably need to fix something -- if the files are the same maybe?'\n );\n }\n fileData.oldLines = oldFile.contents.split(SPLIT_WITH_NEWLINES);\n fileData.newLines = newFile.contents.split(SPLIT_WITH_NEWLINES);\n if (oldFile.cacheKey != null && newFile.cacheKey != null) {\n fileData.cacheKey = `${oldFile.cacheKey}:${newFile.cacheKey}`;\n }\n return fileData;\n}\n"],"mappings":";;;;;;;;;;;AAYA,SAAgB,kBACd,SACA,SACA,SACkB;CAUlB,MAAM,WAAW,gBATH,oBACZ,QAAQ,MACR,QAAQ,MACR,QAAQ,UACR,QAAQ,UACR,QAAQ,QACR,QAAQ,QACR,QACD,CACsC,CAAC,IAAI,MAAM;AAClD,KAAI,YAAY,KACd,OAAM,IAAI,MACR,wGACD;AAEH,UAAS,WAAW,QAAQ,SAAS,MAAM,oBAAoB;AAC/D,UAAS,WAAW,QAAQ,SAAS,MAAM,oBAAoB;AAC/D,KAAI,QAAQ,YAAY,QAAQ,QAAQ,YAAY,KAClD,UAAS,WAAW,GAAG,QAAQ,SAAS,GAAG,QAAQ;AAErD,QAAO"}
@@ -3442,7 +3442,7 @@ function toRegExpDetails(pattern, options) {
3442
3442
  }
3443
3443
 
3444
3444
  //#endregion
3445
- //#region ../../node_modules/.bun/@shikijs+engine-javascript@3.19.0/node_modules/@shikijs/engine-javascript/dist/shared/engine-javascript.hzpS1_41.mjs
3445
+ //#region ../../node_modules/.bun/@shikijs+engine-javascript@3.20.0/node_modules/@shikijs/engine-javascript/dist/shared/engine-javascript.hzpS1_41.mjs
3446
3446
  const MAX = 4294967295;
3447
3447
  var JavaScriptScanner = class {
3448
3448
  constructor(patterns, options = {}) {
@@ -3531,7 +3531,7 @@ var JavaScriptScanner = class {
3531
3531
  };
3532
3532
 
3533
3533
  //#endregion
3534
- //#region ../../node_modules/.bun/@shikijs+engine-javascript@3.19.0/node_modules/@shikijs/engine-javascript/dist/engine-compile.mjs
3534
+ //#region ../../node_modules/.bun/@shikijs+engine-javascript@3.20.0/node_modules/@shikijs/engine-javascript/dist/engine-compile.mjs
3535
3535
  function defaultJavaScriptRegexConstructor(pattern, options) {
3536
3536
  return toRegExp(pattern, {
3537
3537
  global: true,
@@ -3564,7 +3564,7 @@ function createJavaScriptRegexEngine(options = {}) {
3564
3564
  }
3565
3565
 
3566
3566
  //#endregion
3567
- //#region ../../node_modules/.bun/@shikijs+engine-javascript@3.19.0/node_modules/@shikijs/engine-javascript/dist/engine-raw.mjs
3567
+ //#region ../../node_modules/.bun/@shikijs+engine-javascript@3.20.0/node_modules/@shikijs/engine-javascript/dist/engine-raw.mjs
3568
3568
  function createJavaScriptRawEngine() {
3569
3569
  const options = {
3570
3570
  cache: /* @__PURE__ */ new Map(),
@@ -3583,7 +3583,7 @@ function createJavaScriptRawEngine() {
3583
3583
  }
3584
3584
 
3585
3585
  //#endregion
3586
- //#region ../../node_modules/.bun/@shikijs+types@3.19.0/node_modules/@shikijs/types/dist/index.mjs
3586
+ //#region ../../node_modules/.bun/@shikijs+types@3.20.0/node_modules/@shikijs/types/dist/index.mjs
3587
3587
  var ShikiError = class extends Error {
3588
3588
  constructor(message) {
3589
3589
  super(message);
@@ -9498,7 +9498,7 @@ function all(parent) {
9498
9498
  }
9499
9499
 
9500
9500
  //#endregion
9501
- //#region ../../node_modules/.bun/@shikijs+core@3.19.0/node_modules/@shikijs/core/dist/index.mjs
9501
+ //#region ../../node_modules/.bun/@shikijs+core@3.20.0/node_modules/@shikijs/core/dist/index.mjs
9502
9502
  function resolveColorReplacements(theme, options) {
9503
9503
  const replacements = typeof theme === "string" ? {} : { ...theme.colorReplacements };
9504
9504
  const themeName = typeof theme === "string" ? theme : theme.name;
@@ -10354,7 +10354,7 @@ function getLastGrammarState(...args) {
10354
10354
  }
10355
10355
  function tokenizeWithTheme(code, grammar, theme, colorMap, options) {
10356
10356
  const result = _tokenizeWithTheme(code, grammar, theme, colorMap, options);
10357
- const grammarState = new GrammarState(_tokenizeWithTheme(code, grammar, theme, colorMap, options).stateStack, grammar.name, theme.name);
10357
+ const grammarState = new GrammarState(result.stateStack, grammar.name, theme.name);
10358
10358
  setLastGrammarStateToMap(result.tokens, grammarState);
10359
10359
  return result.tokens;
10360
10360
  }
@@ -13098,7 +13098,7 @@ function cleanLastNewline(contents) {
13098
13098
  }
13099
13099
 
13100
13100
  //#endregion
13101
- //#region ../../node_modules/.bun/@shikijs+transformers@3.19.0/node_modules/@shikijs/transformers/dist/index.mjs
13101
+ //#region ../../node_modules/.bun/@shikijs+transformers@3.20.0/node_modules/@shikijs/transformers/dist/index.mjs
13102
13102
  const matchers = [
13103
13103
  [/^(<!--)(.+)(-->)$/, false],
13104
13104
  [/^(\/\*)(.+)(\*\/)$/, false],