@qamposer/react 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -6,14 +6,15 @@ Qamposer is a modular, open-source quantum composer that can be embedded into yo
6
6
 
7
7
  ## Installation
8
8
 
9
- > **Coming Soon** - npm package publication is in progress.
10
-
11
9
  ```bash
12
- # Not yet available
13
10
  npm install @qamposer/react
14
11
  ```
15
12
 
16
- For now, please use the source code directly or contact the maintainers for access.
13
+ For the full version with visualization (Q-sphere, histograms), also install Plotly:
14
+
15
+ ```bash
16
+ npm install plotly.js-basic-dist-min react-plotly.js
17
+ ```
17
18
 
18
19
  ## Examples
19
20
 
@@ -38,32 +39,27 @@ Quantum mechanics and simulation results can be directly leveraged as game logic
38
39
  ### Basic Usage (QamposerMicro)
39
40
 
40
41
  ```tsx
41
- import { QamposerMicro, qiskitAdapter } from "@qamposer/react";
42
- import "@qamposer/react/styles.css";
42
+ import { QamposerMicro } from '@qamposer/react';
43
43
 
44
44
  function App() {
45
- return (
46
- <QamposerMicro
47
- adapter={qiskitAdapter("http://localhost:8000")}
48
- onSimulationComplete={(event) => {
49
- console.log("Result:", event.result);
50
- console.log("QASM:", event.qasm);
51
- }}
52
- />
53
- );
45
+ return <QamposerMicro />;
54
46
  }
55
47
  ```
56
48
 
49
+ > **Note**: By default, QamposerMicro runs in editor-only mode (no simulation). To enable simulation, see [With Backend](#with-backend-simulation) below.
50
+
57
51
  ### Full Version with Visualization (Qamposer)
58
52
 
53
+ The full version includes visualization components (histograms, Q-sphere) that require simulation results, so a backend adapter is needed:
54
+
59
55
  ```tsx
60
- import { Qamposer } from "@qamposer/react/visualization";
61
- import "@qamposer/react/styles.css";
56
+ import { Qamposer } from '@qamposer/react/visualization';
57
+ import { qiskitAdapter } from '@qamposer/react';
62
58
 
63
59
  function App() {
64
60
  return (
65
61
  <Qamposer
66
- adapter={qiskitAdapter("http://localhost:8000")}
62
+ adapter={qiskitAdapter('http://localhost:8080')}
67
63
  defaultTheme="dark"
68
64
  showThemeToggle
69
65
  />
@@ -101,11 +97,24 @@ This library provides two preset components to fit different use cases:
101
97
 
102
98
  ## Backend Requirements
103
99
 
104
- > **Important**: To run quantum simulations, you need to run the `qamposer-backend` server.
100
+ The React components work standalone for circuit editing. To run quantum simulations, you need the `qamposer-backend` server.
101
+
102
+ ### Editor-Only Mode
103
+
104
+ By default, components run in editor-only mode without requiring a backend:
105
+
106
+ ```tsx
107
+ import { QamposerMicro } from '@qamposer/react';
108
+
109
+ // No backend required - editor-only mode (default)
110
+ <QamposerMicro />;
111
+ ```
112
+
113
+ ### With Backend (Simulation)
105
114
 
106
- The React components handle circuit editing and visualization, but actual quantum simulation requires a backend server running Qiskit.
115
+ To enable quantum simulation, start the backend and pass the `qiskitAdapter`:
107
116
 
108
- ### Starting the Backend
117
+ Assuming localhost is used here, but please specify the actual deployment destination for the backend.
109
118
 
110
119
  ```bash
111
120
  # Clone and setup qamposer-backend
@@ -114,17 +123,16 @@ poetry install
114
123
  poetry run uvicorn backend.main:app --host 0.0.0.0 --port 8080 --reload
115
124
  ```
116
125
 
117
- The backend will start at `http://localhost:8000` by default.
118
-
119
- ### Editor-Only Mode (No Backend)
120
-
121
- If you only need the circuit editor without simulation capabilities, use the `noopAdapter`:
122
-
123
126
  ```tsx
124
- import { QamposerMicro, noopAdapter } from "@qamposer/react";
125
-
126
- // No backend required - simulation is disabled
127
- <QamposerMicro adapter={noopAdapter} />;
127
+ import { QamposerMicro, qiskitAdapter } from '@qamposer/react';
128
+
129
+ <QamposerMicro
130
+ adapter={qiskitAdapter('http://localhost:8080')}
131
+ onSimulationComplete={(event) => {
132
+ console.log('Result:', event.result);
133
+ console.log('QASM:', event.qasm);
134
+ }}
135
+ />;
128
136
  ```
129
137
 
130
138
  ## API Reference
@@ -139,7 +147,7 @@ interface QamposerProps {
139
147
  onCircuitChange?: (circuit: Circuit) => void;
140
148
 
141
149
  // Simulation
142
- adapter?: SimulationAdapter; // Backend adapter
150
+ adapter?: SimulationAdapter; // Backend adapter (default: noopAdapter)
143
151
  onSimulationComplete?: (event: SimulationCompleteEvent) => void;
144
152
 
145
153
  // Configuration
@@ -149,7 +157,7 @@ interface QamposerProps {
149
157
  className?: string;
150
158
  showHeader?: boolean; // Default: true
151
159
  title?: string; // Default: 'Qamposer'
152
- defaultTheme?: "light" | "dark"; // Default: 'dark'
160
+ defaultTheme?: 'light' | 'dark'; // Default: 'dark'
153
161
  showThemeToggle?: boolean; // Default: true
154
162
 
155
163
  // Layout (Qamposer only)
@@ -169,31 +177,31 @@ interface QamposerConfig {
169
177
  }
170
178
  ```
171
179
 
172
- ### Adapters
180
+ <!-- ### Adapters
173
181
 
174
182
  ```tsx
175
183
  // Qiskit Backend Adapter
176
- import { qiskitAdapter } from "@qamposer/react";
184
+ import { qiskitAdapter } from '@qamposer/react';
177
185
 
178
- const adapter = qiskitAdapter("http://localhost:8000");
186
+ const adapter = qiskitAdapter('http://localhost:8000');
179
187
 
180
188
  // With options
181
189
  const adapter = qiskitAdapter({
182
- baseUrl: "http://localhost:8000",
183
- headers: { Authorization: "Bearer token" },
190
+ baseUrl: 'http://localhost:8000',
191
+ headers: { Authorization: 'Bearer token' },
184
192
  timeout: 30000,
185
193
  });
186
194
 
187
195
  // No-op Adapter (editor only, no simulation)
188
- import { noopAdapter } from "@qamposer/react";
189
- ```
196
+ import { noopAdapter } from '@qamposer/react';
197
+ ``` -->
190
198
 
191
- ### useQamposer Hook
199
+ <!-- ### useQamposer Hook
192
200
 
193
201
  For building custom UIs, use the `useQamposer` hook within a `QamposerProvider`:
194
202
 
195
203
  ```tsx
196
- import { QamposerProvider, useQamposer } from '@qamposer/react';
204
+ import { QamposerProvider, useQamposer, qiskitAdapter } from '@qamposer/react';
197
205
 
198
206
  function CustomEditor() {
199
207
  const {
@@ -212,14 +220,24 @@ function CustomEditor() {
212
220
  );
213
221
  }
214
222
 
223
+ // Editor-only mode (default)
215
224
  function App() {
216
225
  return (
217
- <QamposerProvider adapter={qiskitAdapter('http://localhost:8000')}>
226
+ <QamposerProvider>
218
227
  <CustomEditor />
219
228
  </QamposerProvider>
220
229
  );
221
230
  }
222
- ```
231
+
232
+ // With backend simulation
233
+ function AppWithSimulation() {
234
+ return (
235
+ <QamposerProvider adapter={qiskitAdapter('http://localhost:8080')}>
236
+ <CustomEditor />
237
+ </QamposerProvider>
238
+ );
239
+ }
240
+ ``` -->
223
241
 
224
242
  <!-- ### Individual Components -->
225
243
 
@@ -240,7 +258,7 @@ import { QSphereView, ResultsPanel } from '@qamposer/react/visualization';
240
258
  ## OpenQASM Utilities
241
259
 
242
260
  ```tsx
243
- import { circuitToQasm, qasmToCircuit } from "@qamposer/react";
261
+ import { circuitToQasm, qasmToCircuit } from '@qamposer/react';
244
262
 
245
263
  // Convert Circuit to OpenQASM
246
264
  const qasm = circuitToQasm(circuit);
@@ -284,7 +302,7 @@ The library uses CSS variables for theming. You can customize colors by overridi
284
302
  Or use the theme hook:
285
303
 
286
304
  ```tsx
287
- import { useTheme } from "@qamposer/react";
305
+ import { useTheme } from '@qamposer/react';
288
306
 
289
307
  function ThemeToggle() {
290
308
  const { theme, toggleTheme } = useTheme();
@@ -310,6 +328,11 @@ For `Qamposer` (full version) with visualization:
310
328
  }
311
329
  ```
312
330
 
331
+ ## Support & Stability
332
+
333
+ - This library is under active development.
334
+ - Please report issues via [GitHub Issues](https://github.com/QAMP-62/qamposer-react/issues).
335
+
313
336
  ## License
314
337
 
315
338
  Licensed under the Apache 2.0.
@@ -43,7 +43,7 @@ interface Circuit {
43
43
  qubits: number;
44
44
  gates: Gate[];
45
45
  }
46
- type BackendType = 'ideal' | 'noisy_fake';
46
+ type BackendType = 'ideal' | 'noisy_fake' | 'real';
47
47
  interface SimulationProfile {
48
48
  type: BackendType;
49
49
  backend_name?: string;
@@ -43,7 +43,7 @@ interface Circuit {
43
43
  qubits: number;
44
44
  gates: Gate[];
45
45
  }
46
- type BackendType = 'ideal' | 'noisy_fake';
46
+ type BackendType = 'ideal' | 'noisy_fake' | 'real';
47
47
  interface SimulationProfile {
48
48
  type: BackendType;
49
49
  backend_name?: string;
package/dist/index.cjs CHANGED
@@ -321,6 +321,38 @@ function QamposerProvider({
321
321
  react.useEffect(() => {
322
322
  adapter.isAvailable().then(setCanSimulate);
323
323
  }, [adapter]);
324
+ const autoSimRequestId = react.useRef(0);
325
+ react.useEffect(() => {
326
+ if (!canSimulate || circuit.gates.length === 0) {
327
+ if (circuit.gates.length === 0) {
328
+ setResult(null);
329
+ }
330
+ return;
331
+ }
332
+ const requestId = ++autoSimRequestId.current;
333
+ setStatus("simulating");
334
+ setError(null);
335
+ const request = {
336
+ qubits: circuit.qubits,
337
+ gates: circuit.gates.map(({ id: _, ...gate }) => gate),
338
+ shots: 1024,
339
+ profile: { type: "ideal" }
340
+ };
341
+ adapter.simulate(request).then((simulationResult) => {
342
+ if (autoSimRequestId.current !== requestId) return;
343
+ setResult(simulationResult);
344
+ setStatus("idle");
345
+ onSimulationComplete?.({
346
+ result: simulationResult,
347
+ circuit: { ...circuit },
348
+ qasm: circuitToQasm(circuit)
349
+ });
350
+ }).catch((err) => {
351
+ if (autoSimRequestId.current !== requestId) return;
352
+ setError(err instanceof Error ? err : new Error(String(err)));
353
+ setStatus("error");
354
+ });
355
+ }, [circuit, canSimulate, adapter, onSimulationComplete]);
324
356
  const addGate = react.useCallback(
325
357
  (gate) => {
326
358
  if (circuit.gates.length >= config.maxGates) {
@@ -490,6 +522,7 @@ function QamposerProvider({
490
522
  }, [circuit]);
491
523
  const simulate = react.useCallback(
492
524
  async (shots = 1024, profile) => {
525
+ autoSimRequestId.current++;
493
526
  if (!canSimulate) {
494
527
  throw new Error("Simulation adapter is not available");
495
528
  }
@@ -2303,6 +2336,11 @@ var css3 = `.simulation-controls__run-btn {
2303
2336
  border-color: var(--qamposer-accent, #4285f4);
2304
2337
  background: rgba(66, 133, 244, 0.1);
2305
2338
  }
2339
+ .simulation-controls__backend-item--disabled {
2340
+ opacity: 0.5;
2341
+ cursor: not-allowed;
2342
+ pointer-events: none;
2343
+ }
2306
2344
  .simulation-controls__backend-item-content {
2307
2345
  flex: 1;
2308
2346
  min-width: 0;
@@ -2334,6 +2372,10 @@ var css3 = `.simulation-controls__run-btn {
2334
2372
  background: rgba(237, 137, 54, 0.2);
2335
2373
  color: #ed8936;
2336
2374
  }
2375
+ .simulation-controls__backend-type--real {
2376
+ background: rgba(160, 174, 192, 0.2);
2377
+ color: #a0aec0;
2378
+ }
2337
2379
  .simulation-controls__backend-desc {
2338
2380
  margin: 0;
2339
2381
  font-size: 0.75rem;
@@ -2425,7 +2467,7 @@ function SimulationControls({
2425
2467
  const [isDialogOpen, setIsDialogOpen] = react.useState(false);
2426
2468
  const [shots, setShots] = react.useState(1024);
2427
2469
  const [backends, setBackends] = react.useState([]);
2428
- const [selectedBackendId, setSelectedBackendId] = react.useState("ideal");
2470
+ const [selectedBackendId, setSelectedBackendId] = react.useState("");
2429
2471
  const [isLoadingBackends, setIsLoadingBackends] = react.useState(false);
2430
2472
  const [backendError, setBackendError] = react.useState(false);
2431
2473
  react.useEffect(() => {
@@ -2433,8 +2475,13 @@ function SimulationControls({
2433
2475
  setIsLoadingBackends(true);
2434
2476
  setBackendError(false);
2435
2477
  adapter.getBackends().then((result) => {
2436
- setBackends(result);
2437
- if (result.length === 1 && result[0].id === "ideal" && !canSimulate) {
2478
+ const nonIdealBackends = result.filter((b) => b.backend_type !== "ideal");
2479
+ setBackends(nonIdealBackends);
2480
+ const firstFake = nonIdealBackends.find((b) => b.backend_type === "noisy_fake");
2481
+ if (firstFake) {
2482
+ setSelectedBackendId(firstFake.id);
2483
+ }
2484
+ if (nonIdealBackends.length === 0 && !canSimulate) {
2438
2485
  setBackendError(true);
2439
2486
  }
2440
2487
  }).finally(() => setIsLoadingBackends(false));
@@ -2442,13 +2489,10 @@ function SimulationControls({
2442
2489
  }, [isDialogOpen, adapter, canSimulate]);
2443
2490
  const selectedBackend = backends.find((b) => b.id === selectedBackendId);
2444
2491
  const buildProfile = () => {
2445
- if (!selectedBackend || selectedBackend.backend_type === "ideal") {
2446
- return { type: "ideal" };
2492
+ if (!selectedBackend || selectedBackend.backend_type === "noisy_fake") {
2493
+ return selectedBackend ? { type: "noisy_fake", backend_name: selectedBackend.id } : void 0;
2447
2494
  }
2448
- return {
2449
- type: "noisy_fake",
2450
- backend_name: selectedBackend.id
2451
- };
2495
+ return void 0;
2452
2496
  };
2453
2497
  const handleRun = async () => {
2454
2498
  if (circuit.gates.length === 0) {
@@ -2535,31 +2579,35 @@ function SimulationControls({
2535
2579
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__error-title", children: "Backend unavailable" }),
2536
2580
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__error-desc", children: "Cannot connect to the simulation backend. Please check that the server is running and CORS is configured correctly." })
2537
2581
  ] })
2538
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => /* @__PURE__ */ jsxRuntime.jsxs(
2539
- "button",
2540
- {
2541
- type: "button",
2542
- className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""}`,
2543
- onClick: () => setSelectedBackendId(backend.id),
2544
- children: [
2545
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-content", children: [
2546
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-header", children: [
2547
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
2548
- /* @__PURE__ */ jsxRuntime.jsx(
2549
- "span",
2550
- {
2551
- className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
2552
- children: backend.backend_type === "ideal" ? "Ideal" : "Noisy"
2553
- }
2554
- )
2582
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => {
2583
+ const isReal = backend.backend_type === "real";
2584
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2585
+ "button",
2586
+ {
2587
+ type: "button",
2588
+ className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""} ${isReal ? "simulation-controls__backend-item--disabled" : ""}`,
2589
+ onClick: () => !isReal && setSelectedBackendId(backend.id),
2590
+ disabled: isReal,
2591
+ children: [
2592
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-content", children: [
2593
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-header", children: [
2594
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
2595
+ /* @__PURE__ */ jsxRuntime.jsx(
2596
+ "span",
2597
+ {
2598
+ className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
2599
+ children: backend.backend_type === "noisy_fake" ? "Noisy" : "Real"
2600
+ }
2601
+ )
2602
+ ] }),
2603
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__backend-desc", children: isReal ? "Coming soon" : backend.description || `${backend.num_qubits} qubits` })
2555
2604
  ] }),
2556
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__backend-desc", children: backend.description || `${backend.num_qubits} qubits` })
2557
- ] }),
2558
- selectedBackendId === backend.id && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) })
2559
- ]
2560
- },
2561
- backend.id
2562
- )) })
2605
+ selectedBackendId === backend.id && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) })
2606
+ ]
2607
+ },
2608
+ backend.id
2609
+ );
2610
+ }) })
2563
2611
  ] })
2564
2612
  ] }),
2565
2613
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__dialog-footer", children: [
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Q as QamposerProviderProps$1, T as Theme, C as Circuit, S as SimulationAdapter, a as SimulationCompleteEvent, b as QamposerConfig, c as QamposerContextValue, d as QasmParseResult } from './index-BbUFQqpD.cjs';
3
- export { h as CircuitRequest, G as Gate, g as GateInfo, f as GateType, j as QSpherePoint, i as SimulationResult, e as ThemeProvider, u as useTheme } from './index-BbUFQqpD.cjs';
2
+ import { Q as QamposerProviderProps$1, T as Theme, C as Circuit, S as SimulationAdapter, a as SimulationCompleteEvent, b as QamposerConfig, c as QamposerContextValue, d as QasmParseResult } from './index-BghK68a6.cjs';
3
+ export { h as CircuitRequest, G as Gate, g as GateInfo, f as GateType, j as QSpherePoint, i as SimulationResult, e as ThemeProvider, u as useTheme } from './index-BghK68a6.cjs';
4
4
  import { ReactNode } from 'react';
5
5
 
6
6
  interface QamposerMicroProps extends Omit<QamposerProviderProps$1, 'children'> {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Q as QamposerProviderProps$1, T as Theme, C as Circuit, S as SimulationAdapter, a as SimulationCompleteEvent, b as QamposerConfig, c as QamposerContextValue, d as QasmParseResult } from './index-BbUFQqpD.js';
3
- export { h as CircuitRequest, G as Gate, g as GateInfo, f as GateType, j as QSpherePoint, i as SimulationResult, e as ThemeProvider, u as useTheme } from './index-BbUFQqpD.js';
2
+ import { Q as QamposerProviderProps$1, T as Theme, C as Circuit, S as SimulationAdapter, a as SimulationCompleteEvent, b as QamposerConfig, c as QamposerContextValue, d as QasmParseResult } from './index-BghK68a6.js';
3
+ export { h as CircuitRequest, G as Gate, g as GateInfo, f as GateType, j as QSpherePoint, i as SimulationResult, e as ThemeProvider, u as useTheme } from './index-BghK68a6.js';
4
4
  import { ReactNode } from 'react';
5
5
 
6
6
  interface QamposerMicroProps extends Omit<QamposerProviderProps$1, 'children'> {
package/dist/index.js CHANGED
@@ -319,6 +319,38 @@ function QamposerProvider({
319
319
  useEffect(() => {
320
320
  adapter.isAvailable().then(setCanSimulate);
321
321
  }, [adapter]);
322
+ const autoSimRequestId = useRef(0);
323
+ useEffect(() => {
324
+ if (!canSimulate || circuit.gates.length === 0) {
325
+ if (circuit.gates.length === 0) {
326
+ setResult(null);
327
+ }
328
+ return;
329
+ }
330
+ const requestId = ++autoSimRequestId.current;
331
+ setStatus("simulating");
332
+ setError(null);
333
+ const request = {
334
+ qubits: circuit.qubits,
335
+ gates: circuit.gates.map(({ id: _, ...gate }) => gate),
336
+ shots: 1024,
337
+ profile: { type: "ideal" }
338
+ };
339
+ adapter.simulate(request).then((simulationResult) => {
340
+ if (autoSimRequestId.current !== requestId) return;
341
+ setResult(simulationResult);
342
+ setStatus("idle");
343
+ onSimulationComplete?.({
344
+ result: simulationResult,
345
+ circuit: { ...circuit },
346
+ qasm: circuitToQasm(circuit)
347
+ });
348
+ }).catch((err) => {
349
+ if (autoSimRequestId.current !== requestId) return;
350
+ setError(err instanceof Error ? err : new Error(String(err)));
351
+ setStatus("error");
352
+ });
353
+ }, [circuit, canSimulate, adapter, onSimulationComplete]);
322
354
  const addGate = useCallback(
323
355
  (gate) => {
324
356
  if (circuit.gates.length >= config.maxGates) {
@@ -488,6 +520,7 @@ function QamposerProvider({
488
520
  }, [circuit]);
489
521
  const simulate = useCallback(
490
522
  async (shots = 1024, profile) => {
523
+ autoSimRequestId.current++;
491
524
  if (!canSimulate) {
492
525
  throw new Error("Simulation adapter is not available");
493
526
  }
@@ -2301,6 +2334,11 @@ var css3 = `.simulation-controls__run-btn {
2301
2334
  border-color: var(--qamposer-accent, #4285f4);
2302
2335
  background: rgba(66, 133, 244, 0.1);
2303
2336
  }
2337
+ .simulation-controls__backend-item--disabled {
2338
+ opacity: 0.5;
2339
+ cursor: not-allowed;
2340
+ pointer-events: none;
2341
+ }
2304
2342
  .simulation-controls__backend-item-content {
2305
2343
  flex: 1;
2306
2344
  min-width: 0;
@@ -2332,6 +2370,10 @@ var css3 = `.simulation-controls__run-btn {
2332
2370
  background: rgba(237, 137, 54, 0.2);
2333
2371
  color: #ed8936;
2334
2372
  }
2373
+ .simulation-controls__backend-type--real {
2374
+ background: rgba(160, 174, 192, 0.2);
2375
+ color: #a0aec0;
2376
+ }
2335
2377
  .simulation-controls__backend-desc {
2336
2378
  margin: 0;
2337
2379
  font-size: 0.75rem;
@@ -2423,7 +2465,7 @@ function SimulationControls({
2423
2465
  const [isDialogOpen, setIsDialogOpen] = useState(false);
2424
2466
  const [shots, setShots] = useState(1024);
2425
2467
  const [backends, setBackends] = useState([]);
2426
- const [selectedBackendId, setSelectedBackendId] = useState("ideal");
2468
+ const [selectedBackendId, setSelectedBackendId] = useState("");
2427
2469
  const [isLoadingBackends, setIsLoadingBackends] = useState(false);
2428
2470
  const [backendError, setBackendError] = useState(false);
2429
2471
  useEffect(() => {
@@ -2431,8 +2473,13 @@ function SimulationControls({
2431
2473
  setIsLoadingBackends(true);
2432
2474
  setBackendError(false);
2433
2475
  adapter.getBackends().then((result) => {
2434
- setBackends(result);
2435
- if (result.length === 1 && result[0].id === "ideal" && !canSimulate) {
2476
+ const nonIdealBackends = result.filter((b) => b.backend_type !== "ideal");
2477
+ setBackends(nonIdealBackends);
2478
+ const firstFake = nonIdealBackends.find((b) => b.backend_type === "noisy_fake");
2479
+ if (firstFake) {
2480
+ setSelectedBackendId(firstFake.id);
2481
+ }
2482
+ if (nonIdealBackends.length === 0 && !canSimulate) {
2436
2483
  setBackendError(true);
2437
2484
  }
2438
2485
  }).finally(() => setIsLoadingBackends(false));
@@ -2440,13 +2487,10 @@ function SimulationControls({
2440
2487
  }, [isDialogOpen, adapter, canSimulate]);
2441
2488
  const selectedBackend = backends.find((b) => b.id === selectedBackendId);
2442
2489
  const buildProfile = () => {
2443
- if (!selectedBackend || selectedBackend.backend_type === "ideal") {
2444
- return { type: "ideal" };
2490
+ if (!selectedBackend || selectedBackend.backend_type === "noisy_fake") {
2491
+ return selectedBackend ? { type: "noisy_fake", backend_name: selectedBackend.id } : void 0;
2445
2492
  }
2446
- return {
2447
- type: "noisy_fake",
2448
- backend_name: selectedBackend.id
2449
- };
2493
+ return void 0;
2450
2494
  };
2451
2495
  const handleRun = async () => {
2452
2496
  if (circuit.gates.length === 0) {
@@ -2533,31 +2577,35 @@ function SimulationControls({
2533
2577
  /* @__PURE__ */ jsx("p", { className: "simulation-controls__error-title", children: "Backend unavailable" }),
2534
2578
  /* @__PURE__ */ jsx("p", { className: "simulation-controls__error-desc", children: "Cannot connect to the simulation backend. Please check that the server is running and CORS is configured correctly." })
2535
2579
  ] })
2536
- ] }) : /* @__PURE__ */ jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => /* @__PURE__ */ jsxs(
2537
- "button",
2538
- {
2539
- type: "button",
2540
- className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""}`,
2541
- onClick: () => setSelectedBackendId(backend.id),
2542
- children: [
2543
- /* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-content", children: [
2544
- /* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-header", children: [
2545
- /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
2546
- /* @__PURE__ */ jsx(
2547
- "span",
2548
- {
2549
- className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
2550
- children: backend.backend_type === "ideal" ? "Ideal" : "Noisy"
2551
- }
2552
- )
2580
+ ] }) : /* @__PURE__ */ jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => {
2581
+ const isReal = backend.backend_type === "real";
2582
+ return /* @__PURE__ */ jsxs(
2583
+ "button",
2584
+ {
2585
+ type: "button",
2586
+ className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""} ${isReal ? "simulation-controls__backend-item--disabled" : ""}`,
2587
+ onClick: () => !isReal && setSelectedBackendId(backend.id),
2588
+ disabled: isReal,
2589
+ children: [
2590
+ /* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-content", children: [
2591
+ /* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-header", children: [
2592
+ /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
2593
+ /* @__PURE__ */ jsx(
2594
+ "span",
2595
+ {
2596
+ className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
2597
+ children: backend.backend_type === "noisy_fake" ? "Noisy" : "Real"
2598
+ }
2599
+ )
2600
+ ] }),
2601
+ /* @__PURE__ */ jsx("p", { className: "simulation-controls__backend-desc", children: isReal ? "Coming soon" : backend.description || `${backend.num_qubits} qubits` })
2553
2602
  ] }),
2554
- /* @__PURE__ */ jsx("p", { className: "simulation-controls__backend-desc", children: backend.description || `${backend.num_qubits} qubits` })
2555
- ] }),
2556
- selectedBackendId === backend.id && /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsx(CheckIcon, {}) })
2557
- ]
2558
- },
2559
- backend.id
2560
- )) })
2603
+ selectedBackendId === backend.id && /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsx(CheckIcon, {}) })
2604
+ ]
2605
+ },
2606
+ backend.id
2607
+ );
2608
+ }) })
2561
2609
  ] })
2562
2610
  ] }),
2563
2611
  /* @__PURE__ */ jsxs("div", { className: "simulation-controls__dialog-footer", children: [
@@ -319,6 +319,38 @@ function QamposerProvider({
319
319
  react.useEffect(() => {
320
320
  adapter.isAvailable().then(setCanSimulate);
321
321
  }, [adapter]);
322
+ const autoSimRequestId = react.useRef(0);
323
+ react.useEffect(() => {
324
+ if (!canSimulate || circuit.gates.length === 0) {
325
+ if (circuit.gates.length === 0) {
326
+ setResult(null);
327
+ }
328
+ return;
329
+ }
330
+ const requestId = ++autoSimRequestId.current;
331
+ setStatus("simulating");
332
+ setError(null);
333
+ const request = {
334
+ qubits: circuit.qubits,
335
+ gates: circuit.gates.map(({ id: _, ...gate }) => gate),
336
+ shots: 1024,
337
+ profile: { type: "ideal" }
338
+ };
339
+ adapter.simulate(request).then((simulationResult) => {
340
+ if (autoSimRequestId.current !== requestId) return;
341
+ setResult(simulationResult);
342
+ setStatus("idle");
343
+ onSimulationComplete?.({
344
+ result: simulationResult,
345
+ circuit: { ...circuit },
346
+ qasm: circuitToQasm(circuit)
347
+ });
348
+ }).catch((err) => {
349
+ if (autoSimRequestId.current !== requestId) return;
350
+ setError(err instanceof Error ? err : new Error(String(err)));
351
+ setStatus("error");
352
+ });
353
+ }, [circuit, canSimulate, adapter, onSimulationComplete]);
322
354
  const addGate = react.useCallback(
323
355
  (gate) => {
324
356
  if (circuit.gates.length >= config.maxGates) {
@@ -488,6 +520,7 @@ function QamposerProvider({
488
520
  }, [circuit]);
489
521
  const simulate = react.useCallback(
490
522
  async (shots = 1024, profile) => {
523
+ autoSimRequestId.current++;
491
524
  if (!canSimulate) {
492
525
  throw new Error("Simulation adapter is not available");
493
526
  }
@@ -2999,6 +3032,11 @@ var css6 = `.simulation-controls__run-btn {
2999
3032
  border-color: var(--qamposer-accent, #4285f4);
3000
3033
  background: rgba(66, 133, 244, 0.1);
3001
3034
  }
3035
+ .simulation-controls__backend-item--disabled {
3036
+ opacity: 0.5;
3037
+ cursor: not-allowed;
3038
+ pointer-events: none;
3039
+ }
3002
3040
  .simulation-controls__backend-item-content {
3003
3041
  flex: 1;
3004
3042
  min-width: 0;
@@ -3030,6 +3068,10 @@ var css6 = `.simulation-controls__run-btn {
3030
3068
  background: rgba(237, 137, 54, 0.2);
3031
3069
  color: #ed8936;
3032
3070
  }
3071
+ .simulation-controls__backend-type--real {
3072
+ background: rgba(160, 174, 192, 0.2);
3073
+ color: #a0aec0;
3074
+ }
3033
3075
  .simulation-controls__backend-desc {
3034
3076
  margin: 0;
3035
3077
  font-size: 0.75rem;
@@ -3121,7 +3163,7 @@ function SimulationControls({
3121
3163
  const [isDialogOpen, setIsDialogOpen] = react.useState(false);
3122
3164
  const [shots, setShots] = react.useState(1024);
3123
3165
  const [backends, setBackends] = react.useState([]);
3124
- const [selectedBackendId, setSelectedBackendId] = react.useState("ideal");
3166
+ const [selectedBackendId, setSelectedBackendId] = react.useState("");
3125
3167
  const [isLoadingBackends, setIsLoadingBackends] = react.useState(false);
3126
3168
  const [backendError, setBackendError] = react.useState(false);
3127
3169
  react.useEffect(() => {
@@ -3129,8 +3171,13 @@ function SimulationControls({
3129
3171
  setIsLoadingBackends(true);
3130
3172
  setBackendError(false);
3131
3173
  adapter.getBackends().then((result) => {
3132
- setBackends(result);
3133
- if (result.length === 1 && result[0].id === "ideal" && !canSimulate) {
3174
+ const nonIdealBackends = result.filter((b) => b.backend_type !== "ideal");
3175
+ setBackends(nonIdealBackends);
3176
+ const firstFake = nonIdealBackends.find((b) => b.backend_type === "noisy_fake");
3177
+ if (firstFake) {
3178
+ setSelectedBackendId(firstFake.id);
3179
+ }
3180
+ if (nonIdealBackends.length === 0 && !canSimulate) {
3134
3181
  setBackendError(true);
3135
3182
  }
3136
3183
  }).finally(() => setIsLoadingBackends(false));
@@ -3138,13 +3185,10 @@ function SimulationControls({
3138
3185
  }, [isDialogOpen, adapter, canSimulate]);
3139
3186
  const selectedBackend = backends.find((b) => b.id === selectedBackendId);
3140
3187
  const buildProfile = () => {
3141
- if (!selectedBackend || selectedBackend.backend_type === "ideal") {
3142
- return { type: "ideal" };
3188
+ if (!selectedBackend || selectedBackend.backend_type === "noisy_fake") {
3189
+ return selectedBackend ? { type: "noisy_fake", backend_name: selectedBackend.id } : void 0;
3143
3190
  }
3144
- return {
3145
- type: "noisy_fake",
3146
- backend_name: selectedBackend.id
3147
- };
3191
+ return void 0;
3148
3192
  };
3149
3193
  const handleRun = async () => {
3150
3194
  if (circuit.gates.length === 0) {
@@ -3231,31 +3275,35 @@ function SimulationControls({
3231
3275
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__error-title", children: "Backend unavailable" }),
3232
3276
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__error-desc", children: "Cannot connect to the simulation backend. Please check that the server is running and CORS is configured correctly." })
3233
3277
  ] })
3234
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => /* @__PURE__ */ jsxRuntime.jsxs(
3235
- "button",
3236
- {
3237
- type: "button",
3238
- className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""}`,
3239
- onClick: () => setSelectedBackendId(backend.id),
3240
- children: [
3241
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-content", children: [
3242
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-header", children: [
3243
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
3244
- /* @__PURE__ */ jsxRuntime.jsx(
3245
- "span",
3246
- {
3247
- className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
3248
- children: backend.backend_type === "ideal" ? "Ideal" : "Noisy"
3249
- }
3250
- )
3278
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => {
3279
+ const isReal = backend.backend_type === "real";
3280
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3281
+ "button",
3282
+ {
3283
+ type: "button",
3284
+ className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""} ${isReal ? "simulation-controls__backend-item--disabled" : ""}`,
3285
+ onClick: () => !isReal && setSelectedBackendId(backend.id),
3286
+ disabled: isReal,
3287
+ children: [
3288
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-content", children: [
3289
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__backend-item-header", children: [
3290
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
3291
+ /* @__PURE__ */ jsxRuntime.jsx(
3292
+ "span",
3293
+ {
3294
+ className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
3295
+ children: backend.backend_type === "noisy_fake" ? "Noisy" : "Real"
3296
+ }
3297
+ )
3298
+ ] }),
3299
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__backend-desc", children: isReal ? "Coming soon" : backend.description || `${backend.num_qubits} qubits` })
3251
3300
  ] }),
3252
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "simulation-controls__backend-desc", children: backend.description || `${backend.num_qubits} qubits` })
3253
- ] }),
3254
- selectedBackendId === backend.id && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) })
3255
- ]
3256
- },
3257
- backend.id
3258
- )) })
3301
+ selectedBackendId === backend.id && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, {}) })
3302
+ ]
3303
+ },
3304
+ backend.id
3305
+ );
3306
+ }) })
3259
3307
  ] })
3260
3308
  ] }),
3261
3309
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "simulation-controls__dialog-footer", children: [
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Q as QamposerProviderProps, T as Theme } from './index-BbUFQqpD.cjs';
2
+ import { Q as QamposerProviderProps, T as Theme } from './index-BghK68a6.cjs';
3
3
  import 'react';
4
4
 
5
5
  interface QamposerProps extends Omit<QamposerProviderProps, 'children'> {
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Q as QamposerProviderProps, T as Theme } from './index-BbUFQqpD.js';
2
+ import { Q as QamposerProviderProps, T as Theme } from './index-BghK68a6.js';
3
3
  import 'react';
4
4
 
5
5
  interface QamposerProps extends Omit<QamposerProviderProps, 'children'> {
@@ -313,6 +313,38 @@ function QamposerProvider({
313
313
  useEffect(() => {
314
314
  adapter.isAvailable().then(setCanSimulate);
315
315
  }, [adapter]);
316
+ const autoSimRequestId = useRef(0);
317
+ useEffect(() => {
318
+ if (!canSimulate || circuit.gates.length === 0) {
319
+ if (circuit.gates.length === 0) {
320
+ setResult(null);
321
+ }
322
+ return;
323
+ }
324
+ const requestId = ++autoSimRequestId.current;
325
+ setStatus("simulating");
326
+ setError(null);
327
+ const request = {
328
+ qubits: circuit.qubits,
329
+ gates: circuit.gates.map(({ id: _, ...gate }) => gate),
330
+ shots: 1024,
331
+ profile: { type: "ideal" }
332
+ };
333
+ adapter.simulate(request).then((simulationResult) => {
334
+ if (autoSimRequestId.current !== requestId) return;
335
+ setResult(simulationResult);
336
+ setStatus("idle");
337
+ onSimulationComplete?.({
338
+ result: simulationResult,
339
+ circuit: { ...circuit },
340
+ qasm: circuitToQasm(circuit)
341
+ });
342
+ }).catch((err) => {
343
+ if (autoSimRequestId.current !== requestId) return;
344
+ setError(err instanceof Error ? err : new Error(String(err)));
345
+ setStatus("error");
346
+ });
347
+ }, [circuit, canSimulate, adapter, onSimulationComplete]);
316
348
  const addGate = useCallback(
317
349
  (gate) => {
318
350
  if (circuit.gates.length >= config.maxGates) {
@@ -482,6 +514,7 @@ function QamposerProvider({
482
514
  }, [circuit]);
483
515
  const simulate = useCallback(
484
516
  async (shots = 1024, profile) => {
517
+ autoSimRequestId.current++;
485
518
  if (!canSimulate) {
486
519
  throw new Error("Simulation adapter is not available");
487
520
  }
@@ -2993,6 +3026,11 @@ var css6 = `.simulation-controls__run-btn {
2993
3026
  border-color: var(--qamposer-accent, #4285f4);
2994
3027
  background: rgba(66, 133, 244, 0.1);
2995
3028
  }
3029
+ .simulation-controls__backend-item--disabled {
3030
+ opacity: 0.5;
3031
+ cursor: not-allowed;
3032
+ pointer-events: none;
3033
+ }
2996
3034
  .simulation-controls__backend-item-content {
2997
3035
  flex: 1;
2998
3036
  min-width: 0;
@@ -3024,6 +3062,10 @@ var css6 = `.simulation-controls__run-btn {
3024
3062
  background: rgba(237, 137, 54, 0.2);
3025
3063
  color: #ed8936;
3026
3064
  }
3065
+ .simulation-controls__backend-type--real {
3066
+ background: rgba(160, 174, 192, 0.2);
3067
+ color: #a0aec0;
3068
+ }
3027
3069
  .simulation-controls__backend-desc {
3028
3070
  margin: 0;
3029
3071
  font-size: 0.75rem;
@@ -3115,7 +3157,7 @@ function SimulationControls({
3115
3157
  const [isDialogOpen, setIsDialogOpen] = useState(false);
3116
3158
  const [shots, setShots] = useState(1024);
3117
3159
  const [backends, setBackends] = useState([]);
3118
- const [selectedBackendId, setSelectedBackendId] = useState("ideal");
3160
+ const [selectedBackendId, setSelectedBackendId] = useState("");
3119
3161
  const [isLoadingBackends, setIsLoadingBackends] = useState(false);
3120
3162
  const [backendError, setBackendError] = useState(false);
3121
3163
  useEffect(() => {
@@ -3123,8 +3165,13 @@ function SimulationControls({
3123
3165
  setIsLoadingBackends(true);
3124
3166
  setBackendError(false);
3125
3167
  adapter.getBackends().then((result) => {
3126
- setBackends(result);
3127
- if (result.length === 1 && result[0].id === "ideal" && !canSimulate) {
3168
+ const nonIdealBackends = result.filter((b) => b.backend_type !== "ideal");
3169
+ setBackends(nonIdealBackends);
3170
+ const firstFake = nonIdealBackends.find((b) => b.backend_type === "noisy_fake");
3171
+ if (firstFake) {
3172
+ setSelectedBackendId(firstFake.id);
3173
+ }
3174
+ if (nonIdealBackends.length === 0 && !canSimulate) {
3128
3175
  setBackendError(true);
3129
3176
  }
3130
3177
  }).finally(() => setIsLoadingBackends(false));
@@ -3132,13 +3179,10 @@ function SimulationControls({
3132
3179
  }, [isDialogOpen, adapter, canSimulate]);
3133
3180
  const selectedBackend = backends.find((b) => b.id === selectedBackendId);
3134
3181
  const buildProfile = () => {
3135
- if (!selectedBackend || selectedBackend.backend_type === "ideal") {
3136
- return { type: "ideal" };
3182
+ if (!selectedBackend || selectedBackend.backend_type === "noisy_fake") {
3183
+ return selectedBackend ? { type: "noisy_fake", backend_name: selectedBackend.id } : void 0;
3137
3184
  }
3138
- return {
3139
- type: "noisy_fake",
3140
- backend_name: selectedBackend.id
3141
- };
3185
+ return void 0;
3142
3186
  };
3143
3187
  const handleRun = async () => {
3144
3188
  if (circuit.gates.length === 0) {
@@ -3225,31 +3269,35 @@ function SimulationControls({
3225
3269
  /* @__PURE__ */ jsx("p", { className: "simulation-controls__error-title", children: "Backend unavailable" }),
3226
3270
  /* @__PURE__ */ jsx("p", { className: "simulation-controls__error-desc", children: "Cannot connect to the simulation backend. Please check that the server is running and CORS is configured correctly." })
3227
3271
  ] })
3228
- ] }) : /* @__PURE__ */ jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => /* @__PURE__ */ jsxs(
3229
- "button",
3230
- {
3231
- type: "button",
3232
- className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""}`,
3233
- onClick: () => setSelectedBackendId(backend.id),
3234
- children: [
3235
- /* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-content", children: [
3236
- /* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-header", children: [
3237
- /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
3238
- /* @__PURE__ */ jsx(
3239
- "span",
3240
- {
3241
- className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
3242
- children: backend.backend_type === "ideal" ? "Ideal" : "Noisy"
3243
- }
3244
- )
3272
+ ] }) : /* @__PURE__ */ jsx("div", { className: "simulation-controls__backend-list", children: backends.map((backend) => {
3273
+ const isReal = backend.backend_type === "real";
3274
+ return /* @__PURE__ */ jsxs(
3275
+ "button",
3276
+ {
3277
+ type: "button",
3278
+ className: `simulation-controls__backend-item ${selectedBackendId === backend.id ? "simulation-controls__backend-item--selected" : ""} ${isReal ? "simulation-controls__backend-item--disabled" : ""}`,
3279
+ onClick: () => !isReal && setSelectedBackendId(backend.id),
3280
+ disabled: isReal,
3281
+ children: [
3282
+ /* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-content", children: [
3283
+ /* @__PURE__ */ jsxs("div", { className: "simulation-controls__backend-item-header", children: [
3284
+ /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-name", children: backend.name }),
3285
+ /* @__PURE__ */ jsx(
3286
+ "span",
3287
+ {
3288
+ className: `simulation-controls__backend-type simulation-controls__backend-type--${backend.backend_type}`,
3289
+ children: backend.backend_type === "noisy_fake" ? "Noisy" : "Real"
3290
+ }
3291
+ )
3292
+ ] }),
3293
+ /* @__PURE__ */ jsx("p", { className: "simulation-controls__backend-desc", children: isReal ? "Coming soon" : backend.description || `${backend.num_qubits} qubits` })
3245
3294
  ] }),
3246
- /* @__PURE__ */ jsx("p", { className: "simulation-controls__backend-desc", children: backend.description || `${backend.num_qubits} qubits` })
3247
- ] }),
3248
- selectedBackendId === backend.id && /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsx(CheckIcon, {}) })
3249
- ]
3250
- },
3251
- backend.id
3252
- )) })
3295
+ selectedBackendId === backend.id && /* @__PURE__ */ jsx("span", { className: "simulation-controls__backend-check", children: /* @__PURE__ */ jsx(CheckIcon, {}) })
3296
+ ]
3297
+ },
3298
+ backend.id
3299
+ );
3300
+ }) })
3253
3301
  ] })
3254
3302
  ] }),
3255
3303
  /* @__PURE__ */ jsxs("div", { className: "simulation-controls__dialog-footer", children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qamposer/react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "React components for quantum circuit composition",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -26,8 +26,7 @@
26
26
  "types": "./dist/visualization.d.cts",
27
27
  "default": "./dist/visualization.cjs"
28
28
  }
29
- },
30
- "./styles.css": "./dist/styles.css"
29
+ }
31
30
  },
32
31
  "files": [
33
32
  "dist"
@@ -77,6 +76,7 @@
77
76
  "eslint": "^9.39.2",
78
77
  "eslint-plugin-react-hooks": "^7.0.1",
79
78
  "happy-dom": "^20.4.0",
79
+ "prettier": "^3.8.1",
80
80
  "react": "^19.0.0",
81
81
  "react-dom": "^19.0.0",
82
82
  "sass": "^1.97.1",