qsharp-lang 1.14.5-dev → 1.15.1-dev

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.
Files changed (338) hide show
  1. package/dist/browser.d.ts +1 -1
  2. package/dist/compiler/compiler.d.ts +1 -1
  3. package/dist/compiler/compiler.js +6 -1
  4. package/dist/debug-service/debug-service.d.ts +1 -1
  5. package/dist/debug-service/debug-service.js +6 -1
  6. package/dist/katas-content.generated.js +1 -1
  7. package/dist/katas-content.generated.md.js +1 -1
  8. package/dist/samples.generated.js +1 -1
  9. package/dist/shared/circuit.d.ts +86 -30
  10. package/dist/shared/circuit.js +4 -0
  11. package/dist/shared/legacyCircuitUpdate.d.ts +9 -0
  12. package/dist/shared/legacyCircuitUpdate.js +312 -0
  13. package/dist/shared/register.d.ts +3 -5
  14. package/dist/utils.d.ts +9 -0
  15. package/dist/utils.js +41 -0
  16. package/docs/Microsoft.Quantum.Core/Length.md +1 -1
  17. package/docs/Microsoft.Quantum.Core/Repeated.md +1 -1
  18. package/docs/Microsoft.Quantum.Core/index.md +1 -1
  19. package/docs/Std.Arithmetic/AddLE.md +1 -1
  20. package/docs/Std.Arithmetic/ApplyIfEqualL.md +1 -1
  21. package/docs/Std.Arithmetic/ApplyIfEqualLE.md +1 -1
  22. package/docs/Std.Arithmetic/ApplyIfGreaterL.md +1 -1
  23. package/docs/Std.Arithmetic/ApplyIfGreaterLE.md +1 -1
  24. package/docs/Std.Arithmetic/ApplyIfGreaterOrEqualL.md +1 -1
  25. package/docs/Std.Arithmetic/ApplyIfGreaterOrEqualLE.md +1 -1
  26. package/docs/Std.Arithmetic/ApplyIfLessL.md +1 -1
  27. package/docs/Std.Arithmetic/ApplyIfLessLE.md +1 -1
  28. package/docs/Std.Arithmetic/ApplyIfLessOrEqualL.md +1 -1
  29. package/docs/Std.Arithmetic/ApplyIfLessOrEqualLE.md +1 -1
  30. package/docs/Std.Arithmetic/FourierTDIncByLE.md +1 -1
  31. package/docs/Std.Arithmetic/IncByI.md +1 -1
  32. package/docs/Std.Arithmetic/IncByIUsingIncByLE.md +1 -1
  33. package/docs/Std.Arithmetic/IncByL.md +1 -1
  34. package/docs/Std.Arithmetic/IncByLE.md +1 -1
  35. package/docs/Std.Arithmetic/IncByLEUsingAddLE.md +1 -1
  36. package/docs/Std.Arithmetic/IncByLUsingIncByLE.md +1 -1
  37. package/docs/Std.Arithmetic/LookAheadDKRSAddLE.md +1 -1
  38. package/docs/Std.Arithmetic/MAJ.md +1 -1
  39. package/docs/Std.Arithmetic/ReflectAboutInteger.md +1 -1
  40. package/docs/Std.Arithmetic/RippleCarryCGAddLE.md +1 -1
  41. package/docs/Std.Arithmetic/RippleCarryCGIncByLE.md +1 -1
  42. package/docs/Std.Arithmetic/RippleCarryTTKIncByLE.md +1 -1
  43. package/docs/Std.Arithmetic/index.md +1 -1
  44. package/docs/Std.Arrays/All.md +1 -1
  45. package/docs/Std.Arrays/Any.md +1 -1
  46. package/docs/Std.Arrays/Chunks.md +1 -1
  47. package/docs/Std.Arrays/CircularlyShifted.md +1 -1
  48. package/docs/Std.Arrays/ColumnAt.md +1 -1
  49. package/docs/Std.Arrays/Count.md +1 -1
  50. package/docs/Std.Arrays/Diagonal.md +1 -1
  51. package/docs/Std.Arrays/DrawMany.md +1 -1
  52. package/docs/Std.Arrays/Enumerated.md +1 -1
  53. package/docs/Std.Arrays/Excluding.md +1 -1
  54. package/docs/Std.Arrays/Filtered.md +1 -1
  55. package/docs/Std.Arrays/FlatMapped.md +1 -1
  56. package/docs/Std.Arrays/Flattened.md +1 -1
  57. package/docs/Std.Arrays/Fold.md +1 -1
  58. package/docs/Std.Arrays/ForEach.md +1 -1
  59. package/docs/Std.Arrays/Head.md +1 -1
  60. package/docs/Std.Arrays/HeadAndRest.md +1 -1
  61. package/docs/Std.Arrays/IndexOf.md +1 -1
  62. package/docs/Std.Arrays/IndexRange.md +1 -1
  63. package/docs/Std.Arrays/Interleaved.md +1 -1
  64. package/docs/Std.Arrays/IsEmpty.md +1 -1
  65. package/docs/Std.Arrays/IsRectangularArray.md +1 -1
  66. package/docs/Std.Arrays/IsSorted.md +1 -1
  67. package/docs/Std.Arrays/IsSquareArray.md +1 -1
  68. package/docs/Std.Arrays/Mapped.md +1 -1
  69. package/docs/Std.Arrays/MappedByIndex.md +1 -1
  70. package/docs/Std.Arrays/MappedOverRange.md +1 -1
  71. package/docs/Std.Arrays/Most.md +1 -1
  72. package/docs/Std.Arrays/MostAndTail.md +1 -1
  73. package/docs/Std.Arrays/Padded.md +1 -1
  74. package/docs/Std.Arrays/Partitioned.md +1 -1
  75. package/docs/Std.Arrays/Rest.md +1 -1
  76. package/docs/Std.Arrays/Reversed.md +1 -1
  77. package/docs/Std.Arrays/SequenceI.md +1 -1
  78. package/docs/Std.Arrays/SequenceL.md +1 -1
  79. package/docs/Std.Arrays/Sorted.md +1 -1
  80. package/docs/Std.Arrays/Subarray.md +1 -1
  81. package/docs/Std.Arrays/Swapped.md +1 -1
  82. package/docs/Std.Arrays/Tail.md +1 -1
  83. package/docs/Std.Arrays/Transposed.md +1 -1
  84. package/docs/Std.Arrays/Unzipped.md +1 -1
  85. package/docs/Std.Arrays/Where.md +1 -1
  86. package/docs/Std.Arrays/Windows.md +1 -1
  87. package/docs/Std.Arrays/Zipped.md +1 -1
  88. package/docs/Std.Arrays/index.md +1 -1
  89. package/docs/Std.Canon/ApplyCNOTChain.md +1 -1
  90. package/docs/Std.Canon/ApplyControlledOnBitString.md +1 -1
  91. package/docs/Std.Canon/ApplyControlledOnInt.md +1 -1
  92. package/docs/Std.Canon/ApplyP.md +1 -1
  93. package/docs/Std.Canon/ApplyPauli.md +1 -1
  94. package/docs/Std.Canon/ApplyPauliFromBitString.md +1 -1
  95. package/docs/Std.Canon/ApplyPauliFromInt.md +1 -1
  96. package/docs/Std.Canon/ApplyQFT.md +1 -1
  97. package/docs/Std.Canon/ApplyToEach.md +1 -1
  98. package/docs/Std.Canon/ApplyToEachA.md +1 -1
  99. package/docs/Std.Canon/ApplyToEachC.md +1 -1
  100. package/docs/Std.Canon/ApplyToEachCA.md +1 -1
  101. package/docs/Std.Canon/ApplyXorInPlace.md +1 -1
  102. package/docs/Std.Canon/ApplyXorInPlaceL.md +1 -1
  103. package/docs/Std.Canon/CX.md +1 -1
  104. package/docs/Std.Canon/CY.md +1 -1
  105. package/docs/Std.Canon/CZ.md +1 -1
  106. package/docs/Std.Canon/Fst.md +1 -1
  107. package/docs/Std.Canon/Relabel.md +1 -1
  108. package/docs/Std.Canon/Snd.md +1 -1
  109. package/docs/Std.Canon/SwapReverseRegister.md +1 -1
  110. package/docs/Std.Canon/index.md +1 -1
  111. package/docs/Std.Convert/BigIntAsBoolArray.md +1 -1
  112. package/docs/Std.Convert/BoolArrayAsBigInt.md +1 -1
  113. package/docs/Std.Convert/BoolArrayAsInt.md +1 -1
  114. package/docs/Std.Convert/BoolArrayAsResultArray.md +1 -1
  115. package/docs/Std.Convert/BoolAsResult.md +1 -1
  116. package/docs/Std.Convert/ComplexAsComplexPolar.md +1 -1
  117. package/docs/Std.Convert/ComplexPolarAsComplex.md +1 -1
  118. package/docs/Std.Convert/DoubleAsStringWithPrecision.md +1 -1
  119. package/docs/Std.Convert/IntAsBigInt.md +1 -1
  120. package/docs/Std.Convert/IntAsBoolArray.md +1 -1
  121. package/docs/Std.Convert/IntAsDouble.md +1 -1
  122. package/docs/Std.Convert/ResultArrayAsBoolArray.md +1 -1
  123. package/docs/Std.Convert/ResultArrayAsInt.md +1 -1
  124. package/docs/Std.Convert/ResultAsBool.md +1 -1
  125. package/docs/Std.Convert/index.md +1 -1
  126. package/docs/Std.Core/Length.md +1 -1
  127. package/docs/Std.Core/Repeated.md +1 -1
  128. package/docs/Std.Core/index.md +1 -1
  129. package/docs/Std.Diagnostics/ApplyIdleNoise.md +1 -1
  130. package/docs/Std.Diagnostics/BitFlipNoise.md +1 -1
  131. package/docs/Std.Diagnostics/CheckAllZero.md +1 -1
  132. package/docs/Std.Diagnostics/CheckOperationsAreEqual.md +1 -1
  133. package/docs/Std.Diagnostics/CheckZero.md +1 -1
  134. package/docs/Std.Diagnostics/ConfigurePauliNoise.md +1 -1
  135. package/docs/Std.Diagnostics/DepolarizingNoise.md +1 -1
  136. package/docs/Std.Diagnostics/DumpMachine.md +1 -1
  137. package/docs/Std.Diagnostics/DumpOperation.md +1 -1
  138. package/docs/Std.Diagnostics/DumpRegister.md +1 -1
  139. package/docs/Std.Diagnostics/Fact.md +1 -1
  140. package/docs/Std.Diagnostics/NoNoise.md +1 -1
  141. package/docs/Std.Diagnostics/PhaseFlipNoise.md +1 -1
  142. package/docs/Std.Diagnostics/StartCountingFunction.md +1 -1
  143. package/docs/Std.Diagnostics/StartCountingOperation.md +1 -1
  144. package/docs/Std.Diagnostics/StartCountingQubits.md +1 -1
  145. package/docs/Std.Diagnostics/StopCountingFunction.md +1 -1
  146. package/docs/Std.Diagnostics/StopCountingOperation.md +1 -1
  147. package/docs/Std.Diagnostics/StopCountingQubits.md +1 -1
  148. package/docs/Std.Diagnostics/index.md +1 -1
  149. package/docs/Std.Intrinsic/AND.md +1 -1
  150. package/docs/Std.Intrinsic/ApplyUnitary.md +1 -1
  151. package/docs/Std.Intrinsic/CCNOT.md +1 -1
  152. package/docs/Std.Intrinsic/CNOT.md +1 -1
  153. package/docs/Std.Intrinsic/Exp.md +1 -1
  154. package/docs/Std.Intrinsic/H.md +1 -1
  155. package/docs/Std.Intrinsic/I.md +1 -1
  156. package/docs/Std.Intrinsic/M.md +1 -1
  157. package/docs/Std.Intrinsic/Measure.md +1 -1
  158. package/docs/Std.Intrinsic/Message.md +1 -1
  159. package/docs/Std.Intrinsic/R.md +1 -1
  160. package/docs/Std.Intrinsic/R1.md +1 -1
  161. package/docs/Std.Intrinsic/R1Frac.md +1 -1
  162. package/docs/Std.Intrinsic/RFrac.md +1 -1
  163. package/docs/Std.Intrinsic/Reset.md +1 -1
  164. package/docs/Std.Intrinsic/ResetAll.md +1 -1
  165. package/docs/Std.Intrinsic/Rx.md +1 -1
  166. package/docs/Std.Intrinsic/Rxx.md +1 -1
  167. package/docs/Std.Intrinsic/Ry.md +1 -1
  168. package/docs/Std.Intrinsic/Ryy.md +1 -1
  169. package/docs/Std.Intrinsic/Rz.md +1 -1
  170. package/docs/Std.Intrinsic/Rzz.md +1 -1
  171. package/docs/Std.Intrinsic/S.md +1 -1
  172. package/docs/Std.Intrinsic/SWAP.md +1 -1
  173. package/docs/Std.Intrinsic/T.md +1 -1
  174. package/docs/Std.Intrinsic/X.md +1 -1
  175. package/docs/Std.Intrinsic/Y.md +1 -1
  176. package/docs/Std.Intrinsic/Z.md +1 -1
  177. package/docs/Std.Intrinsic/index.md +1 -1
  178. package/docs/Std.Logical/Xor.md +1 -1
  179. package/docs/Std.Logical/index.md +1 -1
  180. package/docs/Std.Math/AbsComplex.md +1 -1
  181. package/docs/Std.Math/AbsComplexPolar.md +1 -1
  182. package/docs/Std.Math/AbsD.md +1 -1
  183. package/docs/Std.Math/AbsI.md +1 -1
  184. package/docs/Std.Math/AbsL.md +1 -1
  185. package/docs/Std.Math/AbsSquaredComplex.md +1 -1
  186. package/docs/Std.Math/AbsSquaredComplexPolar.md +1 -1
  187. package/docs/Std.Math/ApproximateFactorial.md +1 -1
  188. package/docs/Std.Math/ArcCos.md +1 -1
  189. package/docs/Std.Math/ArcCosh.md +1 -1
  190. package/docs/Std.Math/ArcSin.md +1 -1
  191. package/docs/Std.Math/ArcSinh.md +1 -1
  192. package/docs/Std.Math/ArcTan.md +1 -1
  193. package/docs/Std.Math/ArcTan2.md +1 -1
  194. package/docs/Std.Math/ArcTanh.md +1 -1
  195. package/docs/Std.Math/ArgComplex.md +1 -1
  196. package/docs/Std.Math/ArgComplexPolar.md +1 -1
  197. package/docs/Std.Math/Binom.md +1 -1
  198. package/docs/Std.Math/BitSizeI.md +1 -1
  199. package/docs/Std.Math/BitSizeL.md +1 -1
  200. package/docs/Std.Math/Ceiling.md +1 -1
  201. package/docs/Std.Math/Complex.md +1 -1
  202. package/docs/Std.Math/ComplexPolar.md +1 -1
  203. package/docs/Std.Math/ContinuedFractionConvergentI.md +1 -1
  204. package/docs/Std.Math/ContinuedFractionConvergentL.md +1 -1
  205. package/docs/Std.Math/Cos.md +1 -1
  206. package/docs/Std.Math/Cosh.md +1 -1
  207. package/docs/Std.Math/DivRemI.md +1 -1
  208. package/docs/Std.Math/DivRemL.md +1 -1
  209. package/docs/Std.Math/DividedByC.md +1 -1
  210. package/docs/Std.Math/DividedByCP.md +1 -1
  211. package/docs/Std.Math/E.md +1 -1
  212. package/docs/Std.Math/ExpModI.md +1 -1
  213. package/docs/Std.Math/ExpModL.md +1 -1
  214. package/docs/Std.Math/ExtendedGreatestCommonDivisorI.md +1 -1
  215. package/docs/Std.Math/ExtendedGreatestCommonDivisorL.md +1 -1
  216. package/docs/Std.Math/FactorialI.md +1 -1
  217. package/docs/Std.Math/FactorialL.md +1 -1
  218. package/docs/Std.Math/Floor.md +1 -1
  219. package/docs/Std.Math/GreatestCommonDivisorI.md +1 -1
  220. package/docs/Std.Math/GreatestCommonDivisorL.md +1 -1
  221. package/docs/Std.Math/HammingWeightI.md +1 -1
  222. package/docs/Std.Math/InverseModI.md +1 -1
  223. package/docs/Std.Math/InverseModL.md +1 -1
  224. package/docs/Std.Math/IsCoprimeI.md +1 -1
  225. package/docs/Std.Math/IsCoprimeL.md +1 -1
  226. package/docs/Std.Math/IsInfinite.md +1 -1
  227. package/docs/Std.Math/IsNaN.md +1 -1
  228. package/docs/Std.Math/LargestFixedPoint.md +1 -1
  229. package/docs/Std.Math/Lg.md +1 -1
  230. package/docs/Std.Math/Log.md +1 -1
  231. package/docs/Std.Math/Log10.md +1 -1
  232. package/docs/Std.Math/LogFactorialD.md +1 -1
  233. package/docs/Std.Math/LogGammaD.md +1 -1
  234. package/docs/Std.Math/LogOf2.md +1 -1
  235. package/docs/Std.Math/Max.md +1 -1
  236. package/docs/Std.Math/MaxD.md +1 -1
  237. package/docs/Std.Math/MaxI.md +1 -1
  238. package/docs/Std.Math/MaxL.md +1 -1
  239. package/docs/Std.Math/Min.md +1 -1
  240. package/docs/Std.Math/MinD.md +1 -1
  241. package/docs/Std.Math/MinI.md +1 -1
  242. package/docs/Std.Math/MinL.md +1 -1
  243. package/docs/Std.Math/MinusC.md +1 -1
  244. package/docs/Std.Math/MinusCP.md +1 -1
  245. package/docs/Std.Math/ModulusI.md +1 -1
  246. package/docs/Std.Math/ModulusL.md +1 -1
  247. package/docs/Std.Math/NegationC.md +1 -1
  248. package/docs/Std.Math/NegationCP.md +1 -1
  249. package/docs/Std.Math/PI.md +1 -1
  250. package/docs/Std.Math/PNorm.md +1 -1
  251. package/docs/Std.Math/PNormalized.md +1 -1
  252. package/docs/Std.Math/PlusC.md +1 -1
  253. package/docs/Std.Math/PlusCP.md +1 -1
  254. package/docs/Std.Math/PowC.md +1 -1
  255. package/docs/Std.Math/PowCP.md +1 -1
  256. package/docs/Std.Math/RealMod.md +1 -1
  257. package/docs/Std.Math/Round.md +1 -1
  258. package/docs/Std.Math/SignD.md +1 -1
  259. package/docs/Std.Math/SignI.md +1 -1
  260. package/docs/Std.Math/SignL.md +1 -1
  261. package/docs/Std.Math/Sin.md +1 -1
  262. package/docs/Std.Math/Sinh.md +1 -1
  263. package/docs/Std.Math/SmallestFixedPoint.md +1 -1
  264. package/docs/Std.Math/Sqrt.md +1 -1
  265. package/docs/Std.Math/SquaredNorm.md +1 -1
  266. package/docs/Std.Math/Tan.md +1 -1
  267. package/docs/Std.Math/Tanh.md +1 -1
  268. package/docs/Std.Math/TimesC.md +1 -1
  269. package/docs/Std.Math/TimesCP.md +1 -1
  270. package/docs/Std.Math/TrailingZeroCountI.md +1 -1
  271. package/docs/Std.Math/TrailingZeroCountL.md +1 -1
  272. package/docs/Std.Math/Truncate.md +1 -1
  273. package/docs/Std.Math/index.md +1 -1
  274. package/docs/Std.Measurement/MResetEachZ.md +1 -1
  275. package/docs/Std.Measurement/MResetX.md +1 -1
  276. package/docs/Std.Measurement/MResetY.md +1 -1
  277. package/docs/Std.Measurement/MResetZ.md +1 -1
  278. package/docs/Std.Measurement/MeasureAllZ.md +1 -1
  279. package/docs/Std.Measurement/MeasureEachZ.md +1 -1
  280. package/docs/Std.Measurement/MeasureInteger.md +1 -1
  281. package/docs/Std.Measurement/index.md +1 -1
  282. package/docs/Std.Random/DrawRandomBool.md +1 -1
  283. package/docs/Std.Random/DrawRandomDouble.md +1 -1
  284. package/docs/Std.Random/DrawRandomInt.md +1 -1
  285. package/docs/Std.Random/index.md +1 -1
  286. package/docs/Std.Range/IsRangeEmpty.md +1 -1
  287. package/docs/Std.Range/RangeEnd.md +1 -1
  288. package/docs/Std.Range/RangeReverse.md +1 -1
  289. package/docs/Std.Range/RangeStart.md +1 -1
  290. package/docs/Std.Range/RangeStep.md +1 -1
  291. package/docs/Std.Range/index.md +1 -1
  292. package/docs/Std.ResourceEstimation/AccountForEstimates.md +1 -1
  293. package/docs/Std.ResourceEstimation/AuxQubitCount.md +1 -1
  294. package/docs/Std.ResourceEstimation/BeginEstimateCaching.md +1 -1
  295. package/docs/Std.ResourceEstimation/BeginRepeatEstimates.md +1 -1
  296. package/docs/Std.ResourceEstimation/CczCount.md +1 -1
  297. package/docs/Std.ResourceEstimation/EndEstimateCaching.md +1 -1
  298. package/docs/Std.ResourceEstimation/EndRepeatEstimates.md +1 -1
  299. package/docs/Std.ResourceEstimation/MeasurementCount.md +1 -1
  300. package/docs/Std.ResourceEstimation/PSSPCLayout.md +1 -1
  301. package/docs/Std.ResourceEstimation/RepeatEstimates.md +1 -1
  302. package/docs/Std.ResourceEstimation/RotationCount.md +1 -1
  303. package/docs/Std.ResourceEstimation/RotationDepth.md +1 -1
  304. package/docs/Std.ResourceEstimation/SingleVariant.md +1 -1
  305. package/docs/Std.ResourceEstimation/TCount.md +1 -1
  306. package/docs/Std.ResourceEstimation/index.md +1 -1
  307. package/docs/Std.StatePreparation/ApproximatelyPreparePureStateCP.md +1 -1
  308. package/docs/Std.StatePreparation/PreparePureStateD.md +1 -1
  309. package/docs/Std.StatePreparation/PrepareUniformSuperposition.md +1 -1
  310. package/docs/Std.StatePreparation/index.md +1 -1
  311. package/docs/Std.TableLookup/Select.md +1 -1
  312. package/docs/Std.TableLookup/index.md +1 -1
  313. package/docs/index.md +1 -1
  314. package/lib/node/qsc_wasm.cjs +2 -2
  315. package/lib/node/qsc_wasm_bg.wasm +0 -0
  316. package/lib/web/qsc_wasm.js +2 -2
  317. package/lib/web/qsc_wasm_bg.wasm +0 -0
  318. package/package.json +1 -1
  319. package/ux/circuit-vis/circuit.ts +11 -0
  320. package/ux/circuit-vis/circuitManipulation.ts +549 -0
  321. package/ux/circuit-vis/constants.ts +7 -0
  322. package/ux/circuit-vis/contextMenu.ts +376 -0
  323. package/ux/circuit-vis/draggable.ts +352 -0
  324. package/ux/circuit-vis/events.ts +818 -0
  325. package/ux/circuit-vis/formatters/gateFormatter.ts +56 -23
  326. package/ux/circuit-vis/formatters/inputFormatter.ts +38 -7
  327. package/ux/circuit-vis/formatters/registerFormatter.ts +12 -30
  328. package/ux/circuit-vis/index.ts +16 -11
  329. package/ux/circuit-vis/metadata.ts +3 -1
  330. package/ux/circuit-vis/panel.ts +333 -0
  331. package/ux/circuit-vis/process.ts +136 -232
  332. package/ux/circuit-vis/sqore.ts +231 -116
  333. package/ux/circuit-vis/utils.ts +269 -1
  334. package/ux/circuit.tsx +71 -37
  335. package/ux/data.ts +4 -2
  336. package/ux/index.ts +1 -1
  337. package/ux/qsharp-circuit.css +260 -4
  338. package/ux/circuit-vis/styles.ts +0 -236
@@ -0,0 +1,818 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT license.
3
+
4
+ import cloneDeep from "lodash/cloneDeep";
5
+ import isEqual from "lodash/isEqual";
6
+ import { ComponentGrid, Operation, Qubit, Unitary } from "./circuit";
7
+ import { Sqore } from "./sqore";
8
+ import { toolboxGateDictionary } from "./panel";
9
+ import {
10
+ getGateLocationString,
11
+ findOperation,
12
+ getToolboxElems,
13
+ getGateElems,
14
+ getHostElems,
15
+ getWireData,
16
+ locationStringToIndexes,
17
+ findParentArray,
18
+ } from "./utils";
19
+ import { addContextMenuToHostElem, promptForArguments } from "./contextMenu";
20
+ import {
21
+ addControl,
22
+ addOperation,
23
+ findAndRemoveOperations,
24
+ moveOperation,
25
+ removeControl,
26
+ removeOperation,
27
+ } from "./circuitManipulation";
28
+ import {
29
+ createGhostElement,
30
+ createWireDropzone,
31
+ removeAllWireDropzones,
32
+ } from "./draggable";
33
+ import { getMinMaxRegIdx } from "../../src/utils";
34
+
35
+ let events: CircuitEvents | null = null;
36
+
37
+ /**
38
+ * Creates and attaches the events that allow editing of the circuit.
39
+ *
40
+ * @param container HTML element for rendering visualization into
41
+ * @param sqore Sqore object
42
+ */
43
+ const enableEvents = (
44
+ container: HTMLElement,
45
+ sqore: Sqore,
46
+ useRefresh: () => void,
47
+ ): void => {
48
+ if (events != null) {
49
+ events.dispose();
50
+ }
51
+ events = new CircuitEvents(container, sqore, useRefresh);
52
+ };
53
+
54
+ class CircuitEvents {
55
+ renderFn: () => void;
56
+ componentGrid: ComponentGrid;
57
+ qubits: Qubit[];
58
+ private circuitSvg: SVGElement;
59
+ private dropzoneLayer: SVGGElement;
60
+ private wireData: number[];
61
+ private selectedOperation: Operation | null = null;
62
+ private selectedWire: number | null = null;
63
+ private movingControl: boolean = false;
64
+ private mouseUpOnCircuit: boolean = false;
65
+ private dragging: boolean = false;
66
+ private disableLeftAutoScroll: boolean = false;
67
+
68
+ constructor(
69
+ private container: HTMLElement,
70
+ sqore: Sqore,
71
+ useRefresh: () => void,
72
+ ) {
73
+ this.renderFn = useRefresh;
74
+
75
+ this.circuitSvg = container.querySelector("svg[id]") as SVGElement;
76
+ this.dropzoneLayer = container.querySelector(
77
+ ".dropzone-layer",
78
+ ) as SVGGElement;
79
+
80
+ this.componentGrid = sqore.circuit.componentGrid;
81
+ this.qubits = sqore.circuit.qubits;
82
+
83
+ this.wireData = getWireData(this.container);
84
+
85
+ this._addContextMenuEvent();
86
+ this._addDropzoneLayerEvents();
87
+ this._addHostElementsEvents();
88
+ this._addGateElementsEvents();
89
+ this._addToolboxElementsEvents();
90
+ this._addDropzoneElementsEvents();
91
+ this._addQubitLineControlEvents();
92
+ this._addDocumentEvents();
93
+ }
94
+
95
+ /**
96
+ * Dispose the CircuitEvents instance and remove event listeners
97
+ */
98
+ dispose() {
99
+ this._removeToolboxElementsEvents();
100
+ this._removeDocumentEvents();
101
+ }
102
+
103
+ /***************************
104
+ * Events Adding Functions *
105
+ ***************************/
106
+
107
+ documentKeydownHandler = (ev: KeyboardEvent) => {
108
+ const selectedLocation = this.selectedOperation
109
+ ? getGateLocationString(this.selectedOperation)
110
+ : null;
111
+ if (ev.ctrlKey && selectedLocation) {
112
+ this.container.classList.remove("moving");
113
+ this.container.classList.add("copying");
114
+ }
115
+ };
116
+
117
+ documentKeyupHandler = (ev: KeyboardEvent) => {
118
+ const selectedLocation = this.selectedOperation
119
+ ? getGateLocationString(this.selectedOperation)
120
+ : null;
121
+ if (ev.ctrlKey && selectedLocation) {
122
+ this.container.classList.remove("copying");
123
+ this.container.classList.add("moving");
124
+ }
125
+ };
126
+
127
+ documentMousedownHandler = () => {
128
+ removeAllWireDropzones(this.circuitSvg);
129
+ };
130
+
131
+ documentMouseupHandler = (ev: MouseEvent) => {
132
+ const copying = ev.ctrlKey;
133
+ this.container.classList.remove("moving", "copying");
134
+ if (this.container) {
135
+ const ghostElem = this.container.querySelector(".ghost");
136
+ if (ghostElem) {
137
+ this.container.removeChild(ghostElem);
138
+ }
139
+
140
+ // Handle deleting operations that have been dragged outside the circuit
141
+ if (!this.mouseUpOnCircuit && this.dragging && !copying) {
142
+ const selectedLocation = this.selectedOperation
143
+ ? getGateLocationString(this.selectedOperation)
144
+ : null;
145
+ if (this.selectedOperation != null && selectedLocation != null) {
146
+ // We are dragging a gate with a location (not from toolbox) outside the circuit
147
+ // If we are moving a control, remove it from the selectedOperation
148
+ if (
149
+ this.movingControl &&
150
+ this.selectedOperation.kind === "unitary" &&
151
+ this.selectedOperation.controls != null &&
152
+ this.selectedWire != null
153
+ ) {
154
+ const controlIndex = this.selectedOperation.controls.findIndex(
155
+ (control) => control.qubit === this.selectedWire,
156
+ );
157
+ if (controlIndex !== -1)
158
+ this.selectedOperation.controls.splice(controlIndex, 1);
159
+ } else {
160
+ // Otherwise, remove the selectedOperation
161
+ removeOperation(this, selectedLocation);
162
+ }
163
+ this.renderFn();
164
+ }
165
+ }
166
+ }
167
+ this.dragging = false;
168
+ this.disableLeftAutoScroll = false;
169
+ this.movingControl = false;
170
+ this.mouseUpOnCircuit = false;
171
+ };
172
+
173
+ /**
174
+ * Enable auto-scrolling when dragging near the edges of the container
175
+ */
176
+ _enableAutoScroll() {
177
+ const scrollSpeed = 10; // Pixels per frame
178
+ const edgeThreshold = 50; // Distance from the edge to trigger scrolling
179
+
180
+ // Utility function to find the nearest scrollable ancestor
181
+ const getScrollableAncestor = (element: Element): HTMLElement => {
182
+ let currentElement: Element | null = element;
183
+ while (currentElement) {
184
+ const overflowY = window.getComputedStyle(currentElement).overflowY;
185
+ const overflowX = window.getComputedStyle(currentElement).overflowX;
186
+ if (
187
+ overflowY === "auto" ||
188
+ overflowY === "scroll" ||
189
+ overflowX === "auto" ||
190
+ overflowX === "scroll"
191
+ ) {
192
+ return currentElement as HTMLElement;
193
+ }
194
+ currentElement = currentElement.parentElement;
195
+ }
196
+ return document.documentElement; // Fallback to the root element
197
+ };
198
+
199
+ const scrollableAncestor = getScrollableAncestor(this.circuitSvg);
200
+
201
+ const onMouseMove = (ev: MouseEvent) => {
202
+ const rect = scrollableAncestor.getBoundingClientRect();
203
+
204
+ const topBoundary = rect.top;
205
+ const bottomBoundary = rect.bottom;
206
+ const leftBoundary = rect.left;
207
+ const rightBoundary = rect.right;
208
+
209
+ // If the mouse has moved past the left boundary, we want to re-enable left auto-scrolling
210
+ if (
211
+ this.disableLeftAutoScroll &&
212
+ ev.clientX > leftBoundary + 3 * edgeThreshold
213
+ ) {
214
+ this.disableLeftAutoScroll = false;
215
+ }
216
+
217
+ // Check if the cursor is near the edges
218
+ if (ev.clientY < topBoundary + edgeThreshold) {
219
+ // Scroll up
220
+ scrollableAncestor.scrollTop -= scrollSpeed;
221
+ } else if (ev.clientY > bottomBoundary - edgeThreshold) {
222
+ // Scroll down
223
+ scrollableAncestor.scrollTop += scrollSpeed;
224
+ }
225
+
226
+ if (
227
+ !this.disableLeftAutoScroll &&
228
+ ev.clientX < leftBoundary + edgeThreshold
229
+ ) {
230
+ // Scroll left
231
+ scrollableAncestor.scrollLeft -= scrollSpeed;
232
+ } else if (ev.clientX > rightBoundary - edgeThreshold) {
233
+ // Scroll right
234
+ scrollableAncestor.scrollLeft += scrollSpeed;
235
+ }
236
+ };
237
+
238
+ const onMouseUp = () => {
239
+ // Remove the mousemove listener when dragging stops
240
+ document.removeEventListener("mousemove", onMouseMove);
241
+ document.removeEventListener("mouseup", onMouseUp);
242
+ };
243
+
244
+ // Add the mousemove listener when dragging starts
245
+ document.addEventListener("mousemove", onMouseMove);
246
+ document.addEventListener("mouseup", onMouseUp);
247
+ }
248
+
249
+ /**
250
+ * Add events for document
251
+ */
252
+ _addDocumentEvents() {
253
+ document.addEventListener("keydown", this.documentKeydownHandler);
254
+ document.addEventListener("keyup", this.documentKeyupHandler);
255
+ document.addEventListener("mouseup", this.documentMouseupHandler);
256
+ document.addEventListener("mousedown", this.documentMousedownHandler);
257
+ }
258
+
259
+ /**
260
+ * Remove events for document
261
+ */
262
+ _removeDocumentEvents() {
263
+ document.removeEventListener("keydown", this.documentKeydownHandler);
264
+ document.removeEventListener("keyup", this.documentKeyupHandler);
265
+ document.removeEventListener("mouseup", this.documentMouseupHandler);
266
+ document.removeEventListener("mousedown", this.documentMousedownHandler);
267
+ }
268
+
269
+ /**
270
+ * Add events specifically for dropzoneLayer
271
+ */
272
+ _addDropzoneLayerEvents() {
273
+ this.container.addEventListener(
274
+ "mouseup",
275
+ () => (this.dropzoneLayer.style.display = "none"),
276
+ );
277
+
278
+ this.circuitSvg.addEventListener("mouseup", () => {
279
+ this.mouseUpOnCircuit = true;
280
+ });
281
+ }
282
+
283
+ /**
284
+ * Disable contextmenu default behaviors
285
+ */
286
+ _addContextMenuEvent() {
287
+ this.container.addEventListener("contextmenu", (ev: MouseEvent) => {
288
+ ev.preventDefault();
289
+ });
290
+ }
291
+
292
+ /**
293
+ * Add events for circuit objects in the circuit
294
+ */
295
+ _addHostElementsEvents() {
296
+ const elems = getHostElems(this.container);
297
+ elems.forEach((elem) => {
298
+ elem.addEventListener("mousedown", (ev: MouseEvent) => {
299
+ if (ev.button !== 0) return;
300
+ if (elem.classList.contains("control-dot")) {
301
+ this.movingControl = true;
302
+ }
303
+ const selectedWireStr = elem.getAttribute("data-wire");
304
+ this.selectedWire =
305
+ selectedWireStr != null ? parseInt(selectedWireStr) : null;
306
+ });
307
+
308
+ addContextMenuToHostElem(this, elem);
309
+ });
310
+ }
311
+
312
+ /**
313
+ * Add events for circuit objects in the circuit
314
+ */
315
+ _addGateElementsEvents() {
316
+ const elems = getGateElems(this.container);
317
+ elems.forEach((elem) => {
318
+ elem?.addEventListener("mousedown", (ev: MouseEvent) => {
319
+ // Allow dragging even when initiated on the arg-button
320
+ if ((ev.target as HTMLElement).classList.contains("arg-button")) {
321
+ // Find the sibling element with the data-wire attribute
322
+ const siblingWithWire = (
323
+ ev.target as HTMLElement
324
+ ).parentElement?.querySelector("[data-wire]");
325
+ if (siblingWithWire) {
326
+ const selectedWireStr = siblingWithWire.getAttribute("data-wire");
327
+ this.selectedWire =
328
+ selectedWireStr != null ? parseInt(selectedWireStr) : null;
329
+ }
330
+ }
331
+
332
+ let selectedLocation = null;
333
+ if (elem.getAttribute("data-expanded") !== "true") {
334
+ selectedLocation = elem.getAttribute("data-location");
335
+ this.selectedOperation = findOperation(
336
+ this.componentGrid,
337
+ selectedLocation,
338
+ );
339
+ }
340
+ if (ev.button !== 0) return;
341
+ ev.stopPropagation();
342
+ removeAllWireDropzones(this.circuitSvg);
343
+ if (this.selectedOperation == null || !selectedLocation) return;
344
+
345
+ this._createGhostElement(ev);
346
+
347
+ // Make sure the selectedOperation has location data
348
+ if (this.selectedOperation.dataAttributes == null) {
349
+ this.selectedOperation.dataAttributes = {
350
+ location: selectedLocation,
351
+ };
352
+ } else {
353
+ this.selectedOperation.dataAttributes["location"] = selectedLocation;
354
+ }
355
+
356
+ this.container.classList.add("moving");
357
+ this.dropzoneLayer.style.display = "block";
358
+ });
359
+
360
+ // Enable arg-button behavior
361
+ const argButtons = elem.querySelectorAll<SVGElement>(".arg-button");
362
+ argButtons.forEach((argButton) => {
363
+ argButton.classList.add("edit-mode");
364
+
365
+ // Add click event to trigger promptForArguments
366
+ argButton.addEventListener("click", async () => {
367
+ if (this.selectedOperation == null) return;
368
+ const params = this.selectedOperation.params;
369
+ const displayArgs = argButton.textContent || "";
370
+ if (params) {
371
+ const args = await promptForArguments(params, [displayArgs]);
372
+ if (args.length > 0) {
373
+ this.selectedOperation.args = args;
374
+ this.renderFn();
375
+ }
376
+ }
377
+ });
378
+ });
379
+ });
380
+ }
381
+
382
+ toolboxMousedownHandler = (ev: MouseEvent) => {
383
+ if (ev.button !== 0) return;
384
+ this.container.classList.add("moving");
385
+ this.dropzoneLayer.style.display = "block";
386
+ const elem = ev.currentTarget as HTMLElement;
387
+ const type = elem.getAttribute("data-type");
388
+ if (type == null) return;
389
+ this.selectedOperation = toolboxGateDictionary[type];
390
+ this.disableLeftAutoScroll = true;
391
+ this._createGhostElement(ev);
392
+ };
393
+
394
+ /**
395
+ * Add events for gates in the toolbox
396
+ */
397
+ _addToolboxElementsEvents() {
398
+ const elems = getToolboxElems(this.container);
399
+ elems.forEach((elem) => {
400
+ elem.addEventListener("mousedown", this.toolboxMousedownHandler);
401
+ });
402
+ }
403
+
404
+ /**
405
+ * Remove events for gates in the toolbox
406
+ */
407
+ _removeToolboxElementsEvents() {
408
+ const elems = getToolboxElems(this.container);
409
+ elems.forEach((elem) => {
410
+ elem.removeEventListener("mousedown", this.toolboxMousedownHandler);
411
+ });
412
+ }
413
+
414
+ /**
415
+ * Add events for dropzone elements
416
+ */
417
+ _addDropzoneElementsEvents() {
418
+ const dropzoneElems =
419
+ this.dropzoneLayer.querySelectorAll<SVGRectElement>(".dropzone");
420
+ dropzoneElems.forEach((dropzoneElem) => {
421
+ dropzoneElem.addEventListener("mouseup", async (ev: MouseEvent) => {
422
+ const copying = ev.ctrlKey;
423
+ const originalGrid = cloneDeep(this.componentGrid);
424
+ const targetLoc = dropzoneElem.getAttribute("data-dropzone-location");
425
+ const insertNewColumn =
426
+ dropzoneElem.getAttribute("data-dropzone-inter-column") == "true" ||
427
+ false;
428
+ const targetWireStr = dropzoneElem.getAttribute("data-dropzone-wire");
429
+ const targetWire =
430
+ targetWireStr != null ? parseInt(targetWireStr) : null;
431
+
432
+ if (
433
+ targetLoc == null ||
434
+ targetWire == null ||
435
+ this.selectedOperation == null
436
+ )
437
+ return;
438
+ const sourceLocation = getGateLocationString(this.selectedOperation);
439
+
440
+ if (sourceLocation == null) {
441
+ if (
442
+ this.selectedOperation.params != undefined &&
443
+ (this.selectedOperation.args === undefined ||
444
+ this.selectedOperation.args.length === 0)
445
+ ) {
446
+ // Prompt for arguments and wait for user input
447
+ const args = await promptForArguments(
448
+ this.selectedOperation.params,
449
+ );
450
+ if (!args || args.length === 0) {
451
+ // User canceled the prompt, exit early
452
+ return;
453
+ }
454
+
455
+ // Create a deep copy of the source operation
456
+ this.selectedOperation = JSON.parse(
457
+ JSON.stringify(this.selectedOperation),
458
+ );
459
+ if (this.selectedOperation == null) return;
460
+
461
+ // Assign the arguments to the selected operation
462
+ this.selectedOperation.args = args;
463
+ }
464
+
465
+ // Add a new operation from the toolbox
466
+ addOperation(
467
+ this,
468
+ this.selectedOperation,
469
+ targetLoc,
470
+ targetWire,
471
+ insertNewColumn,
472
+ );
473
+ } else if (sourceLocation && this.selectedWire != null) {
474
+ if (copying) {
475
+ if (
476
+ this.movingControl &&
477
+ this.selectedOperation.kind === "unitary"
478
+ ) {
479
+ addControl(this.selectedOperation, targetWire);
480
+ moveOperation(
481
+ this,
482
+ sourceLocation,
483
+ targetLoc,
484
+ this.selectedWire,
485
+ targetWire,
486
+ false,
487
+ insertNewColumn,
488
+ );
489
+ } else {
490
+ addOperation(
491
+ this,
492
+ this.selectedOperation,
493
+ targetLoc,
494
+ targetWire,
495
+ insertNewColumn,
496
+ );
497
+ }
498
+ } else {
499
+ moveOperation(
500
+ this,
501
+ sourceLocation,
502
+ targetLoc,
503
+ this.selectedWire,
504
+ targetWire,
505
+ this.movingControl,
506
+ insertNewColumn,
507
+ );
508
+ }
509
+ }
510
+
511
+ this.selectedWire = null;
512
+ this.selectedOperation = null;
513
+ this.movingControl = false;
514
+
515
+ if (isEqual(originalGrid, this.componentGrid) === false)
516
+ this.renderFn();
517
+ });
518
+ });
519
+ }
520
+
521
+ /**
522
+ * Add event listeners for the buttons to add or remove qubit lines.
523
+ * The add button will append a new qubit line to the circuit.
524
+ * The remove button will remove the last qubit line from the circuit,
525
+ * along with any operations associated with it.
526
+ */
527
+ _addQubitLineControlEvents() {
528
+ const addQubitLineButton = this.container.querySelector(".add-qubit-line");
529
+ const removeQubitLineButton =
530
+ this.container.querySelector(".remove-qubit-line");
531
+
532
+ if (
533
+ addQubitLineButton &&
534
+ !addQubitLineButton.hasAttribute("data-event-added")
535
+ ) {
536
+ addQubitLineButton.addEventListener("click", () => {
537
+ this.qubits.push({ id: this.qubits.length });
538
+ this.renderFn();
539
+ });
540
+ addQubitLineButton.setAttribute("data-event-added", "true");
541
+ }
542
+
543
+ if (
544
+ removeQubitLineButton &&
545
+ !removeQubitLineButton.hasAttribute("data-event-added")
546
+ ) {
547
+ removeQubitLineButton.addEventListener("click", () => {
548
+ // Determines if the operation is associated with the last qubit line
549
+ const check = (op: Operation) => {
550
+ const targets = op.kind === "measurement" ? op.results : op.targets;
551
+ if (targets.some((reg) => reg.qubit == this.qubits.length - 1)) {
552
+ return true;
553
+ }
554
+ const controls =
555
+ op.kind === "measurement"
556
+ ? op.qubits
557
+ : op.kind === "ket"
558
+ ? []
559
+ : op.controls;
560
+ if (
561
+ controls &&
562
+ controls.some((reg) => reg.qubit == this.qubits.length - 1)
563
+ ) {
564
+ return true;
565
+ }
566
+ return false;
567
+ };
568
+
569
+ // Count number of operations associated with the last qubit line
570
+ const numOperations = this.componentGrid.reduce(
571
+ (acc, column) =>
572
+ acc + column.components.filter((op) => check(op)).length,
573
+ 0,
574
+ );
575
+ if (numOperations === 0) {
576
+ this.qubits.pop();
577
+ this.renderFn();
578
+ } else {
579
+ const message =
580
+ numOperations === 1
581
+ ? `There is ${numOperations} operation associated with the last qubit line. Do you want to remove it?`
582
+ : `There are ${numOperations} operations associated with the last qubit line. Do you want to remove them?`;
583
+ _createConfirmPrompt(message, (confirmed) => {
584
+ if (confirmed) {
585
+ // Remove all operations associated with the last qubit line
586
+ findAndRemoveOperations(this.componentGrid, check);
587
+ this.qubits.pop();
588
+ this.renderFn();
589
+ }
590
+ });
591
+ }
592
+ });
593
+ removeQubitLineButton.setAttribute("data-event-added", "true");
594
+ }
595
+ }
596
+
597
+ /*****************
598
+ * Misc. *
599
+ *****************/
600
+
601
+ /**
602
+ * Creates a ghost element for visual feedback during dragging.
603
+ * This function initializes the dragging state, enables auto-scrolling,
604
+ * and creates a visual representation of the selected operation.
605
+ *
606
+ * @param ev - The mouse event that triggered the creation of the ghost element.
607
+ */
608
+ _createGhostElement(ev: MouseEvent) {
609
+ if (this.selectedOperation == null) return;
610
+ this.dragging = true;
611
+ this._enableAutoScroll();
612
+ createGhostElement(
613
+ ev,
614
+ this.container,
615
+ this.selectedOperation,
616
+ this.movingControl,
617
+ );
618
+ }
619
+
620
+ /**
621
+ * Start the process of adding a control to the selected operation.
622
+ * This function creates dropzones for each wire that isn't already a target or control.
623
+ *
624
+ * @param selectedOperation - The unitary operation to which the control will be added.
625
+ * @param selectedLocation - The location string of the selected operation.
626
+ */
627
+ _startAddingControl(selectedOperation: Unitary, selectedLocation: string) {
628
+ this.selectedOperation = selectedOperation;
629
+ this.container.classList.add("adding-control");
630
+
631
+ // Create dropzones for each wire that isn't already a target or control
632
+ for (let wireIndex = 0; wireIndex < this.wireData.length; wireIndex++) {
633
+ const isTarget = this.selectedOperation?.targets.some(
634
+ (target) => target.qubit === wireIndex,
635
+ );
636
+ const isControl = this.selectedOperation?.controls?.some(
637
+ (control) => control.qubit === wireIndex,
638
+ );
639
+
640
+ if (!isTarget && !isControl) {
641
+ const dropzone = createWireDropzone(
642
+ this.circuitSvg,
643
+ this.wireData,
644
+ wireIndex,
645
+ );
646
+ dropzone.addEventListener("mousedown", (ev: MouseEvent) =>
647
+ ev.stopPropagation(),
648
+ );
649
+ dropzone.addEventListener("click", () => {
650
+ if (
651
+ this.selectedOperation != null &&
652
+ this.selectedOperation.kind === "unitary"
653
+ ) {
654
+ const successful = addControl(this.selectedOperation, wireIndex);
655
+ this.selectedOperation = null;
656
+ this.container.classList.remove("adding-control");
657
+ if (successful) {
658
+ const indexes = locationStringToIndexes(selectedLocation);
659
+ const [columnIndex, position] = indexes[indexes.length - 1];
660
+ const selectedOperationParent = findParentArray(
661
+ this.componentGrid,
662
+ selectedLocation,
663
+ );
664
+ if (!selectedOperationParent) return;
665
+
666
+ const [minTarget, maxTarget] = getMinMaxRegIdx(
667
+ selectedOperation,
668
+ this.wireData.length,
669
+ );
670
+ selectedOperationParent[columnIndex].components.forEach(
671
+ (op, opIndex) => {
672
+ if (opIndex === position) return; // Don't check the selected operation against itself
673
+ const [minOp, maxOp] = getMinMaxRegIdx(
674
+ op,
675
+ this.wireData.length,
676
+ );
677
+ // Check if selectedOperation's range overlaps with op's range
678
+ if (
679
+ (minOp >= minTarget && minOp <= maxTarget) ||
680
+ (maxOp >= minTarget && maxOp <= maxTarget) ||
681
+ (minTarget >= minOp && minTarget <= minOp) ||
682
+ (maxTarget >= maxOp && maxTarget <= maxOp)
683
+ ) {
684
+ // If they overlap, move the operation
685
+ selectedOperationParent[columnIndex].components.splice(
686
+ position,
687
+ 1,
688
+ );
689
+ // Not sure if this check is needed as we already know there
690
+ // should be other operations in this column.
691
+ if (
692
+ selectedOperationParent[columnIndex].components.length ===
693
+ 0
694
+ ) {
695
+ selectedOperationParent.splice(columnIndex, 1);
696
+ }
697
+
698
+ selectedOperationParent.splice(columnIndex, 0, {
699
+ components: [selectedOperation],
700
+ });
701
+ }
702
+ },
703
+ );
704
+
705
+ this.renderFn();
706
+ }
707
+ }
708
+ });
709
+ this.circuitSvg.appendChild(dropzone);
710
+ }
711
+ }
712
+ }
713
+
714
+ /**
715
+ * Start the process of removing a control from the selected operation.
716
+ * This function creates dropzones only for wires that the selected operation has a control.
717
+ *
718
+ * @param selectedOperation - The unitary operation from which the control will be removed.
719
+ */
720
+ _startRemovingControl(selectedOperation: Unitary) {
721
+ this.selectedOperation = selectedOperation;
722
+ this.container.classList.add("removing-control");
723
+
724
+ // Create dropzones only for wires that the selectedOperation has a control
725
+ this.selectedOperation.controls?.forEach((control) => {
726
+ const dropzone = createWireDropzone(
727
+ this.circuitSvg,
728
+ this.wireData,
729
+ control.qubit,
730
+ );
731
+ dropzone.addEventListener("mousedown", (ev: MouseEvent) =>
732
+ ev.stopPropagation(),
733
+ );
734
+ dropzone.addEventListener("click", () => {
735
+ if (
736
+ this.selectedOperation != null &&
737
+ this.selectedOperation.kind === "unitary"
738
+ ) {
739
+ const successful = removeControl(
740
+ this.selectedOperation,
741
+ control.qubit,
742
+ );
743
+ this.selectedOperation = null;
744
+ this.container.classList.remove("removing-control");
745
+ if (successful) {
746
+ this.renderFn();
747
+ }
748
+ }
749
+ });
750
+ this.circuitSvg.appendChild(dropzone);
751
+ });
752
+ }
753
+ }
754
+
755
+ /**
756
+ * Create a confirm dialog box
757
+ * @param message - The message to display in the confirm dialog
758
+ * @param callback - The callback function to handle the user's response (true for OK, false for Cancel)
759
+ */
760
+ const _createConfirmPrompt = (
761
+ message: string,
762
+ callback: (confirmed: boolean) => void,
763
+ ) => {
764
+ // Create the confirm overlay
765
+ const overlay = document.createElement("div");
766
+ overlay.classList.add("prompt-overlay");
767
+ overlay.addEventListener("contextmenu", (e) => {
768
+ e.preventDefault();
769
+ e.stopPropagation();
770
+ });
771
+
772
+ // Create the confirm container
773
+ const confirmContainer = document.createElement("div");
774
+ confirmContainer.classList.add("prompt-container");
775
+
776
+ // Create the message element
777
+ const messageElem = document.createElement("div");
778
+ messageElem.classList.add("prompt-message");
779
+ messageElem.textContent = message;
780
+
781
+ // Create the buttons container
782
+ const buttonsContainer = document.createElement("div");
783
+ buttonsContainer.classList.add("prompt-buttons");
784
+
785
+ // Create the OK button
786
+ const okButton = document.createElement("button");
787
+ okButton.classList.add("prompt-button");
788
+ okButton.textContent = "OK";
789
+ okButton.addEventListener("click", () => {
790
+ callback(true); // User confirmed
791
+ document.body.removeChild(overlay);
792
+ });
793
+
794
+ // Create the Cancel button
795
+ const cancelButton = document.createElement("button");
796
+ cancelButton.classList.add("prompt-button");
797
+ cancelButton.textContent = "Cancel";
798
+ cancelButton.addEventListener("click", () => {
799
+ callback(false); // User canceled
800
+ document.body.removeChild(overlay);
801
+ });
802
+
803
+ buttonsContainer.appendChild(okButton);
804
+ buttonsContainer.appendChild(cancelButton);
805
+
806
+ confirmContainer.appendChild(messageElem);
807
+ confirmContainer.appendChild(buttonsContainer);
808
+
809
+ overlay.appendChild(confirmContainer);
810
+ document.body.appendChild(overlay);
811
+
812
+ // Remove focus from any currently focused element
813
+ if (document.activeElement) {
814
+ (document.activeElement as HTMLElement).blur();
815
+ }
816
+ };
817
+
818
+ export { enableEvents, CircuitEvents };