Przeglądaj źródła

fix(app): line selection styling

adamelmore 3 tygodni temu
rodzic
commit
9a89cd91d7

+ 70 - 14
packages/ui/src/components/diff-ssr.tsx

@@ -29,10 +29,16 @@ export function Diff<T>(props: SSRDiffProps<T>) {
   const getRoot = () => fileDiffRef?.shadowRoot ?? undefined
 
   const findSide = (element: HTMLElement): "additions" | "deletions" => {
+    const line = element.closest("[data-line], [data-alt-line]")
+    if (line instanceof HTMLElement) {
+      const type = line.dataset.lineType
+      if (type === "change-deletion") return "deletions"
+      if (type === "change-addition" || type === "change-additions") return "additions"
+    }
+
     const code = element.closest("[data-code]")
     if (!(code instanceof HTMLElement)) return "additions"
-    if (code.hasAttribute("data-deletions")) return "deletions"
-    return "additions"
+    return code.hasAttribute("data-deletions") ? "deletions" : "additions"
   }
 
   const applyCommentedLines = (ranges: SelectedLineRange[]) => {
@@ -45,19 +51,69 @@ export function Diff<T>(props: SSRDiffProps<T>) {
       node.removeAttribute("data-comment-selected")
     }
 
+    const diffs = root.querySelector("[data-diffs]")
+    if (!(diffs instanceof HTMLElement)) return
+
+    const split = diffs.dataset.type === "split"
+
+    const code = Array.from(diffs.querySelectorAll("[data-code]")).filter(
+      (node): node is HTMLElement => node instanceof HTMLElement,
+    )
+    if (code.length === 0) return
+
+    const lineIndex = (element: HTMLElement) => {
+      const raw = element.dataset.lineIndex
+      if (!raw) return
+      const values = raw
+        .split(",")
+        .map((value) => parseInt(value, 10))
+        .filter((value) => !Number.isNaN(value))
+      if (values.length === 0) return
+      if (!split) return values[0]
+      if (values.length === 2) return values[1]
+      return values[0]
+    }
+
+    const rowIndex = (line: number, side: "additions" | "deletions" | undefined) => {
+      const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`)).filter(
+        (node): node is HTMLElement => node instanceof HTMLElement,
+      )
+      if (nodes.length === 0) return
+
+      const targetSide = side ?? "additions"
+
+      for (const node of nodes) {
+        if (findSide(node) === targetSide) return lineIndex(node)
+        if (parseInt(node.dataset.altLine ?? "", 10) === line) return lineIndex(node)
+      }
+    }
+
     for (const range of ranges) {
-      const start = Math.max(1, Math.min(range.start, range.end))
-      const end = Math.max(range.start, range.end)
-
-      for (let line = start; line <= end; line++) {
-        const expectedSide =
-          line === end ? (range.endSide ?? range.side) : line === start ? range.side : (range.side ?? range.endSide)
-
-        const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`))
-        for (const node of nodes) {
-          if (!(node instanceof HTMLElement)) continue
-          if (expectedSide && findSide(node) !== expectedSide) continue
-          node.setAttribute("data-comment-selected", "")
+      const start = rowIndex(range.start, range.side)
+      if (start === undefined) continue
+
+      const end = (() => {
+        const same = range.end === range.start && (range.endSide == null || range.endSide === range.side)
+        if (same) return start
+        return rowIndex(range.end, range.endSide ?? range.side)
+      })()
+      if (end === undefined) continue
+
+      const first = Math.min(start, end)
+      const last = Math.max(start, end)
+
+      for (const block of code) {
+        for (const element of Array.from(block.children)) {
+          if (!(element instanceof HTMLElement)) continue
+          const idx = lineIndex(element)
+          if (idx === undefined) continue
+          if (idx > last) break
+          if (idx < first) continue
+          element.setAttribute("data-comment-selected", "")
+          const next = element.nextSibling
+          if (next instanceof HTMLElement && next.hasAttribute("data-line-annotation")) {
+            next.setAttribute("data-comment-selected", "")
+          }
         }
       }
     }

+ 59 - 14
packages/ui/src/components/diff.tsx

@@ -191,24 +191,69 @@ export function Diff<T>(props: DiffProps<T>) {
       node.removeAttribute("data-comment-selected")
     }
 
-    for (const range of ranges) {
-      const start = Math.max(1, Math.min(range.start, range.end))
-      const end = Math.max(range.start, range.end)
+    const diffs = root.querySelector("[data-diffs]")
+    if (!(diffs instanceof HTMLElement)) return
+
+    const split = diffs.dataset.type === "split"
+
+    const code = Array.from(diffs.querySelectorAll("[data-code]")).filter(
+      (node): node is HTMLElement => node instanceof HTMLElement,
+    )
+    if (code.length === 0) return
+
+    const lineIndex = (element: HTMLElement) => {
+      const raw = element.dataset.lineIndex
+      if (!raw) return
+      const values = raw
+        .split(",")
+        .map((value) => parseInt(value, 10))
+        .filter((value) => !Number.isNaN(value))
+      if (values.length === 0) return
+      if (!split) return values[0]
+      if (values.length === 2) return values[1]
+      return values[0]
+    }
 
-      for (let line = start; line <= end; line++) {
-        const expectedSide =
-          line === end ? (range.endSide ?? range.side) : line === start ? range.side : (range.side ?? range.endSide)
+    const rowIndex = (line: number, side: SelectionSide | undefined) => {
+      const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`)).filter(
+        (node): node is HTMLElement => node instanceof HTMLElement,
+      )
+      if (nodes.length === 0) return
 
-        const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-alt-line="${line}"]`))
-        for (const node of nodes) {
-          if (!(node instanceof HTMLElement)) continue
+      const targetSide = side ?? "additions"
 
-          if (expectedSide) {
-            const side = findSide(node)
-            if (side && side !== expectedSide) continue
-          }
+      for (const node of nodes) {
+        if (findSide(node) === targetSide) return lineIndex(node)
+        if (parseInt(node.dataset.altLine ?? "", 10) === line) return lineIndex(node)
+      }
+    }
 
-          node.setAttribute("data-comment-selected", "")
+    for (const range of ranges) {
+      const start = rowIndex(range.start, range.side)
+      if (start === undefined) continue
+
+      const end = (() => {
+        const same = range.end === range.start && (range.endSide == null || range.endSide === range.side)
+        if (same) return start
+        return rowIndex(range.end, range.endSide ?? range.side)
+      })()
+      if (end === undefined) continue
+
+      const first = Math.min(start, end)
+      const last = Math.max(start, end)
+
+      for (const block of code) {
+        for (const element of Array.from(block.children)) {
+          if (!(element instanceof HTMLElement)) continue
+          const idx = lineIndex(element)
+          if (idx === undefined) continue
+          if (idx > last) break
+          if (idx < first) continue
+          element.setAttribute("data-comment-selected", "")
+          const next = element.nextSibling
+          if (next instanceof HTMLElement && next.hasAttribute("data-line-annotation")) {
+            next.setAttribute("data-comment-selected", "")
+          }
         }
       }
     }

+ 5 - 5
packages/ui/src/pierre/index.ts

@@ -44,12 +44,12 @@ const unsafeCSS = `
   background-color: var(--diffs-bg-selection-text);
 }
 
-[data-diffs] [data-comment-selected] {
-  background-color: var(--diffs-bg-selection);
+[data-diffs] [data-comment-selected]:not([data-selected-line]) [data-column-content] {
+  box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection);
 }
 
-[data-diffs] [data-comment-selected] [data-column-number] {
-  background-color: var(--diffs-bg-selection-number);
+[data-diffs] [data-comment-selected]:not([data-selected-line]) [data-column-number] {
+  box-shadow: inset 0 0 0 9999px var(--diffs-bg-selection-number);
   color: var(--diffs-selection-number-fg);
 }
 
@@ -73,7 +73,7 @@ const unsafeCSS = `
 /* The deletion word-diff emphasis is stronger than additions; soften it while selected so the selection highlight reads consistently. */
 [data-diffs] [data-line-type='change-deletion'][data-selected-line] {
   --diffs-bg-deletion-emphasis: light-dark(
-    rgb(from var(--diffs-deletion-base) r g b / 0.15),
+    rgb(from var(--diffs-deletion-base) r g b / 0.07),
     rgb(from var(--diffs-deletion-base) r g b / 0.1)
   );
 }