@teselagen/ove 0.8.40 → 0.8.41

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/index.umd.js CHANGED
@@ -124411,14 +124411,34 @@ ${seq.sequence}
124411
124411
  track.alignmentData.sequence
124412
124412
  );
124413
124413
  const mismatches = matchHighlightRanges.filter(({ isMatch }) => !isMatch);
124414
+ const alignedSeq = track.alignmentData.sequence;
124415
+ const seqLen = alignedSeq.length;
124416
+ const startIndex = seqLen - alignedSeq.replace(/^-+/, "").length;
124417
+ const endIndex = alignedSeq.replace(/-+$/, "").length;
124418
+ const gapRanges = [
124419
+ startIndex > 0 && {
124420
+ start: 0,
124421
+ end: startIndex - 1,
124422
+ differenceType: "gap"
124423
+ },
124424
+ endIndex < seqLen && {
124425
+ start: endIndex,
124426
+ end: seqLen - 1,
124427
+ differenceType: "gap"
124428
+ }
124429
+ ].filter(Boolean);
124414
124430
  return __spreadProps(__spreadValues({}, track), {
124415
124431
  sequenceData: sequenceData2,
124416
124432
  matchHighlightRanges,
124417
- additionalSelectionLayers: matchHighlightRanges.filter(({ isMatch }) => !isMatch).map((range2) => {
124418
- return __spreadProps(__spreadValues(__spreadValues({}, range2), highlightRangeProps), {
124433
+ additionalSelectionLayers: [
124434
+ ...matchHighlightRanges.filter(({ isMatch }) => !isMatch).map((range2) => __spreadProps(__spreadValues(__spreadValues({}, range2), highlightRangeProps), {
124419
124435
  className: "veAlignmentMismatch"
124420
- });
124421
- }),
124436
+ })),
124437
+ ...gapRanges.map((range2) => __spreadProps(__spreadValues(__spreadValues({}, range2), highlightRangeProps), {
124438
+ className: "veAlignmentMismatch"
124439
+ }))
124440
+ ],
124441
+ gapRanges,
124422
124442
  mismatches
124423
124443
  });
124424
124444
  });
@@ -124552,23 +124572,30 @@ ${seq.sequence}
124552
124572
  const startIndex = seqLength - nonTempSeqWithoutLeadingDashes.length;
124553
124573
  const endIndex = seqLength - (seqLength - nonTempSeqWithoutTrailingDashes.length);
124554
124574
  for (let index2 = startIndex; index2 < endIndex; index2++) {
124555
- const isMatch = tempSeq[index2].toLowerCase() === nonTempSeq[index2].toLowerCase();
124556
- const previousRange = ranges[ranges.length - 1];
124557
- if (previousRange) {
124558
- if (previousRange.isMatch === isMatch) {
124559
- previousRange.end++;
124575
+ const tempBase = tempSeq[index2].toLowerCase();
124576
+ const nonTempBase = nonTempSeq[index2].toLowerCase();
124577
+ const isMatch = tempBase === nonTempBase;
124578
+ let differenceType = null;
124579
+ if (!isMatch) {
124580
+ if (tempBase === "-") {
124581
+ differenceType = "insertion";
124582
+ } else if (nonTempBase === "-") {
124583
+ differenceType = "deletion";
124560
124584
  } else {
124561
- ranges.push({
124562
- start: index2,
124563
- end: index2,
124564
- isMatch
124565
- });
124585
+ differenceType = "mismatch";
124566
124586
  }
124587
+ }
124588
+ const previousRange = ranges[ranges.length - 1];
124589
+ if (previousRange && previousRange.isMatch === isMatch && previousRange.differenceType === differenceType) {
124590
+ previousRange.end++;
124591
+ } else if (previousRange) {
124592
+ ranges.push({ start: index2, end: index2, isMatch, differenceType });
124567
124593
  } else {
124568
124594
  ranges.push({
124569
124595
  start: startIndex,
124570
124596
  end: startIndex,
124571
- isMatch
124597
+ isMatch,
124598
+ differenceType
124572
124599
  });
124573
124600
  }
124574
124601
  }
@@ -145343,7 +145370,7 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
145343
145370
  input.click();
145344
145371
  }
145345
145372
  __name(showFileDialog, "showFileDialog");
145346
- const version = "0.8.40";
145373
+ const version = "0.8.41";
145347
145374
  const packageJson = {
145348
145375
  version
145349
145376
  };
@@ -151610,11 +151637,13 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
151610
151637
  dimensions: { width = 200 },
151611
151638
  laneHeight,
151612
151639
  laneSpacing = 1,
151613
- isTrackSelected = []
151640
+ isTrackSelected = [],
151641
+ activeFilterType = "all"
151614
151642
  } = this.props;
151615
151643
  const charWidth2 = this.getCharWidth();
151616
151644
  const {
151617
151645
  matchHighlightRanges: _matchHighlightRanges,
151646
+ gapRanges = [],
151618
151647
  alignmentData: { trimmedRange } = {}
151619
151648
  } = alignmentTracks[i2];
151620
151649
  const matchHighlightRanges = !trimmedRange ? _matchHighlightRanges : flatMap(_matchHighlightRanges, (r2) => {
@@ -151641,10 +151670,19 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
151641
151670
  charWidth2
151642
151671
  );
151643
151672
  const toAdd = `M${xStart},${y2} L${xStart + width2},${y2} L${xStart + width2},${y2 + height} L${xStart},${y2 + height}`;
151644
- if (!range2.isMatch) {
151673
+ if (!range2.isMatch && (activeFilterType === "all" || range2.differenceType === activeFilterType)) {
151645
151674
  redPath += toAdd;
151646
151675
  }
151647
151676
  });
151677
+ if (activeFilterType === "gap") {
151678
+ gapRanges.forEach((range2) => {
151679
+ const { xStart, width: width2 } = getXStartAndWidthFromNonCircularRange(
151680
+ range2,
151681
+ charWidth2
151682
+ );
151683
+ redPath += `M${xStart},${y2} L${xStart + width2},${y2} L${xStart + width2},${y2 + height} L${xStart},${y2 + height}`;
151684
+ });
151685
+ }
151648
151686
  return /* @__PURE__ */ React.createElement(
151649
151687
  "div",
151650
151688
  {
@@ -151674,7 +151712,8 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
151674
151712
  "scrollAlignmentView",
151675
151713
  "laneHeight",
151676
151714
  "laneSpacing",
151677
- "isTrackSelected"
151715
+ "isTrackSelected",
151716
+ "activeFilterType"
151678
151717
  ].some((key) => props[key] !== newProps[key]))
151679
151718
  return true;
151680
151719
  return false;
@@ -151952,6 +151991,66 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
151952
151991
  return splitRangeIntoTwoPartsIfItIsCircular(inverted, seqLen);
151953
151992
  }
151954
151993
  __name(getTrimmedRangesToDisplay, "getTrimmedRangesToDisplay");
151994
+ function groupConsecutiveDifferences(differences) {
151995
+ const grouped = [];
151996
+ for (const diff of differences) {
151997
+ if (diff.type === "mismatch") {
151998
+ grouped.push(__spreadProps(__spreadValues({}, diff), { start: diff.position, end: diff.position }));
151999
+ continue;
152000
+ }
152001
+ const last2 = grouped[grouped.length - 1];
152002
+ if (last2 && last2.type === diff.type && last2.end === diff.position - 1) {
152003
+ grouped[grouped.length - 1] = __spreadProps(__spreadValues({}, last2), { end: diff.position });
152004
+ } else {
152005
+ grouped.push(__spreadProps(__spreadValues({}, diff), { start: diff.position, end: diff.position }));
152006
+ }
152007
+ }
152008
+ return grouped;
152009
+ }
152010
+ __name(groupConsecutiveDifferences, "groupConsecutiveDifferences");
152011
+ function findAlignmentDifferences(alignedSeqs) {
152012
+ var _a2;
152013
+ if (alignedSeqs.length < 2 || !((_a2 = alignedSeqs[0]) == null ? void 0 : _a2.length)) return [];
152014
+ const template = alignedSeqs[0].toLowerCase();
152015
+ const nonTemplates = alignedSeqs.slice(1).map((s2) => s2.toLowerCase());
152016
+ const trackBounds = nonTemplates.map((seq) => {
152017
+ const withoutLeading = seq.replace(/^-+/, "");
152018
+ const withoutTrailing = seq.replace(/-+$/, "");
152019
+ const start2 = seq.length - withoutLeading.length;
152020
+ const end2 = seq.length - (seq.length - withoutTrailing.length);
152021
+ return { start: start2, end: end2 };
152022
+ });
152023
+ const differences = [];
152024
+ for (let i2 = 0; i2 < template.length; i2++) {
152025
+ const templateBase = template[i2];
152026
+ const allNonTemplateBases = nonTemplates.map((seq) => seq[i2]);
152027
+ const bases = [templateBase, ...allNonTemplateBases];
152028
+ const alignedIndices = trackBounds.reduce((acc, { start: start2, end: end2 }, idx) => {
152029
+ if (i2 >= start2 && i2 < end2) acc.push(idx);
152030
+ return acc;
152031
+ }, []);
152032
+ if (alignedIndices.length === 0) {
152033
+ differences.push({ position: i2, type: "gap", bases });
152034
+ continue;
152035
+ }
152036
+ const alignedBases = alignedIndices.map((idx) => allNonTemplateBases[idx]);
152037
+ const templateIsGap = templateBase === "-";
152038
+ const nonTemplateHasBase = alignedBases.some((b3) => b3 !== "-");
152039
+ const nonTemplateHasGap = alignedBases.some((b3) => b3 === "-");
152040
+ if (templateIsGap && nonTemplateHasBase) {
152041
+ differences.push({ position: i2, type: "insertion", bases });
152042
+ } else if (!templateIsGap && nonTemplateHasGap) {
152043
+ differences.push({ position: i2, type: "deletion", bases });
152044
+ } else if (!templateIsGap) {
152045
+ const uniqueBases = /* @__PURE__ */ new Set([templateBase, ...alignedBases]);
152046
+ if (uniqueBases.size > 1) {
152047
+ differences.push({ position: i2, type: "mismatch", bases });
152048
+ }
152049
+ }
152050
+ }
152051
+ return differences;
152052
+ }
152053
+ __name(findAlignmentDifferences, "findAlignmentDifferences");
151955
152054
  function scrollToAlignmentSelection() {
151956
152055
  const el = document.querySelector(".veCaret");
151957
152056
  if (el) {
@@ -151965,159 +152064,145 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
151965
152064
  }
151966
152065
  }
151967
152066
  __name(updateCaretPosition, "updateCaretPosition");
152067
+ const FILTER_OPTIONS = [
152068
+ { value: "all", label: "All" },
152069
+ { value: "mismatch", label: "Mismatches" },
152070
+ { value: "insertion", label: "Insertions" },
152071
+ { value: "deletion", label: "Deletions" },
152072
+ { value: "gap", label: "Gaps" }
152073
+ ];
151968
152074
  function FindMismatches(props) {
151969
- const { alignmentJson, id: id2 } = props;
152075
+ var _a2;
152076
+ const { alignmentJson, id: id2, onFilterChange } = props;
151970
152077
  const alignedSeqs = reactExports.useMemo(
151971
152078
  () => alignmentJson.map((t2) => {
151972
- var _a2;
151973
- return ((_a2 = t2.alignmentData) == null ? void 0 : _a2.sequence) || "";
152079
+ var _a3;
152080
+ return ((_a3 = t2.alignmentData) == null ? void 0 : _a3.sequence) || "";
151974
152081
  }),
151975
152082
  [alignmentJson]
151976
152083
  );
151977
- const mismatches = reactExports.useMemo(() => {
151978
- const result = [{ position: 0, bases: [""] }];
151979
- if (alignedSeqs.length > 1 && alignedSeqs[0].length) {
151980
- for (let i2 = 0; i2 < alignedSeqs[0].length; i2++) {
151981
- const bases = alignedSeqs.map((seq) => seq[i2]);
151982
- const uniqueBases = new Set(bases);
151983
- if (uniqueBases.size > 1 && !uniqueBases.has("-")) {
151984
- result.push({ position: i2, bases });
151985
- }
151986
- }
151987
- }
151988
- return result;
151989
- }, [alignedSeqs]);
152084
+ const [activeFilter, setActiveFilter] = React.useState("all");
152085
+ const allDifferences = reactExports.useMemo(
152086
+ () => groupConsecutiveDifferences(findAlignmentDifferences(alignedSeqs)),
152087
+ [alignedSeqs]
152088
+ );
152089
+ const countsByType = reactExports.useMemo(() => {
152090
+ const counts = { all: 0, mismatch: 0, insertion: 0, deletion: 0, gap: 0 };
152091
+ allDifferences.forEach((d2) => {
152092
+ counts[d2.type] = (counts[d2.type] || 0) + 1;
152093
+ counts.all++;
152094
+ });
152095
+ return counts;
152096
+ }, [allDifferences]);
152097
+ const differences = reactExports.useMemo(() => {
152098
+ const filtered = activeFilter === "all" ? allDifferences : allDifferences.filter((d2) => d2.type === activeFilter);
152099
+ return [{ position: -1, start: -1, end: -1, bases: [""] }, ...filtered];
152100
+ }, [allDifferences, activeFilter]);
151990
152101
  const currentCaretPosition = useSelector(
151991
152102
  (state2) => {
151992
- var _a2;
151993
- return (_a2 = state2.VectorEditor.__allEditorsOptions.alignments[id2]) == null ? void 0 : _a2.caretPosition;
152103
+ var _a3;
152104
+ return (_a3 = state2.VectorEditor.__allEditorsOptions.alignments[id2]) == null ? void 0 : _a3.caretPosition;
151994
152105
  }
151995
152106
  );
151996
152107
  const [currentIdx, setCurrentIdx] = React.useState(0);
151997
- const [disablePrev, setDisablePrev] = React.useState(true);
151998
- const [disableNext, setDisableNext] = React.useState(false);
151999
- const currentMismatch = mismatches[currentIdx];
152000
- const handleButtonsState = reactExports.useCallback(
152001
- (caret) => {
152002
- if (mismatches.length <= 1) {
152003
- setDisablePrev(true);
152004
- setDisableNext(true);
152005
- return;
152006
- }
152007
- const firstMismatchPos = mismatches[1].position;
152008
- const lastMismatchPos = mismatches[mismatches.length - 1].position;
152009
- setDisablePrev(caret <= firstMismatchPos);
152010
- setDisableNext(caret >= lastMismatchPos);
152011
- },
152012
- [mismatches]
152013
- );
152108
+ const currentDiff = differences[currentIdx];
152109
+ const disablePrev = currentIdx <= 1;
152110
+ const disableNext = currentIdx >= differences.length - 1;
152111
+ reactExports.useEffect(() => {
152112
+ setCurrentIdx(0);
152113
+ }, [activeFilter]);
152114
+ reactExports.useEffect(() => {
152115
+ onFilterChange == null ? void 0 : onFilterChange({ activeFilter });
152116
+ }, [activeFilter, onFilterChange]);
152014
152117
  reactExports.useEffect(() => {
152015
152118
  if (currentCaretPosition !== -1) {
152016
- const mismatchIdx = mismatches.findIndex(
152017
- (m2) => m2.position === currentCaretPosition || m2.position === currentCaretPosition - 1
152119
+ const diffIdx = differences.findIndex(
152120
+ (d2, i2) => i2 > 0 && currentCaretPosition >= d2.start && currentCaretPosition <= d2.end + 1
152018
152121
  );
152019
- if (mismatchIdx !== -1 && mismatchIdx !== currentIdx) {
152020
- handleButtonsState(currentCaretPosition);
152021
- setCurrentIdx(mismatchIdx);
152122
+ if (diffIdx !== -1 && diffIdx !== currentIdx) {
152123
+ setCurrentIdx(diffIdx);
152022
152124
  }
152023
152125
  }
152024
- }, [currentCaretPosition, mismatches, currentIdx, handleButtonsState]);
152025
- const updateView = /* @__PURE__ */ __name((mismatch) => {
152026
- const idx = mismatches.indexOf(mismatch);
152027
- const position2 = mismatch.position;
152028
- handleButtonsState(position2);
152126
+ }, [currentCaretPosition, differences, currentIdx]);
152127
+ const updateView = /* @__PURE__ */ __name((diff) => {
152128
+ const idx = differences.indexOf(diff);
152129
+ const { start: start2, end: end2 } = diff;
152029
152130
  setCurrentIdx(idx);
152030
- updateCaretPosition({ start: position2, end: position2 });
152131
+ updateCaretPosition({ start: start2, end: end2 });
152031
152132
  setTimeout(() => {
152032
152133
  scrollToAlignmentSelection();
152033
152134
  }, 0);
152034
152135
  }, "updateView");
152035
- const prevMismatch = /* @__PURE__ */ __name(() => {
152036
- if (currentIdx > 1) {
152037
- const newIdx = Math.max(0, currentIdx - 1);
152038
- let prev = mismatches[newIdx];
152039
- if (currentCaretPosition > 0) {
152040
- prev = [...mismatches].reverse().find((m2) => m2.position < currentCaretPosition);
152041
- }
152042
- if (prev) {
152043
- updateView(prev);
152044
- }
152045
- }
152046
- }, "prevMismatch");
152047
- const nextMismatch = /* @__PURE__ */ __name(() => {
152048
- if (currentIdx < mismatches.length - 1) {
152049
- const newIdx = Math.min(mismatches.length - 1, currentIdx + 1);
152050
- let next = mismatches[newIdx];
152051
- if (currentCaretPosition > 0) {
152052
- next = mismatches.find(
152053
- (m2) => m2.position > currentCaretPosition && m2.position > 1
152054
- );
152055
- }
152056
- if (next) {
152057
- updateView(next);
152136
+ const prevDifference = /* @__PURE__ */ __name(() => {
152137
+ var _a3, _b2;
152138
+ const pivot = currentCaretPosition >= 0 ? currentCaretPosition : (_b2 = (_a3 = differences[currentIdx]) == null ? void 0 : _a3.start) != null ? _b2 : 0;
152139
+ const prev = [...differences].reverse().find((d2) => d2.start >= 0 && d2.start < pivot);
152140
+ if (prev) updateView(prev);
152141
+ }, "prevDifference");
152142
+ const nextDifference = /* @__PURE__ */ __name(() => {
152143
+ var _a3, _b2;
152144
+ const pivot = currentCaretPosition >= 0 ? currentCaretPosition : (_b2 = (_a3 = differences[currentIdx]) == null ? void 0 : _a3.start) != null ? _b2 : -1;
152145
+ const next = differences.find((d2) => d2.start > pivot && d2.start >= 0);
152146
+ if (next) updateView(next);
152147
+ }, "nextDifference");
152148
+ const noDifferences = differences.length <= 1;
152149
+ const activeOption = FILTER_OPTIONS.find((o2) => o2.value === activeFilter);
152150
+ const activeLabel = (_a2 = activeOption == null ? void 0 : activeOption.label) != null ? _a2 : "Differences";
152151
+ const filterMenu = /* @__PURE__ */ React.createElement(Menu, null, FILTER_OPTIONS.map(({ value, label }) => {
152152
+ var _a3;
152153
+ const count2 = (_a3 = countsByType[value]) != null ? _a3 : 0;
152154
+ const isActive2 = activeFilter === value;
152155
+ return /* @__PURE__ */ React.createElement(
152156
+ MenuItem,
152157
+ {
152158
+ key: value,
152159
+ active: isActive2,
152160
+ onClick: /* @__PURE__ */ __name(() => setActiveFilter(value), "onClick"),
152161
+ text: /* @__PURE__ */ React.createElement("span", { className: "veDiffMenuItem-inner" }, label, /* @__PURE__ */ React.createElement(Tag, { round: true, minimal: true, style: { marginLeft: 6 } }, count2))
152058
152162
  }
152059
- }
152060
- }, "nextMismatch");
152061
- return /* @__PURE__ */ React.createElement(
152062
- "div",
152163
+ );
152164
+ }));
152165
+ return /* @__PURE__ */ React.createElement("div", { className: "veDiffNavigator" }, /* @__PURE__ */ React.createElement(
152166
+ Popover,
152063
152167
  {
152064
- style: {
152065
- display: "flex",
152066
- flexDirection: "row",
152067
- justifyContent: "center",
152068
- alignItems: "center",
152069
- gap: 10
152070
- }
152071
- },
152072
- mismatches.length === 1 ? /* @__PURE__ */ React.createElement("span", { style: { fontStyle: "italic", color: "grey" } }, "no mismatches") : /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React.createElement(
152073
- "div",
152074
- {
152075
- style: {
152076
- display: "flex",
152077
- alignItems: "center"
152078
- }
152079
- },
152080
- /* @__PURE__ */ React.createElement("strong", null, "Mismatches"),
152081
- /* @__PURE__ */ React.createElement("div", { style: { display: "flex", gap: 2 } }, /* @__PURE__ */ React.createElement(
152082
- Button,
152083
- {
152084
- intent: "primary",
152085
- icon: "arrow-left",
152086
- "data-tip": "Previous Mismatch",
152087
- onClick: prevMismatch,
152088
- disabled: disablePrev,
152089
- small: true,
152090
- minimal: true
152091
- }
152092
- ), /* @__PURE__ */ React.createElement(
152168
+ minimal: true,
152169
+ position: Position.BOTTOM_LEFT,
152170
+ content: filterMenu,
152171
+ target: /* @__PURE__ */ React.createElement(
152093
152172
  Button,
152094
152173
  {
152095
- intent: "primary",
152096
- icon: "arrow-right",
152097
- "data-tip": "Next Mismatch",
152098
- onClick: nextMismatch,
152099
- disabled: disableNext,
152174
+ minimal: true,
152175
+ "data-tip": "Filter Difference Type",
152100
152176
  small: true,
152101
- minimal: true
152102
- }
152103
- ))
152104
- ), /* @__PURE__ */ React.createElement(
152105
- "span",
152106
- {
152107
- style: {
152108
- fontSize: "0.8em",
152109
- color: "grey",
152110
- lineHeight: "0.8em"
152111
- }
152112
- },
152113
- currentMismatch.position > 1 && /* @__PURE__ */ React.createElement("span", null, "Position: ", currentMismatch.position + 1, " | "),
152114
- "(",
152115
- currentIdx,
152116
- " of ",
152117
- mismatches.length - 1,
152118
- ")"
152119
- ))
152120
- );
152177
+ rightIcon: "caret-down",
152178
+ className: "veDiffFilter-trigger"
152179
+ },
152180
+ activeLabel
152181
+ )
152182
+ }
152183
+ ), noDifferences ? /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-empty" }, "no", " ", activeFilter === "all" ? "differences" : activeLabel.toLowerCase()) : /* @__PURE__ */ React.createElement("div", { className: "veDiffNav" }, /* @__PURE__ */ React.createElement(
152184
+ Button,
152185
+ {
152186
+ minimal: true,
152187
+ small: true,
152188
+ "data-tip": "Previous Difference",
152189
+ icon: "arrow-left",
152190
+ intent: Intent.PRIMARY,
152191
+ onClick: prevDifference,
152192
+ disabled: disablePrev
152193
+ }
152194
+ ), /* @__PURE__ */ React.createElement("div", { className: "veDiffNav-center" }, /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-fraction" }, currentIdx, /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-sep" }, "/"), differences.length - 1), (currentDiff == null ? void 0 : currentDiff.start) > -1 && /* @__PURE__ */ React.createElement("span", { className: "veDiffNav-pos" }, ":", currentDiff.start + 1)), /* @__PURE__ */ React.createElement(
152195
+ Button,
152196
+ {
152197
+ minimal: true,
152198
+ small: true,
152199
+ "data-tip": "Next Difference",
152200
+ icon: "arrow-right",
152201
+ intent: Intent.PRIMARY,
152202
+ onClick: nextDifference,
152203
+ disabled: disableNext
152204
+ }
152205
+ )));
152121
152206
  }
152122
152207
  __name(FindMismatches, "FindMismatches");
152123
152208
  function getGapMap(sequence2) {
@@ -152806,17 +152891,18 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
152806
152891
  minimal: true,
152807
152892
  position: "bottom",
152808
152893
  content: /* @__PURE__ */ React.createElement(VisibilityOptions$2, __spreadValues({}, props)),
152809
- target: /* @__PURE__ */ React.createElement(Tooltip, { content: "Visibility Options" }, /* @__PURE__ */ React.createElement(
152894
+ target: /* @__PURE__ */ React.createElement(
152810
152895
  Button,
152811
152896
  {
152812
152897
  className: "tg-alignment-visibility-toggle",
152813
152898
  small: true,
152899
+ "data-tip": "Visibility Options",
152814
152900
  rightIcon: "caret-down",
152815
152901
  intent: Intent.PRIMARY,
152816
152902
  minimal: true,
152817
152903
  icon: "eye-open"
152818
152904
  }
152819
- ))
152905
+ )
152820
152906
  }
152821
152907
  );
152822
152908
  }, "AlignmentVisibilityTool"));
@@ -166604,6 +166690,10 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
166604
166690
  const [tempTrimAfter, setTempTrimAfter] = reactExports.useState({});
166605
166691
  const [tempTrimmingCaret, setTempTrimmingCaret] = reactExports.useState({});
166606
166692
  const [searchMatchLayers, setSearchMatchLayers] = React.useState([]);
166693
+ const [activeFilterType, setActiveFilterType] = reactExports.useState("all");
166694
+ const handleFilterChange = reactExports.useCallback(({ activeFilter }) => {
166695
+ setActiveFilterType(activeFilter);
166696
+ }, []);
166607
166697
  const bindOutsideChangeHelper = reactExports.useRef({});
166608
166698
  const alignmentHolder = reactExports.useRef(null);
166609
166699
  const alignmentHolderTop = reactExports.useRef(null);
@@ -167329,7 +167419,9 @@ ${seqDataToCopy}\r
167329
167419
  chromatogramData
167330
167420
  }) : linearViewOptions)), {
167331
167421
  additionalSelectionLayers: [
167332
- ...additionalSelectionLayers || [],
167422
+ ...i2 !== 0 ? (additionalSelectionLayers || []).filter(
167423
+ (layer) => activeFilterType === "all" ? layer.differenceType !== "gap" : layer.differenceType === activeFilterType
167424
+ ) : additionalSelectionLayers || [],
167333
167425
  ...searchMatchLayers || []
167334
167426
  ],
167335
167427
  dimensions: {
@@ -167988,7 +168080,14 @@ ${seqDataToCopy}\r
167988
168080
  setSearchMatchLayers
167989
168081
  }
167990
168082
  ),
167991
- /* @__PURE__ */ React.createElement(FindMismatches, { alignmentJson: alignmentTracks, id: id2 }),
168083
+ /* @__PURE__ */ React.createElement(
168084
+ FindMismatches,
168085
+ {
168086
+ alignmentJson: alignmentTracks,
168087
+ id: id2,
168088
+ onFilterChange: handleFilterChange
168089
+ }
168090
+ ),
167992
168091
  additionalTopEl,
167993
168092
  saveMessage && /* @__PURE__ */ React.createElement(
167994
168093
  "div",
@@ -168089,6 +168188,7 @@ ${seqDataToCopy}\r
168089
168188
  }
168090
168189
  )),
168091
168190
  alignmentTracks,
168191
+ activeFilterType,
168092
168192
  dimensions: {
168093
168193
  width: Math.max(width, 10) || 10
168094
168194
  },
package/ove.css CHANGED
@@ -11297,6 +11297,10 @@ path.partWithSelectedTag {
11297
11297
  /* .alignmentViewTrackContainer:hover .alignmentTrackNameDiv {
11298
11298
  opacity: 1 !important;
11299
11299
  } */
11300
+ .ve-alignment-top-bar {
11301
+ align-items: center;
11302
+ }
11303
+
11300
11304
  .ve-alignment-top-bar > * {
11301
11305
  overflow-wrap: normal;
11302
11306
  flex: 0 0 auto;
@@ -11313,6 +11317,82 @@ path.partWithSelectedTag {
11313
11317
  .veAlignmentMismatch {
11314
11318
  opacity: 0.9;
11315
11319
  }
11320
+
11321
+ .veDiffNavigator {
11322
+ display: flex;
11323
+ align-items: center;
11324
+ gap: 4px;
11325
+ }
11326
+
11327
+ /* Menu item content layout */
11328
+ .veDiffMenuItem-inner {
11329
+ display: flex;
11330
+ align-items: center;
11331
+ gap: 6px;
11332
+ }
11333
+
11334
+ /* Navigation pill — groups prev/counter/next into one unit */
11335
+ .veDiffNav {
11336
+ display: flex;
11337
+ align-items: center;
11338
+ border-radius: 3px;
11339
+ background: rgba(92, 112, 128, 0.06);
11340
+ border: 1px solid rgba(92, 112, 128, 0.18);
11341
+ }
11342
+
11343
+ .veDiffNav-center {
11344
+ display: flex;
11345
+ align-items: baseline;
11346
+ gap: 3px;
11347
+ padding: 0 6px;
11348
+ min-width: 64px;
11349
+ justify-content: center;
11350
+ }
11351
+
11352
+ .veDiffNav-fraction {
11353
+ font-size: 11px;
11354
+ font-variant-numeric: tabular-nums;
11355
+ color: #5c7080;
11356
+ line-height: 1;
11357
+ }
11358
+
11359
+ .veDiffNav-sep {
11360
+ margin: 0 1px;
11361
+ opacity: 0.45;
11362
+ }
11363
+
11364
+ /* Position number — monospace fits sequence coordinates */
11365
+ .veDiffNav-pos {
11366
+ font-size: 10px;
11367
+ font-family: monospace;
11368
+ font-variant-numeric: tabular-nums;
11369
+ color: #a7b6c2;
11370
+ line-height: 1;
11371
+ }
11372
+
11373
+ .veDiffNav-empty {
11374
+ font-size: 11px;
11375
+ font-style: italic;
11376
+ color: #a7b6c2;
11377
+ padding: 0 4px;
11378
+ }
11379
+
11380
+ .bp3-dark .veDiffNav {
11381
+ background: rgba(167, 182, 194, 0.05);
11382
+ border-color: rgba(167, 182, 194, 0.14);
11383
+ }
11384
+
11385
+ .bp3-dark .veDiffNav-fraction {
11386
+ color: #5c7080;
11387
+ }
11388
+
11389
+ .bp3-dark .veDiffNav-pos {
11390
+ color: #4f6272;
11391
+ }
11392
+
11393
+ .bp3-dark .veDiffNav-empty {
11394
+ color: #5c7080;
11395
+ }
11316
11396
  .veRowItem:has(.rowViewTextContainer) .veAlignmentMismatch {
11317
11397
  opacity: 0.5;
11318
11398
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teselagen/ove",
3
- "version": "0.8.40",
3
+ "version": "0.8.41",
4
4
  "main": "./src/index.js",
5
5
  "type": "module",
6
6
  "repository": "https://github.com/TeselaGen/tg-oss",