@pierre/diffs 1.0.1 → 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.
- package/README.md +75 -5
- package/dist/managers/LineSelectionManager.js +8 -8
- package/dist/managers/LineSelectionManager.js.map +1 -1
- package/dist/managers/MouseEventManager.d.ts +5 -5
- package/dist/managers/MouseEventManager.d.ts.map +1 -1
- package/dist/managers/MouseEventManager.js +6 -6
- package/dist/managers/MouseEventManager.js.map +1 -1
- package/dist/renderers/DiffHunksRenderer.js +9 -5
- package/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/dist/renderers/FileRenderer.js +9 -5
- package/dist/renderers/FileRenderer.js.map +1 -1
- package/dist/utils/parseDiffFromFile.d.ts +2 -1
- package/dist/utils/parseDiffFromFile.d.ts.map +1 -1
- package/dist/utils/parseDiffFromFile.js +2 -2
- package/dist/utils/parseDiffFromFile.js.map +1 -1
- package/dist/worker/worker-portable.js +7 -7
- package/dist/worker/worker-portable.js.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,19 +1,52 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Diffs, from Pierre
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@pierre/diffs` is an open source diff and file rendering library built on
|
|
4
|
+
[Shiki](https://shiki.style/). It's super customizable and packed with the
|
|
5
|
+
features you need. Made with love by
|
|
6
|
+
[The Pierre Computer Company](https://pierre.computer). Available as vanilla
|
|
7
|
+
JavaScript and React components.
|
|
8
|
+
|
|
9
|
+
**View examples and read documentation on [Diffs.com](https://diffs.com).**
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Diff file versions, patches, and arbitrary files
|
|
14
|
+
- Split or stacked layout
|
|
15
|
+
- Automatically adapts to Shiki themes
|
|
16
|
+
- Supports light and dark mode
|
|
17
|
+
- Options for diff highlight styles, in-line highlighting, wrapping, line
|
|
18
|
+
numbers, and more
|
|
19
|
+
- Supports custom fonts and `font-feature-settings`
|
|
20
|
+
- Flexible annotation framework for injecting comments, annotations, and more
|
|
21
|
+
- Add your own accept/reject changes UI
|
|
22
|
+
- Select and highlight lines
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
bun i @pierre/diffs
|
|
28
|
+
```
|
|
4
29
|
|
|
5
30
|
## Development
|
|
6
31
|
|
|
7
|
-
|
|
32
|
+
Technically you can use the package manager of your choice, but we use
|
|
33
|
+
[bun](https://bun.sh/).
|
|
8
34
|
|
|
9
35
|
```bash
|
|
10
|
-
|
|
36
|
+
# From the root of the mono repo: setup dependencies
|
|
37
|
+
bun install
|
|
38
|
+
|
|
39
|
+
# Start the demo vite test server from root
|
|
40
|
+
bun run demo:dev
|
|
41
|
+
|
|
42
|
+
# To run the docs from root
|
|
43
|
+
bun run docs:dev
|
|
11
44
|
```
|
|
12
45
|
|
|
13
46
|
### Testing
|
|
14
47
|
|
|
15
48
|
```bash
|
|
16
|
-
# Run tests
|
|
49
|
+
# Run tests and related command from within the package directory
|
|
17
50
|
bun test
|
|
18
51
|
|
|
19
52
|
# Update snapshots
|
|
@@ -25,3 +58,40 @@ bun run tsc
|
|
|
25
58
|
|
|
26
59
|
Tests are located in the `test/` folder and use Bun's native testing framework
|
|
27
60
|
with snapshot support.
|
|
61
|
+
|
|
62
|
+
## Publishing
|
|
63
|
+
|
|
64
|
+
**Applicable to the Pierre team only.**
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# You may need to login with npm first:
|
|
68
|
+
npm login
|
|
69
|
+
|
|
70
|
+
# Always run publish from within the package directory
|
|
71
|
+
cd packages/diffs
|
|
72
|
+
bun publish
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Building Icons
|
|
76
|
+
|
|
77
|
+
**For Pierre team only.**
|
|
78
|
+
|
|
79
|
+
To build all our SVG icons from Figma there's a couple preparation steps that
|
|
80
|
+
you need to run first.
|
|
81
|
+
|
|
82
|
+
Perform a full export of all `Published Icons` the `Pierre Design` Figma file
|
|
83
|
+
|
|
84
|
+
Do this by selecting all the icons but not the art board and in the bottom right
|
|
85
|
+
click `Export XXX Layers` and make sure to point it to a `./svg` folder at the
|
|
86
|
+
root level of this project
|
|
87
|
+
|
|
88
|
+
Once that's done, simply run:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
bun run icons:build
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This will run a full build of all the icons into
|
|
95
|
+
`./apps/docs/components/icons/icons`
|
|
96
|
+
|
|
97
|
+
Then make sure to check in any changes needed
|
|
@@ -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("
|
|
70
|
+
this.pre.addEventListener("pointerdown", this.handleMouseDown);
|
|
71
71
|
}
|
|
72
72
|
removeEventListeners() {
|
|
73
73
|
if (this.pre == null) return;
|
|
74
|
-
this.pre.removeEventListener("
|
|
75
|
-
document.removeEventListener("
|
|
76
|
-
document.removeEventListener("
|
|
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("
|
|
109
|
-
document.addEventListener("
|
|
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("
|
|
120
|
-
document.removeEventListener("
|
|
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":"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"}
|
|
@@ -7,13 +7,13 @@ interface OnLineClickProps extends LineEventBaseProps {
|
|
|
7
7
|
event: PointerEvent;
|
|
8
8
|
}
|
|
9
9
|
interface OnLineEnterLeaveProps extends LineEventBaseProps {
|
|
10
|
-
event:
|
|
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:
|
|
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:
|
|
49
|
-
handleMouseMove: (event:
|
|
50
|
-
handleMouseLeave: (event:
|
|
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,
|
|
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("
|
|
24
|
-
this.pre?.removeEventListener("
|
|
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("
|
|
59
|
-
debugLogIfEnabled(__debugMouseEvents, "move", "FileDiff.DEBUG.attachEventListeners: Attaching
|
|
60
|
-
pre.addEventListener("
|
|
61
|
-
debugLogIfEnabled(__debugMouseEvents, "move", "FileDiff.DEBUG.attachEventListeners: Attaching
|
|
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":";AA8DA,SAAS,gBACP,MACA,MAC8B;AAC9B,KAAI,QAAQ,KAAM,QAAO;AACzB,KAAI,SAAS,OACX,QAAO,KAAK,SAAS;KAErB,QAAO,KAAK,SAAS;;AAIzB,SAAS,mBACP,MAK2B;AAC3B,QAAO,MAAM,SAAS;;AAmBxB,IAAa,oBAAb,MAAoE;CAClE,AAAQ;CACR,AAAQ;CACR,AAAQ;CAER,YACE,AAAQA,MACR,AAAQC,SACR;EAFQ;EACA;;CAGV,WAAW,SAAgD;AACzD,OAAK,UAAU;;CAGjB,UAAgB;AACd,OAAK,KAAK,oBAAoB,SAAS,KAAK,iBAAiB;AAC7D,OAAK,KAAK,oBAAoB,eAAe,KAAK,gBAAgB;AAClE,OAAK,KAAK,oBAAoB,cAAc,KAAK,iBAAiB;AAClE,SAAO,KAAK,KAAK,QAAQ;AACzB,SAAO,KAAK,KAAK,QAAQ;AACzB,OAAK,MAAM;;CAGb,MAAM,KAA2B;EAC/B,MAAM,EACJ,oBACA,aACA,mBACA,aACA,aACA,cACA,qBAAqB,UACnB,KAAK;AAET,OAAK,SAAS;AACd,OAAK,MAAM;AAEX,MAAI,sBAAsB,KAAK,aAAa,MAAM;AAChD,QAAK,YAAY,SAAS,cAAc,MAAM;AAC9C,QAAK,UAAU,QAAQ,YAAY;GACnC,MAAM,cAAc,SAAS,cAAc,OAAO;AAClD,eAAY,OAAO;AACnB,QAAK,UAAU,YAAY,YAAY;aAC9B,CAAC,sBAAsB,KAAK,aAAa,MAAM;AACxD,QAAK,UAAU,YAAY,YAAY,KAAK,UAAU;AACtD,QAAK,YAAY;;AAGnB,MACE,eAAe,QACf,qBAAqB,QACrB,gBAAgB,MAChB;AACA,OAAI,iBAAiB,SAAS,KAAK,iBAAiB;AACpD,OAAI,eAAe,KACjB,KAAI,QAAQ,mBAAmB;YACtB,qBAAqB,KAC9B,KAAI,QAAQ,yBAAyB;AAEvC,qBACE,oBACA,SACA,2EACO;IACL,MAAMC,UAAoB,EAAE;AAC5B,QAAI,uBAAuB,UAAU,uBAAuB,SAAS;AACnE,SAAI,eAAe,KACjB,SAAQ,KAAK,cAAc;AAE7B,SAAI,qBAAqB,KACvB,SAAQ,KAAK,oBAAoB;AAEnC,SAAI,gBAAgB,KAClB,SAAQ,KAAK,6BAA6B;;AAG9C,WAAO;OACL,CACL;;AAEH,MAAI,eAAe,QAAQ,eAAe,QAAQ,oBAAoB;AACpE,OAAI,iBAAiB,eAAe,KAAK,gBAAgB;AACzD,qBACE,oBACA,QACA,oEACD;AACD,OAAI,iBAAiB,gBAAgB,KAAK,iBAAiB;AAC3D,qBACE,oBACA,QACA,qEACD;;;CAIL,uBAAgE;AAC9D,MAAI,KAAK,eAAe,MAAM;AAC5B,OAAI,KAAK,SAAS,UAAU,KAAK,YAAY,SAAS,YACpD,QAAO;IACL,YAAY,KAAK,YAAY;IAC7B,MAAM,KAAK,YAAY;IACxB;AAEH,OAAI,KAAK,SAAS,UAAU,KAAK,YAAY,SAAS,OACpD,QAAO,EACL,YAAY,KAAK,YAAY,YAC9B;;;CAMP,oBAAoB,UAA8B;AAChD,oBACE,KAAK,QAAQ,oBACb,SACA,oCACA,MACD;AACD,OAAK,iBAAiB;GAAE,WAAW;GAAS;GAAO,CAAC;;CAGtD,mBAAmB,UAA8B;AAC/C,oBACE,KAAK,QAAQ,oBACb,QACA,mCACA,MACD;AACD,OAAK,iBAAiB;GAAE,WAAW;GAAQ;GAAO,CAAC;;CAGrD,oBAAoB,UAA8B;EAChD,MAAM,EAAE,uBAAuB,KAAK;AACpC,oBACE,oBACA,QACA,4CACD;AACD,MAAI,KAAK,eAAe,MAAM;AAC5B,qBACE,oBACA,QACA,mEACD;AACD;;AAEF,OAAK,WAAW,eAAe,YAAY,KAAK,UAAU;AAC1D,OAAK,QAAQ,cAAc;GACzB,GAAG,KAAK;GACR;GACD,CAAqC;AACtC,OAAK,cAAc;;CAGrB,AAAQ,iBAAiB,EAAE,WAAW,SAAgC;EACpE,MAAM,EAAE,uBAAuB,KAAK;EACpC,MAAM,eAAe,MAAM,cAAc;AACzC,oBACE,oBACA,WACA,oCACA;GAAE;GAAW;GAAc,CAC5B;EACD,MAAM,OAAO,KAAK,YAAY,aAAa;AAC3C,oBACE,oBACA,WACA,wDACA,KACD;EACD,MAAM,EACJ,aACA,mBACA,aACA,aACA,iBACE,KAAK;AACT,UAAQ,WAAR;GACE,KAAK;AACH,QACE,gBAAgB,MAAM,KAAK,KAAK,IAChC,KAAK,aAAa,gBAAgB,KAAK,aACvC;AACA,uBACE,oBACA,QACA,oFACD;AACD;;AAEF,QAAI,KAAK,eAAe,MAAM;AAC5B,uBACE,oBACA,QACA,4GACD;AACD,UAAK,WAAW,eAAe,YAAY,KAAK,UAAU;AAC1D,mBAAc;MACZ,GAAG,KAAK;MACR;MACD,CAAqC;AACtC,UAAK,cAAc;;AAErB,QAAI,gBAAgB,MAAM,KAAK,KAAK,EAAE;AACpC,uBACE,oBACA,QACA,uGACD;AACD,UAAK,cAAc;AACnB,SAAI,KAAK,aAAa,KACpB,MAAK,eAAe,YAAY,KAAK,UAAU;AAEjD,mBAAc;MACZ,GAAG,KAAK;MACR;MACD,CAAqC;;AAExC;GAEF,KAAK;AACH,sBACE,oBACA,SACA,gEACA,KACD;AACD,QAAI,QAAQ,KAAM;AAClB,QAAI,mBAAmB,KAAK,IAAI,gBAAgB,MAAM;AACpD,uBACE,oBACA,SACA,qEACD;AACD,kBAAa,KAAK,WAAW,KAAK,UAAU;AAC5C;;AAEF,QAAI,gBAAgB,MAAM,KAAK,KAAK,CAClC,KAAI,qBAAqB,QAAQ,KAAK,cAAc;AAClD,uBACE,oBACA,SACA,+EACD;AACD,uBAAkB;MAAE,GAAG;MAAM;MAAO,CAA2B;eACtD,eAAe,MAAM;AAC9B,uBACE,oBACA,SACA,yEACD;AACD,iBAAY;MAAE,GAAG;MAAM;MAAO,CAA2B;UAEzD,mBACE,oBACA,SACA,mFACD;AAGL;;;CAIN,AAAQ,YACN,MAC0B;EAC1B,IAAI,eAAe;EACnB,MAAM,cAAc,KAAK,MAAM,YAAY;AACzC,OAAI,EAAE,mBAAmB,aACvB,QAAO;AAET,kBAAe,gBAAgB,kBAAkB,QAAQ;AACzD,UAAO,UAAU,QAAQ,WAAW,iBAAiB,QAAQ;IAC7D;AACF,MAAI,EAAE,uBAAuB,aAAc,QAAO;AAClD,MAAI,YAAY,QAAQ,eAAe,MAAM;GAC3C,MAAM,YAAY,SAAS,YAAY,QAAQ,YAAY;AAC3D,OAAI,MAAM,UAAU,CAClB;GAEF,IAAIC;AACJ,QAAK,MAAM,WAAW,MAAM;AAC1B,QAAI,YAAY,YAAa;AAC7B,QAAI,mBAAmB,aAAa;AAClC,iBACE,cACC,cAAc,QAAQ,UAAU,OAAO,YACvC,gBAAgB,QAAQ,UAAU,SAAS,YAC3C,gBAAgB,QAAQ,UAAU,SAAS;AAC9C,SAAI,aAAa,KACf;;;AAIN,UAAO,aAAa,OAChB;IAAE,MAAM;IAAa;IAAW;IAAW,GAC3C;;EAEN,MAAM,aAAa,SAAS,YAAY,QAAQ,QAAQ,GAAG;AAC3D,MAAI,MAAM,WAAW,CAAE;EACvB,MAAM,WAAW,YAAY,QAAQ;AACrC,MACE,aAAa,aACb,aAAa,sBACb,aAAa,qBACb,aAAa,kBAEb;EAGF,MAAM,uBAAuB;GAC3B,MAAMC,kBAAgB,YAAY,SAAS;AAC3C,UAAOA,2BAAyB,eAC9BA,gBAAc,QAAQ,gBAAgB,OACpCA,kBACA;MACF;AAEJ,MAAI,KAAK,SAAS,OAChB,QAAO;GACL,MAAM;GACN;GACA;GACA;GACA;GACD;AAiBH,SAAO;GACL,MAAM;GACN,uBAhB4C;AAC5C,QAAI,aAAa,kBACf,QAAO;AAET,QAAI,aAAa,kBACf,QAAO;IAET,MAAM,SAAS,YAAY,QAAQ,cAAc;AACjD,QAAI,EAAE,kBAAkB,aACtB,QAAO;AAET,WAAO,eAAe,OAAO,UAAU,cAAc;OACnD;GAKF;GACA;GACA;GACA;GACA;GACD;;;AAIL,SAAS,kBACP,eAAqC,QACrC,WACA,GAAG,MACH;AACA,SAAQ,cAAR;EACE,KAAK,OACH;EACF,KAAK,OACH;EACF,KAAK;AACH,OAAI,cAAc,QAChB;AAEF;EACF,KAAK;AACH,OAAI,cAAc,OAChB;AAEF;;AAEJ,SAAQ,IAAI,GAAG,KAAK;;AAGtB,SAAgB,uBACd,EACE,aACA,mBACA,aACA,aACA,oBACA,sBAEF,cACiC;AACjC,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACD"}
|
|
@@ -150,14 +150,18 @@ var DiffHunksRenderer = class {
|
|
|
150
150
|
}
|
|
151
151
|
renderDiff(diff = this.renderCache?.diff) {
|
|
152
152
|
if (diff == null) return;
|
|
153
|
+
const cache = this.workerManager?.getDiffResultCache(diff);
|
|
154
|
+
if (cache != null && this.renderCache == null) this.renderCache = {
|
|
155
|
+
diff,
|
|
156
|
+
highlighted: true,
|
|
157
|
+
...cache
|
|
158
|
+
};
|
|
153
159
|
const { options, forceRender } = this.getRenderOptions(diff);
|
|
154
|
-
let cache = this.workerManager?.getDiffResultCache(diff);
|
|
155
|
-
if (cache != null && !areRenderOptionsEqual(options, cache.options)) cache = void 0;
|
|
156
160
|
this.renderCache ??= {
|
|
157
161
|
diff,
|
|
158
|
-
highlighted:
|
|
159
|
-
options
|
|
160
|
-
result:
|
|
162
|
+
highlighted: false,
|
|
163
|
+
options,
|
|
164
|
+
result: void 0
|
|
161
165
|
};
|
|
162
166
|
if (this.workerManager?.isWorkingPool() === true) {
|
|
163
167
|
this.renderCache.result ??= this.workerManager.getPlainDiffAST(diff);
|