@teselagen/ove 0.8.39 → 0.8.40

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
@@ -145343,7 +145343,7 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
145343
145343
  input.click();
145344
145344
  }
145345
145345
  __name(showFileDialog, "showFileDialog");
145346
- const version = "0.8.39";
145346
+ const version = "0.8.40";
145347
145347
  const packageJson = {
145348
145348
  version
145349
145349
  };
@@ -151952,6 +151952,853 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
151952
151952
  return splitRangeIntoTwoPartsIfItIsCircular(inverted, seqLen);
151953
151953
  }
151954
151954
  __name(getTrimmedRangesToDisplay, "getTrimmedRangesToDisplay");
151955
+ function scrollToAlignmentSelection() {
151956
+ const el = document.querySelector(".veCaret");
151957
+ if (el) {
151958
+ el.scrollIntoView({ inline: "center", block: "nearest" });
151959
+ }
151960
+ }
151961
+ __name(scrollToAlignmentSelection, "scrollToAlignmentSelection");
151962
+ function updateCaretPosition({ start: start2, end: end2 }) {
151963
+ if (window.updateAlignmentSelection) {
151964
+ window.updateAlignmentSelection({ start: start2, end: end2 });
151965
+ }
151966
+ }
151967
+ __name(updateCaretPosition, "updateCaretPosition");
151968
+ function FindMismatches(props) {
151969
+ const { alignmentJson, id: id2 } = props;
151970
+ const alignedSeqs = reactExports.useMemo(
151971
+ () => alignmentJson.map((t2) => {
151972
+ var _a2;
151973
+ return ((_a2 = t2.alignmentData) == null ? void 0 : _a2.sequence) || "";
151974
+ }),
151975
+ [alignmentJson]
151976
+ );
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]);
151990
+ const currentCaretPosition = useSelector(
151991
+ (state2) => {
151992
+ var _a2;
151993
+ return (_a2 = state2.VectorEditor.__allEditorsOptions.alignments[id2]) == null ? void 0 : _a2.caretPosition;
151994
+ }
151995
+ );
151996
+ 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
+ );
152014
+ reactExports.useEffect(() => {
152015
+ if (currentCaretPosition !== -1) {
152016
+ const mismatchIdx = mismatches.findIndex(
152017
+ (m2) => m2.position === currentCaretPosition || m2.position === currentCaretPosition - 1
152018
+ );
152019
+ if (mismatchIdx !== -1 && mismatchIdx !== currentIdx) {
152020
+ handleButtonsState(currentCaretPosition);
152021
+ setCurrentIdx(mismatchIdx);
152022
+ }
152023
+ }
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);
152029
+ setCurrentIdx(idx);
152030
+ updateCaretPosition({ start: position2, end: position2 });
152031
+ setTimeout(() => {
152032
+ scrollToAlignmentSelection();
152033
+ }, 0);
152034
+ }, "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);
152058
+ }
152059
+ }
152060
+ }, "nextMismatch");
152061
+ return /* @__PURE__ */ React.createElement(
152062
+ "div",
152063
+ {
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(
152093
+ Button,
152094
+ {
152095
+ intent: "primary",
152096
+ icon: "arrow-right",
152097
+ "data-tip": "Next Mismatch",
152098
+ onClick: nextMismatch,
152099
+ disabled: disableNext,
152100
+ 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
+ );
152121
+ }
152122
+ __name(FindMismatches, "FindMismatches");
152123
+ function getGapMap(sequence2) {
152124
+ const gapMap = [0];
152125
+ sequence2.split("").forEach((char) => {
152126
+ if (char === "-") {
152127
+ gapMap[Math.max(0, gapMap.length - 1)] = (gapMap[Math.max(0, gapMap.length - 1)] || 0) + 1;
152128
+ } else {
152129
+ gapMap.push(gapMap[gapMap.length - 1] || 0);
152130
+ }
152131
+ });
152132
+ return gapMap;
152133
+ }
152134
+ __name(getGapMap, "getGapMap");
152135
+ const MATCH_COLOR = "gold";
152136
+ const CURRENT_MATCH_COLOR = "green";
152137
+ const MISMATCH_COLOR = "red";
152138
+ const ANNOTATION_TYPES = ["features", "parts", "primers"];
152139
+ const initialSearchState = {
152140
+ searchText: "",
152141
+ matches: [],
152142
+ currentMatchIndex: 0,
152143
+ searched: false,
152144
+ featureMatches: [],
152145
+ dnaOrAA: "DNA",
152146
+ ambiguousOrLiteral: "LITERAL",
152147
+ mismatchesAllowed: 0
152148
+ };
152149
+ function searchReducer(state2, action2) {
152150
+ switch (action2.type) {
152151
+ case "SET_SEARCH_TEXT":
152152
+ return __spreadProps(__spreadValues({}, state2), { searchText: action2.payload });
152153
+ case "SET_MATCHES":
152154
+ return __spreadProps(__spreadValues({}, state2), {
152155
+ matches: action2.payload.matches,
152156
+ currentMatchIndex: action2.payload.currentMatchIndex
152157
+ });
152158
+ case "SET_CURRENT_MATCH_INDEX":
152159
+ return __spreadProps(__spreadValues({}, state2), { currentMatchIndex: action2.payload });
152160
+ case "SET_SEARCHED":
152161
+ return __spreadProps(__spreadValues({}, state2), { searched: action2.payload });
152162
+ case "SEARCH_COMPLETE":
152163
+ return __spreadProps(__spreadValues({}, state2), {
152164
+ matches: action2.payload.matches,
152165
+ currentMatchIndex: action2.payload.currentMatchIndex,
152166
+ searched: action2.payload.searched
152167
+ });
152168
+ case "SET_FEATURE_MATCHES":
152169
+ return __spreadProps(__spreadValues({}, state2), { featureMatches: action2.payload });
152170
+ case "SET_DNA_OR_AA":
152171
+ return __spreadProps(__spreadValues({}, state2), { dnaOrAA: action2.payload });
152172
+ case "SET_AMBIGUOUS_OR_LITERAL":
152173
+ return __spreadProps(__spreadValues({}, state2), { ambiguousOrLiteral: action2.payload });
152174
+ case "SET_MISMATCHES_ALLOWED":
152175
+ return __spreadProps(__spreadValues({}, state2), { mismatchesAllowed: Math.max(0, action2.payload) });
152176
+ case "RESET":
152177
+ return __spreadValues({}, initialSearchState);
152178
+ default:
152179
+ return state2;
152180
+ }
152181
+ }
152182
+ __name(searchReducer, "searchReducer");
152183
+ function AlignmentSearchBar(props) {
152184
+ const { alignmentTracks = [], setSearchMatchLayers } = props;
152185
+ const [searchState, dispatch] = reactExports.useReducer(searchReducer, initialSearchState);
152186
+ const {
152187
+ searchText,
152188
+ matches,
152189
+ currentMatchIndex,
152190
+ searched,
152191
+ featureMatches,
152192
+ dnaOrAA,
152193
+ ambiguousOrLiteral,
152194
+ mismatchesAllowed
152195
+ } = searchState;
152196
+ const debouncedSearch = reactExports.useRef(
152197
+ debounce((text2, search2, featureSearch) => {
152198
+ search2(text2);
152199
+ featureSearch(text2);
152200
+ }, 50)
152201
+ ).current;
152202
+ reactExports.useEffect(() => {
152203
+ return () => {
152204
+ debouncedSearch.cancel();
152205
+ };
152206
+ }, [debouncedSearch]);
152207
+ const [highlightAll, setHighlightAll] = reactExports.useState(false);
152208
+ const [isExpanded, setIsExpanded] = reactExports.useState(false);
152209
+ const [isOpen2, setIsOpen] = reactExports.useState(false);
152210
+ const [isPopoverOpen, setIsPopoverOpen] = reactExports.useState(false);
152211
+ const handleToggleExpanded = reactExports.useCallback(() => {
152212
+ setIsExpanded((prev) => {
152213
+ const next = !prev;
152214
+ if (!next) setIsPopoverOpen(true);
152215
+ return next;
152216
+ });
152217
+ }, [setIsPopoverOpen]);
152218
+ reactExports.useEffect(() => {
152219
+ dispatch({ type: "RESET" });
152220
+ if (setSearchMatchLayers) setSearchMatchLayers([]);
152221
+ }, [setSearchMatchLayers]);
152222
+ const buildMatchLayers = reactExports.useCallback(
152223
+ (allMatches, activeIndex) => {
152224
+ if (!setSearchMatchLayers) return;
152225
+ if (!allMatches.length) {
152226
+ setSearchMatchLayers([]);
152227
+ return;
152228
+ }
152229
+ const makeMismatchLayers = /* @__PURE__ */ __name((match) => (match.mismatchAlignmentPositions || []).map((pos) => ({
152230
+ start: pos,
152231
+ end: pos,
152232
+ color: MISMATCH_COLOR,
152233
+ className: "veSearchMismatch",
152234
+ ignoreGaps: true,
152235
+ hideCarets: true
152236
+ })), "makeMismatchLayers");
152237
+ const layers = highlightAll ? allMatches.flatMap((match, i2) => [
152238
+ {
152239
+ start: match.alignmentStart,
152240
+ end: match.alignmentEnd,
152241
+ color: i2 === activeIndex ? CURRENT_MATCH_COLOR : MATCH_COLOR,
152242
+ className: i2 === activeIndex ? "veSearchLayerActive" : "veSearchLayer",
152243
+ ignoreGaps: true
152244
+ },
152245
+ ...makeMismatchLayers(match)
152246
+ ]) : [
152247
+ {
152248
+ start: allMatches[activeIndex].alignmentStart,
152249
+ end: allMatches[activeIndex].alignmentEnd,
152250
+ color: CURRENT_MATCH_COLOR,
152251
+ className: "veSearchLayerActive",
152252
+ ignoreGaps: true
152253
+ },
152254
+ ...makeMismatchLayers(allMatches[activeIndex])
152255
+ ];
152256
+ setSearchMatchLayers(layers);
152257
+ },
152258
+ [setSearchMatchLayers, highlightAll]
152259
+ );
152260
+ const navigateTo = reactExports.useCallback(
152261
+ (allMatches, index2) => {
152262
+ const match = allMatches[index2];
152263
+ if (!match) return;
152264
+ updateCaretPosition({
152265
+ start: match.alignmentStart,
152266
+ end: match.alignmentEnd
152267
+ });
152268
+ setTimeout(() => {
152269
+ scrollToAlignmentSelection();
152270
+ }, 0);
152271
+ buildMatchLayers(allMatches, index2);
152272
+ },
152273
+ [buildMatchLayers]
152274
+ );
152275
+ const runSearch = reactExports.useCallback(
152276
+ (text2) => {
152277
+ const query = text2.trim();
152278
+ if (!query) {
152279
+ dispatch({
152280
+ type: "SEARCH_COMPLETE",
152281
+ payload: { matches: [], currentMatchIndex: 0, searched: false }
152282
+ });
152283
+ if (setSearchMatchLayers) setSearchMatchLayers([]);
152284
+ return;
152285
+ }
152286
+ const allMatches = [];
152287
+ alignmentTracks.slice(0, 1).forEach((track, trackIndex) => {
152288
+ var _a2, _b2;
152289
+ const rawSeq = ((_a2 = track.sequenceData) == null ? void 0 : _a2.sequence) || "";
152290
+ const alignedSeq = ((_b2 = track.alignmentData) == null ? void 0 : _b2.sequence) || "";
152291
+ const gapMap = getGapMap(alignedSeq);
152292
+ const gapOffset = /* @__PURE__ */ __name((n2) => {
152293
+ var _a3, _b3;
152294
+ return (_b3 = (_a3 = gapMap[n2]) != null ? _a3 : gapMap[gapMap.length - 1]) != null ? _b3 : 0;
152295
+ }, "gapOffset");
152296
+ let seqMatches = [];
152297
+ if (dnaOrAA === "DNA" && ambiguousOrLiteral === "LITERAL" && mismatchesAllowed > 0) {
152298
+ const approxMatches = findApproxMatches(
152299
+ query.toLowerCase(),
152300
+ rawSeq.toLowerCase(),
152301
+ mismatchesAllowed,
152302
+ false
152303
+ );
152304
+ seqMatches = approxMatches.map((m2) => ({
152305
+ start: m2.index,
152306
+ end: m2.index + m2.match.length - 1,
152307
+ mismatchPositions: m2.mismatchPositions
152308
+ }));
152309
+ } else {
152310
+ seqMatches = findSequenceMatches(rawSeq, query, {
152311
+ isCircular: false,
152312
+ isAmbiguous: ambiguousOrLiteral === "AMBIGUOUS",
152313
+ isProteinSearch: dnaOrAA !== "DNA",
152314
+ searchReverseStrand: dnaOrAA === "DNA"
152315
+ });
152316
+ }
152317
+ const hitsToProcess = query.length < 2 ? seqMatches.slice(0, 1) : seqMatches;
152318
+ hitsToProcess.forEach(({ start: start2, end: end2, mismatchPositions }) => {
152319
+ const alignmentStart = start2 + gapOffset(start2);
152320
+ const alignmentEnd = end2 + gapOffset(end2);
152321
+ const mismatchAlignmentPositions = (mismatchPositions || []).map(
152322
+ (p2) => {
152323
+ const absPos = start2 + p2;
152324
+ return absPos + gapOffset(absPos);
152325
+ }
152326
+ );
152327
+ allMatches.push({
152328
+ trackIndex,
152329
+ alignmentStart,
152330
+ alignmentEnd,
152331
+ mismatchAlignmentPositions
152332
+ });
152333
+ });
152334
+ });
152335
+ const results = query.length < 2 ? allMatches.slice(0, 1) : allMatches;
152336
+ dispatch({
152337
+ type: "SEARCH_COMPLETE",
152338
+ payload: { matches: results, currentMatchIndex: 0, searched: true }
152339
+ });
152340
+ if (results.length) {
152341
+ navigateTo(results, 0);
152342
+ } else {
152343
+ if (setSearchMatchLayers) setSearchMatchLayers([]);
152344
+ }
152345
+ },
152346
+ [
152347
+ alignmentTracks,
152348
+ navigateTo,
152349
+ dnaOrAA,
152350
+ ambiguousOrLiteral,
152351
+ mismatchesAllowed,
152352
+ setSearchMatchLayers
152353
+ ]
152354
+ );
152355
+ const runFeatureSearch = reactExports.useCallback(
152356
+ (text2) => {
152357
+ const query = text2.trim().toLowerCase();
152358
+ if (!query) {
152359
+ dispatch({ type: "SET_FEATURE_MATCHES", payload: [] });
152360
+ return;
152361
+ }
152362
+ const allMatches = [];
152363
+ alignmentTracks.slice(0, 1).forEach((track, trackIndex) => {
152364
+ const { sequenceData: sequenceData2, alignmentData } = track;
152365
+ const alignedSeq = (alignmentData == null ? void 0 : alignmentData.sequence) || "";
152366
+ const gapMap = getGapMap(alignedSeq);
152367
+ const gapOffset = /* @__PURE__ */ __name((n2) => {
152368
+ var _a2, _b2;
152369
+ return (_b2 = (_a2 = gapMap[n2]) != null ? _a2 : gapMap[gapMap.length - 1]) != null ? _b2 : 0;
152370
+ }, "gapOffset");
152371
+ const trackName = (alignmentData == null ? void 0 : alignmentData.name) || (sequenceData2 == null ? void 0 : sequenceData2.name) || (sequenceData2 == null ? void 0 : sequenceData2.id) || "";
152372
+ ANNOTATION_TYPES.forEach((type2) => {
152373
+ const anns = sequenceData2 == null ? void 0 : sequenceData2[type2];
152374
+ if (!anns) return;
152375
+ const annsArray = Array.isArray(anns) ? anns : Object.values(anns);
152376
+ annsArray.forEach((ann) => {
152377
+ if (!ann.name) return;
152378
+ if (ann.name.toLowerCase().includes(query)) {
152379
+ const alignmentStart = ann.start + gapOffset(ann.start);
152380
+ const alignmentEnd = ann.end + gapOffset(ann.end);
152381
+ allMatches.push({
152382
+ trackIndex,
152383
+ trackName,
152384
+ type: type2,
152385
+ annotation: ann,
152386
+ alignmentStart,
152387
+ alignmentEnd
152388
+ });
152389
+ }
152390
+ });
152391
+ });
152392
+ });
152393
+ dispatch({ type: "SET_FEATURE_MATCHES", payload: allMatches });
152394
+ },
152395
+ [alignmentTracks]
152396
+ );
152397
+ const goToPrev = reactExports.useCallback(() => {
152398
+ if (!matches.length) return;
152399
+ const newIndex = currentMatchIndex === 0 ? matches.length - 1 : currentMatchIndex - 1;
152400
+ dispatch({ type: "SET_CURRENT_MATCH_INDEX", payload: newIndex });
152401
+ navigateTo(matches, newIndex);
152402
+ }, [matches, currentMatchIndex, navigateTo]);
152403
+ const goToNext = reactExports.useCallback(() => {
152404
+ if (!matches.length) return;
152405
+ const newIndex = currentMatchIndex === matches.length - 1 ? 0 : currentMatchIndex + 1;
152406
+ dispatch({ type: "SET_CURRENT_MATCH_INDEX", payload: newIndex });
152407
+ navigateTo(matches, newIndex);
152408
+ }, [matches, currentMatchIndex, navigateTo]);
152409
+ const handleKeyDown = reactExports.useCallback(
152410
+ (e2) => {
152411
+ if (e2.key === "Escape") {
152412
+ setIsOpen(false);
152413
+ }
152414
+ if (e2.key === "Enter") {
152415
+ if (e2.shiftKey) {
152416
+ goToPrev();
152417
+ } else {
152418
+ goToNext();
152419
+ }
152420
+ e2.preventDefault();
152421
+ e2.stopPropagation();
152422
+ }
152423
+ },
152424
+ [goToPrev, goToNext]
152425
+ );
152426
+ reactExports.useEffect(() => {
152427
+ if (!searched || !searchText.trim()) return;
152428
+ runSearch(searchText);
152429
+ runFeatureSearch(searchText);
152430
+ }, [
152431
+ dnaOrAA,
152432
+ ambiguousOrLiteral,
152433
+ mismatchesAllowed,
152434
+ runSearch,
152435
+ runFeatureSearch,
152436
+ searched,
152437
+ searchText
152438
+ ]);
152439
+ reactExports.useEffect(() => {
152440
+ if (searchText.trim().length < 1) setHighlightAll(false);
152441
+ }, [searchText]);
152442
+ const prevHighlightAll = reactExports.useRef(highlightAll);
152443
+ reactExports.useEffect(() => {
152444
+ if (prevHighlightAll.current !== highlightAll) {
152445
+ prevHighlightAll.current = highlightAll;
152446
+ if (matches.length) buildMatchLayers(matches, currentMatchIndex);
152447
+ }
152448
+ }, [highlightAll, matches, currentMatchIndex, buildMatchLayers]);
152449
+ const hasMatches = matches.length > 0;
152450
+ const handleChange = reactExports.useCallback(
152451
+ (e2) => {
152452
+ const value = e2.target.value;
152453
+ dispatch({ type: "SET_SEARCH_TEXT", payload: value });
152454
+ debouncedSearch(value, runSearch, runFeatureSearch);
152455
+ },
152456
+ [debouncedSearch, runSearch, runFeatureSearch]
152457
+ );
152458
+ const handleFeatureClick = reactExports.useCallback((featureMatch) => {
152459
+ updateCaretPosition({
152460
+ start: featureMatch.alignmentStart,
152461
+ end: featureMatch.alignmentEnd
152462
+ });
152463
+ setTimeout(() => {
152464
+ scrollToAlignmentSelection();
152465
+ }, 0);
152466
+ }, []);
152467
+ const matchCounter = /* @__PURE__ */ React.createElement(
152468
+ "span",
152469
+ {
152470
+ style: {
152471
+ marginRight: 3,
152472
+ color: "lightgrey",
152473
+ fontSize: "0.9em",
152474
+ whiteSpace: "nowrap"
152475
+ }
152476
+ },
152477
+ hasMatches ? currentMatchIndex + 1 : 0,
152478
+ "/",
152479
+ matches.length
152480
+ );
152481
+ const inlineNavEl = /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center" } }, !isExpanded && /* @__PURE__ */ React.createElement(
152482
+ Popover,
152483
+ {
152484
+ autoFocus: false,
152485
+ enforceFocus: false,
152486
+ isOpen: isPopoverOpen,
152487
+ onInteraction: setIsPopoverOpen,
152488
+ position: Position.TOP,
152489
+ content: /* @__PURE__ */ React.createElement(
152490
+ "div",
152491
+ {
152492
+ className: "ve-find-options-popover",
152493
+ style: {
152494
+ display: "flex",
152495
+ flexDirection: "column",
152496
+ paddingLeft: 20,
152497
+ paddingBottom: 10,
152498
+ paddingTop: 10,
152499
+ paddingRight: 20,
152500
+ gap: 6
152501
+ }
152502
+ },
152503
+ /* @__PURE__ */ React.createElement(
152504
+ FindOptionsPanel,
152505
+ {
152506
+ dnaOrAA,
152507
+ ambiguousOrLiteral,
152508
+ mismatchesAllowed,
152509
+ searchText,
152510
+ matches,
152511
+ dispatch,
152512
+ highlightAll,
152513
+ setHighlightAll,
152514
+ isExpanded,
152515
+ onToggleExpanded: handleToggleExpanded
152516
+ }
152517
+ )
152518
+ ),
152519
+ target: /* @__PURE__ */ React.createElement(Button, { minimal: true, icon: "wrench", "data-tip": "Options" })
152520
+ }
152521
+ ), matchCounter, /* @__PURE__ */ React.createElement(
152522
+ Button,
152523
+ {
152524
+ minimal: true,
152525
+ small: true,
152526
+ icon: "caret-left",
152527
+ "data-tip": "Previous",
152528
+ disabled: !hasMatches,
152529
+ onClick: goToPrev
152530
+ }
152531
+ ), /* @__PURE__ */ React.createElement(
152532
+ Button,
152533
+ {
152534
+ minimal: true,
152535
+ small: true,
152536
+ icon: "caret-right",
152537
+ "data-tip": "Next",
152538
+ disabled: !hasMatches,
152539
+ onClick: goToNext
152540
+ }
152541
+ ), /* @__PURE__ */ React.createElement(
152542
+ Button,
152543
+ {
152544
+ minimal: true,
152545
+ small: true,
152546
+ "data-tip": "Close (Esc)",
152547
+ icon: "small-cross",
152548
+ onClick: /* @__PURE__ */ __name(() => setIsOpen(false), "onClick")
152549
+ }
152550
+ ));
152551
+ const expandedNavEl = /* @__PURE__ */ React.createElement("span", { style: { display: "flex", alignItems: "center" } }, matchCounter, /* @__PURE__ */ React.createElement(
152552
+ Button,
152553
+ {
152554
+ minimal: true,
152555
+ small: true,
152556
+ icon: "caret-up",
152557
+ disabled: !hasMatches,
152558
+ onClick: goToPrev
152559
+ }
152560
+ ), /* @__PURE__ */ React.createElement(
152561
+ Button,
152562
+ {
152563
+ minimal: true,
152564
+ small: true,
152565
+ icon: "caret-down",
152566
+ disabled: !hasMatches,
152567
+ onClick: goToNext
152568
+ }
152569
+ ));
152570
+ if (!isOpen2) {
152571
+ return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(
152572
+ Button,
152573
+ {
152574
+ minimal: true,
152575
+ small: true,
152576
+ intent: "primary",
152577
+ icon: "search",
152578
+ rightIcon: "caret-right",
152579
+ "data-tip": "Search",
152580
+ onClick: /* @__PURE__ */ __name(() => setIsOpen(true), "onClick")
152581
+ }
152582
+ ));
152583
+ }
152584
+ const annotationPopoverOpen = searched && featureMatches.length > 0;
152585
+ const inputEl = /* @__PURE__ */ React.createElement(
152586
+ InputGroup,
152587
+ {
152588
+ className: "tg-find-tool-input alignment-search-bar",
152589
+ leftIcon: "search",
152590
+ placeholder: "Search...",
152591
+ autoFocus: true,
152592
+ value: searchText,
152593
+ onChange: handleChange,
152594
+ onKeyDown: handleKeyDown,
152595
+ rightElement: inlineNavEl
152596
+ }
152597
+ );
152598
+ return /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, !isExpanded && /* @__PURE__ */ React.createElement(
152599
+ Popover,
152600
+ {
152601
+ autoFocus: false,
152602
+ enforceFocus: false,
152603
+ modifiers: {
152604
+ arrow: false
152605
+ },
152606
+ position: Position.BOTTOM,
152607
+ isOpen: annotationPopoverOpen,
152608
+ content: /* @__PURE__ */ React.createElement(
152609
+ AnnotationResultsComp,
152610
+ {
152611
+ featureMatches,
152612
+ onClickMatch: handleFeatureClick
152613
+ }
152614
+ ),
152615
+ target: inputEl
152616
+ }
152617
+ ), isExpanded && /* @__PURE__ */ React.createElement(
152618
+ "div",
152619
+ {
152620
+ style: {
152621
+ position: "absolute",
152622
+ top: 0,
152623
+ left: 0,
152624
+ padding: 10,
152625
+ paddingBottom: 25,
152626
+ display: "flex",
152627
+ alignItems: "flex-start",
152628
+ gap: 10,
152629
+ zIndex: 5e4,
152630
+ background: "white",
152631
+ boxShadow: "0 2px 8px rgba(0,0,0,0.2)",
152632
+ borderRadius: 3
152633
+ }
152634
+ },
152635
+ /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, /* @__PURE__ */ React.createElement(
152636
+ TextArea,
152637
+ {
152638
+ autoFocus: true,
152639
+ placeholder: "Search sequences and annotations...",
152640
+ value: searchText,
152641
+ onChange: handleChange,
152642
+ onKeyDown: handleKeyDown,
152643
+ style: { resize: "vertical", width: 350, height: 190 }
152644
+ }
152645
+ ), annotationPopoverOpen && /* @__PURE__ */ React.createElement(
152646
+ AnnotationResultsComp,
152647
+ {
152648
+ featureMatches,
152649
+ onClickMatch: handleFeatureClick
152650
+ }
152651
+ )),
152652
+ /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 5 } }, expandedNavEl, /* @__PURE__ */ React.createElement(
152653
+ FindOptionsPanel,
152654
+ {
152655
+ dnaOrAA,
152656
+ ambiguousOrLiteral,
152657
+ mismatchesAllowed,
152658
+ searchText,
152659
+ matches,
152660
+ dispatch,
152661
+ highlightAll,
152662
+ setHighlightAll,
152663
+ isExpanded,
152664
+ onToggleExpanded: handleToggleExpanded
152665
+ }
152666
+ )),
152667
+ /* @__PURE__ */ React.createElement(
152668
+ Button,
152669
+ {
152670
+ minimal: true,
152671
+ style: { position: "absolute", bottom: 0, right: 0 },
152672
+ onClick: /* @__PURE__ */ __name(() => setIsOpen(false), "onClick"),
152673
+ icon: "cross"
152674
+ }
152675
+ )
152676
+ ));
152677
+ }
152678
+ __name(AlignmentSearchBar, "AlignmentSearchBar");
152679
+ function AnnotationResultsComp({ featureMatches, onClickMatch }) {
152680
+ const byType = {};
152681
+ ANNOTATION_TYPES.forEach((type2) => {
152682
+ byType[type2] = [];
152683
+ });
152684
+ featureMatches.forEach((match) => {
152685
+ if (byType[match.type]) {
152686
+ byType[match.type].push(match);
152687
+ }
152688
+ });
152689
+ const featureColorMap = getFeatureToColorMap({ includeHidden: true });
152690
+ return /* @__PURE__ */ React.createElement("div", { className: "veAnnotationFindMatches" }, ANNOTATION_TYPES.map((type2) => {
152691
+ const anns = byType[type2];
152692
+ if (!anns.length) return null;
152693
+ const showing = anns.slice(0, 10);
152694
+ return /* @__PURE__ */ React.createElement("div", { key: type2 }, /* @__PURE__ */ React.createElement("div", { className: "veAnnotationFoundType" }, anns.length, " ", getSingular(type2), " match", anns.length > 1 ? "es" : null, anns.length > 10 ? ` (only showing 10)` : null, ":"), /* @__PURE__ */ React.createElement("div", null, showing.map((match, i2) => {
152695
+ const { annotation } = match;
152696
+ const annotationColor = type2 === "parts" ? "#ac68cc" : annotation.color || featureColorMap[annotation.type];
152697
+ return /* @__PURE__ */ React.createElement(
152698
+ "div",
152699
+ {
152700
+ key: i2,
152701
+ onClick: /* @__PURE__ */ __name(() => onClickMatch(match), "onClick"),
152702
+ className: "veAnnotationFoundResult"
152703
+ },
152704
+ /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(
152705
+ "div",
152706
+ {
152707
+ style: {
152708
+ background: annotationColor,
152709
+ height: 15,
152710
+ width: 15,
152711
+ marginRight: 3
152712
+ }
152713
+ }
152714
+ ), annotation.name),
152715
+ /* @__PURE__ */ React.createElement("div", { className: "veAnnotationFoundResultRange" }, annotation.start + 1, "-", annotation.end + 1)
152716
+ );
152717
+ })));
152718
+ }));
152719
+ }
152720
+ __name(AnnotationResultsComp, "AnnotationResultsComp");
152721
+ function FindOptionsPanel({
152722
+ dnaOrAA,
152723
+ ambiguousOrLiteral,
152724
+ mismatchesAllowed,
152725
+ searchText,
152726
+ matches,
152727
+ dispatch,
152728
+ highlightAll,
152729
+ setHighlightAll,
152730
+ isExpanded,
152731
+ onToggleExpanded
152732
+ }) {
152733
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
152734
+ TgHTMLSelect,
152735
+ {
152736
+ options: [
152737
+ { label: "DNA", value: "DNA" },
152738
+ { label: "Amino Acids", value: "AA" }
152739
+ ],
152740
+ value: dnaOrAA,
152741
+ onChange: /* @__PURE__ */ __name((e2) => dispatch({ type: "SET_DNA_OR_AA", payload: e2.target.value }), "onChange")
152742
+ }
152743
+ ), /* @__PURE__ */ React.createElement("div", { style: { display: "flex" } }, /* @__PURE__ */ React.createElement(
152744
+ TgHTMLSelect,
152745
+ {
152746
+ options: [
152747
+ { label: "Literal", value: "LITERAL" },
152748
+ { label: "Ambiguous", value: "AMBIGUOUS" }
152749
+ ],
152750
+ value: ambiguousOrLiteral,
152751
+ onChange: /* @__PURE__ */ __name((e2) => dispatch({
152752
+ type: "SET_AMBIGUOUS_OR_LITERAL",
152753
+ payload: e2.target.value
152754
+ }), "onChange")
152755
+ }
152756
+ ), /* @__PURE__ */ React.createElement(InfoHelper, { style: { marginLeft: 10 } }, /* @__PURE__ */ React.createElement("div", null, "Ambiguous substitutions:", /* @__PURE__ */ React.createElement("div", { style: { display: "flex", fontSize: 12 } }, /* @__PURE__ */ React.createElement("div", { style: { marginRight: 20 } }, /* @__PURE__ */ React.createElement("div", { style: { fontSize: 14, marginBottom: 4, marginTop: 5 } }, "DNA:"), /* @__PURE__ */ React.createElement("div", null, "M: AC"), /* @__PURE__ */ React.createElement("div", null, "R: AG"), /* @__PURE__ */ React.createElement("div", null, "W: AT"), /* @__PURE__ */ React.createElement("div", null, "S: CG"), /* @__PURE__ */ React.createElement("div", null, "Y: CT"), /* @__PURE__ */ React.createElement("div", null, "K: GT"), /* @__PURE__ */ React.createElement("div", null, "V: ACG"), /* @__PURE__ */ React.createElement("div", null, "H: ACT"), /* @__PURE__ */ React.createElement("div", null, "D: AGT"), /* @__PURE__ */ React.createElement("div", null, "B: CGT"), /* @__PURE__ */ React.createElement("div", null, "X: GATC"), /* @__PURE__ */ React.createElement("div", null, "N: GATC"), /* @__PURE__ */ React.createElement("div", null, "*: any")), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { fontSize: 14, marginBottom: 4, marginTop: 5 } }, "AA:"), /* @__PURE__ */ React.createElement("div", null, "B: ND"), /* @__PURE__ */ React.createElement("div", null, "J: IL"), /* @__PURE__ */ React.createElement("div", null, "X: ACDEFGHIKLMNPQRSTVWY"), /* @__PURE__ */ React.createElement("div", null, "Z: QE"), /* @__PURE__ */ React.createElement("div", null, "*: any")))))), /* @__PURE__ */ React.createElement(
152757
+ "div",
152758
+ {
152759
+ style: {
152760
+ marginTop: "8px",
152761
+ display: "flex",
152762
+ flexDirection: "row",
152763
+ gap: "3px",
152764
+ alignItems: "center"
152765
+ }
152766
+ },
152767
+ /* @__PURE__ */ React.createElement("label", null, "Mismatches Allowed:"),
152768
+ /* @__PURE__ */ React.createElement(
152769
+ NumericInput,
152770
+ {
152771
+ min: 0,
152772
+ max: 10,
152773
+ className: "tg-mismatches-allowed-input",
152774
+ style: { width: "60px" },
152775
+ value: mismatchesAllowed,
152776
+ disabled: dnaOrAA !== "DNA" || ambiguousOrLiteral !== "LITERAL",
152777
+ onValueChange: /* @__PURE__ */ __name((value) => dispatch({
152778
+ type: "SET_MISMATCHES_ALLOWED",
152779
+ payload: Number.parseInt(value, 10) || 0
152780
+ }), "onValueChange")
152781
+ }
152782
+ ),
152783
+ /* @__PURE__ */ React.createElement(InfoHelper, { style: { marginLeft: 10 } }, /* @__PURE__ */ React.createElement("div", null, "Number of mismatches allowed when searching DNA sequences with literal matching.", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("br", null), "Higher values may slow down search performance."))
152784
+ ), /* @__PURE__ */ React.createElement(
152785
+ Switch,
152786
+ {
152787
+ checked: highlightAll,
152788
+ onChange: /* @__PURE__ */ __name(() => setHighlightAll((v2) => !v2), "onChange"),
152789
+ disabled: searchText.trim().length < 2 || matches.length > MAX_MATCHES_DISPLAYED
152790
+ },
152791
+ /* @__PURE__ */ React.createElement(
152792
+ Tooltip,
152793
+ {
152794
+ disabled: matches.length <= MAX_MATCHES_DISPLAYED,
152795
+ content: `Disabled because there are >${MAX_MATCHES_DISPLAYED} matches`
152796
+ },
152797
+ "Highlight All"
152798
+ )
152799
+ ), /* @__PURE__ */ React.createElement(Switch, { checked: isExpanded, onChange: onToggleExpanded }, "Expanded"));
152800
+ }
152801
+ __name(FindOptionsPanel, "FindOptionsPanel");
151955
152802
  const AlignmentVisibilityTool = pure(/* @__PURE__ */ __name(function AlignmentVisibilityTool2(props) {
151956
152803
  return /* @__PURE__ */ React.createElement(
151957
152804
  Popover,
@@ -165135,7 +165982,6 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
165135
165982
  const PropertySidePanel = /* @__PURE__ */ __name(({ properties: properties2, setProperties, style: style2 }) => {
165136
165983
  const sidebarRef = React.useRef(null);
165137
165984
  const [mismatchesCount, setMismatchesCount] = React.useState(0);
165138
- const [mismatchesInRange, setMismatchesInRange] = React.useState(0);
165139
165985
  const { track, isOpen: isOpen2, selection, isPairwise } = properties2;
165140
165986
  const getSequenceInRegion = reactExports.useCallback(() => {
165141
165987
  var _a2, _b2;
@@ -165154,6 +166000,30 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
165154
166000
  if (!Array.isArray(tr)) return [];
165155
166001
  return isPairwise ? tr.filter((m2) => (m2 == null ? void 0 : m2.color) === "red") : tr;
165156
166002
  }, [track, mismatchKey, isPairwise]);
166003
+ const mismatchSchema = reactExports.useMemo(
166004
+ () => ({
166005
+ fields: [
166006
+ {
166007
+ path: "start",
166008
+ type: "number",
166009
+ displayName: "Start",
166010
+ render: /* @__PURE__ */ __name((val2) => val2 + 1, "render")
166011
+ },
166012
+ {
166013
+ path: "end",
166014
+ type: "number",
166015
+ displayName: "End",
166016
+ render: /* @__PURE__ */ __name((val2) => val2 + 1, "render")
166017
+ }
166018
+ ]
166019
+ }),
166020
+ []
166021
+ );
166022
+ const mismatchEntities = reactExports.useMemo(() => {
166023
+ return (trackMismatches || []).map((m2, i2) => __spreadProps(__spreadValues({}, m2), {
166024
+ id: i2.toString()
166025
+ }));
166026
+ }, [trackMismatches]);
165157
166027
  reactExports.useEffect(() => {
165158
166028
  if (!isOpen2 || sidebarRef.current === null || !track) {
165159
166029
  return;
@@ -165171,21 +166041,6 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
165171
166041
  }
165172
166042
  });
165173
166043
  setMismatchesCount(mismatchCount);
165174
- setMismatchesInRange(mismatchCount);
165175
- if (selection && selection.start > -1 && selection.end > -1) {
165176
- let count2 = 0;
165177
- trackMismatches == null ? void 0 : trackMismatches.forEach((tm) => {
165178
- if (tm === null || tm.start === null || tm.end === null) {
165179
- return;
165180
- }
165181
- const overlapStart = Math.max(tm.start, selection.start);
165182
- const overlapEnd = Math.min(tm.end, selection.end);
165183
- if (overlapEnd >= overlapStart) {
165184
- count2 += overlapEnd - overlapStart + 1;
165185
- }
165186
- });
165187
- setMismatchesInRange(count2);
165188
- }
165189
166044
  }, [isOpen2, track, selection, trackMismatches]);
165190
166045
  const aminoFreq = reactExports.useMemo(() => {
165191
166046
  var _a2, _b2;
@@ -165221,7 +166076,7 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
165221
166076
  width: "100%"
165222
166077
  }
165223
166078
  }
165224
- ), /* @__PURE__ */ React.createElement("h5", null, "Track Properties"), /* @__PURE__ */ React.createElement("div", { className: "bp3-tab-panel" }, /* @__PURE__ */ React.createElement(RowItem, { item: name2, title: "Name" }), /* @__PURE__ */ React.createElement(RowItem, { item: isProtein2 ? proteinSize : size2, title: "Length" }), /* @__PURE__ */ React.createElement(
166079
+ ), /* @__PURE__ */ React.createElement(HeaderItem, { title: "Track Properties" }), /* @__PURE__ */ React.createElement("div", { className: "bp3-tab-panel" }, /* @__PURE__ */ React.createElement(RowItem, { item: name2, title: "Name" }), /* @__PURE__ */ React.createElement(RowItem, { item: isProtein2 ? proteinSize : size2, title: "Length" }), /* @__PURE__ */ React.createElement(
165225
166080
  RowItem,
165226
166081
  {
165227
166082
  item: molecularWeight == null ? void 0 : molecularWeight.toFixed(2),
@@ -165235,18 +166090,45 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
165235
166090
  title: "Extinction Coefficient"
165236
166091
  }
165237
166092
  )), /* @__PURE__ */ React.createElement(
165238
- RowItem,
165239
- {
165240
- item: `${mismatchesInRange}/${mismatchesCount}`,
165241
- title: "Mismatches"
165242
- }
165243
- ), /* @__PURE__ */ React.createElement(
165244
166093
  RowItem,
165245
166094
  {
165246
166095
  item: selection && selection.start > -1 ? /* @__PURE__ */ React.createElement("span", null, selection.start + 1, " - ", selection.end + 1) : /* @__PURE__ */ React.createElement("span", null, "1 - ", isProtein2 ? proteinSize : size2),
165247
166096
  title: "Region"
165248
166097
  }
165249
- )), /* @__PURE__ */ React.createElement("h5", null, isProtein2 ? "Amino Acid" : "Base Pair", " Frequencies"), /* @__PURE__ */ React.createElement("div", { className: "sidebar-table" }, /* @__PURE__ */ React.createElement("div", { className: "sidebar-row" }, /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, isProtein2 ? "Amino Acid" : "Base"), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, "Count"), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, "Percentage")), frequencyEntries.map(([aa, data], idx) => {
166098
+ ), /* @__PURE__ */ React.createElement(HeaderItem, { title: `Mismatches (${mismatchesCount})` }), trackMismatches && trackMismatches.length > 0 && /* @__PURE__ */ React.createElement(
166099
+ "div",
166100
+ {
166101
+ style: {
166102
+ margin: "0px 10px"
166103
+ }
166104
+ },
166105
+ /* @__PURE__ */ React.createElement(
166106
+ WrappedDT,
166107
+ {
166108
+ formName: "mismatchesTable",
166109
+ isSimple: true,
166110
+ noHeader: true,
166111
+ noFooter: true,
166112
+ withSearch: false,
166113
+ noPadding: true,
166114
+ compact: true,
166115
+ maxHeight: 150,
166116
+ entities: mismatchEntities,
166117
+ schema: mismatchSchema,
166118
+ onRowClick: /* @__PURE__ */ __name((e2, row) => {
166119
+ updateCaretPosition({ start: row.start, end: row.end });
166120
+ setTimeout(() => {
166121
+ scrollToAlignmentSelection();
166122
+ }, 0);
166123
+ }, "onRowClick")
166124
+ }
166125
+ )
166126
+ )), /* @__PURE__ */ React.createElement(
166127
+ HeaderItem,
166128
+ {
166129
+ title: `${isProtein2 ? "Amino Acid" : "Base Pair"} Frequencies`
166130
+ }
166131
+ ), /* @__PURE__ */ React.createElement("div", { className: "sidebar-table" }, /* @__PURE__ */ React.createElement("div", { className: "sidebar-row" }, /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, isProtein2 ? "Amino Acid" : "Base"), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, "Count"), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, "Percentage")), frequencyEntries.map(([aa, data], idx) => {
165250
166132
  return /* @__PURE__ */ React.createElement("div", { className: `sidebar-row property-amino-acid-${idx}` }, /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, aa, " ", isProtein2 ? `(${aminoAcidShortNames[aa]})` : ""), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, data.count), /* @__PURE__ */ React.createElement("div", { className: "sidebar-cell" }, data.percentage.toFixed(1), "%"));
165251
166133
  })));
165252
166134
  } else {
@@ -165303,11 +166185,29 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
165303
166185
  );
165304
166186
  }, "PropertySidePanel");
165305
166187
  function RowItem({ item, title, units }) {
165306
- if (!item) return;
166188
+ if (item == null) {
166189
+ return null;
166190
+ }
165307
166191
  const propertyClass = title.split(" ").join("-").toLowerCase();
165308
- return /* @__PURE__ */ React.createElement("div", { className: `ve-flex-row property-${propertyClass}` }, /* @__PURE__ */ React.createElement("div", { className: "ve-column-left" }, title), /* @__PURE__ */ React.createElement("div", { className: "ve-column-right" }, item, " ", units != null ? units : ""));
166192
+ return /* @__PURE__ */ React.createElement("div", { className: `ve-flex-row property-${propertyClass}` }, /* @__PURE__ */ React.createElement("div", { style: { fontWeight: "bold" }, className: "ve-column-left" }, title), /* @__PURE__ */ React.createElement("div", { className: "ve-column-right" }, item, " ", units != null ? units : ""));
165309
166193
  }
165310
166194
  __name(RowItem, "RowItem");
166195
+ const HeaderItem = /* @__PURE__ */ __name(({ title }) => {
166196
+ return /* @__PURE__ */ React.createElement(
166197
+ "h5",
166198
+ {
166199
+ style: {
166200
+ margin: 0,
166201
+ fontSize: 15,
166202
+ fontWeight: "bold",
166203
+ textAlign: "center",
166204
+ padding: "5px 0",
166205
+ borderBottom: "1px solid #f1f1f1"
166206
+ }
166207
+ },
166208
+ title
166209
+ );
166210
+ }, "HeaderItem");
165311
166211
  function calculatePairwiseIdentity(seq1, seq2, excludeGaps = true) {
165312
166212
  if (seq1.length !== seq2.length) {
165313
166213
  throw new Error("Sequences must be aligned (same length)");
@@ -165703,6 +166603,7 @@ Part of ${annotation.translationType} Translation from BPs ${annotation.start +
165703
166603
  const [tempTrimBefore, setTempTrimBefore] = reactExports.useState({});
165704
166604
  const [tempTrimAfter, setTempTrimAfter] = reactExports.useState({});
165705
166605
  const [tempTrimmingCaret, setTempTrimmingCaret] = reactExports.useState({});
166606
+ const [searchMatchLayers, setSearchMatchLayers] = React.useState([]);
165706
166607
  const bindOutsideChangeHelper = reactExports.useRef({});
165707
166608
  const alignmentHolder = reactExports.useRef(null);
165708
166609
  const alignmentHolderTop = reactExports.useRef(null);
@@ -166427,7 +167328,10 @@ ${seqDataToCopy}\r
166427
167328
  alignmentData,
166428
167329
  chromatogramData
166429
167330
  }) : linearViewOptions)), {
166430
- additionalSelectionLayers,
167331
+ additionalSelectionLayers: [
167332
+ ...additionalSelectionLayers || [],
167333
+ ...searchMatchLayers || []
167334
+ ],
166431
167335
  dimensions: {
166432
167336
  width: linearViewWidth
166433
167337
  },
@@ -166955,7 +167859,7 @@ ${seqDataToCopy}\r
166955
167859
  display: "flex",
166956
167860
  minHeight: "32px",
166957
167861
  width: "100%",
166958
- flexWrap: "nowrap",
167862
+ flexWrap: "wrap",
166959
167863
  flexDirection: "row",
166960
167864
  flex: "0 0 auto"
166961
167865
  },
@@ -167076,6 +167980,15 @@ ${seqDataToCopy}\r
167076
167980
  currentPairwiseAlignmentIndex
167077
167981
  }, alignmentVisibilityToolOptions)
167078
167982
  ),
167983
+ /* @__PURE__ */ React.createElement(
167984
+ AlignmentSearchBar,
167985
+ {
167986
+ alignmentTracks,
167987
+ id: id2,
167988
+ setSearchMatchLayers
167989
+ }
167990
+ ),
167991
+ /* @__PURE__ */ React.createElement(FindMismatches, { alignmentJson: alignmentTracks, id: id2 }),
167079
167992
  additionalTopEl,
167080
167993
  saveMessage && /* @__PURE__ */ React.createElement(
167081
167994
  "div",
@@ -172365,108 +173278,6 @@ ${seqDataToCopy}\r
172365
173278
  ]
172366
173279
  };
172367
173280
  const DigestTool$1 = withEditorInteractions(DigestTool);
172368
- const _Mismatches = class _Mismatches extends React.Component {
172369
- constructor() {
172370
- super(...arguments);
172371
- __publicField(this, "getGapMap", /* @__PURE__ */ __name((sequence2) => {
172372
- const gapMap = [0];
172373
- sequence2.split("").forEach((char) => {
172374
- if (char === "-") {
172375
- gapMap[Math.max(0, gapMap.length - 1)] = (gapMap[Math.max(0, gapMap.length - 1)] || 0) + 1;
172376
- } else {
172377
- gapMap.push(gapMap[gapMap.length - 1] || 0);
172378
- }
172379
- });
172380
- return gapMap;
172381
- }, "getGapMap"));
172382
- __publicField(this, "getMismatchList", /* @__PURE__ */ __name((alignmentData, mismatches) => {
172383
- const mismatchList = [];
172384
- let getGaps = /* @__PURE__ */ __name(() => ({
172385
- gapsBefore: 0,
172386
- gapsInside: 0
172387
- }), "getGaps");
172388
- const gapMap = this.getGapMap(alignmentData.sequence);
172389
- getGaps = /* @__PURE__ */ __name((rangeOrCaretPosition) => {
172390
- if (typeof rangeOrCaretPosition !== "object") {
172391
- return {
172392
- gapsBefore: gapMap[Math.min(rangeOrCaretPosition, gapMap.length - 1)]
172393
- };
172394
- }
172395
- const { start: start2, end: end2 } = rangeOrCaretPosition;
172396
- const toReturn = {
172397
- gapsBefore: gapMap[start2],
172398
- gapsInside: gapMap[Math.min(end2, gapMap.length - 1)] - gapMap[Math.min(start2, gapMap.length - 1)]
172399
- };
172400
- return toReturn;
172401
- }, "getGaps");
172402
- const gapsBeforeSequence = getGaps(0).gapsBefore;
172403
- for (let mismatchI = 0; mismatchI < mismatches.length; mismatchI++) {
172404
- const mismatchEnd = mismatches[mismatchI].end;
172405
- const mismatchStart = mismatches[mismatchI].start;
172406
- const mismatchDifference = mismatchEnd - mismatchStart;
172407
- if (mismatchDifference === 0) {
172408
- mismatchList.push({
172409
- mismatches: mismatchStart + 1 - gapsBeforeSequence,
172410
- start: mismatchStart - gapsBeforeSequence,
172411
- end: mismatchStart - gapsBeforeSequence
172412
- });
172413
- } else {
172414
- for (let innerI = 0; innerI <= mismatchDifference; innerI++) {
172415
- mismatchList.push({
172416
- mismatches: mismatchStart + innerI + 1 - gapsBeforeSequence,
172417
- start: mismatchStart + innerI - gapsBeforeSequence,
172418
- end: mismatchStart + innerI - gapsBeforeSequence
172419
- });
172420
- }
172421
- }
172422
- }
172423
- return mismatchList;
172424
- }, "getMismatchList"));
172425
- }
172426
- UNSAFE_componentWillMount() {
172427
- const { alignmentData, mismatches } = this.props;
172428
- const mismatchList = this.getMismatchList(alignmentData, mismatches);
172429
- const schema2 = {
172430
- fields: [{ path: "mismatches", type: "number" }]
172431
- };
172432
- this.setState({ mismatchList, schema: schema2 });
172433
- }
172434
- render() {
172435
- const { mismatchList, schema: schema2 } = this.state;
172436
- let tableOfMismatches;
172437
- if (mismatchList.length === 0) {
172438
- tableOfMismatches = null;
172439
- } else {
172440
- tableOfMismatches = /* @__PURE__ */ React.createElement(
172441
- WrappedDT,
172442
- {
172443
- maxHeight: 168,
172444
- formName: "mismatchesTable",
172445
- isSimple: true,
172446
- compact: true,
172447
- noRouter: true,
172448
- schema: schema2,
172449
- entities: mismatchList
172450
- }
172451
- );
172452
- }
172453
- return /* @__PURE__ */ React.createElement("div", { style: { maxHeight: 180.8, overflowY: "scroll" } }, /* @__PURE__ */ React.createElement(
172454
- "div",
172455
- {
172456
- style: {
172457
- // margin: 10,
172458
- display: "flex",
172459
- flexDirection: "column",
172460
- alignItems: "center"
172461
- }
172462
- },
172463
- /* @__PURE__ */ React.createElement("div", { style: { width: 100, margin: 4 } }, tableOfMismatches)
172464
- ));
172465
- }
172466
- };
172467
- __name(_Mismatches, "Mismatches");
172468
- let Mismatches = _Mismatches;
172469
- const Mismatches$1 = withSelectedEntities("mismatchesTable")(Mismatches);
172470
173281
  function PCRTool(props) {
172471
173282
  const {
172472
173283
  sequenceData: sequenceData2,
@@ -172638,7 +173449,7 @@ ${seqDataToCopy}\r
172638
173449
  comp: PropertiesDialog$1,
172639
173450
  panelSpecificProps: ["PropertiesProps"]
172640
173451
  },
172641
- mismatches: Mismatches$1
173452
+ mismatches: FindMismatches
172642
173453
  };
172643
173454
  const reorder = /* @__PURE__ */ __name((list2, startIndex, endIndex) => {
172644
173455
  const result = Array.from(list2);
@@ -175438,18 +176249,6 @@ ${seqDataToCopy}\r
175438
176249
  window.createVectorEditor = createVectorEditor;
175439
176250
  window.createAlignmentView = createAlignmentView;
175440
176251
  window.createVersionHistoryView = createVersionHistoryView;
175441
- function getGapMap(sequence2) {
175442
- const gapMap = [0];
175443
- sequence2.split("").forEach((char) => {
175444
- if (char === "-") {
175445
- gapMap[Math.max(0, gapMap.length - 1)] = (gapMap[Math.max(0, gapMap.length - 1)] || 0) + 1;
175446
- } else {
175447
- gapMap.push(gapMap[gapMap.length - 1] || 0);
175448
- }
175449
- });
175450
- return gapMap;
175451
- }
175452
- __name(getGapMap, "getGapMap");
175453
176252
  exports2.getGaps = () => ({
175454
176253
  gapsBefore: 0,
175455
176254
  gapsInside: 0