gensplore 0.0.13 → 0.0.15

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/dist/gensplore.js CHANGED
@@ -187,7 +187,7 @@ var ue = ({ isOpen: e, onClose: t, children: n }) => /* @__PURE__ */ x("div", {
187
187
  })
188
188
  })]
189
189
  })
190
- }), de = ({ x: e, y: t, onClose: n, onCopy: r, onCopyRC: i }) => e === null || t === null ? null : /* @__PURE__ */ S("div", {
190
+ }), de = ({ x: e, y: t, onClose: n, onCopy: r, onCopyRC: i, isComparison: a = !1 }) => e === null || t === null ? null : /* @__PURE__ */ S("div", {
191
191
  className: "fixed bg-white shadow-lg border border-gray-200 rounded-md py-1 z-50",
192
192
  style: {
193
193
  left: e,
@@ -196,11 +196,11 @@ var ue = ({ isOpen: e, onClose: t, children: n }) => /* @__PURE__ */ x("div", {
196
196
  children: [/* @__PURE__ */ x("button", {
197
197
  className: "block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100",
198
198
  onClick: r,
199
- children: "Copy Selection"
199
+ children: a ? "Copy sample selection" : "Copy Selection"
200
200
  }), /* @__PURE__ */ x("button", {
201
201
  className: "block w-full text-left px-4 py-2 text-sm text-gray-700 hover:bg-gray-100",
202
202
  onClick: i,
203
- children: "Copy as Reverse Complement"
203
+ children: a ? "Copy sample as reverse complement" : "Copy as Reverse Complement"
204
204
  })]
205
205
  });
206
206
  //#endregion
@@ -2907,7 +2907,7 @@ var Pi = Re(ji), Fi = Object.assign(Mi, {
2907
2907
  Panel: Ni,
2908
2908
  Title: Pi,
2909
2909
  Description: dt
2910
- }), Ii = "function e(e,t){if(!t||typeof t.sequence!=`string`)throw Error(`Expected an aligned DNA sequence.`);let n=t.sequence.toUpperCase();if(!e.length||n.length!==e.length)throw Error(`Aligned sequence length must match the reference.`);if(/[^ACGTRYSWKMBDHVN-]/.test(n))throw Error(`Aligned sequences must contain IUPAC DNA bases or deletion gaps (-).`);let r=[],i=0;for(let t=0;t<n.length;){if(n[t]===e[t]){t++;continue}let a=n[t]===`-`?`Deletion`:/[^ACGT]/.test(n[t]+e[t])?`Ambiguous`:`Substitution`,o=t+1;if(a===`Deletion`||a===`Ambiguous`)for(;o<n.length&&n[o]!==e[o]&&(a===`Deletion`?n[o]===`-`:n[o]!==`-`&&/[^ACGT]/.test(n[o]+e[o]));)o++;r.push({type:a,start:t,end:o,reference:e.slice(t,o),alternative:a===`Deletion`?``:n.slice(t,o)}),i+=o-t,t=o}let a=new Set;for(let n of t.insertions||[]){let t=n.position,o=typeof n.sequence==`string`?n.sequence.toUpperCase():``;if(!Number.isInteger(t)||t<0||t>e.length||a.has(t))throw Error(`Insertions need unique integer positions from 0 to the reference length.`);if(!o||/[^ACGTRYSWKMBDHVN]/.test(o))throw Error(`Insertions must contain ungapped IUPAC DNA bases.`);a.add(t),r.push({type:`Insertion`,start:t,end:t,reference:``,alternative:o}),i+=o.length}return r.sort((e,t)=>e.start-t.start||e.end-t.end),{name:t.name||`Alternative`,distance:i,differences:r}}const t=e=>{switch(e){case`TTT`:case`TTC`:return`F`;case`TTA`:case`TTG`:case`CTT`:case`CTC`:case`CTA`:case`CTG`:return`L`;case`ATT`:case`ATC`:case`ATA`:return`I`;case`ATG`:return`M`;case`GTT`:case`GTC`:case`GTA`:case`GTG`:return`V`;case`TCT`:case`TCC`:case`TCA`:case`TCG`:case`AGT`:case`AGC`:return`S`;case`CCT`:case`CCC`:case`CCA`:case`CCG`:return`P`;case`ACT`:case`ACC`:case`ACA`:case`ACG`:return`T`;case`GCT`:case`GCC`:case`GCA`:case`GCG`:return`A`;case`TAT`:case`TAC`:return`Y`;case`TAA`:case`TAG`:case`TGA`:return`*`;case`CAT`:case`CAC`:return`H`;case`CAA`:case`CAG`:return`Q`;case`AAT`:case`AAC`:return`N`;case`AAA`:case`AAG`:return`K`;case`GAT`:case`GAC`:return`D`;case`GAA`:case`GAG`:return`E`;case`TGT`:case`TGC`:return`C`;case`TGG`:return`W`;case`CGT`:case`CGC`:case`CGA`:case`CGG`:case`AGA`:case`AGG`:return`R`;case`GGT`:case`GGC`:case`GGA`:case`GGG`:return`G`;default:return`X`}};function n(e){let t=e.trim().split(/\\r?\\n/);if(!t[0]?.startsWith(`>`))throw Error(`Expected a FASTA header starting with >.`);if(t.slice(1).some(e=>e.startsWith(`>`)))throw Error(`Please supply exactly one FASTA record.`);let n=t.slice(1).join(``).replace(/\\s/g,``).toUpperCase();if(!n||/[^ACGTRYSWKMBDHVN]/.test(n))throw Error(`Expected an ungapped DNA sequence (IUPAC bases).`);return{name:t[0].slice(1).trim()||`Alternative`,sequence:n}}function r(e,t,n=128){let r=e.length,i=t.length;if(!r||!i)throw Error(`Both sequences must contain bases.`);if(Math.max(r,i)>1e5)throw Error(`Comparison supports sequences up to 100,000 bases.`);let a=()=>Error(`Sequences exceed the ${n}-edit comparison limit. Use complete sequences in the same orientation and with the same starting point.`);if(Math.abs(r-i)>n)throw a();let o=2*n+1,s=n+1,c=s*s,l=new Uint8Array((r+1)*o),u=(e,t,n)=>e<=t&&e<=n?0:t<=n?1:2,d=new Uint32Array(o*3).fill(c);d[n*3]=0;for(let e=1;e<=Math.min(i,n);e++)d[(e+n)*3+2]=e*s+1,l[e+n]=(e===1?0:2)<<4;for(let a=1;a<=r;a++){let r=new Uint32Array(o*3).fill(c);for(let f=Math.max(0,a-n);f<=Math.min(i,a+n);f++){let i=f-a+n,p=i*3;if(f===0){r[p+1]=a*s+1,l[a*o+i]=(a===1?0:1)<<2;continue}let m=u(d[p],d[p+1],d[p+2]);r[p]=Math.min(c,d[p+m]+(e[a-1]===t[f-1]?0:s));let h=0,g=0;if(i+1<o){let e=p+3,t=d[e]+s+1,n=d[e+1]+s,i=d[e+2]+s+1;h=u(t,n,i),r[p+1]=Math.min(c,t,n,i)}if(i>0){let e=p-3,t=r[e]+s+1,n=r[e+1]+s+1,i=r[e+2]+s;g=u(t,n,i),r[p+2]=Math.min(c,t,n,i)}l[a*o+i]=m|h<<2|g<<4}d=r}let f=(i-r+n)*3,p=u(d[f],d[f+1],d[f+2]),m=Math.floor(d[f+p]/s);if(m>n)throw a();let h=r,g=i,_=[];for(;h||g;){let r=l[h*o+g-h+n]>>p*2&3;p===0?_.push([e[--h],t[--g]]):p===1?_.push([e[--h],`-`]):_.push([`-`,t[--g]]),p=r}_.reverse();let v=[],y=0;for(let[e,t]of _){if(e!==t){let n=e===`-`?`Insertion`:t===`-`?`Deletion`:/[^ACGT]/.test(e+t)?`Ambiguous`:`Substitution`,r=v.at(-1);r&&r.type===n&&n!==`Substitution`&&n!==`Ambiguous`&&r.end===y?(r.reference+=e===`-`?``:e,r.alternative+=t===`-`?``:t,r.end+=e===`-`?0:1):v.push({type:n,start:y,end:y+(e===`-`?0:1),reference:e===`-`?``:e,alternative:t===`-`?``:t})}e!==`-`&&y++}return{distance:m,differences:v}}function i(e,t){return e.locations?.length?e.locations:e.start>e.end?[{start:e.start,end:t-1},{start:0,end:e.end}]:[{start:e.start,end:e.end}]}const a={A:`T`,T:`A`,C:`G`,G:`C`,R:`Y`,Y:`R`,S:`S`,W:`W`,K:`M`,M:`K`,B:`V`,V:`B`,D:`H`,H:`D`,N:`N`},o=e=>[...e].reverse().map(e=>a[e]||`N`).join(``),s=e=>{let n=``;for(let r=0;r+2<e.length;r+=3)n+=t(e.slice(r,r+3));return n},c=(e,t,n)=>{let r=e.notes?.[t];return(Array.isArray(r)?r[0]:r)??n};function l(e,t,n){if(![`CDS`,`mat_peptide`].includes(t.type))return null;let a=i(t,e.length),l=[];for(let t of a){if(!Number.isInteger(t.start)||!Number.isInteger(t.end)||t.start<0||t.end>=e.length||t.end<t.start)return{warning:`Unsupported coding location`,codons:[],changes:[]};for(let e=t.start;e<=t.end;e++)l.push(e)}t.strand<0&&l.reverse();let u=Number(c(t,`codon_start`,1))-1;if(![0,1,2].includes(u))return{warning:`Unsupported codon_start`,codons:[],changes:[]};l.splice(0,u);let d=Number(c(t,`transl_table`,1));if(![1,11].includes(d)||[`transl_except`,`ribosomal_slippage`,`exception`].some(e=>t.notes?.[e]))return{warning:`AA comparison unavailable for this translation table or exception`,codons:[],changes:[]};let f=new Map(l.map((e,t)=>[e,t])),p=e=>t.strand<0?o(e):e,m=l.map(t=>p(e[t])).join(``),h=s(m),g=[...h].map((e,t)=>({positions:l.slice(t*3,t*3+3),aminoAcid:e,codonIndex:t})),_=new Set,v=new Map,y=new Map,b=1/0,x=!1;for(let e of n)if(e.type===`Insertion`){let n=t.strand<0?e.start-1:e.start,r=f.get(n),i=t.strand<0?e.start:e.start-1;r>0&&l[r-1]===i?(y.set(r,p(e.alternative)),e.alternative.length%3&&(b=Math.min(b,r))):(f.has(n)||f.has(i))&&(x=!0)}else if(e.type===`Deletion`){let t=[];for(let n=e.start;n<e.end;n++){let e=f.get(n);e!==void 0&&(_.add(e),t.push(e))}t.length%3&&(b=Math.min(b,...t))}else for(let t=e.start;t<e.end;t++){let n=f.get(t);n!==void 0&&v.set(n,p(e.alternative[t-e.start]))}let S=``,C=[];for(let e=0;e<l.length;e++)C[e]=S.length,S+=y.get(e)||``,_.has(e)||(S+=v.get(e)??m[e]);let w=Math.floor(b/3),T=Number.isFinite(b)?h.slice(0,w):h,E=s(Number.isFinite(b)?S.slice(0,C[w*3]):S),D=[],O=e=>{let n=Math.min(e.start,Math.max(0,g.length-1)),r=g[n],i=e.start<g.length?(r?.positions[0]??l[0])+(t.strand<0?.5:-.5):(r?.positions[2]??l[0])+(t.strand<0?-.5:.5);return{...e,anchor:r?.positions[1]??l[0],...e.type===`Insertion`?{pointerPosition:i}:{},aaPosition:e.type===`Insertion`?e.start:e.start+1}};try{if(T&&E){let e=[];for(let t of r(T,E).differences){let n={...t,type:t.type===`Ambiguous`?/X/.test(t.reference+t.alternative)?`Ambiguous`:`Substitution`:t.type},r=e.at(-1);n.type===`Ambiguous`&&r?.type===`Ambiguous`&&r.end===n.start?(r.end=n.end,r.reference+=n.reference,r.alternative+=n.alternative):e.push(n)}D=e.map(O)}else(T||E)&&(D=[O({type:T?`Deletion`:`Insertion`,start:0,end:T.length,reference:T,alternative:E})])}catch{return{codons:g,changes:[],warning:`AA comparison exceeds the alignment limit`}}return Number.isFinite(b)&&D.push(O({type:`Frameshift`,start:w,end:w+1,reference:``,alternative:``})),{codons:g,changes:D,warning:x?`Insertion at a coding boundary: AA assignment is uncertain`:void 0}}function u(e,t,n){return t.map(t=>l(e,t,n))}self.onmessage=({data:t})=>{try{let i=t.alignedSequence||n(t.fasta),a=t.alignedSequence?e(t.reference,i):r(t.reference,i.sequence);self.postMessage({...a,name:i.name,proteins:u(t.reference,t.features||[],a.differences)})}catch(e){self.postMessage({error:e.message})}};", Li = typeof self < "u" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", Ii], { type: "text/javascript;charset=utf-8" });
2910
+ }), Ii = "function e(e,t){if(!t||typeof t.sequence!=`string`)throw Error(`Expected an aligned DNA sequence.`);let n=t.sequence.toUpperCase();if(!e.length||n.length!==e.length)throw Error(`Aligned sequence length must match the reference.`);if(/[^ACGTRYSWKMBDHVN-]/.test(n))throw Error(`Aligned sequences must contain IUPAC DNA bases or deletion gaps (-).`);let r=0,i=n.length;for(;r<i&&n[r]===`N`;)r++;for(;i>r&&n[i-1]===`N`;)i--;let a=r===i?{start:0,end:0}:{start:r,end:i},o=[],s=0;for(let t=a.start;t<a.end;){if(n[t]===e[t]){t++;continue}let r=n[t]===`-`?`Deletion`:/[^ACGT]/.test(n[t]+e[t])?`Ambiguous`:`Substitution`,i=t+1;if(r===`Deletion`||r===`Ambiguous`)for(;i<a.end&&n[i]!==e[i]&&(r===`Deletion`?n[i]===`-`:n[i]!==`-`&&/[^ACGT]/.test(n[i]+e[i]));)i++;o.push({type:r,start:t,end:i,reference:e.slice(t,i),alternative:r===`Deletion`?``:n.slice(t,i)}),s+=i-t,t=i}let c=new Set;for(let n of t.insertions||[]){let t=n.position,r=typeof n.sequence==`string`?n.sequence.toUpperCase():``;if(!Number.isInteger(t)||t<0||t>e.length||c.has(t))throw Error(`Insertions need unique integer positions from 0 to the reference length.`);if(!r||/[^ACGTRYSWKMBDHVN]/.test(r))throw Error(`Insertions must contain ungapped IUPAC DNA bases.`);c.add(t),o.push({type:`Insertion`,start:t,end:t,reference:``,alternative:r}),s+=r.length}return o.sort((e,t)=>e.start-t.start||e.end-t.end),{name:t.name||`Alternative`,distance:s,differences:o,coverage:a}}const t=e=>{switch(e){case`TTT`:case`TTC`:return`F`;case`TTA`:case`TTG`:case`CTT`:case`CTC`:case`CTA`:case`CTG`:return`L`;case`ATT`:case`ATC`:case`ATA`:return`I`;case`ATG`:return`M`;case`GTT`:case`GTC`:case`GTA`:case`GTG`:return`V`;case`TCT`:case`TCC`:case`TCA`:case`TCG`:case`AGT`:case`AGC`:return`S`;case`CCT`:case`CCC`:case`CCA`:case`CCG`:return`P`;case`ACT`:case`ACC`:case`ACA`:case`ACG`:return`T`;case`GCT`:case`GCC`:case`GCA`:case`GCG`:return`A`;case`TAT`:case`TAC`:return`Y`;case`TAA`:case`TAG`:case`TGA`:return`*`;case`CAT`:case`CAC`:return`H`;case`CAA`:case`CAG`:return`Q`;case`AAT`:case`AAC`:return`N`;case`AAA`:case`AAG`:return`K`;case`GAT`:case`GAC`:return`D`;case`GAA`:case`GAG`:return`E`;case`TGT`:case`TGC`:return`C`;case`TGG`:return`W`;case`CGT`:case`CGC`:case`CGA`:case`CGG`:case`AGA`:case`AGG`:return`R`;case`GGT`:case`GGC`:case`GGA`:case`GGG`:return`G`;default:return`X`}};function n(e){let t=e.trim().split(/\\r?\\n/);if(!t[0]?.startsWith(`>`))throw Error(`Expected a FASTA header starting with >.`);if(t.slice(1).some(e=>e.startsWith(`>`)))throw Error(`Please supply exactly one FASTA record.`);let n=t.slice(1).join(``).replace(/\\s/g,``).toUpperCase();if(!n||/[^ACGTRYSWKMBDHVN]/.test(n))throw Error(`Expected an ungapped DNA sequence (IUPAC bases).`);return{name:t[0].slice(1).trim()||`Alternative`,sequence:n}}function r(e,t,n=`N`,r=256,{leading:a=1/0,trailing:o=1/0}={}){if(!e.length||!t.length)throw Error(`Both sequences must contain bases.`);if(Math.max(e.length,t.length)>1e5)throw Error(`Comparison supports sequences up to 100,000 bases.`);let s=0,c=0;for(;s<t.length&&s<a&&t[s]===n;)s++;if(s===t.length)return{distance:0,differences:[],coverage:{start:0,end:0}};for(;c<t.length-s&&c<o&&t[t.length-c-1]===n;)c++;let l=e.length-c;if(s>=l)throw Error(`Terminal padding leaves no comparable reference span.`);let u=i(e.slice(s,l),t.slice(s,t.length-c),r);return{...u,coverage:{start:s,end:l},differences:u.differences.map(e=>({...e,start:e.start+s,end:e.end+s}))}}function i(e,t,n=256){let r=e.length,i=t.length;if(!r||!i)throw Error(`Both sequences must contain bases.`);if(Math.max(r,i)>1e5)throw Error(`Comparison supports sequences up to 100,000 bases.`);let a=()=>Error(`Sequences exceed the ${n}-edit comparison limit. Use complete sequences in the same orientation and with the same starting point.`);if(Math.abs(r-i)>n)throw a();let o=2*n+1,s=n+1,c=s*s,l=new Uint8Array((r+1)*o),u=(e,t,n)=>e<=t&&e<=n?0:t<=n?1:2,d=new Uint32Array(o*3).fill(c);d[n*3]=0;for(let e=1;e<=Math.min(i,n);e++)d[(e+n)*3+2]=e*s+1,l[e+n]=(e===1?0:2)<<4;for(let a=1;a<=r;a++){let r=new Uint32Array(o*3).fill(c);for(let f=Math.max(0,a-n);f<=Math.min(i,a+n);f++){let i=f-a+n,p=i*3;if(f===0){r[p+1]=a*s+1,l[a*o+i]=(a===1?0:1)<<2;continue}let m=u(d[p],d[p+1],d[p+2]);r[p]=Math.min(c,d[p+m]+(e[a-1]===t[f-1]?0:s));let h=0,g=0;if(i+1<o){let e=p+3,t=d[e]+s+1,n=d[e+1]+s,i=d[e+2]+s+1;h=u(t,n,i),r[p+1]=Math.min(c,t,n,i)}if(i>0){let e=p-3,t=r[e]+s+1,n=r[e+1]+s+1,i=r[e+2]+s;g=u(t,n,i),r[p+2]=Math.min(c,t,n,i)}l[a*o+i]=m|h<<2|g<<4}d=r}let f=(i-r+n)*3,p=u(d[f],d[f+1],d[f+2]),m=Math.floor(d[f+p]/s);if(m>n)throw a();let h=r,g=i,_=[];for(;h||g;){let r=l[h*o+g-h+n]>>p*2&3;p===0?_.push([e[--h],t[--g]]):p===1?_.push([e[--h],`-`]):_.push([`-`,t[--g]]),p=r}_.reverse();let v=[],y=0;for(let[e,t]of _){if(e!==t){let n=e===`-`?`Insertion`:t===`-`?`Deletion`:/[^ACGT]/.test(e+t)?`Ambiguous`:`Substitution`,r=v.at(-1);r&&r.type===n&&n!==`Substitution`&&n!==`Ambiguous`&&r.end===y?(r.reference+=e===`-`?``:e,r.alternative+=t===`-`?``:t,r.end+=e===`-`?0:1):v.push({type:n,start:y,end:y+(e===`-`?0:1),reference:e===`-`?``:e,alternative:t===`-`?``:t})}e!==`-`&&y++}return{distance:m,differences:v}}function a(e,t){return e.locations?.length?e.locations:e.start>e.end?[{start:e.start,end:t-1},{start:0,end:e.end}]:[{start:e.start,end:e.end}]}const o={A:`T`,T:`A`,C:`G`,G:`C`,R:`Y`,Y:`R`,S:`S`,W:`W`,K:`M`,M:`K`,B:`V`,V:`B`,D:`H`,H:`D`,N:`N`},s=e=>[...e].reverse().map(e=>o[e]||`N`).join(``),c=e=>{let n=``;for(let r=0;r+2<e.length;r+=3)n+=t(e.slice(r,r+3));return n},l=(e,t,n)=>{let r=e.notes?.[t];return(Array.isArray(r)?r[0]:r)??n};function u(e,t,n,o){if(![`CDS`,`mat_peptide`].includes(t.type))return null;let u=a(t,e.length),d=[];for(let t of u){if(!Number.isInteger(t.start)||!Number.isInteger(t.end)||t.start<0||t.end>=e.length||t.end<t.start)return{warning:`Unsupported coding location`,codons:[],changes:[]};for(let e=t.start;e<=t.end;e++)d.push(e)}t.strand<0&&d.reverse();let f=Number(l(t,`codon_start`,1))-1;if(![0,1,2].includes(f))return{warning:`Unsupported codon_start`,codons:[],changes:[]};d.splice(0,f);let p=Number(l(t,`transl_table`,1));if(![1,11].includes(p)||[`transl_except`,`ribosomal_slippage`,`exception`].some(e=>t.notes?.[e]))return{warning:`AA comparison unavailable for this translation table or exception`,codons:[],changes:[]};let m=new Map(d.map((e,t)=>[e,t])),h=e=>t.strand<0?s(e):e,g=d.map(t=>h(e[t])).join(``),_=c(g),v=[..._].map((e,t)=>({positions:d.slice(t*3,t*3+3),aminoAcid:e,codonIndex:t})),y=new Set,b=new Map,x=new Map;o&&d.forEach((e,t)=>{(e<o.start||e>=o.end)&&b.set(t,`N`)});let S=1/0,C=!1;for(let e of n)if(e.type===`Insertion`){let n=t.strand<0?e.start-1:e.start,r=m.get(n),i=t.strand<0?e.start:e.start-1;r>0&&d[r-1]===i?(x.set(r,h(e.alternative)),e.alternative.length%3&&(S=Math.min(S,r))):(m.has(n)||m.has(i))&&(C=!0)}else if(e.type===`Deletion`){let t=[];for(let n=e.start;n<e.end;n++){let e=m.get(n);e!==void 0&&(y.add(e),t.push(e))}t.length%3&&(S=Math.min(S,...t))}else for(let t=e.start;t<e.end;t++){let n=m.get(t);n!==void 0&&b.set(n,h(e.alternative[t-e.start]))}let w=``,T=[];for(let e=0;e<d.length;e++)T[e]=w.length,w+=x.get(e)||``,y.has(e)||(w+=b.get(e)??g[e]);let E=Math.floor(S/3),D=Number.isFinite(S)?_.slice(0,E):_,O=c(Number.isFinite(S)?w.slice(0,T[E*3]):w),k=[],A=e=>{let n=Math.min(e.start,Math.max(0,v.length-1)),r=v[n],i=e.start<v.length?(r?.positions[0]??d[0])+(t.strand<0?.5:-.5):(r?.positions[2]??d[0])+(t.strand<0?-.5:.5);return{...e,anchor:r?.positions[1]??d[0],...e.type===`Insertion`?{pointerPosition:i}:{},aaPosition:e.type===`Insertion`?e.start:e.start+1}};try{if(D&&O){let e=e=>v[e].positions.some(e=>e<o.start||e>=o.end),t=0,n=0;if(o){for(;t<D.length&&e(t);)t++;for(;n<D.length-t&&e(D.length-n-1);)n++}let a=o?r(D,O,`X`,256,{leading:t,trailing:n}):i(D,O),s=[];for(let e of a.differences){let t={...e,type:e.type===`Ambiguous`?/X/.test(e.reference+e.alternative)?`Ambiguous`:`Substitution`:e.type},n=s.at(-1);t.type===`Ambiguous`&&n?.type===`Ambiguous`&&n.end===t.start?(n.end=t.end,n.reference+=t.reference,n.alternative+=t.alternative):s.push(t)}k=s.map(A)}else(D||O)&&(k=[A({type:D?`Deletion`:`Insertion`,start:0,end:D.length,reference:D,alternative:O})])}catch{return{codons:v,changes:[],warning:`AA comparison exceeds the alignment limit`}}return Number.isFinite(S)&&k.push(A({type:`Frameshift`,start:E,end:E+1,reference:``,alternative:``})),{codons:v,changes:k,warning:C?`Insertion at a coding boundary: AA assignment is uncertain`:void 0}}function d(e,t,n,r){return t.map(t=>u(e,t,n,r))}self.onmessage=({data:t})=>{try{let i=t.alignedSequence||n(t.fasta),a=t.alignedSequence?e(t.reference,i):r(t.reference,i.sequence);self.postMessage({...a,name:i.name,proteins:d(t.reference,t.features||[],a.differences,a.coverage)})}catch(e){self.postMessage({error:e.message})}};", Li = typeof self < "u" && self.Blob && new Blob(["URL.revokeObjectURL(import.meta.url);", Ii], { type: "text/javascript;charset=utf-8" });
2911
2911
  function Ri(e) {
2912
2912
  let t;
2913
2913
  try {
@@ -3088,6 +3088,7 @@ function zi({ reference: e, features: t, fastaUrl: n, alignedSequence: r, onResu
3088
3088
  children: D.name
3089
3089
  })]
3090
3090
  }),
3091
+ D.coverage && (D.coverage.start > 0 || D.coverage.end < e.length) && /* @__PURE__ */ x("p", { children: D.coverage.end > D.coverage.start ? `Terminal Ns excluded; comparing reference positions ${D.coverage.start + 1}–${D.coverage.end}.` : "No covered bases to compare (the alternative contains only Ns)." }),
3091
3092
  D.proteins?.some((e) => e?.warning) && /* @__PURE__ */ x("ul", {
3092
3093
  "aria-label": "Amino-acid comparison notes",
3093
3094
  children: D.proteins.map((e, n) => e?.warning && /* @__PURE__ */ S("li", { children: [
@@ -23762,8 +23763,28 @@ async function kC(e) {
23762
23763
  return t;
23763
23764
  }
23764
23765
  //#endregion
23766
+ //#region src/comparison/selection.mjs
23767
+ function AC(e, t, n, r) {
23768
+ if (t = Math.max(0, Math.min(e.length, t)), n = Math.max(0, Math.min(e.length, n)), t >= n) return "";
23769
+ let i = [...e.slice(t, n)];
23770
+ if (!r) return i.join("");
23771
+ let { coverage: a, differences: o } = r;
23772
+ if (a) for (let e = t; e < n; e++) (e < a.start || e >= a.end) && (i[e - t] = "N");
23773
+ let s = /* @__PURE__ */ new Map();
23774
+ for (let e of o) {
23775
+ if (e.type === "Insertion") {
23776
+ (e.start > t && e.start <= n || t === 0 && e.start === 0) && s.set(e.start, e.alternative);
23777
+ continue;
23778
+ }
23779
+ for (let r = Math.max(t, e.start); r < Math.min(n, e.end); r++) i[r - t] = e.type === "Deletion" ? "" : e.alternative[r - e.start];
23780
+ }
23781
+ let c = s.get(t) || "";
23782
+ for (let e = t; e < n; e++) c += i[e - t] + (s.get(e + 1) || "");
23783
+ return c;
23784
+ }
23785
+ //#endregion
23765
23786
  //#region node_modules/react-use/esm/misc/util.js
23766
- var AC = function() {}, jC = typeof window < "u", MC = jC ? m : d, NC = {
23787
+ var jC = function() {}, MC = typeof window < "u", NC = MC ? m : d, PC = {
23767
23788
  x: 0,
23768
23789
  y: 0,
23769
23790
  width: 0,
@@ -23773,8 +23794,8 @@ var AC = function() {}, jC = typeof window < "u", MC = jC ? m : d, NC = {
23773
23794
  bottom: 0,
23774
23795
  right: 0
23775
23796
  };
23776
- function PC() {
23777
- var e = v(null), t = e[0], n = e[1], r = v(NC), i = r[0], a = r[1], o = h(function() {
23797
+ function FC() {
23798
+ var e = v(null), t = e[0], n = e[1], r = v(PC), i = r[0], a = r[1], o = h(function() {
23778
23799
  return new window.ResizeObserver(function(e) {
23779
23800
  if (e[0]) {
23780
23801
  var t = e[0].contentRect, n = t.x, r = t.y, i = t.width, o = t.height, s = t.top, c = t.left, l = t.bottom, u = t.right;
@@ -23791,18 +23812,18 @@ function PC() {
23791
23812
  }
23792
23813
  });
23793
23814
  }, []);
23794
- return MC(function() {
23815
+ return NC(function() {
23795
23816
  if (t) return o.observe(t), function() {
23796
23817
  o.disconnect();
23797
23818
  };
23798
23819
  }, [t]), [n, i];
23799
23820
  }
23800
- var FC = jC && window.ResizeObserver !== void 0 ? PC : (function() {
23801
- return [AC, NC];
23821
+ var IC = MC && window.ResizeObserver !== void 0 ? FC : (function() {
23822
+ return [jC, PC];
23802
23823
  });
23803
23824
  //#endregion
23804
23825
  //#region node_modules/react-icons/bs/index.mjs
23805
- function IC(e) {
23826
+ function LC(e) {
23806
23827
  return ie({
23807
23828
  tag: "svg",
23808
23829
  attr: {
@@ -23816,7 +23837,7 @@ function IC(e) {
23816
23837
  }]
23817
23838
  })(e);
23818
23839
  }
23819
- function LC(e) {
23840
+ function RC(e) {
23820
23841
  return ie({
23821
23842
  tag: "svg",
23822
23843
  attr: {
@@ -23832,7 +23853,7 @@ function LC(e) {
23832
23853
  }
23833
23854
  //#endregion
23834
23855
  //#region src/SearchPanel.jsx
23835
- function RC({ value: e, onChange: t, ...n }) {
23856
+ function zC({ value: e, onChange: t, ...n }) {
23836
23857
  let [r, i] = v(e ?? ""), a = _();
23837
23858
  return d(() => {
23838
23859
  clearTimeout(a.current), i(e ?? "");
@@ -23845,7 +23866,7 @@ function RC({ value: e, onChange: t, ...n }) {
23845
23866
  }
23846
23867
  });
23847
23868
  }
23848
- function zC({ searchPanelOpen: e, setSearchPanelOpen: t, searchInput: n, setSearchInput: r, searchType: i, setSearchType: a, curSeqHitIndex: o, sequenceHits: s, setCurSeqHitIndex: c, includeRC: l, setIncludeRC: u }) {
23869
+ function BC({ searchPanelOpen: e, setSearchPanelOpen: t, searchInput: n, setSearchInput: r, searchType: i, setSearchType: a, curSeqHitIndex: o, sequenceHits: s, setCurSeqHitIndex: c, includeRC: l, setIncludeRC: u }) {
23849
23870
  return /* @__PURE__ */ S("div", {
23850
23871
  className: "bg-white p-1 text-sm shadow rounded ",
23851
23872
  children: [/* @__PURE__ */ x("div", {
@@ -23873,7 +23894,7 @@ function zC({ searchPanelOpen: e, setSearchPanelOpen: t, searchInput: n, setSear
23873
23894
  children: e.label
23874
23895
  }, e.value))
23875
23896
  }),
23876
- /* @__PURE__ */ x(RC, {
23897
+ /* @__PURE__ */ x(zC, {
23877
23898
  type: "text",
23878
23899
  value: n,
23879
23900
  onChange: (e) => {
@@ -23914,7 +23935,7 @@ function zC({ searchPanelOpen: e, setSearchPanelOpen: t, searchInput: n, setSear
23914
23935
  ]
23915
23936
  }),
23916
23937
  s.length > 0 && /* @__PURE__ */ S(b, { children: [
23917
- /* @__PURE__ */ x("button", { children: /* @__PURE__ */ x(LC, {
23938
+ /* @__PURE__ */ x("button", { children: /* @__PURE__ */ x(RC, {
23918
23939
  onClick: () => c((e) => e == 0 ? s.length - 1 : e - 1),
23919
23940
  className: "mx-3 text-gray-600 hover:text-gray-800"
23920
23941
  }) }),
@@ -23922,7 +23943,7 @@ function zC({ searchPanelOpen: e, setSearchPanelOpen: t, searchInput: n, setSear
23922
23943
  o + 1,
23923
23944
  " of ",
23924
23945
  s.length,
23925
- /* @__PURE__ */ x("button", { children: /* @__PURE__ */ x(IC, {
23946
+ /* @__PURE__ */ x("button", { children: /* @__PURE__ */ x(LC, {
23926
23947
  onClick: () => c((e) => e == s.length - 1 ? 0 : e + 1),
23927
23948
  className: "mx-3 text-gray-600 hover:text-gray-800"
23928
23949
  }) })
@@ -23934,13 +23955,13 @@ function zC({ searchPanelOpen: e, setSearchPanelOpen: t, searchInput: n, setSear
23934
23955
  }
23935
23956
  //#endregion
23936
23957
  //#region src/components/GensploreView.jsx
23937
- function BC({ genbankString: e, searchInput: t, setSearchInput: n, setTitleCallback: r, fastaUrl: i, alignedSequence: a }) {
23958
+ function VC({ genbankString: e, searchInput: t, setSearchInput: n, setTitleCallback: r, fastaUrl: i, alignedSequence: a }) {
23938
23959
  let [o, s] = v(""), c = t === void 0 ? o : t, u = l((e) => {
23939
23960
  s(e), n?.(e);
23940
23961
  }, [n]), [f, p] = v(null), [g, y] = v(!1), [C, w] = v({
23941
23962
  busy: !1,
23942
23963
  error: ""
23943
- }), [T, E] = v(!1), [D, O] = v(0), [k, A] = v(null), [j, M] = v(null), [N, P] = v(null), [F, I] = v("nuc"), [L, { width: R }] = FC(), [z, ee] = v(null), [B, te] = v({
23964
+ }), [T, E] = v(!1), [D, O] = v(0), [k, A] = v(null), [j, M] = v(null), [N, P] = v(null), [F, I] = v("nuc"), [L, { width: R }] = IC(), [z, ee] = v(null), [B, te] = v({
23944
23965
  x: null,
23945
23966
  y: null
23946
23967
  }), [V, ne] = v(null), [re, ie] = v([]), [ae, oe] = v(0), [se, ce] = v(!1), fe = F === "nuc" ? parseInt(c) : null, pe = F === "annot" ? c : null, me = F === "sequence" && c ? c.toUpperCase() : null, [he, ge] = v(0);
@@ -23995,7 +24016,9 @@ function BC({ genbankString: e, searchInput: t, setSearchInput: n, setTitleCallb
23995
24016
  }, [
23996
24017
  V,
23997
24018
  k,
23998
- j
24019
+ j,
24020
+ f,
24021
+ C
23999
24022
  ]);
24000
24023
  let H = Math.floor(R * .0965 / 2 ** D);
24001
24024
  H < 30 && (H = 30);
@@ -24120,8 +24143,12 @@ function BC({ genbankString: e, searchInput: t, setSearchInput: n, setTitleCallb
24120
24143
  });
24121
24144
  }, He = (e = !1) => {
24122
24145
  if (k === null || j === null) return;
24123
- let t = Math.min(k, j), n = Math.max(k, j), r = V.parsedSequence.sequence.substring(t, n);
24124
- e && (r = Hi(r)), navigator.clipboard.writeText(r), J.success(`Copied ${e ? "reverse complement " : ""}to clipboard`);
24146
+ if (C.busy || C.error) {
24147
+ J.info("Load a comparison successfully or clear it before copying.");
24148
+ return;
24149
+ }
24150
+ let t = Math.min(k, j), n = Math.max(k, j), r = AC(V.parsedSequence.sequence, t, n, f);
24151
+ e && (r = Hi(r)), navigator.clipboard.writeText(r), J.success(`Copied ${f ? "sample " : ""}${e ? "reverse complement " : ""}to clipboard`);
24125
24152
  };
24126
24153
  return d(() => (document.addEventListener("click", Ve), () => {
24127
24154
  document.removeEventListener("click", Ve);
@@ -24178,7 +24205,7 @@ function BC({ genbankString: e, searchInput: t, setSearchInput: n, setTitleCallb
24178
24205
  /* @__PURE__ */ x(Oo, {}),
24179
24206
  /* @__PURE__ */ x("div", {
24180
24207
  className: "fixed top-0 right-0 z-10",
24181
- children: /* @__PURE__ */ x(zC, {
24208
+ children: /* @__PURE__ */ x(BC, {
24182
24209
  searchInput: c,
24183
24210
  setSearchInput: u,
24184
24211
  searchPanelOpen: T,
@@ -24241,7 +24268,7 @@ function BC({ genbankString: e, searchInput: t, setSearchInput: n, setTitleCallb
24241
24268
  /* @__PURE__ */ x("button", {
24242
24269
  onClick: () => He(),
24243
24270
  className: "ml-2 p-1 hover:bg-gray-200 rounded-full",
24244
- title: "Copy selection",
24271
+ title: f ? "Copy sample selection" : "Copy selection",
24245
24272
  children: /* @__PURE__ */ x(le, { className: "h-4 w-4 text-gray-500" })
24246
24273
  })
24247
24274
  ]
@@ -24342,7 +24369,8 @@ function BC({ genbankString: e, searchInput: t, setSearchInput: n, setTitleCallb
24342
24369
  },
24343
24370
  onCopyRC: () => {
24344
24371
  He(!0), Ve();
24345
- }
24372
+ },
24373
+ isComparison: !!f
24346
24374
  }),
24347
24375
  Fe && /* @__PURE__ */ x(ue, {
24348
24376
  isOpen: Fe,
@@ -24408,6 +24436,6 @@ function BC({ genbankString: e, searchInput: t, setSearchInput: n, setTitleCallb
24408
24436
  }
24409
24437
  //#endregion
24410
24438
  //#region src/index.js
24411
- var VC = BC;
24439
+ var HC = VC;
24412
24440
  //#endregion
24413
- export { VC as default };
24441
+ export { HC as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gensplore",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "React component for displaying genbank files",
5
5
  "keywords": [
6
6
  "genbank",