@genomicx/ui 0.9.0 → 0.9.1

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/index.d.ts CHANGED
@@ -16,4 +16,5 @@ export type { StatusBadgeProps, StatusBadgeVariant } from './components/StatusBa
16
16
  export { loadWasmModule, createModuleInstance } from './wasm/loader';
17
17
  export type { EmscriptenModule, WasmModuleFactory } from './wasm/types';
18
18
  export { downloadBlob, downloadText, downloadBuffer } from './utils/download';
19
+ export { parseGenbankString, parseSequenceFile } from './utils/parseSequence';
19
20
  export type { ProgressUpdate } from './types/progress';
package/dist/index.js CHANGED
@@ -1,100 +1,100 @@
1
- import { jsxs as l, jsx as e, Fragment as x } from "react/jsx-runtime";
2
- import { useState as p, useRef as y, useCallback as f } from "react";
3
- import { Link as g } from "react-router-dom";
4
- import v from "react-hot-toast";
5
- function N({ disabled: a = !1 }) {
6
- const [n, o] = p(
1
+ import { jsxs as t, jsx as e, Fragment as f } from "react/jsx-runtime";
2
+ import { useState as x, useRef as y, useCallback as v } from "react";
3
+ import { Link as u } from "react-router-dom";
4
+ import N from "react-hot-toast";
5
+ function k({ disabled: n = !1 }) {
6
+ const [a, o] = x(
7
7
  () => document.documentElement.getAttribute("data-theme") || "dark"
8
- ), r = (t) => {
9
- o(t), document.documentElement.setAttribute("data-theme", t), localStorage.setItem("gx-theme", t);
8
+ ), r = (l) => {
9
+ o(l), document.documentElement.setAttribute("data-theme", l), localStorage.setItem("gx-theme", l);
10
10
  };
11
- return /* @__PURE__ */ l("div", { className: `gx-theme-toggle${a ? " disabled" : ""}`, title: a ? "Theme switching disabled" : void 0, children: [
11
+ return /* @__PURE__ */ t("div", { className: `gx-theme-toggle${n ? " disabled" : ""}`, title: n ? "Theme switching disabled" : void 0, children: [
12
12
  /* @__PURE__ */ e(
13
13
  "button",
14
14
  {
15
- onClick: () => !a && r("dark"),
16
- className: `gx-theme-btn${n === "dark" ? " active" : ""}`,
15
+ onClick: () => !n && r("dark"),
16
+ className: `gx-theme-btn${a === "dark" ? " active" : ""}`,
17
17
  "aria-label": "Dark theme",
18
- disabled: a,
18
+ disabled: n,
19
19
  children: /* @__PURE__ */ e("svg", { className: "gx-theme-btn-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e("path", { d: "M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z" }) })
20
20
  }
21
21
  ),
22
22
  /* @__PURE__ */ e(
23
23
  "button",
24
24
  {
25
- onClick: () => !a && r("light"),
26
- className: `gx-theme-btn${n === "light" ? " active" : ""}`,
25
+ onClick: () => !n && r("light"),
26
+ className: `gx-theme-btn${a === "light" ? " active" : ""}`,
27
27
  "aria-label": "Light theme",
28
- disabled: a,
28
+ disabled: n,
29
29
  children: /* @__PURE__ */ e("svg", { className: "gx-theme-btn-icon", fill: "currentColor", viewBox: "0 0 20 20", children: /* @__PURE__ */ e("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z", clipRule: "evenodd" }) })
30
30
  }
31
31
  )
32
32
  ] });
33
33
  }
34
- const b = () => /* @__PURE__ */ l("svg", { className: "gx-nav-logo-icon", viewBox: "0 0 24 24", fill: "none", stroke: "var(--gx-accent)", strokeWidth: "2", children: [
34
+ const b = () => /* @__PURE__ */ t("svg", { className: "gx-nav-logo-icon", viewBox: "0 0 24 24", fill: "none", stroke: "var(--gx-accent)", strokeWidth: "2", children: [
35
35
  /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "10" }),
36
36
  /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "6" }),
37
37
  /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "2" })
38
38
  ] });
39
- function M({ appName: a, appSubtitle: n, version: o, icon: r, githubUrl: t, actions: c, mobileActions: i }) {
40
- const [s, m] = p(!1);
41
- return /* @__PURE__ */ l("nav", { className: "gx-nav", children: [
42
- /* @__PURE__ */ e("div", { className: "gx-nav-inner", children: /* @__PURE__ */ l("div", { className: "gx-nav-row", children: [
43
- /* @__PURE__ */ l(g, { to: "/", className: "gx-nav-logo", children: [
39
+ function C({ appName: n, appSubtitle: a, version: o, icon: r, githubUrl: l, actions: s, mobileActions: c }) {
40
+ const [i, h] = x(!1);
41
+ return /* @__PURE__ */ t("nav", { className: "gx-nav", children: [
42
+ /* @__PURE__ */ e("div", { className: "gx-nav-inner", children: /* @__PURE__ */ t("div", { className: "gx-nav-row", children: [
43
+ /* @__PURE__ */ t(u, { to: "/", className: "gx-nav-logo", children: [
44
44
  r ?? /* @__PURE__ */ e(b, {}),
45
- /* @__PURE__ */ l("div", { children: [
46
- /* @__PURE__ */ l("h1", { className: "gx-nav-logo-name", children: [
47
- a,
48
- o && /* @__PURE__ */ l("span", { className: "gx-nav-logo-version", children: [
45
+ /* @__PURE__ */ t("div", { children: [
46
+ /* @__PURE__ */ t("h1", { className: "gx-nav-logo-name", children: [
47
+ n,
48
+ o && /* @__PURE__ */ t("span", { className: "gx-nav-logo-version", children: [
49
49
  "v",
50
50
  o
51
51
  ] })
52
52
  ] }),
53
- n && /* @__PURE__ */ e("p", { className: "gx-nav-logo-sub", children: n })
53
+ a && /* @__PURE__ */ e("p", { className: "gx-nav-logo-sub", children: a })
54
54
  ] })
55
55
  ] }),
56
- /* @__PURE__ */ l("div", { className: "gx-nav-desktop", children: [
57
- c,
58
- /* @__PURE__ */ e(g, { to: "/about", className: "gx-nav-link", children: "About" }),
59
- t && /* @__PURE__ */ l("a", { href: t, target: "_blank", rel: "noopener noreferrer", className: "gx-nav-link", children: [
56
+ /* @__PURE__ */ t("div", { className: "gx-nav-desktop", children: [
57
+ s,
58
+ /* @__PURE__ */ e(u, { to: "/about", className: "gx-nav-link", children: "About" }),
59
+ l && /* @__PURE__ */ t("a", { href: l, target: "_blank", rel: "noopener noreferrer", className: "gx-nav-link", children: [
60
60
  "GitHub",
61
61
  /* @__PURE__ */ e("svg", { className: "gx-nav-link-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" }) })
62
62
  ] }),
63
- /* @__PURE__ */ e(N, {})
63
+ /* @__PURE__ */ e(k, {})
64
64
  ] }),
65
- /* @__PURE__ */ l("div", { className: "gx-nav-mobile-toggle", children: [
66
- /* @__PURE__ */ e(N, {}),
67
- /* @__PURE__ */ e("button", { onClick: () => m(!s), className: "gx-nav-hamburger", "aria-label": "Toggle menu", children: s ? /* @__PURE__ */ e("svg", { className: "gx-nav-hamburger-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) : /* @__PURE__ */ e("svg", { className: "gx-nav-hamburger-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" }) }) })
65
+ /* @__PURE__ */ t("div", { className: "gx-nav-mobile-toggle", children: [
66
+ /* @__PURE__ */ e(k, {}),
67
+ /* @__PURE__ */ e("button", { onClick: () => h(!i), className: "gx-nav-hamburger", "aria-label": "Toggle menu", children: i ? /* @__PURE__ */ e("svg", { className: "gx-nav-hamburger-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) : /* @__PURE__ */ e("svg", { className: "gx-nav-hamburger-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" }) }) })
68
68
  ] })
69
69
  ] }) }),
70
- s && /* @__PURE__ */ l("div", { className: "gx-nav-dropdown", children: [
71
- i,
72
- /* @__PURE__ */ e(g, { to: "/about", onClick: () => m(!1), className: "gx-nav-dropdown-link", children: "About" }),
73
- t && /* @__PURE__ */ e("a", { href: t, target: "_blank", rel: "noopener noreferrer", className: "gx-nav-dropdown-link", children: "GitHub ↗" })
70
+ i && /* @__PURE__ */ t("div", { className: "gx-nav-dropdown", children: [
71
+ c,
72
+ /* @__PURE__ */ e(u, { to: "/about", onClick: () => h(!1), className: "gx-nav-dropdown-link", children: "About" }),
73
+ l && /* @__PURE__ */ e("a", { href: l, target: "_blank", rel: "noopener noreferrer", className: "gx-nav-dropdown-link", children: "GitHub ↗" })
74
74
  ] })
75
75
  ] });
76
76
  }
77
- const B = [
77
+ const M = [
78
78
  "A description of what happened and what you expected",
79
79
  "Your input files (if applicable)",
80
80
  "Browser name and version",
81
81
  "Steps to reproduce the issue"
82
82
  ];
83
- function C({ onClose: a, bugReportEmail: n, bugReportUrl: o, bugReportItems: r }) {
84
- const t = r ?? B;
85
- return /* @__PURE__ */ e("div", { className: "gx-modal-overlay", onClick: a, children: /* @__PURE__ */ l("div", { className: "gx-modal", onClick: (c) => c.stopPropagation(), children: [
86
- /* @__PURE__ */ l("div", { className: "gx-modal-header", children: [
83
+ function B({ onClose: n, bugReportEmail: a, bugReportUrl: o, bugReportItems: r }) {
84
+ const l = r ?? M;
85
+ return /* @__PURE__ */ e("div", { className: "gx-modal-overlay", onClick: n, children: /* @__PURE__ */ t("div", { className: "gx-modal", onClick: (s) => s.stopPropagation(), children: [
86
+ /* @__PURE__ */ t("div", { className: "gx-modal-header", children: [
87
87
  /* @__PURE__ */ e("h3", { className: "gx-modal-title", children: "Report a Bug" }),
88
- /* @__PURE__ */ e("button", { className: "gx-modal-close", onClick: a, "aria-label": "Close", children: "×" })
88
+ /* @__PURE__ */ e("button", { className: "gx-modal-close", onClick: n, "aria-label": "Close", children: "×" })
89
89
  ] }),
90
- /* @__PURE__ */ l("div", { className: "gx-modal-body", children: [
90
+ /* @__PURE__ */ t("div", { className: "gx-modal-body", children: [
91
91
  /* @__PURE__ */ e("p", { children: "To report a bug, please email the following to:" }),
92
- /* @__PURE__ */ e("p", { className: "gx-modal-email", children: /* @__PURE__ */ e("a", { href: `mailto:${n}`, children: n }) }),
93
- /* @__PURE__ */ l("div", { className: "gx-modal-checklist", children: [
92
+ /* @__PURE__ */ e("p", { className: "gx-modal-email", children: /* @__PURE__ */ e("a", { href: `mailto:${a}`, children: a }) }),
93
+ /* @__PURE__ */ t("div", { className: "gx-modal-checklist", children: [
94
94
  /* @__PURE__ */ e("p", { className: "gx-modal-checklist-title", children: "Please include:" }),
95
- /* @__PURE__ */ e("ol", { className: "gx-modal-checklist-items", children: t.map((c, i) => /* @__PURE__ */ e("li", { children: c }, i)) })
95
+ /* @__PURE__ */ e("ol", { className: "gx-modal-checklist-items", children: l.map((s, c) => /* @__PURE__ */ e("li", { children: s }, c)) })
96
96
  ] }),
97
- o && /* @__PURE__ */ l("p", { className: "gx-modal-github-hint", children: [
97
+ o && /* @__PURE__ */ t("p", { className: "gx-modal-github-hint", children: [
98
98
  "You can also open an issue on",
99
99
  " ",
100
100
  /* @__PURE__ */ e("a", { href: o, target: "_blank", rel: "noopener noreferrer", children: "GitHub" }),
@@ -103,118 +103,118 @@ function C({ onClose: a, bugReportEmail: n, bugReportUrl: o, bugReportItems: r }
103
103
  ] })
104
104
  ] }) });
105
105
  }
106
- function L({ appName: a = "GenomicX", bugReportEmail: n, bugReportUrl: o, onReportBug: r, bugReportItems: t }) {
107
- const [c, i] = p(!1);
108
- function s() {
109
- n ? i(!0) : r && r();
106
+ function L({ appName: n = "GenomicX", bugReportEmail: a, bugReportUrl: o, onReportBug: r, bugReportItems: l }) {
107
+ const [s, c] = x(!1);
108
+ function i() {
109
+ a ? c(!0) : r && r();
110
110
  }
111
- return /* @__PURE__ */ l(x, { children: [
112
- /* @__PURE__ */ e("footer", { className: "gx-footer", children: /* @__PURE__ */ e("div", { className: "gx-footer-inner", children: /* @__PURE__ */ l("div", { className: "gx-footer-content", children: [
113
- /* @__PURE__ */ l("div", { className: "gx-footer-text", children: [
114
- /* @__PURE__ */ l("p", { className: "gx-footer-text-title", children: [
115
- a,
111
+ return /* @__PURE__ */ t(f, { children: [
112
+ /* @__PURE__ */ e("footer", { className: "gx-footer", children: /* @__PURE__ */ e("div", { className: "gx-footer-inner", children: /* @__PURE__ */ t("div", { className: "gx-footer-content", children: [
113
+ /* @__PURE__ */ t("div", { className: "gx-footer-text", children: [
114
+ /* @__PURE__ */ t("p", { className: "gx-footer-text-title", children: [
115
+ n,
116
116
  " — Powered by WebAssembly"
117
117
  ] }),
118
118
  /* @__PURE__ */ e("p", { className: "gx-footer-text-sub", children: "All processing runs locally in your browser — no data leaves your computer" })
119
119
  ] }),
120
- /* @__PURE__ */ l("div", { className: "gx-footer-links", children: [
120
+ /* @__PURE__ */ t("div", { className: "gx-footer-links", children: [
121
121
  /* @__PURE__ */ e("a", { href: "https://genomicx.org", target: "_blank", rel: "noopener noreferrer", className: "gx-footer-link", children: "genomicx.org" }),
122
- (n || o || r) && /* @__PURE__ */ e("button", { onClick: s, className: "gx-footer-link", children: "Report Bug" })
122
+ (a || o || r) && /* @__PURE__ */ e("button", { onClick: i, className: "gx-footer-link", children: "Report Bug" })
123
123
  ] })
124
124
  ] }) }) }),
125
- c && n && /* @__PURE__ */ e(
126
- C,
125
+ s && a && /* @__PURE__ */ e(
126
+ B,
127
127
  {
128
- onClose: () => i(!1),
129
- bugReportEmail: n,
128
+ onClose: () => c(!1),
129
+ bugReportEmail: a,
130
130
  bugReportUrl: o,
131
- bugReportItems: t
131
+ bugReportItems: l
132
132
  }
133
133
  )
134
134
  ] });
135
135
  }
136
- function H({ children: a, onReportBug: n, ...o }) {
137
- return /* @__PURE__ */ l("div", { style: { minHeight: "100vh", display: "flex", flexDirection: "column", background: "var(--gx-bg)" }, children: [
138
- /* @__PURE__ */ e(M, { ...o }),
139
- /* @__PURE__ */ e("main", { style: { flex: 1 }, children: a }),
140
- /* @__PURE__ */ e(L, { appName: o.appName, onReportBug: n })
136
+ function _({ children: n, onReportBug: a, ...o }) {
137
+ return /* @__PURE__ */ t("div", { style: { minHeight: "100vh", display: "flex", flexDirection: "column", background: "var(--gx-bg)" }, children: [
138
+ /* @__PURE__ */ e(C, { ...o }),
139
+ /* @__PURE__ */ e("main", { style: { flex: 1 }, children: n }),
140
+ /* @__PURE__ */ e(L, { appName: o.appName, onReportBug: a })
141
141
  ] });
142
142
  }
143
- function R({ logs: a, progress: n, title: o = "Console" }) {
144
- const r = y(null), t = () => {
145
- navigator.clipboard.writeText(a.join(`
143
+ function E({ logs: n, progress: a, title: o = "Console" }) {
144
+ const r = y(null), l = () => {
145
+ navigator.clipboard.writeText(n.join(`
146
146
  `)).then(() => {
147
- v.success("Logs copied to clipboard!");
147
+ N.success("Logs copied to clipboard!");
148
148
  }).catch(() => {
149
- v.error("Failed to copy logs");
149
+ N.error("Failed to copy logs");
150
150
  });
151
- }, c = n && n.step !== "idle" && n.step !== "Complete!";
152
- return /* @__PURE__ */ l("div", { className: "gx-console", children: [
153
- c && /* @__PURE__ */ l("div", { className: "gx-console-progress", children: [
154
- /* @__PURE__ */ l("div", { className: "gx-console-progress-row", children: [
155
- /* @__PURE__ */ e("span", { className: "gx-console-progress-step", children: n.step }),
156
- /* @__PURE__ */ l("span", { className: "gx-console-progress-pct", children: [
157
- n.percent,
151
+ }, s = a && a.step !== "idle" && a.step !== "Complete!";
152
+ return /* @__PURE__ */ t("div", { className: "gx-console", children: [
153
+ s && /* @__PURE__ */ t("div", { className: "gx-console-progress", children: [
154
+ /* @__PURE__ */ t("div", { className: "gx-console-progress-row", children: [
155
+ /* @__PURE__ */ e("span", { className: "gx-console-progress-step", children: a.step }),
156
+ /* @__PURE__ */ t("span", { className: "gx-console-progress-pct", children: [
157
+ a.percent,
158
158
  "%"
159
159
  ] })
160
160
  ] }),
161
- /* @__PURE__ */ e("div", { className: "progress-bg", children: /* @__PURE__ */ e("div", { className: "progress-bar", style: { width: `${n.percent}%` } }) }),
162
- n.message && /* @__PURE__ */ e("div", { className: "gx-console-progress-msg", children: n.message })
161
+ /* @__PURE__ */ e("div", { className: "progress-bg", children: /* @__PURE__ */ e("div", { className: "progress-bar", style: { width: `${a.percent}%` } }) }),
162
+ a.message && /* @__PURE__ */ e("div", { className: "gx-console-progress-msg", children: a.message })
163
163
  ] }),
164
- /* @__PURE__ */ l("div", { className: "gx-console-header", children: [
165
- /* @__PURE__ */ l("div", { className: "gx-console-title-row", children: [
164
+ /* @__PURE__ */ t("div", { className: "gx-console-header", children: [
165
+ /* @__PURE__ */ t("div", { className: "gx-console-title-row", children: [
166
166
  /* @__PURE__ */ e("h3", { className: "gx-console-title", children: o }),
167
- /* @__PURE__ */ l("span", { className: "gx-console-count", children: [
167
+ /* @__PURE__ */ t("span", { className: "gx-console-count", children: [
168
168
  "(",
169
- a.length,
169
+ n.length,
170
170
  " messages)"
171
171
  ] })
172
172
  ] }),
173
- /* @__PURE__ */ l("button", { onClick: t, className: "gx-console-copy", disabled: a.length === 0, children: [
173
+ /* @__PURE__ */ t("button", { onClick: l, className: "gx-console-copy", disabled: n.length === 0, children: [
174
174
  /* @__PURE__ */ e("svg", { className: "gx-console-copy-icon", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ e("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" }) }),
175
175
  "Copy"
176
176
  ] })
177
177
  ] }),
178
- /* @__PURE__ */ e("div", { ref: r, className: "gx-console-body", children: a.length === 0 ? /* @__PURE__ */ e("div", { className: "gx-console-empty", children: "No logs yet..." }) : a.map((i, s) => /* @__PURE__ */ e("div", { className: "gx-console-line", children: i }, s)) })
178
+ /* @__PURE__ */ e("div", { ref: r, className: "gx-console-body", children: n.length === 0 ? /* @__PURE__ */ e("div", { className: "gx-console-empty", children: "No logs yet..." }) : n.map((c, i) => /* @__PURE__ */ e("div", { className: "gx-console-line", children: c }, i)) })
179
179
  ] });
180
180
  }
181
- function S({
182
- files: a,
183
- onFilesChange: n,
181
+ function H({
182
+ files: n,
183
+ onFilesChange: a,
184
184
  disabled: o = !1,
185
185
  multiple: r = !0,
186
- accept: t = ".fasta,.fa,.fna,.fsa,.fasta.gz,.fa.gz,.fna.gz",
187
- label: c = "Drop files here or click to browse",
188
- hint: i,
189
- filterFn: s
186
+ accept: l = ".fasta,.fa,.fna,.fsa,.fasta.gz,.fa.gz,.fna.gz",
187
+ label: s = "Drop files here or click to browse",
188
+ hint: c,
189
+ filterFn: i
190
190
  }) {
191
- const m = f(
191
+ const h = v(
192
192
  (d) => {
193
193
  if (!d.target.files) return;
194
- let h = Array.from(d.target.files);
195
- s && (h = h.filter(s)), h.length > 0 && n(h);
194
+ let g = Array.from(d.target.files);
195
+ i && (g = g.filter(i)), g.length > 0 && a(g);
196
196
  },
197
- [n, s]
198
- ), w = f(
197
+ [a, i]
198
+ ), m = v(
199
199
  (d) => {
200
200
  if (d.preventDefault(), !d.dataTransfer.files) return;
201
- let h = Array.from(d.dataTransfer.files);
202
- s && (h = h.filter(s)), h.length > 0 && n(h);
201
+ let g = Array.from(d.dataTransfer.files);
202
+ i && (g = g.filter(i)), g.length > 0 && a(g);
203
203
  },
204
- [n, s]
204
+ [a, i]
205
205
  );
206
- return /* @__PURE__ */ e("div", { className: "gx-file-upload", onDrop: w, onDragOver: (d) => d.preventDefault(), children: /* @__PURE__ */ l("label", { className: "gx-file-upload-area", children: [
206
+ return /* @__PURE__ */ e("div", { className: "gx-file-upload", onDrop: m, onDragOver: (d) => d.preventDefault(), children: /* @__PURE__ */ t("label", { className: "gx-file-upload-area", children: [
207
207
  /* @__PURE__ */ e(
208
208
  "input",
209
209
  {
210
210
  type: "file",
211
211
  multiple: r,
212
- accept: t,
213
- onChange: m,
212
+ accept: l,
213
+ onChange: h,
214
214
  disabled: o
215
215
  }
216
216
  ),
217
- /* @__PURE__ */ l(
217
+ /* @__PURE__ */ t(
218
218
  "svg",
219
219
  {
220
220
  className: "gx-file-upload-icon",
@@ -232,23 +232,23 @@ function S({
232
232
  ]
233
233
  }
234
234
  ),
235
- a.length === 0 ? /* @__PURE__ */ l(x, { children: [
236
- /* @__PURE__ */ e("div", { className: "gx-file-upload-label", children: c }),
237
- i && /* @__PURE__ */ e("div", { className: "gx-file-upload-hint", children: i })
238
- ] }) : /* @__PURE__ */ l(x, { children: [
239
- /* @__PURE__ */ l("div", { className: "gx-file-upload-label", children: [
240
- a.length,
235
+ n.length === 0 ? /* @__PURE__ */ t(f, { children: [
236
+ /* @__PURE__ */ e("div", { className: "gx-file-upload-label", children: s }),
237
+ c && /* @__PURE__ */ e("div", { className: "gx-file-upload-hint", children: c })
238
+ ] }) : /* @__PURE__ */ t(f, { children: [
239
+ /* @__PURE__ */ t("div", { className: "gx-file-upload-label", children: [
240
+ n.length,
241
241
  " file",
242
- a.length !== 1 ? "s" : "",
242
+ n.length !== 1 ? "s" : "",
243
243
  " selected"
244
244
  ] }),
245
- /* @__PURE__ */ e("ul", { className: "gx-file-list", children: a.map((d) => /* @__PURE__ */ e("li", { children: d.name }, d.name)) })
245
+ /* @__PURE__ */ e("ul", { className: "gx-file-list", children: n.map((d) => /* @__PURE__ */ e("li", { children: d.name }, d.name)) })
246
246
  ] })
247
247
  ] }) });
248
248
  }
249
- function _({ value: a, label: n }) {
250
- const o = Math.min(100, Math.max(0, a));
251
- return /* @__PURE__ */ l("div", { className: "gx-progress-wrap", children: [
249
+ function q({ value: n, label: a }) {
250
+ const o = Math.min(100, Math.max(0, n));
251
+ return /* @__PURE__ */ t("div", { className: "gx-progress-wrap", children: [
252
252
  /* @__PURE__ */ e(
253
253
  "div",
254
254
  {
@@ -260,88 +260,142 @@ function _({ value: a, label: n }) {
260
260
  children: /* @__PURE__ */ e("div", { className: "progress-bar", style: { width: `${o}%` } })
261
261
  }
262
262
  ),
263
- n && /* @__PURE__ */ e("p", { className: "gx-progress-label", children: n })
263
+ a && /* @__PURE__ */ e("p", { className: "gx-progress-label", children: a })
264
264
  ] });
265
265
  }
266
- const $ = {
267
- info: /* @__PURE__ */ l("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
266
+ const S = {
267
+ info: /* @__PURE__ */ t("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
268
268
  /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "10" }),
269
269
  /* @__PURE__ */ e("line", { x1: "12", y1: "16", x2: "12", y2: "12" }),
270
270
  /* @__PURE__ */ e("line", { x1: "12", y1: "8", x2: "12.01", y2: "8" })
271
271
  ] }),
272
- warning: /* @__PURE__ */ l("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
272
+ warning: /* @__PURE__ */ t("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
273
273
  /* @__PURE__ */ e("path", { d: "M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" }),
274
274
  /* @__PURE__ */ e("line", { x1: "12", y1: "9", x2: "12", y2: "13" }),
275
275
  /* @__PURE__ */ e("line", { x1: "12", y1: "17", x2: "12.01", y2: "17" })
276
276
  ] }),
277
- error: /* @__PURE__ */ l("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
277
+ error: /* @__PURE__ */ t("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
278
278
  /* @__PURE__ */ e("circle", { cx: "12", cy: "12", r: "10" }),
279
279
  /* @__PURE__ */ e("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
280
280
  /* @__PURE__ */ e("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
281
281
  ] }),
282
- success: /* @__PURE__ */ l("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
282
+ success: /* @__PURE__ */ t("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", "aria-hidden": "true", children: [
283
283
  /* @__PURE__ */ e("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
284
284
  /* @__PURE__ */ e("polyline", { points: "22 4 12 14.01 9 11.01" })
285
285
  ] })
286
286
  };
287
- function E({ variant: a, children: n }) {
288
- return /* @__PURE__ */ l("div", { className: `gx-alert gx-alert--${a}`, role: "alert", children: [
289
- /* @__PURE__ */ e("span", { className: `gx-alert-icon gx-alert-icon--${a}`, children: $[a] }),
290
- /* @__PURE__ */ e("div", { className: "gx-alert-body", children: n })
287
+ function P({ variant: n, children: a }) {
288
+ return /* @__PURE__ */ t("div", { className: `gx-alert gx-alert--${n}`, role: "alert", children: [
289
+ /* @__PURE__ */ e("span", { className: `gx-alert-icon gx-alert-icon--${n}`, children: S[n] }),
290
+ /* @__PURE__ */ e("div", { className: "gx-alert-body", children: a })
291
291
  ] });
292
292
  }
293
- function I({ variant: a, children: n }) {
294
- return /* @__PURE__ */ e("span", { className: `gx-badge gx-badge--${a}`, children: n });
293
+ function U({ variant: n, children: a }) {
294
+ return /* @__PURE__ */ e("span", { className: `gx-badge gx-badge--${n}`, children: a });
295
295
  }
296
- const A = "https://static.genomicx.org/wasm", u = /* @__PURE__ */ new Map();
297
- async function z(a, n = A) {
298
- const o = `${n}/${a}`;
299
- if (u.has(o)) return u.get(o);
300
- const [r, t] = await Promise.all([
301
- fetch(`${n}/${a}.js`),
302
- fetch(`${n}/${a}.wasm`)
296
+ const z = "https://static.genomicx.org/wasm", p = /* @__PURE__ */ new Map();
297
+ async function A(n, a = z) {
298
+ const o = `${a}/${n}`;
299
+ if (p.has(o)) return p.get(o);
300
+ const [r, l] = await Promise.all([
301
+ fetch(`${a}/${n}.js`),
302
+ fetch(`${a}/${n}.wasm`)
303
303
  ]);
304
- if (!r.ok) throw new Error(`Failed to fetch ${a}.js: ${r.status}`);
305
- if (!t.ok) throw new Error(`Failed to fetch ${a}.wasm: ${t.status}`);
306
- const [c, i] = await Promise.all([
304
+ if (!r.ok) throw new Error(`Failed to fetch ${n}.js: ${r.status}`);
305
+ if (!l.ok) throw new Error(`Failed to fetch ${n}.wasm: ${l.status}`);
306
+ const [s, c] = await Promise.all([
307
307
  r.text(),
308
- t.arrayBuffer()
309
- ]), m = { factory: new Function("Module", c + "; return Module;")({}), wasmBinary: i };
310
- return u.set(o, m), m;
308
+ l.arrayBuffer()
309
+ ]), h = { factory: new Function("Module", s + "; return Module;")({}), wasmBinary: c };
310
+ return p.set(o, h), h;
311
311
  }
312
- async function O(a, n) {
313
- const { factory: o, wasmBinary: r } = await z(a, n), t = [], c = [], i = await o({
312
+ async function F(n, a) {
313
+ const { factory: o, wasmBinary: r } = await A(n, a), l = [], s = [], c = await o({
314
314
  wasmBinary: r.slice(0),
315
- print: (s) => t.push(s),
316
- printErr: (s) => c.push(s),
315
+ print: (i) => l.push(i),
316
+ printErr: (i) => s.push(i),
317
317
  noInitialRun: !0
318
318
  });
319
- return i._stdout = t, i._stderr = c, i;
319
+ return c._stdout = l, c._stderr = s, c;
320
320
  }
321
- function k(a, n) {
322
- const o = URL.createObjectURL(a), r = document.createElement("a");
323
- r.href = o, r.download = n, r.click(), URL.revokeObjectURL(o);
321
+ function w(n, a) {
322
+ const o = URL.createObjectURL(n), r = document.createElement("a");
323
+ r.href = o, r.download = a, r.click(), URL.revokeObjectURL(o);
324
324
  }
325
- function P(a, n, o = "text/plain") {
326
- k(new Blob([a], { type: o }), n);
325
+ function V(n, a, o = "text/plain") {
326
+ w(new Blob([n], { type: o }), a);
327
327
  }
328
- function G(a, n) {
329
- k(new Blob([a]), n);
328
+ function X(n, a) {
329
+ w(new Blob([n]), a);
330
+ }
331
+ function $(n) {
332
+ const a = n.split(/(?=^LOCUS\s)/m).filter((r) => r.trim().startsWith("LOCUS")), o = [];
333
+ for (const r of a) {
334
+ const l = r.match(/^LOCUS\s+(\S+)/m);
335
+ if (!l) continue;
336
+ const s = l[1], c = r.match(/ORIGIN([\s\S]*?)(\/\/|$)/);
337
+ if (!c) continue;
338
+ const i = c[1].replace(/[^a-zA-Z]/g, "").toUpperCase();
339
+ i && o.push({ name: s, sequence: i });
340
+ }
341
+ return o;
342
+ }
343
+ function W(n) {
344
+ const a = [];
345
+ let o = "", r = [];
346
+ for (const l of n.split(`
347
+ `)) {
348
+ const s = l.trim();
349
+ s.startsWith(">") ? (o && a.push({ name: o, sequence: r.join("") }), o = s.slice(1).split(/\s+/)[0], r = []) : s && o && r.push(s.toUpperCase());
350
+ }
351
+ return o && a.push({ name: o, sequence: r.join("") }), a;
352
+ }
353
+ async function T(n) {
354
+ const a = new DecompressionStream("gzip"), o = a.writable.getWriter(), r = a.readable.getReader();
355
+ o.write(n), o.close();
356
+ const l = [];
357
+ let s = !1;
358
+ for (; !s; ) {
359
+ const m = await r.read();
360
+ s = m.done, m.value && l.push(m.value);
361
+ }
362
+ const c = l.reduce((m, d) => m + d.length, 0), i = new Uint8Array(c);
363
+ let h = 0;
364
+ for (const m of l)
365
+ i.set(m, h), h += m.length;
366
+ return new TextDecoder().decode(i);
367
+ }
368
+ const j = /* @__PURE__ */ new Set([".gb", ".gbk", ".genbank"]);
369
+ function D(n) {
370
+ const a = n.endsWith(".gz") ? n.slice(0, -3) : n, o = a.slice(a.lastIndexOf(".")).toLowerCase();
371
+ return j.has(o);
372
+ }
373
+ async function Y(n) {
374
+ const a = n.name.endsWith(".gz");
375
+ let o;
376
+ if (a) {
377
+ const r = await n.arrayBuffer();
378
+ o = await T(r);
379
+ } else
380
+ o = await n.text();
381
+ return D(n.name) ? $(o) : W(o);
330
382
  }
331
383
  export {
332
- E as Alert,
384
+ P as Alert,
333
385
  L as AppFooter,
334
- H as AppShell,
335
- C as BugReportModal,
336
- S as FileUpload,
337
- R as LogConsole,
338
- M as NavBar,
339
- _ as ProgressBar,
340
- I as StatusBadge,
341
- N as ThemeToggle,
342
- O as createModuleInstance,
343
- k as downloadBlob,
344
- G as downloadBuffer,
345
- P as downloadText,
346
- z as loadWasmModule
386
+ _ as AppShell,
387
+ B as BugReportModal,
388
+ H as FileUpload,
389
+ E as LogConsole,
390
+ C as NavBar,
391
+ q as ProgressBar,
392
+ U as StatusBadge,
393
+ k as ThemeToggle,
394
+ F as createModuleInstance,
395
+ w as downloadBlob,
396
+ X as downloadBuffer,
397
+ V as downloadText,
398
+ A as loadWasmModule,
399
+ $ as parseGenbankString,
400
+ Y as parseSequenceFile
347
401
  };
@@ -0,0 +1,13 @@
1
+ /** Parse a multi-record GenBank string into name/sequence pairs. */
2
+ export declare function parseGenbankString(text: string): {
3
+ name: string;
4
+ sequence: string;
5
+ }[];
6
+ /**
7
+ * Parse a sequence File (FASTA or GenBank, optionally gzip-compressed)
8
+ * into an array of { name, sequence } records.
9
+ */
10
+ export declare function parseSequenceFile(file: File): Promise<{
11
+ name: string;
12
+ sequence: string;
13
+ }[]>;
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@genomicx/ui",
3
- "version": "0.9.0",
3
+ "version": "0.9.1",
4
4
  "description": "Shared UI components, styles, and WASM loader for GenomicX tools",
5
+ "license": "GPL-3.0",
5
6
  "type": "module",
6
7
  "main": "./dist/index.js",
7
8
  "module": "./dist/index.js",