dsh-diff-approval 0.14.1 → 0.16.0

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/lib/client.js CHANGED
@@ -535,7 +535,10 @@ window.__ModuleLoader__.load({
535
535
  return value;
536
536
  }
537
537
  };
538
- new ArrayDiff();
538
+ const arrayDiff = new ArrayDiff();
539
+ function diffArrays(oldArr, newArr, options) {
540
+ return arrayDiff.diff(oldArr, newArr, options);
541
+ }
539
542
  //#endregion
540
543
  //#region node_modules/.pnpm/diff@9.0.0/node_modules/diff/libesm/patch/create.js
541
544
  function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
@@ -722,6 +725,246 @@ window.__ModuleLoader__.load({
722
725
  added
723
726
  };
724
727
  }
728
+ /** Minimum similarity for a del/add pair to receive an intra-line diff. */
729
+ const INTRA_SIMILARITY_THRESHOLD = .4;
730
+ /** Lines longer than this are skipped (a single pathological line would make the
731
+ * token-diff O(n²) and only ever show a noise floor). Mirrors the highlighting
732
+ * cap so a review stays bounded. */
733
+ const INTRA_MAX_LINE_LENGTH = 2e3;
734
+ /** A similarity-alignment block larger than this many cell-and-compare pairs
735
+ * falls back to by-order pairing: the O(n·m) scan and DP would stall on a
736
+ * whole-file rewrite for no benefit. */
737
+ const INTRA_MAX_ALIGN_CELLS = 8192;
738
+ const WORD_CHAR_RE = /[\p{L}\p{N}_]/u;
739
+ /** CJK characters — Chinese han, Japanese kana, CJK fullwidth forms. Each is an
740
+ * independent unit (there is no whitespace word boundary), so one token each. */
741
+ function isCJKCode$1(cp) {
742
+ return cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 19903 || cp >= 19968 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65072 && cp <= 65103 || cp >= 65280 && cp <= 65519 || cp >= 131072 && cp <= 195103;
743
+ }
744
+ /** Space, tab, or the ideographic space — whitespace is a break opportunity. */
745
+ function isSpaceCode$1(cp) {
746
+ return cp === 32 || cp === 9 || cp === 12288;
747
+ }
748
+ /**
749
+ * Tokenize a line for an intra-line diff, into a lossless array of tokens whose
750
+ * concatenation equals the input. Word-based for space-delimited scripts: a
751
+ * maximal run of letters/numbers/underscore (any script except CJK) is one
752
+ * token, so a whole edited word stays a single run instead of per-character.
753
+ * Each CJK character is its own token (there is no word boundary), as is each
754
+ * punctuation/symbol character (a run of different punctuation carries no
755
+ * meaning, so it diffs atomically), while a maximal whitespace run stays one
756
+ * token as a natural break. This yields clean word-level highlights for English
757
+ * and per-character precision for CJK and punctuation.
758
+ * @param text - the line's content.
759
+ * @returns the tokens.
760
+ */
761
+ function tokenizeLine(text) {
762
+ const tokens = [];
763
+ let cur = "";
764
+ let runKind;
765
+ const flush = () => {
766
+ if (cur !== "") {
767
+ tokens.push(cur);
768
+ cur = "";
769
+ }
770
+ };
771
+ for (const ch of text) {
772
+ const cp = ch.codePointAt(0) ?? 0;
773
+ const word = WORD_CHAR_RE.test(ch);
774
+ if (isCJKCode$1(cp) || !word && !isSpaceCode$1(cp)) {
775
+ flush();
776
+ runKind = void 0;
777
+ tokens.push(ch);
778
+ continue;
779
+ }
780
+ const kind = word ? "word" : "space";
781
+ if (kind !== runKind) {
782
+ flush();
783
+ runKind = kind;
784
+ }
785
+ cur += ch;
786
+ }
787
+ flush();
788
+ return tokens;
789
+ }
790
+ /**
791
+ * Raw similarity of a del/add line pair in `[0, 1]`, or `-1` when the pair
792
+ * cannot be meaningfully compared (identical lines, either side empty, or over
793
+ * the length cap). Used both by the intra-line gate and by the similarity
794
+ * alignment, so the two always agree on what counts as "changed".
795
+ * @param oldText - the removed side's line text.
796
+ * @param newText - the added side's line text.
797
+ * @returns the similarity ratio, or `-1` when incomparable.
798
+ */
799
+ function lineSimilarity(oldText, newText) {
800
+ if (oldText === newText || oldText === "" || newText === "") return -1;
801
+ if (oldText.length > INTRA_MAX_LINE_LENGTH || newText.length > INTRA_MAX_LINE_LENGTH) return -1;
802
+ return 2 * diffArrays(tokenizeLine(oldText), tokenizeLine(newText)).reduce((sum, change) => change.removed || change.added ? sum : sum + change.value.join("").length, 0) / (oldText.length + newText.length);
803
+ }
804
+ /**
805
+ * Compute the intra-line runs for one del/add line pair, or `undefined` when
806
+ * the pair should not be annotated: identical lines (no internal change) or
807
+ * lines too dissimilar to be a modification (a rewrite, not an edit).
808
+ * Word-based via the `diff` package's `diffArrays` over `tokenizeLine`'s
809
+ * tokens, so an English edit highlights whole changed words and a CJK edit
810
+ * highlights the individual changed characters.
811
+ * @param oldText - the removed side's line text.
812
+ * @param newText - the added side's line text.
813
+ * @returns the del-side and add-side runs, or `undefined` to skip annotation.
814
+ */
815
+ function intraRunsOf(oldText, newText) {
816
+ if (lineSimilarity(oldText, newText) < INTRA_SIMILARITY_THRESHOLD) return void 0;
817
+ const changes = diffArrays(tokenizeLine(oldText), tokenizeLine(newText));
818
+ const del = [];
819
+ const add = [];
820
+ for (const change of changes) {
821
+ const text = change.value.join("");
822
+ if (change.removed) del.push({
823
+ text,
824
+ kind: "del"
825
+ });
826
+ else if (change.added) add.push({
827
+ text,
828
+ kind: "add"
829
+ });
830
+ else {
831
+ del.push({
832
+ text,
833
+ kind: "same"
834
+ });
835
+ add.push({
836
+ text,
837
+ kind: "same"
838
+ });
839
+ }
840
+ }
841
+ if (!del.some((run) => run.kind === "del") && !add.some((run) => run.kind === "add")) return void 0;
842
+ return {
843
+ del,
844
+ add
845
+ };
846
+ }
847
+ /**
848
+ * Align a del run with the following add run. By order (the baseline) pairs
849
+ * `del[i]`↔`add[i]`. With similarity alignment, an order-preserving best match
850
+ * pairs each del with the add that maximises total similarity, keeping a pair
851
+ * only when it clears the similarity threshold — so a lone insert or delete in
852
+ * a mixed block stays unaligned instead of being forced onto a wrong line.
853
+ * @param delRows - the run's del rows (index + text).
854
+ * @param addRows - the run's add rows (index + text).
855
+ * @param alignBySimilarity - whether to use the similarity-based matching.
856
+ * @returns the aligned pairs and the unmatched sides.
857
+ */
858
+ function alignChangedBlock(delRows, addRows, alignBySimilarity) {
859
+ const byOrder = () => {
860
+ const min = Math.min(delRows.length, addRows.length);
861
+ const pairs = [];
862
+ for (let i = 0; i < min; i++) pairs.push({
863
+ delIndex: delRows[i].index,
864
+ addIndex: addRows[i].index
865
+ });
866
+ return {
867
+ pairs,
868
+ delOnly: delRows.slice(min).map((row) => row.index),
869
+ addOnly: addRows.slice(min).map((row) => row.index),
870
+ usedSimilarity: false
871
+ };
872
+ };
873
+ if (!alignBySimilarity) return byOrder();
874
+ const n = delRows.length;
875
+ const m = addRows.length;
876
+ if (n * m > INTRA_MAX_ALIGN_CELLS) return byOrder();
877
+ const sim = [];
878
+ for (let i = 0; i < n; i++) {
879
+ const row = [];
880
+ for (let j = 0; j < m; j++) row.push(lineSimilarity(delRows[i].text, addRows[j].text));
881
+ sim.push(row);
882
+ }
883
+ const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
884
+ for (let i = 1; i <= n; i++) for (let j = 1; j <= m; j++) {
885
+ const skipDel = dp[i - 1][j];
886
+ const skipAdd = dp[i][j - 1];
887
+ const s = sim[i - 1][j - 1];
888
+ const pair = s >= INTRA_SIMILARITY_THRESHOLD ? dp[i - 1][j - 1] + s : Number.NEGATIVE_INFINITY;
889
+ dp[i][j] = Math.max(skipDel, skipAdd, pair);
890
+ }
891
+ const pairs = [];
892
+ const delOnly = [];
893
+ const addOnly = [];
894
+ let i = n;
895
+ let j = m;
896
+ while (i > 0 || j > 0) {
897
+ const s = i > 0 && j > 0 ? sim[i - 1][j - 1] : Number.NEGATIVE_INFINITY;
898
+ if (i > 0 && j > 0 && s >= INTRA_SIMILARITY_THRESHOLD && dp[i][j] === dp[i - 1][j - 1] + s) {
899
+ pairs.push({
900
+ delIndex: delRows[i - 1].index,
901
+ addIndex: addRows[j - 1].index
902
+ });
903
+ i--;
904
+ j--;
905
+ } else if (i > 0 && dp[i][j] === dp[i - 1][j]) {
906
+ delOnly.push(delRows[i - 1].index);
907
+ i--;
908
+ } else if (j > 0) {
909
+ addOnly.push(addRows[j - 1].index);
910
+ j--;
911
+ } else break;
912
+ }
913
+ pairs.reverse();
914
+ delOnly.reverse();
915
+ addOnly.reverse();
916
+ return {
917
+ pairs,
918
+ delOnly,
919
+ addOnly,
920
+ usedSimilarity: true
921
+ };
922
+ }
923
+ /**
924
+ * Derive intra-line runs for a whole-file row list. Each del/add block is
925
+ * aligned (by order, or by similarity when `alignBySimilarity`), and each
926
+ * matched pair is compared by `intraRunsOf`. Returns a map keyed by the row's
927
+ * index in `rows`, present only for rows that carry a highlight.
928
+ * @param rows - the unified `WholeFileDiff` row list.
929
+ * @param alignBySimilarity - align blocks by similarity instead of by order.
930
+ * @returns per-row-index intra-line runs for annotated del/add rows.
931
+ */
932
+ function computeIntraLineDiff(rows, alignBySimilarity = false) {
933
+ const result = /* @__PURE__ */ new Map();
934
+ let i = 0;
935
+ while (i < rows.length) {
936
+ if (rows[i].kind !== "del") {
937
+ i++;
938
+ continue;
939
+ }
940
+ const delIndices = [];
941
+ while (i < rows.length && rows[i].kind === "del") {
942
+ delIndices.push(i);
943
+ i++;
944
+ }
945
+ const addIndices = [];
946
+ while (i < rows.length && rows[i].kind === "add") {
947
+ addIndices.push(i);
948
+ i++;
949
+ }
950
+ const alignment = alignChangedBlock(delIndices.map((index) => ({
951
+ index,
952
+ text: rows[index].text
953
+ })), addIndices.map((index) => ({
954
+ index,
955
+ text: rows[index].text
956
+ })), alignBySimilarity);
957
+ if (alignBySimilarity && !alignment.usedSimilarity) continue;
958
+ for (const pair of alignment.pairs) {
959
+ const intra = intraRunsOf(rows[pair.delIndex].text, rows[pair.addIndex].text);
960
+ if (intra !== void 0) {
961
+ result.set(pair.delIndex, intra.del);
962
+ result.set(pair.addIndex, intra.add);
963
+ }
964
+ }
965
+ }
966
+ return result;
967
+ }
725
968
  /**
726
969
  * Split a side's text into its content lines, with the diff card's terminator
727
970
  * rule: empty text is zero lines, and a single trailing newline is a line
@@ -761,57 +1004,78 @@ window.__ModuleLoader__.load({
761
1004
  };
762
1005
  }
763
1006
  /**
764
- * Regroup the whole-file rows into aligned split pairs, pairing a deletion run
765
- * with a following addition run line-by-line (so a replaced line is one pair),
766
- * and leaving a stray deletion or addition as a one-sided pair.
1007
+ * Regroup the whole-file rows into aligned split pairs. By order, a deletion
1008
+ * run pairs line-by-line with a following addition run; with similarity
1009
+ * alignment, each deletion pairs with its most-similar addition (order
1010
+ * preserved, threshold-bounded) so a mixed insert/delete block does not force a
1011
+ * wrong line together. A stray deletion or addition stays a one-sided pair.
767
1012
  * @param rows - the whole-file diff rows.
1013
+ * @param alignBySimilarity - align a change block by similarity instead of order.
768
1014
  * @returns the split pairs plus the row→pair index map.
769
1015
  */
770
- function computeSideBySideDiff(rows) {
1016
+ function computeSideBySideDiff(rows, alignBySimilarity = false) {
771
1017
  const pairs = [];
772
1018
  const pairOfRow = /* @__PURE__ */ new Map();
773
- const pendingDel = [];
774
- const push = (pair, rows) => {
1019
+ const push = (pair, pairRows) => {
775
1020
  const index = pairs.length;
776
1021
  pairs.push(pair);
777
- for (const r of rows) pairOfRow.set(r, index);
778
- };
779
- const flushPending = () => {
780
- for (const { index, row } of pendingDel) push({
781
- kind: "del",
782
- left: leftSideOf(row),
783
- right: void 0
784
- }, [index]);
785
- pendingDel.length = 0;
1022
+ for (const r of pairRows) pairOfRow.set(r, index);
786
1023
  };
787
- for (let i = 0; i < rows.length; i++) {
1024
+ let i = 0;
1025
+ while (i < rows.length) {
788
1026
  const row = rows[i];
789
1027
  if (row.kind === "context") {
790
- flushPending();
791
1028
  push({
792
1029
  kind: "context",
793
1030
  left: leftSideOf(row),
794
1031
  right: rightSideOf(row)
795
1032
  }, [i]);
796
- } else if (row.kind === "del") pendingDel.push({
797
- index: i,
798
- row
799
- });
800
- else {
801
- const del = pendingDel.shift();
802
- if (del !== void 0) push({
1033
+ i++;
1034
+ continue;
1035
+ }
1036
+ const delRows = [];
1037
+ const addRows = [];
1038
+ if (row.kind === "del") while (i < rows.length && rows[i].kind === "del") {
1039
+ delRows.push({
1040
+ index: i,
1041
+ row: rows[i]
1042
+ });
1043
+ i++;
1044
+ }
1045
+ while (i < rows.length && rows[i].kind === "add") {
1046
+ addRows.push({
1047
+ index: i,
1048
+ row: rows[i]
1049
+ });
1050
+ i++;
1051
+ }
1052
+ const alignment = alignChangedBlock(delRows.map((d) => ({
1053
+ index: d.index,
1054
+ text: d.row.text
1055
+ })), addRows.map((a) => ({
1056
+ index: a.index,
1057
+ text: a.row.text
1058
+ })), alignBySimilarity);
1059
+ for (const p of alignment.pairs) {
1060
+ const del = delRows.find((d) => d.index === p.delIndex);
1061
+ const add = addRows.find((a) => a.index === p.addIndex);
1062
+ push({
803
1063
  kind: "replace",
804
1064
  left: leftSideOf(del.row),
805
- right: rightSideOf(row)
806
- }, [del.index, i]);
807
- else push({
808
- kind: "add",
809
- left: void 0,
810
- right: rightSideOf(row)
811
- }, [i]);
1065
+ right: rightSideOf(add.row)
1066
+ }, [p.delIndex, p.addIndex]);
812
1067
  }
1068
+ for (const d of alignment.delOnly) push({
1069
+ kind: "del",
1070
+ left: leftSideOf(delRows.find((x) => x.index === d).row),
1071
+ right: void 0
1072
+ }, [d]);
1073
+ for (const a of alignment.addOnly) push({
1074
+ kind: "add",
1075
+ left: void 0,
1076
+ right: rightSideOf(addRows.find((x) => x.index === a).row)
1077
+ }, [a]);
813
1078
  }
814
- flushPending();
815
1079
  return {
816
1080
  pairs,
817
1081
  pairOfRow
@@ -11833,6 +12097,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11833
12097
  const IMPORT_UNTRACKED_KEY = "diff-approval:import-untracked";
11834
12098
  const TAB_WIDTH_KEY = "diff-approval:tab-size";
11835
12099
  const SPLIT_MODE_KEY = "diff-approval:split-mode";
12100
+ const NAV_LEAD_KEY = "diff-approval:nav-lead-rows";
11836
12101
  const WRAP_PREFIX = "diff-approval:wrap:";
11837
12102
  /**
11838
12103
  * Whether copying a reference should also paste it into the chat input and
@@ -11901,6 +12166,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11901
12166
  function setSplitMode(value) {
11902
12167
  localStorage.setItem(SPLIT_MODE_KEY, value ? "1" : "0");
11903
12168
  }
12169
+ /**
12170
+ * How many rows of lead the diff block jump leaves above the jumped-to block,
12171
+ * and how far the anchored navigation scans. Defaults to 2; an out-of-range or
12172
+ * non-integer value falls back to the default.
12173
+ * @returns the lead row count.
12174
+ */
12175
+ function navLeadRows() {
12176
+ const raw = Number.parseInt(localStorage.getItem(NAV_LEAD_KEY) ?? "", 10);
12177
+ if (!Number.isInteger(raw)) return 2;
12178
+ return Math.max(0, Math.min(10, raw));
12179
+ }
12180
+ /** Persist the block-jump lead row count. */
12181
+ function setNavLeadRows(value) {
12182
+ localStorage.setItem(NAV_LEAD_KEY, String(Math.max(0, Math.min(10, value))));
12183
+ }
11904
12184
  const QUICK_SUMMON_KEY = "diff-approval:quick-summon-key";
11905
12185
  /**
11906
12186
  * The quick-summon chord. Stored as `Modifier+...+Key`; falls back to
@@ -11936,7 +12216,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11936
12216
  }
11937
12217
  //#endregion
11938
12218
  //#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
11939
- const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_confirmBackdrop{z-index:5;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{justify-content:flex-end;gap:8px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);-webkit-text-size-adjust:100%;text-size-adjust:100%;cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{-webkit-user-select:none;user-select:none;height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{flex:1 1 0;min-width:0;height:15px;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:15px}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}";
12219
+ const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_fullscreenBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelectorChevron{flex:none}.F1KBNa_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:8px;font-size:16px;line-height:1}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:auto}.F1KBNa_bulkActions{flex:none;gap:6px;padding-top:8px;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_confirmBackdrop{z-index:5;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{justify-content:flex-end;gap:8px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);-webkit-user-select:text;user-select:text;flex:1;font-size:12px;line-height:18px;overflow:auto hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);-webkit-text-size-adjust:100%;text-size-adjust:100%;cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_diffBody [data-diff-search=hit]{background-image:linear-gradient(#facc1529,#facc1529)}.F1KBNa_diffBody [data-diff-search=current]{background-image:linear-gradient(#facc1552,#facc1552)}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlash;position:absolute;left:0;right:0}@keyframes F1KBNa_diffFlash{0%{opacity:1}to{opacity:0}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{-webkit-user-select:none;user-select:none;height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:22px}.F1KBNa_subline{white-space:pre;height:22px;line-height:22px;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{flex:1 1 0;min-width:0;height:15px;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:15px}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 26%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 24%, transparent)}";
11940
12220
  const tagId = "dsh-diff-approval/PendingPanel.module.css";
11941
12221
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
11942
12222
  const tag = document.createElement("style");
@@ -11946,115 +12226,124 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
11946
12226
  document.head.appendChild(tag);
11947
12227
  }
11948
12228
  var PendingPanel_module_css_default = {
11949
- "confirmBackdrop": "F1KBNa_confirmBackdrop",
11950
- "kindHint": "F1KBNa_kindHint",
11951
- "splitRdel": "F1KBNa_splitRdel",
11952
- "missingHint": "F1KBNa_missingHint",
11953
- "expandExpanded": "F1KBNa_expandExpanded",
11954
- "readError": "F1KBNa_readError",
12229
+ "settingsRowTitle": "F1KBNa_settingsRowTitle",
12230
+ "rail": "F1KBNa_rail",
11955
12231
  "diffBody": "F1KBNa_diffBody",
11956
- "lines": "F1KBNa_lines",
11957
- "langLabel": "F1KBNa_langLabel",
11958
- "splitCol": "F1KBNa_splitCol",
11959
- "splitRadd": "F1KBNa_splitRadd",
11960
- "diffPath": "F1KBNa_diffPath",
11961
- "diffActions": "F1KBNa_diffActions",
12232
+ "settingsSelector": "F1KBNa_settingsSelector",
12233
+ "badgeLabel": "F1KBNa_badgeLabel",
12234
+ "panel": "F1KBNa_panel",
12235
+ "hint": "F1KBNa_hint",
12236
+ "importButton": "F1KBNa_importButton",
12237
+ "addCount": "F1KBNa_addCount",
11962
12238
  "rowPath": "F1KBNa_rowPath",
11963
- "listScroll": "F1KBNa_listScroll",
12239
+ "searchInput": "F1KBNa_searchInput",
12240
+ "title": "F1KBNa_title",
11964
12241
  "actionPrimary": "F1KBNa_actionPrimary",
11965
- "importButton": "F1KBNa_importButton",
11966
- "rows": "F1KBNa_rows",
11967
- "searchCount": "F1KBNa_searchCount",
11968
- "statusBar": "F1KBNa_statusBar",
11969
- "footerButtons": "F1KBNa_footerButtons",
11970
- "layer": "F1KBNa_layer",
11971
- "badgeLabel": "F1KBNa_badgeLabel",
12242
+ "blockActions": "F1KBNa_blockActions",
12243
+ "del": "F1KBNa_del",
12244
+ "importNote": "F1KBNa_importNote",
12245
+ "diffBodySplit": "F1KBNa_diffBodySplit",
12246
+ "splitCols": "F1KBNa_splitCols",
12247
+ "note": "F1KBNa_note",
11972
12248
  "divergedHint": "F1KBNa_divergedHint",
11973
- "actionError": "F1KBNa_actionError",
11974
- "code": "F1KBNa_code",
11975
- "splitDivider": "F1KBNa_splitDivider",
11976
- "confirmCard": "F1KBNa_confirmCard",
11977
- "title": "F1KBNa_title",
12249
+ "noteCentered": "F1KBNa_noteCentered",
12250
+ "kindHint": "F1KBNa_kindHint",
12251
+ "fileListFloat": "F1KBNa_fileListFloat",
12252
+ "toggleOn": "F1KBNa_toggleOn",
11978
12253
  "wrap": "F1KBNa_wrap",
11979
- "statusAction": "F1KBNa_statusAction",
11980
- "noticeButton": "F1KBNa_noticeButton",
11981
- "flexSpacer": "F1KBNa_flexSpacer",
11982
- "confirmActions": "F1KBNa_confirmActions",
11983
- "searchInput": "F1KBNa_searchInput",
11984
- "settingsRowText": "F1KBNa_settingsRowText",
11985
- "header": "F1KBNa_header",
11986
- "diffStats": "F1KBNa_diffStats",
11987
- "settingsRowTitle": "F1KBNa_settingsRowTitle",
11988
- "blockFlash": "F1KBNa_blockFlash",
11989
- "row": "F1KBNa_row",
12254
+ "kindTag": "F1KBNa_kindTag",
12255
+ "subline": "F1KBNa_subline",
12256
+ "settingsRow": "F1KBNa_settingsRow",
12257
+ "langLabel": "F1KBNa_langLabel",
12258
+ "missingHint": "F1KBNa_missingHint",
12259
+ "settingsRowDesc": "F1KBNa_settingsRowDesc",
12260
+ "blockPosition": "F1KBNa_blockPosition",
12261
+ "statusBar": "F1KBNa_statusBar",
12262
+ "footerButtons": "F1KBNa_footerButtons",
11990
12263
  "fullscreenBackdrop": "F1KBNa_fullscreenBackdrop",
12264
+ "diffActions": "F1KBNa_diffActions",
12265
+ "divider": "F1KBNa_divider",
12266
+ "splitRdel": "F1KBNa_splitRdel",
11991
12267
  "missing": "F1KBNa_missing",
11992
- "actionQuietDisabled": "F1KBNa_actionQuietDisabled",
11993
- "searchBar": "F1KBNa_searchBar",
11994
- "overviewRuler": "F1KBNa_overviewRuler",
11995
- "notice": "F1KBNa_notice",
11996
- "splitCols": "F1KBNa_splitCols",
11997
- "markerAdd": "F1KBNa_markerAdd",
11998
- "splitRoot": "F1KBNa_splitRoot",
11999
- "blockPosition": "F1KBNa_blockPosition",
12268
+ "headerActions": "F1KBNa_headerActions",
12269
+ "stepperButton": "F1KBNa_stepperButton",
12270
+ "diffFlash": "F1KBNa_diffFlash",
12271
+ "rowMeta": "F1KBNa_rowMeta",
12272
+ "close": "F1KBNa_close",
12273
+ "diffPath": "F1KBNa_diffPath",
12000
12274
  "overviewMarker": "F1KBNa_overviewMarker",
12001
- "noticeText": "F1KBNa_noticeText",
12002
- "iconAction": "F1KBNa_iconAction",
12003
- "splitHScrollRow": "F1KBNa_splitHScrollRow",
12004
- "delCount": "F1KBNa_delCount",
12005
- "splitLadd": "F1KBNa_splitLadd",
12006
- "hint": "F1KBNa_hint",
12275
+ "confirmActions": "F1KBNa_confirmActions",
12007
12276
  "splitHScroll": "F1KBNa_splitHScroll",
12008
- "note": "F1KBNa_note",
12009
- "settingsPage": "F1KBNa_settingsPage",
12277
+ "actionError": "F1KBNa_actionError",
12278
+ "toggleThumb": "F1KBNa_toggleThumb",
12279
+ "readError": "F1KBNa_readError",
12280
+ "statusAction": "F1KBNa_statusAction",
12281
+ "diffStats": "F1KBNa_diffStats",
12282
+ "settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
12283
+ "delCount": "F1KBNa_delCount",
12284
+ "detailEmpty": "F1KBNa_detailEmpty",
12285
+ "confirmCard": "F1KBNa_confirmCard",
12286
+ "group": "F1KBNa_group",
12287
+ "settingsRowText": "F1KBNa_settingsRowText",
12288
+ "markerDel": "F1KBNa_markerDel",
12289
+ "context": "F1KBNa_context",
12290
+ "expand": "F1KBNa_expand",
12291
+ "splitRoot": "F1KBNa_splitRoot",
12292
+ "rows": "F1KBNa_rows",
12293
+ "overviewRuler": "F1KBNa_overviewRuler",
12294
+ "listScroll": "F1KBNa_listScroll",
12295
+ "flexSpacer": "F1KBNa_flexSpacer",
12296
+ "states": "F1KBNa_states",
12010
12297
  "splitLdel": "F1KBNa_splitLdel",
12011
- "rail": "F1KBNa_rail",
12012
- "del": "F1KBNa_del",
12013
- "noteCentered": "F1KBNa_noteCentered",
12014
- "line": "F1KBNa_line",
12298
+ "langSelect": "F1KBNa_langSelect",
12299
+ "rowHead": "F1KBNa_rowHead",
12015
12300
  "action": "F1KBNa_action",
12301
+ "toggle": "F1KBNa_toggle",
12302
+ "code": "F1KBNa_code",
12303
+ "resizeHandle": "F1KBNa_resizeHandle",
12304
+ "intraAdd": "F1KBNa_intraAdd",
12305
+ "layer": "F1KBNa_layer",
12306
+ "settingsPage": "F1KBNa_settingsPage",
12016
12307
  "fileList": "F1KBNa_fileList",
12017
- "rowMeta": "F1KBNa_rowMeta",
12018
- "diffFlash": "F1KBNa_diffFlash",
12019
- "add": "F1KBNa_add",
12020
- "settingsSelector": "F1KBNa_settingsSelector",
12021
- "detailEmpty": "F1KBNa_detailEmpty",
12022
- "langSelect": "F1KBNa_langSelect",
12023
- "fileListFloat": "F1KBNa_fileListFloat",
12024
- "emptyState": "F1KBNa_emptyState",
12025
- "kindTag": "F1KBNa_kindTag",
12026
12308
  "rowFailed": "F1KBNa_rowFailed",
12027
- "addCount": "F1KBNa_addCount",
12309
+ "gutter": "F1KBNa_gutter",
12028
12310
  "wrapActive": "F1KBNa_wrapActive",
12029
- "close": "F1KBNa_close",
12030
- "diffHeader": "F1KBNa_diffHeader",
12031
- "badge": "F1KBNa_badge",
12311
+ "blockFlash": "F1KBNa_blockFlash",
12312
+ "splitHScrollFill": "F1KBNa_splitHScrollFill",
12313
+ "noticeText": "F1KBNa_noticeText",
12314
+ "emptyState": "F1KBNa_emptyState",
12032
12315
  "bulkActions": "F1KBNa_bulkActions",
12033
- "expand": "F1KBNa_expand",
12034
- "group": "F1KBNa_group",
12035
- "rowHead": "F1KBNa_rowHead",
12036
- "settingsSelectorChevron": "F1KBNa_settingsSelectorChevron",
12037
- "settingsRow": "F1KBNa_settingsRow",
12038
- "panel": "F1KBNa_panel",
12039
- "detail": "F1KBNa_detail",
12040
- "split": "F1KBNa_split",
12041
- "importNote": "F1KBNa_importNote",
12042
- "resizeHandle": "F1KBNa_resizeHandle",
12043
- "diff": "F1KBNa_diff",
12044
- "blockActions": "F1KBNa_blockActions",
12316
+ "diffHeader": "F1KBNa_diffHeader",
12317
+ "markerAdd": "F1KBNa_markerAdd",
12318
+ "intraDel": "F1KBNa_intraDel",
12319
+ "splitHScrollRow": "F1KBNa_splitHScrollRow",
12320
+ "header": "F1KBNa_header",
12321
+ "splitLadd": "F1KBNa_splitLadd",
12322
+ "notice": "F1KBNa_notice",
12045
12323
  "confirmText": "F1KBNa_confirmText",
12046
- "vSpacer": "F1KBNa_vSpacer",
12047
- "gutter": "F1KBNa_gutter",
12048
- "states": "F1KBNa_states",
12049
- "markerDel": "F1KBNa_markerDel",
12050
- "context": "F1KBNa_context",
12051
- "diffBodySplit": "F1KBNa_diffBodySplit",
12052
12324
  "diffBodyWrap": "F1KBNa_diffBodyWrap",
12053
- "subline": "F1KBNa_subline",
12054
- "splitHScrollFill": "F1KBNa_splitHScrollFill",
12055
- "settingsRowDesc": "F1KBNa_settingsRowDesc",
12056
- "headerActions": "F1KBNa_headerActions",
12057
- "badgeCount": "F1KBNa_badgeCount"
12325
+ "line": "F1KBNa_line",
12326
+ "noticeButton": "F1KBNa_noticeButton",
12327
+ "lines": "F1KBNa_lines",
12328
+ "confirmBackdrop": "F1KBNa_confirmBackdrop",
12329
+ "searchCount": "F1KBNa_searchCount",
12330
+ "stepperValue": "F1KBNa_stepperValue",
12331
+ "split": "F1KBNa_split",
12332
+ "splitCol": "F1KBNa_splitCol",
12333
+ "splitDivider": "F1KBNa_splitDivider",
12334
+ "badgeCount": "F1KBNa_badgeCount",
12335
+ "detail": "F1KBNa_detail",
12336
+ "searchBar": "F1KBNa_searchBar",
12337
+ "add": "F1KBNa_add",
12338
+ "splitRadd": "F1KBNa_splitRadd",
12339
+ "vSpacer": "F1KBNa_vSpacer",
12340
+ "stepper": "F1KBNa_stepper",
12341
+ "diff": "F1KBNa_diff",
12342
+ "expandExpanded": "F1KBNa_expandExpanded",
12343
+ "badge": "F1KBNa_badge",
12344
+ "row": "F1KBNa_row",
12345
+ "iconAction": "F1KBNa_iconAction",
12346
+ "actionQuietDisabled": "F1KBNa_actionQuietDisabled"
12058
12347
  };
12059
12348
  //#endregion
12060
12349
  //#region lib/types/client/PendingPanel.js
@@ -12090,6 +12379,51 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12090
12379
  const FLOAT_LIST_MARGIN_PX = 12;
12091
12380
  /** Fixed diff-row height in px; the virtual window and jump math are built on it. */
12092
12381
  const ROW_HEIGHT_PX = 22;
12382
+ /** Tolerance absorbed when comparing a block's offset to the navigation anchor,
12383
+ * so a sub-pixel float error (wrapped row heights, fractional scrollTop) never
12384
+ * mis-classifies the block the view is sitting on. Half a row height. */
12385
+ const NAV_ANCHOR_TOLERANCE_PX = ROW_HEIGHT_PX / 4;
12386
+ /** The diff view-mode toggle glyph: the whole file as one column of text lines
12387
+ * (unified) or two side-by-side columns of text lines (split). Hand-drawn
12388
+ * because the icon library has no single/double-column glyph. Rendered 1:1
12389
+ * (viewBox matches the size) with integer bar geometry, so every thin line
12390
+ * lands on whole pixels and stays crisp on any display scale. */
12391
+ function ViewModeIcon({ split, size = 14 }) {
12392
+ const lineY = [
12393
+ 1,
12394
+ 4,
12395
+ 7,
12396
+ 10,
12397
+ 13
12398
+ ];
12399
+ const lineH = 1;
12400
+ return (0, react_jsx_runtime.jsx)("svg", {
12401
+ width: size,
12402
+ height: size,
12403
+ viewBox: "0 0 14 14",
12404
+ fill: "none",
12405
+ xmlns: "http://www.w3.org/2000/svg",
12406
+ children: split ? (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [lineY.map((y) => (0, react_jsx_runtime.jsx)("rect", {
12407
+ x: "1",
12408
+ y,
12409
+ width: "5",
12410
+ height: lineH,
12411
+ fill: "currentColor"
12412
+ }, `l${y}`)), lineY.map((y) => (0, react_jsx_runtime.jsx)("rect", {
12413
+ x: "8",
12414
+ y,
12415
+ width: "5",
12416
+ height: lineH,
12417
+ fill: "currentColor"
12418
+ }, `r${y}`))] }) : lineY.map((y) => (0, react_jsx_runtime.jsx)("rect", {
12419
+ x: "1",
12420
+ y,
12421
+ width: "12",
12422
+ height: lineH,
12423
+ fill: "currentColor"
12424
+ }, `u${y}`))
12425
+ });
12426
+ }
12093
12427
  /** Total width of the two line-number gutters, subtracted from the code width
12094
12428
  * when measuring wrapped line heights. */
12095
12429
  const WRAP_GUTTERS_PX = 88;
@@ -12304,6 +12638,55 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12304
12638
  }
12305
12639
  return nodes.length === 0 ? "\xA0" : nodes;
12306
12640
  }
12641
+ /** Chip styling for each intra-line run: removed chars and added chars stand out. */
12642
+ const INTRA_CLASS = {
12643
+ same: void 0,
12644
+ del: PendingPanel_module_css_default.intraDel,
12645
+ add: PendingPanel_module_css_default.intraAdd
12646
+ };
12647
+ /** Clip intra-line runs to a character range, renumbering each cut run. */
12648
+ function clipIntra(intra, start, end) {
12649
+ const out = [];
12650
+ let pos = 0;
12651
+ for (const run of intra) {
12652
+ const runStart = pos;
12653
+ const runEnd = pos + run.text.length;
12654
+ pos = runEnd;
12655
+ if (runEnd <= start || runStart >= end) continue;
12656
+ const text = run.text.slice(Math.max(runStart, start) - runStart, Math.min(runEnd, end) - runStart);
12657
+ if (text.length === 0) continue;
12658
+ out.push({
12659
+ text,
12660
+ kind: run.kind
12661
+ });
12662
+ }
12663
+ return out;
12664
+ }
12665
+ /**
12666
+ * Render a character range as intra-line runs, with the syntax color clipped
12667
+ * back onto each run. Context (`same`) runs show no draw; removed/added runs
12668
+ * carry the chip draw. `intra` must cover `[start, end)` — it is clipped and
12669
+ * reassembled per run, so the returned nodes concatenate to that range.
12670
+ * @param runs - the syntax highlight for the whole line, or undefined.
12671
+ * @param intra - the intra-line runs for the whole line.
12672
+ * @param start - the range start (character offset in the line).
12673
+ * @param end - the range end (exclusive).
12674
+ * @returns the merged spans for the range.
12675
+ */
12676
+ function renderIntra(runs, intra, start, end) {
12677
+ const clipped = clipIntra(intra, start, end);
12678
+ let cursor = start;
12679
+ return clipped.map((run, i) => {
12680
+ const runStart = cursor;
12681
+ const runEnd = runStart + run.text.length;
12682
+ cursor = runEnd;
12683
+ const syntax = runs !== void 0 && runs.length > 0 ? clipRuns(runs, runStart, runEnd) : run.text;
12684
+ return (0, react_jsx_runtime.jsx)("span", {
12685
+ className: INTRA_CLASS[run.kind],
12686
+ children: syntax
12687
+ }, i);
12688
+ });
12689
+ }
12307
12690
  /**
12308
12691
  * One rendered diff row, memoized so a poll or an unrelated state change
12309
12692
  * does not re-render rows whose content, highlight, and focus are unchanged.
@@ -12424,10 +12807,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12424
12807
  return blocks;
12425
12808
  }
12426
12809
  /** One side's line-content for the split view: the highlighted runs or plain text. */
12427
- function splitSideContent(side, wrapped, runs) {
12810
+ function splitSideContent(side, wrapped, runs, intra) {
12428
12811
  if (side === void 0) return "";
12429
12812
  const highlighted = runs !== void 0 && runs.length > 0;
12430
- if (wrapped === void 0) return highlighted ? runs.map((span, i) => (0, react_jsx_runtime.jsx)("span", {
12813
+ const hasIntra = intra !== void 0 && intra.length > 0;
12814
+ if (wrapped === void 0) return hasIntra ? renderIntra(runs, intra, 0, side.text.length) : highlighted ? runs.map((span, i) => (0, react_jsx_runtime.jsx)("span", {
12431
12815
  style: span.style,
12432
12816
  children: span.text
12433
12817
  }, i)) : side.text === "" ? "\xA0" : side.text;
@@ -12435,7 +12819,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12435
12819
  return wrapped.map((line, i) => {
12436
12820
  const start = offset;
12437
12821
  offset += line.length;
12438
- const content = highlighted ? clipRuns(runs, start, offset) : line === "" ? "\xA0" : line;
12822
+ const content = hasIntra ? renderIntra(runs, intra, start, offset) : highlighted ? clipRuns(runs, start, offset) : line === "" ? "\xA0" : line;
12439
12823
  return (0, react_jsx_runtime.jsx)("div", {
12440
12824
  className: PendingPanel_module_css_default.subline,
12441
12825
  children: content
@@ -12451,7 +12835,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12451
12835
  * one side is longer. The gutter and code are top-aligned so sub-lines line up
12452
12836
  * across the divider.
12453
12837
  */
12454
- function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, onHover }) {
12838
+ function SplitSideRow({ index, side, wrapped, runs, kind, isLeft, height, focused, searchHit, searchCurrent, onHover, intra }) {
12455
12839
  const tint = isLeft ? kind === "del" || kind === "replace" ? PendingPanel_module_css_default.splitLdel : "" : kind === "add" || kind === "replace" ? PendingPanel_module_css_default.splitRadd : "";
12456
12840
  return (0, react_jsx_runtime.jsxs)("div", {
12457
12841
  className: PendingPanel_module_css_default.line,
@@ -12468,14 +12852,26 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12468
12852
  }), (0, react_jsx_runtime.jsx)("span", {
12469
12853
  className: `${PendingPanel_module_css_default.code} ${tint}`,
12470
12854
  "data-diff-code": true,
12471
- children: splitSideContent(side, wrapped, runs)
12855
+ children: splitSideContent(side, wrapped, runs, intra)
12472
12856
  })]
12473
12857
  });
12474
12858
  }
12475
12859
  /** The two-column (side-by-side) whole-file diff view. */
12476
- const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, onBlockKeep, onBlockRevert }, ref) {
12477
- const { pairs, pairOfRow } = (0, react.useMemo)(() => computeSideBySideDiff(model.diff.rows), [model]);
12860
+ const SplitDiff = (0, react.forwardRef)(function SplitDiff({ file, model, runs, langWrap, tabWidthSpaces, busy, t, selection, leadRows, onBlockKeep, onBlockRevert }, ref) {
12861
+ const { pairs, pairOfRow } = (0, react.useMemo)(() => computeSideBySideDiff(model.diff.rows, true), [model]);
12478
12862
  const pairCount = pairs.length;
12863
+ const pairRowIndices = (0, react.useMemo)(() => {
12864
+ const map = /* @__PURE__ */ new Map();
12865
+ model.diff.rows.forEach((row, rowIndex) => {
12866
+ const pairIndex = pairOfRow.get(rowIndex);
12867
+ if (pairIndex === void 0) return;
12868
+ const entry = map.get(pairIndex) ?? {};
12869
+ if (row.kind !== "add") entry.left = rowIndex;
12870
+ if (row.kind !== "del") entry.right = rowIndex;
12871
+ map.set(pairIndex, entry);
12872
+ });
12873
+ return map;
12874
+ }, [model, pairOfRow]);
12479
12875
  const bodyRef = (0, react.useRef)(null);
12480
12876
  const [scrollTop, setScrollTop] = (0, react.useState)(0);
12481
12877
  const [viewportH, setViewportH] = (0, react.useState)(0);
@@ -12519,17 +12915,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12519
12915
  observer?.disconnect();
12520
12916
  };
12521
12917
  }, [file.id]);
12522
- const blockOfPair = (0, react.useMemo)(() => model.blocks.map((block) => ({
12523
- start: pairOfRow.get(block.start) ?? 0,
12524
- end: pairOfRow.get(block.end) ?? 0
12525
- })), [model, pairOfRow]);
12918
+ const blockOfPair = (0, react.useMemo)(() => model.blocks.map((block) => {
12919
+ let start = Number.POSITIVE_INFINITY;
12920
+ let end = Number.NEGATIVE_INFINITY;
12921
+ for (let row = block.start; row <= block.end; row++) {
12922
+ const pair = pairOfRow.get(row);
12923
+ if (pair === void 0) continue;
12924
+ if (pair < start) start = pair;
12925
+ if (pair > end) end = pair;
12926
+ }
12927
+ return {
12928
+ start: Number.isFinite(start) ? start : 0,
12929
+ end: Number.isFinite(end) ? end : 0
12930
+ };
12931
+ }), [model, pairOfRow]);
12526
12932
  const blockIndexByPair = (0, react.useMemo)(() => {
12527
12933
  const map = /* @__PURE__ */ new Map();
12528
- blockOfPair.forEach((block, bi) => {
12529
- for (let k = block.start; k <= block.end; k++) map.set(k, bi);
12934
+ model.blocks.forEach((block, bi) => {
12935
+ for (let row = block.start; row <= block.end; row++) {
12936
+ const pair = pairOfRow.get(row);
12937
+ if (pair !== void 0) map.set(pair, bi);
12938
+ }
12530
12939
  });
12531
12940
  return map;
12532
- }, [blockOfPair]);
12941
+ }, [model, pairOfRow]);
12533
12942
  const onPairHover = (0, react.useCallback)((k) => {
12534
12943
  const bi = blockIndexByPair.get(k);
12535
12944
  setHoveredBlock(bi);
@@ -12688,13 +13097,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12688
13097
  if (block === void 0) return;
12689
13098
  const body = bodyRef.current;
12690
13099
  if (body === null) return;
12691
- const target = off(block.start) - 44;
13100
+ const target = off(block.start) - leadRows * ROW_HEIGHT_PX;
12692
13101
  const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
12693
13102
  if (body.scrollTop !== clamped) body.scrollTop = clamped;
12694
13103
  setScrollTop(clamped);
12695
- }, [focus, flashKey]);
13104
+ }, [flashKey]);
12696
13105
  const onScroll = () => {
12697
- setScrollTop(bodyRef.current?.scrollTop ?? 0);
13106
+ const body = bodyRef.current;
13107
+ if (body === null) return;
13108
+ setScrollTop(body.scrollTop);
13109
+ const count = blockOfPair.length;
13110
+ if (count === 0) return;
13111
+ const anchor = body.scrollTop + leadRows * ROW_HEIGHT_PX;
13112
+ let ref = -1;
13113
+ for (let index = 0; index < count; index++) if (off(blockOfPair[index].start) <= anchor + NAV_ANCHOR_TOLERANCE_PX) ref = index;
13114
+ setFocus(ref === -1 ? 0 : ref);
12698
13115
  };
12699
13116
  const inFocused = (k) => {
12700
13117
  const block = blockOfPair[focus];
@@ -12736,6 +13153,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12736
13153
  visiblePairs.map((pair, offset) => {
12737
13154
  const index = start + offset;
12738
13155
  const leftRuns = pair.left === void 0 ? void 0 : runs?.oldRuns?.[(pair.left.line ?? 0) - 1];
13156
+ const sideIndex = pairRowIndices.get(index);
12739
13157
  return (0, react_jsx_runtime.jsx)(SplitSideRow, {
12740
13158
  index,
12741
13159
  side: pair.left,
@@ -12747,7 +13165,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12747
13165
  focused: inFocused(index),
12748
13166
  searchHit: searchHitSet.has(index),
12749
13167
  searchCurrent: index === currentSearchPair,
12750
- onHover: () => onPairHover(index)
13168
+ onHover: () => onPairHover(index),
13169
+ intra: sideIndex?.left === void 0 ? void 0 : model.intra.get(sideIndex.left)
12751
13170
  }, index);
12752
13171
  }),
12753
13172
  end < pairCount && (0, react_jsx_runtime.jsx)("div", {
@@ -12775,6 +13194,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12775
13194
  visiblePairs.map((pair, offset) => {
12776
13195
  const index = start + offset;
12777
13196
  const rightRuns = pair.right === void 0 ? void 0 : runs?.newRuns?.[(pair.right.line ?? 0) - 1];
13197
+ const sideIndex = pairRowIndices.get(index);
12778
13198
  return (0, react_jsx_runtime.jsx)(SplitSideRow, {
12779
13199
  index,
12780
13200
  side: pair.right,
@@ -12786,7 +13206,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
12786
13206
  focused: inFocused(index),
12787
13207
  searchHit: searchHitSet.has(index),
12788
13208
  searchCurrent: index === currentSearchPair,
12789
- onHover: () => onPairHover(index)
13209
+ onHover: () => onPairHover(index),
13210
+ intra: sideIndex?.right === void 0 ? void 0 : model.intra.get(sideIndex.right)
12790
13211
  }, index);
12791
13212
  }),
12792
13213
  end < pairCount && (0, react_jsx_runtime.jsx)("div", {
@@ -13043,6 +13464,39 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13043
13464
  return codeCellAt(node)?.textContent?.length ?? 0;
13044
13465
  }
13045
13466
  /**
13467
+ * Reconstruct the plain text of the current selection so auto-wrap's visual
13468
+ * line breaks never leak into the clipboard. A wrapped row renders its code as
13469
+ * several `.subline` block elements, and the browser's default copy inserts a
13470
+ * newline between them; those segments form one logical line, so they are joined
13471
+ * without a newline while the real newline between diff rows is kept.
13472
+ */
13473
+ function selectedPlainText() {
13474
+ const selection = window.getSelection();
13475
+ if (selection === null || selection.rangeCount === 0 || selection.isCollapsed) return void 0;
13476
+ const range = selection.getRangeAt(0);
13477
+ const container = document.createElement("div");
13478
+ container.appendChild(range.cloneContents());
13479
+ const parts = [];
13480
+ let atLineStart = true;
13481
+ const push = (text) => {
13482
+ if (text.length === 0) return;
13483
+ parts.push(text);
13484
+ atLineStart = text.endsWith("\n");
13485
+ };
13486
+ const walk = (node) => {
13487
+ if (node.nodeType === Node.TEXT_NODE) {
13488
+ push(node.textContent ?? "");
13489
+ return;
13490
+ }
13491
+ if (!(node instanceof Element)) return;
13492
+ const el = node;
13493
+ if ((el.dataset.diffRow !== void 0 || el.dataset.diffSplitRow !== void 0 || el.dataset.diffSplitIndex !== void 0) && !atLineStart) push("\n");
13494
+ for (const child of node.childNodes) walk(child);
13495
+ };
13496
+ walk(container);
13497
+ return parts.join("");
13498
+ }
13499
+ /**
13046
13500
  * Derive the selected diff-row range from a native text selection. A
13047
13501
  * boundary sitting exactly at a line edge contributes no content: a start at
13048
13502
  * the line's end skips to the next line, an end at the line's start falls
@@ -13137,16 +13591,28 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13137
13591
  setWrapEnabled(wrapKey, next);
13138
13592
  };
13139
13593
  const [tabWidthSpaces] = (0, react.useState)(() => tabWidth());
13140
- const splitView = splitMode();
13594
+ const [splitView, setSplitView] = (0, react.useState)(() => splitMode());
13595
+ const leadRows = navLeadRows();
13596
+ const toggleSplitView = () => {
13597
+ const next = !splitView;
13598
+ setSplitView(next);
13599
+ setSplitMode(next);
13600
+ };
13141
13601
  const splitDiffRef = (0, react.useRef)(null);
13142
13602
  const model = (0, react.useMemo)(() => {
13143
13603
  const diff = computeWholeFileDiff(file.oldText, file.newText);
13604
+ const intra = splitView ? computeIntraLineDiff(diff.rows, true) : /* @__PURE__ */ new Map();
13144
13605
  return {
13145
13606
  diff,
13146
- blocks: changeBlocksOf(diff)
13607
+ blocks: changeBlocksOf(diff),
13608
+ intra
13147
13609
  };
13148
- }, [file.oldText, file.newText]);
13149
- const splitPairs = (0, react.useMemo)(() => splitView ? computeSideBySideDiff(model.diff.rows).pairs : null, [splitView, model]);
13610
+ }, [
13611
+ file.oldText,
13612
+ file.newText,
13613
+ splitView
13614
+ ]);
13615
+ const splitPairs = (0, react.useMemo)(() => splitView ? computeSideBySideDiff(model.diff.rows, true).pairs : null, [splitView, model]);
13150
13616
  const rulerMarkers = (0, react.useMemo)(() => {
13151
13617
  const rows = model.diff.rows;
13152
13618
  const total = rows.length;
@@ -13372,14 +13838,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13372
13838
  }
13373
13839
  const visibleRows = rows.slice(start, end);
13374
13840
  const blockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
13375
- const blockActionsTop = blockEnd === void 0 ? 0 : Math.min(offsetOf(blockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
13841
+ const blockActionsTop = blockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(blockEnd + 1) - scrollTop, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
13376
13842
  const selectionBlockEnd = (() => {
13377
13843
  if (coveredBlockIndices.length === 0) return void 0;
13378
13844
  const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
13379
13845
  if (lastIndex === void 0) return void 0;
13380
13846
  return model.blocks[lastIndex]?.end;
13381
13847
  })();
13382
- const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.min(offsetOf(selectionBlockEnd + 1), Math.max(0, totalHeight - BLOCK_ACTIONS_FRAME_PX));
13848
+ const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(selectionBlockEnd + 1) - scrollTop, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
13383
13849
  const widestLine = (0, react.useMemo)(() => {
13384
13850
  let widest = 0;
13385
13851
  for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
@@ -13418,15 +13884,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13418
13884
  if (block === void 0) return;
13419
13885
  const body = bodyRef.current;
13420
13886
  if (body === null) return;
13421
- const target = offsetOf(block.start) - 44;
13887
+ const target = offsetOf(block.start) - leadRows * ROW_HEIGHT_PX;
13422
13888
  const clamped = Math.max(0, Math.min(target, body.scrollHeight - body.clientHeight));
13423
13889
  if (body.scrollTop !== clamped) body.scrollTop = clamped;
13424
13890
  setScrollTop(clamped);
13425
- }, [
13426
- focus,
13427
- scrollTick,
13428
- rowOffsets === null
13429
- ]);
13891
+ }, [scrollTick, rowOffsets === null]);
13430
13892
  const jump = (direction) => {
13431
13893
  if (rowCount === 0) return;
13432
13894
  setFocus((current) => {
@@ -13491,6 +13953,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13491
13953
  if (body === null) return;
13492
13954
  setScrollTop(body.scrollTop);
13493
13955
  setViewportHeight(body.clientHeight);
13956
+ const count = model.blocks.length;
13957
+ if (rowCount === 0 || count === 0) return;
13958
+ const anchor = body.scrollTop + leadRows * ROW_HEIGHT_PX;
13959
+ let ref = -1;
13960
+ for (let index = 0; index < count; index++) {
13961
+ const block = model.blocks[index];
13962
+ if (block !== void 0 && offsetOf(block.start) <= anchor + NAV_ANCHOR_TOLERANCE_PX) ref = index;
13963
+ }
13964
+ setFocus(ref === -1 ? 0 : ref);
13494
13965
  };
13495
13966
  (0, react.useEffect)(() => {
13496
13967
  const update = () => setSelection(splitView ? splitRowRangeOf(window.getSelection()) : rowRangeOf(window.getSelection()));
@@ -13500,6 +13971,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13500
13971
  document.removeEventListener("selectionchange", update);
13501
13972
  };
13502
13973
  }, [file.id, splitView]);
13974
+ (0, react.useEffect)(() => {
13975
+ const onCopy = (event) => {
13976
+ const anchor = window.getSelection()?.anchorNode;
13977
+ if (!((anchor instanceof Element ? anchor : anchor?.parentElement)?.closest("[data-diff-code]") !== null)) return;
13978
+ const text = selectedPlainText();
13979
+ if (text === void 0) return;
13980
+ event.preventDefault();
13981
+ event.clipboardData?.setData("text/plain", text);
13982
+ };
13983
+ document.addEventListener("copy", onCopy);
13984
+ return () => {
13985
+ document.removeEventListener("copy", onCopy);
13986
+ };
13987
+ }, []);
13503
13988
  const selectionReference = (() => {
13504
13989
  if (selection === void 0) return void 0;
13505
13990
  if (splitView) {
@@ -13662,10 +14147,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13662
14147
  removed: model.diff.removed
13663
14148
  })
13664
14149
  }),
13665
- file.kind === "create" && (0, react_jsx_runtime.jsx)("span", {
13666
- className: PendingPanel_module_css_default.kindHint,
13667
- children: t("panel.createHint")
13668
- }),
13669
14150
  model.blocks.length > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
13670
14151
  label: `${t("action.prevDiff")} (Ctrl+↑)`,
13671
14152
  side: "bottom",
@@ -13710,6 +14191,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13710
14191
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutline16, { size: 14 })
13711
14192
  })
13712
14193
  }),
14194
+ (0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.divider }),
14195
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
14196
+ label: t(splitView ? "action.viewUnified" : "action.viewSplit"),
14197
+ side: "bottom",
14198
+ delayMs: 500,
14199
+ children: (0, react_jsx_runtime.jsx)("button", {
14200
+ type: "button",
14201
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
14202
+ "data-diff-toggle-view": true,
14203
+ "aria-label": t(splitView ? "action.viewUnified" : "action.viewSplit"),
14204
+ onClick: toggleSplitView,
14205
+ children: (0, react_jsx_runtime.jsx)(ViewModeIcon, { split: splitView })
14206
+ })
14207
+ }),
13713
14208
  (0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
13714
14209
  (0, react_jsx_runtime.jsx)("button", {
13715
14210
  type: "button",
@@ -13729,7 +14224,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13729
14224
  onClick: () => {
13730
14225
  onRevert(file.sessionId, file.id);
13731
14226
  },
13732
- children: t("action.revert")
14227
+ children: file.kind === "create" ? t("action.delete") : t("action.revert")
13733
14228
  })
13734
14229
  ]
13735
14230
  }),
@@ -13752,22 +14247,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13752
14247
  busy,
13753
14248
  t,
13754
14249
  selection,
14250
+ leadRows,
13755
14251
  onBlockKeep,
13756
14252
  onBlockRevert
13757
14253
  }) : (0, react_jsx_runtime.jsxs)("div", {
13758
14254
  className: PendingPanel_module_css_default.diffBodyWrap,
14255
+ onMouseLeave: () => {
14256
+ setHoveredBlock(void 0);
14257
+ },
13759
14258
  children: [
13760
- (0, react_jsx_runtime.jsxs)("div", {
14259
+ (0, react_jsx_runtime.jsx)("div", {
13761
14260
  className: PendingPanel_module_css_default.diffBody,
13762
14261
  ref: bodyRef,
13763
14262
  tabIndex: 0,
13764
14263
  onScroll,
13765
- onMouseLeave: () => {
13766
- setHoveredBlock(void 0);
13767
- },
13768
14264
  style: { tabSize: tabWidthSpaces },
13769
14265
  "data-diff-body": true,
13770
- children: [(0, react_jsx_runtime.jsxs)("div", {
14266
+ children: (0, react_jsx_runtime.jsxs)("div", {
13771
14267
  className: `${PendingPanel_module_css_default.lines}${langWrap ? " " + PendingPanel_module_css_default.wrap : ""}`,
13772
14268
  style: langWrap ? {
13773
14269
  width: "100%",
@@ -13798,87 +14294,88 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
13798
14294
  "aria-hidden": "true"
13799
14295
  })
13800
14296
  ]
13801
- }), selectionRange !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
13802
- className: PendingPanel_module_css_default.blockActions,
13803
- "data-diff-selection-actions": true,
13804
- style: { top: selectionActionsTop },
13805
- children: [(0, react_jsx_runtime.jsx)("button", {
14297
+ })
14298
+ }),
14299
+ selectionRange !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
14300
+ className: PendingPanel_module_css_default.blockActions,
14301
+ "data-diff-selection-actions": true,
14302
+ style: { top: selectionActionsTop },
14303
+ children: [(0, react_jsx_runtime.jsx)("button", {
14304
+ type: "button",
14305
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
14306
+ "data-diff-selection-keep": true,
14307
+ disabled: busy,
14308
+ onClick: () => {
14309
+ handleSelectionAction("keep");
14310
+ },
14311
+ children: t("action.keep")
14312
+ }), (0, react_jsx_runtime.jsx)("button", {
14313
+ type: "button",
14314
+ className: PendingPanel_module_css_default.action,
14315
+ "data-diff-selection-revert": true,
14316
+ disabled: busy,
14317
+ onClick: () => {
14318
+ handleSelectionAction("revert");
14319
+ },
14320
+ children: t("action.revert")
14321
+ })]
14322
+ }) : hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
14323
+ className: PendingPanel_module_css_default.blockActions,
14324
+ "data-diff-block-actions": true,
14325
+ style: { top: blockActionsTop },
14326
+ children: [
14327
+ (0, react_jsx_runtime.jsx)("span", {
14328
+ className: PendingPanel_module_css_default.blockPosition,
14329
+ "data-diff-block-position": true,
14330
+ children: t("panel.blockPosition", {
14331
+ current: hoveredBlock + 1,
14332
+ total: model.blocks.length
14333
+ })
14334
+ }),
14335
+ (0, react_jsx_runtime.jsx)("button", {
14336
+ type: "button",
14337
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
14338
+ "data-diff-block-prev": true,
14339
+ "aria-label": t("action.prevDiff"),
14340
+ disabled: busy,
14341
+ onClick: () => {
14342
+ stepBlock(-1);
14343
+ },
14344
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
14345
+ }),
14346
+ (0, react_jsx_runtime.jsx)("button", {
14347
+ type: "button",
14348
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
14349
+ "data-diff-block-next": true,
14350
+ "aria-label": t("action.nextDiff"),
14351
+ disabled: busy,
14352
+ onClick: () => {
14353
+ stepBlock(1);
14354
+ },
14355
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
14356
+ }),
14357
+ (0, react_jsx_runtime.jsx)("button", {
13806
14358
  type: "button",
13807
14359
  className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
13808
- "data-diff-selection-keep": true,
14360
+ "data-diff-block-keep": true,
13809
14361
  disabled: busy,
13810
14362
  onClick: () => {
13811
- handleSelectionAction("keep");
14363
+ handleBlockAction("keep");
13812
14364
  },
13813
14365
  children: t("action.keep")
13814
- }), (0, react_jsx_runtime.jsx)("button", {
14366
+ }),
14367
+ (0, react_jsx_runtime.jsx)("button", {
13815
14368
  type: "button",
13816
14369
  className: PendingPanel_module_css_default.action,
13817
- "data-diff-selection-revert": true,
14370
+ "data-diff-block-revert": true,
13818
14371
  disabled: busy,
13819
14372
  onClick: () => {
13820
- handleSelectionAction("revert");
14373
+ handleBlockAction("revert");
13821
14374
  },
13822
14375
  children: t("action.revert")
13823
- })]
13824
- }) : hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
13825
- className: PendingPanel_module_css_default.blockActions,
13826
- "data-diff-block-actions": true,
13827
- style: { top: blockActionsTop },
13828
- children: [
13829
- (0, react_jsx_runtime.jsx)("span", {
13830
- className: PendingPanel_module_css_default.blockPosition,
13831
- "data-diff-block-position": true,
13832
- children: t("panel.blockPosition", {
13833
- current: hoveredBlock + 1,
13834
- total: model.blocks.length
13835
- })
13836
- }),
13837
- (0, react_jsx_runtime.jsx)("button", {
13838
- type: "button",
13839
- className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
13840
- "data-diff-block-prev": true,
13841
- "aria-label": t("action.prevDiff"),
13842
- disabled: busy,
13843
- onClick: () => {
13844
- stepBlock(-1);
13845
- },
13846
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
13847
- }),
13848
- (0, react_jsx_runtime.jsx)("button", {
13849
- type: "button",
13850
- className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
13851
- "data-diff-block-next": true,
13852
- "aria-label": t("action.nextDiff"),
13853
- disabled: busy,
13854
- onClick: () => {
13855
- stepBlock(1);
13856
- },
13857
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
13858
- }),
13859
- (0, react_jsx_runtime.jsx)("button", {
13860
- type: "button",
13861
- className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
13862
- "data-diff-block-keep": true,
13863
- disabled: busy,
13864
- onClick: () => {
13865
- handleBlockAction("keep");
13866
- },
13867
- children: t("action.keep")
13868
- }),
13869
- (0, react_jsx_runtime.jsx)("button", {
13870
- type: "button",
13871
- className: PendingPanel_module_css_default.action,
13872
- "data-diff-block-revert": true,
13873
- disabled: busy,
13874
- onClick: () => {
13875
- handleBlockAction("revert");
13876
- },
13877
- children: t("action.revert")
13878
- })
13879
- ]
13880
- }) : null]
13881
- }),
14376
+ })
14377
+ ]
14378
+ }) : null,
13882
14379
  focusedBlock !== void 0 && flashKey > 0 && (0, react_jsx_runtime.jsx)("div", {
13883
14380
  className: PendingPanel_module_css_default.blockFlash,
13884
14381
  "data-diff-block-flash": true,
@@ -14699,42 +15196,26 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14699
15196
  //#endregion
14700
15197
  //#region lib/types/client/SettingsTab.js
14701
15198
  /** DSH Settings top-level section for this plugin's preferences. */
14702
- /** A pill picker offering the two boolean states 打开 / 关闭. */
14703
- function OnOffPicker({ value, open, onOpenChange, onSelect, dataAttribute, t }) {
14704
- return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
14705
- open,
14706
- onClose: () => {
14707
- onOpenChange(false);
14708
- },
14709
- items: [{
14710
- id: "on",
14711
- label: t("action.toggleOn")
14712
- }, {
14713
- id: "off",
14714
- label: t("action.toggleOff")
14715
- }],
14716
- selectedId: value ? "on" : "off",
14717
- onSelect: (id) => {
14718
- onOpenChange(false);
14719
- onSelect(id === "on");
15199
+ /** A toggle switch offering the two boolean states 打开 / 关闭. */
15200
+ function OnOffToggle({ value, onSelect, dataAttribute, t }) {
15201
+ return (0, react_jsx_runtime.jsx)("button", {
15202
+ type: "button",
15203
+ role: "switch",
15204
+ "aria-checked": value,
15205
+ "aria-label": value ? t("action.toggleOn") : t("action.toggleOff"),
15206
+ className: `${PendingPanel_module_css_default.toggle}${value ? " " + PendingPanel_module_css_default.toggleOn : ""}`,
15207
+ [dataAttribute]: true,
15208
+ onClick: () => {
15209
+ onSelect(!value);
14720
15210
  },
14721
- align: "end",
14722
- portal: true,
14723
- anchor: (0, react_jsx_runtime.jsxs)("button", {
14724
- type: "button",
14725
- className: PendingPanel_module_css_default.settingsSelector,
14726
- "aria-haspopup": "menu",
14727
- "aria-expanded": open,
14728
- onClick: () => {
14729
- onOpenChange(!open);
14730
- },
14731
- [dataAttribute]: true,
14732
- children: [value ? t("action.toggleOn") : t("action.toggleOff"), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { className: PendingPanel_module_css_default.settingsSelectorChevron })]
15211
+ children: (0, react_jsx_runtime.jsx)("span", {
15212
+ className: PendingPanel_module_css_default.toggleThumb,
15213
+ "aria-hidden": "true"
14733
15214
  })
14734
15215
  });
14735
15216
  }
14736
- /** One Agent-preset-style preference row: title + description, pill picker right. */
14737
- function PreferenceRow({ title, description, value, open, onOpenChange, onSelect, dataAttribute, t }) {
15217
+ /** One Agent-preset-style preference row: title + description, toggle right. */
15218
+ function PreferenceRow({ title, description, value, onSelect, dataAttribute, t }) {
14738
15219
  return (0, react_jsx_runtime.jsxs)("div", {
14739
15220
  className: PendingPanel_module_css_default.settingsRow,
14740
15221
  children: [(0, react_jsx_runtime.jsxs)("div", {
@@ -14746,10 +15227,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14746
15227
  className: PendingPanel_module_css_default.settingsRowDesc,
14747
15228
  children: description
14748
15229
  })]
14749
- }), (0, react_jsx_runtime.jsx)(OnOffPicker, {
15230
+ }), (0, react_jsx_runtime.jsx)(OnOffToggle, {
14750
15231
  value,
14751
- open,
14752
- onOpenChange,
14753
15232
  onSelect,
14754
15233
  dataAttribute,
14755
15234
  t
@@ -14814,6 +15293,53 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14814
15293
  })]
14815
15294
  });
14816
15295
  }
15296
+ /** A +/- number stepper for an integer preference, clamped to [min, max]. */
15297
+ function StepperRow({ title, description, value, onChange, min, max, dataAttribute, t }) {
15298
+ return (0, react_jsx_runtime.jsxs)("div", {
15299
+ className: PendingPanel_module_css_default.settingsRow,
15300
+ children: [(0, react_jsx_runtime.jsxs)("div", {
15301
+ className: PendingPanel_module_css_default.settingsRowText,
15302
+ children: [(0, react_jsx_runtime.jsx)("div", {
15303
+ className: PendingPanel_module_css_default.settingsRowTitle,
15304
+ children: title
15305
+ }), (0, react_jsx_runtime.jsx)("div", {
15306
+ className: PendingPanel_module_css_default.settingsRowDesc,
15307
+ children: description
15308
+ })]
15309
+ }), (0, react_jsx_runtime.jsxs)("div", {
15310
+ className: PendingPanel_module_css_default.stepper,
15311
+ children: [
15312
+ (0, react_jsx_runtime.jsx)("button", {
15313
+ type: "button",
15314
+ className: PendingPanel_module_css_default.stepperButton,
15315
+ "data-diff-stepper-down": true,
15316
+ "aria-label": t("action.decrease"),
15317
+ disabled: value <= min,
15318
+ onClick: () => {
15319
+ onChange(Math.max(min, value - 1));
15320
+ },
15321
+ children: "−"
15322
+ }),
15323
+ (0, react_jsx_runtime.jsx)("span", {
15324
+ className: PendingPanel_module_css_default.stepperValue,
15325
+ [dataAttribute]: true,
15326
+ children: value
15327
+ }),
15328
+ (0, react_jsx_runtime.jsx)("button", {
15329
+ type: "button",
15330
+ className: PendingPanel_module_css_default.stepperButton,
15331
+ "data-diff-stepper-up": true,
15332
+ "aria-label": t("action.increase"),
15333
+ disabled: value >= max,
15334
+ onClick: () => {
15335
+ onChange(Math.min(max, value + 1));
15336
+ },
15337
+ children: "+"
15338
+ })
15339
+ ]
15340
+ })]
15341
+ });
15342
+ }
14817
15343
  /** Build the `Modifier+...+Key` chord label from a keydown event; a bare
14818
15344
  * modifier key alone returns undefined (wait for the full combo). */
14819
15345
  function chordLabel(event) {
@@ -14886,13 +15412,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14886
15412
  */
14887
15413
  function DiffApprovalSettingsTab({ t }) {
14888
15414
  const [pasteOnCopy, setPasteOnCopyState] = (0, react.useState)(pasteOnCopyEnabled);
14889
- const [pasteOnCopyOpen, setPasteOnCopyOpen] = (0, react.useState)(false);
14890
15415
  const [includeUntracked, setIncludeUntrackedState] = (0, react.useState)(includeUntrackedEnabled);
14891
- const [includeUntrackedOpen, setIncludeUntrackedOpen] = (0, react.useState)(false);
14892
15416
  const [tab, setTabState] = (0, react.useState)(tabWidth);
14893
15417
  const [tabOpen, setTabOpen] = (0, react.useState)(false);
14894
15418
  const [split, setSplitState] = (0, react.useState)(splitMode);
14895
- const [splitOpen, setSplitOpen] = (0, react.useState)(false);
15419
+ const [lead, setLeadState] = (0, react.useState)(navLeadRows);
14896
15420
  const [summon, setSummonState] = (0, react.useState)(quickSummonKey);
14897
15421
  const setSummon = (value) => {
14898
15422
  setSummonState(value);
@@ -14914,6 +15438,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14914
15438
  setSplitState(value);
14915
15439
  setSplitMode(value);
14916
15440
  };
15441
+ const setLead = (value) => {
15442
+ setLeadState(value);
15443
+ setNavLeadRows(value);
15444
+ };
14917
15445
  return (0, react_jsx_runtime.jsxs)("div", {
14918
15446
  className: PendingPanel_module_css_default.settingsPage,
14919
15447
  "data-diff-settings": true,
@@ -14922,8 +15450,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14922
15450
  title: t("panel.pasteOnCopy"),
14923
15451
  description: t("panel.pasteOnCopyDesc"),
14924
15452
  value: pasteOnCopy,
14925
- open: pasteOnCopyOpen,
14926
- onOpenChange: setPasteOnCopyOpen,
14927
15453
  onSelect: setPasteOnCopy,
14928
15454
  dataAttribute: "data-diff-paste-on-copy-select",
14929
15455
  t
@@ -14932,8 +15458,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14932
15458
  title: t("panel.importUntracked"),
14933
15459
  description: t("panel.importUntrackedDesc"),
14934
15460
  value: includeUntracked,
14935
- open: includeUntrackedOpen,
14936
- onOpenChange: setIncludeUntrackedOpen,
14937
15461
  onSelect: setIncludeUntracked,
14938
15462
  dataAttribute: "data-diff-import-untracked-select",
14939
15463
  t
@@ -14951,12 +15475,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
14951
15475
  title: t("panel.splitMode"),
14952
15476
  description: t("panel.splitModeDesc"),
14953
15477
  value: split,
14954
- open: splitOpen,
14955
- onOpenChange: setSplitOpen,
14956
15478
  onSelect: setSplit,
14957
15479
  dataAttribute: "data-diff-split-mode-select",
14958
15480
  t
14959
15481
  }),
15482
+ (0, react_jsx_runtime.jsx)(StepperRow, {
15483
+ title: t("panel.navLeadRows"),
15484
+ description: t("panel.navLeadRowsDesc"),
15485
+ value: lead,
15486
+ onChange: setLead,
15487
+ min: 0,
15488
+ max: 10,
15489
+ dataAttribute: "data-diff-nav-lead-rows",
15490
+ t
15491
+ }),
14960
15492
  (0, react_jsx_runtime.jsx)(ShortcutRow, {
14961
15493
  title: t("panel.quickSummon"),
14962
15494
  description: t("panel.quickSummonDesc"),
@@ -15506,7 +16038,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15506
16038
  "panel.missingHint": "该文件已不存在,回退会恢复该文件。",
15507
16039
  "panel.externalChanged": "检测到文件在外部被修改,已更新对比并新建撤销点;重做历史已被重置。",
15508
16040
  "panel.dismiss": "知道了",
15509
- "panel.createHint": "回退会删除该新建的文件。",
15510
16041
  "panel.pasteOnCopy": "复制引用后自动粘贴到消息输入框",
15511
16042
  "panel.pasteOnCopyDesc": "开启后,复制的引用会自动填入消息输入框,输入框会获得焦点。",
15512
16043
  "panel.importUntracked": "导入未跟踪的文件改动",
@@ -15515,8 +16046,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15515
16046
  "panel.tabWidthDesc": "差异中制表符的缩进宽度,可选 2 / 4 / 8 个空格(默认 4),同时作用于行宽折行测量。",
15516
16047
  "panel.splitMode": "双栏对比",
15517
16048
  "panel.splitModeDesc": "开启后整文件差异用左「改前」|右「当前」双栏、逐行对齐的视图展示,默认关闭使用单栏(合并)视图。",
16049
+ "panel.navLeadRows": "差异跳转行距",
16050
+ "panel.navLeadRowsDesc": "按上/下跳转差异时,目标差异上方保留的行数(默认 2)。也用于从当前滚动位置定位上/下一个差异。",
15518
16051
  "panel.quickSummon": "快速呼出",
15519
- "panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板(默认 Ctrl+D)。点击右侧按钮后按下新的按键组合即可修改,Esc 取消。",
16052
+ "panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板。点击右侧按钮后按下新的按键组合即可修改。",
15520
16053
  "panel.recordShortcut": "按下快捷键…",
15521
16054
  "settings.tabLabel": "改动审批",
15522
16055
  "row.create": "新增文件",
@@ -15526,6 +16059,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15526
16059
  "row.removed": "-{removed}",
15527
16060
  "action.keep": "保留",
15528
16061
  "action.revert": "回退",
16062
+ "action.delete": "删除",
15529
16063
  "action.keepAll": "全部保留",
15530
16064
  "action.revertAll": "全部回退",
15531
16065
  "action.openFile": "打开文件",
@@ -15535,6 +16069,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15535
16069
  "action.nextDiff": "下一处差异",
15536
16070
  "action.showFileList": "展开文件列表",
15537
16071
  "action.hideFileList": "收起文件列表",
16072
+ "action.viewSplit": "切换到双栏",
16073
+ "action.viewUnified": "切换到单栏",
15538
16074
  "action.copyHint": "复制引用",
15539
16075
  "action.copied": "已复制",
15540
16076
  "action.langAuto": "自动",
@@ -15543,6 +16079,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15543
16079
  "action.wrap": "自动换行",
15544
16080
  "action.toggleOn": "打开",
15545
16081
  "action.toggleOff": "关闭",
16082
+ "action.decrease": "减小",
16083
+ "action.increase": "增大",
15546
16084
  "action.importVcs": "导入工作区改动",
15547
16085
  "action.importVcsBusy": "导入中…",
15548
16086
  "panel.importNone": "没有可导入的改动",
@@ -15577,7 +16115,6 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15577
16115
  "panel.missingHint": "This file no longer exists; reverting restores it.",
15578
16116
  "panel.externalChanged": "A file changed outside the review. The comparison was updated and a new undo point created; the redo history was reset.",
15579
16117
  "panel.dismiss": "Got it",
15580
- "panel.createHint": "Reverting removes this created file.",
15581
16118
  "panel.pasteOnCopy": "Paste the copied reference into the composer",
15582
16119
  "panel.pasteOnCopyDesc": "When enabled, a copied reference is pasted into the composer, which then receives focus.",
15583
16120
  "panel.importUntracked": "Import changes to untracked files",
@@ -15586,8 +16123,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15586
16123
  "panel.tabWidthDesc": "The indent width of a tab character in the differences, as 2 / 4 / 8 spaces (default 4). Also drives the wrapped-line measurement.",
15587
16124
  "panel.splitMode": "Side-by-side view",
15588
16125
  "panel.splitModeDesc": "When on, the whole-file differences render as a side-by-side (left \"before\" | right \"current\") line-aligned view. Off (default) uses the single-column unified view.",
16126
+ "panel.navLeadRows": "Block jump lead rows",
16127
+ "panel.navLeadRowsDesc": "Rows left above the jumped-to diff block on up/down navigation (default 2). Also used to locate the previous/next diff from the current scroll position.",
15589
16128
  "panel.quickSummon": "Quick summon",
15590
- "panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut (default Ctrl+D). Click the button and press a new chord to change it; Esc cancels.",
16129
+ "panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut. Click the button and press a new chord to change it.",
15591
16130
  "panel.recordShortcut": "Press keys…",
15592
16131
  "settings.tabLabel": "Diff Approval",
15593
16132
  "row.create": "New file",
@@ -15597,6 +16136,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15597
16136
  "row.removed": "-{removed}",
15598
16137
  "action.keep": "Keep",
15599
16138
  "action.revert": "Revert",
16139
+ "action.delete": "Delete",
15600
16140
  "action.keepAll": "Keep all",
15601
16141
  "action.revertAll": "Revert all",
15602
16142
  "action.openFile": "Open file",
@@ -15606,6 +16146,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15606
16146
  "action.nextDiff": "Next diff",
15607
16147
  "action.showFileList": "Show file list",
15608
16148
  "action.hideFileList": "Hide file list",
16149
+ "action.viewSplit": "Switch to side-by-side",
16150
+ "action.viewUnified": "Switch to unified",
15609
16151
  "action.copyHint": "Copy reference",
15610
16152
  "action.copied": "Copied",
15611
16153
  "action.langAuto": "Auto",
@@ -15614,6 +16156,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
15614
16156
  "action.wrap": "Wrap lines",
15615
16157
  "action.toggleOn": "On",
15616
16158
  "action.toggleOff": "Off",
16159
+ "action.decrease": "Decrease",
16160
+ "action.increase": "Increase",
15617
16161
  "action.importVcs": "Import workspace changes",
15618
16162
  "action.importVcsBusy": "Importing…",
15619
16163
  "panel.importNone": "No changes to import",