@opentrons/components 0.1.6-alpha.2 → 0.1.6-alpha.21

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 (373) hide show
  1. package/Makefile +5 -1
  2. package/package.json +6 -7
  3. package/src/__mocks__/file.js +10 -0
  4. package/src/alerts/AlertItem.stories.tsx +49 -0
  5. package/src/alerts/AlertItem.tsx +85 -0
  6. package/src/alerts/index.ts +3 -0
  7. package/src/atoms/Checkbox/Checkbox.stories.tsx +24 -0
  8. package/src/atoms/Checkbox/index.tsx +127 -0
  9. package/src/atoms/CheckboxField/CheckboxField.stories.tsx +30 -0
  10. package/src/atoms/CheckboxField/index.tsx +171 -0
  11. package/src/atoms/Chip/Chip.stories.tsx +59 -0
  12. package/src/atoms/Chip/index.tsx +172 -0
  13. package/src/atoms/Divider/index.tsx +15 -0
  14. package/src/atoms/InputField/InputField.stories.tsx +77 -0
  15. package/src/atoms/InputField/index.tsx +383 -0
  16. package/src/atoms/ListButton/ListButton.stories.tsx +133 -0
  17. package/src/atoms/ListButton/ListButtonChildren/ListButtonAccordion.tsx +65 -0
  18. package/src/atoms/ListButton/ListButtonChildren/ListButtonAccordionContainer.tsx +23 -0
  19. package/src/atoms/ListButton/ListButtonChildren/ListButtonRadioButton.tsx +108 -0
  20. package/src/atoms/ListButton/ListButtonChildren/index.ts +3 -0
  21. package/src/atoms/ListButton/index.tsx +72 -0
  22. package/src/atoms/ListItem/ListItem.stories.tsx +96 -0
  23. package/src/atoms/ListItem/ListItemChildren/ListItemCustomize.tsx +78 -0
  24. package/src/atoms/ListItem/ListItemChildren/ListItemDescriptor.tsx +42 -0
  25. package/src/atoms/ListItem/ListItemChildren/index.ts +2 -0
  26. package/src/atoms/ListItem/index.tsx +89 -0
  27. package/src/atoms/MenuList/MenuItem.stories.tsx +20 -0
  28. package/src/atoms/MenuList/MenuItem.tsx +55 -0
  29. package/src/atoms/MenuList/MenuList.stories.tsx +31 -0
  30. package/src/atoms/MenuList/OverflowBtn.stories.tsx +17 -0
  31. package/src/atoms/MenuList/OverflowBtn.tsx +76 -0
  32. package/src/atoms/MenuList/index.tsx +50 -0
  33. package/src/atoms/Snackbar/Snackbar.stories.tsx +67 -0
  34. package/src/atoms/Snackbar/index.tsx +91 -0
  35. package/src/atoms/StepMeter/index.tsx +53 -0
  36. package/src/atoms/StyledText/LegacyStyledText.stories.tsx +106 -0
  37. package/src/atoms/StyledText/LegacyStyledText.tsx +95 -0
  38. package/src/atoms/StyledText/StyledText.stories.tsx +46 -0
  39. package/src/atoms/StyledText/StyledText.tsx +323 -0
  40. package/src/atoms/StyledText/index.ts +2 -0
  41. package/src/atoms/Tag/Tag.stories.tsx +48 -0
  42. package/src/atoms/Tag/index.tsx +116 -0
  43. package/src/atoms/Toast/ODDToast.stories.tsx +68 -0
  44. package/src/atoms/Toast/Toast.stories.tsx +55 -0
  45. package/src/atoms/Toast/index.tsx +439 -0
  46. package/src/atoms/ToggleGroup/ToggleGroup.stories.tsx +39 -0
  47. package/src/atoms/ToggleGroup/index.tsx +91 -0
  48. package/src/atoms/Tooltip/Tooltip.stories.tsx +99 -0
  49. package/src/atoms/Tooltip/index.tsx +38 -0
  50. package/src/atoms/buttons/AlertPrimaryButton.tsx +26 -0
  51. package/src/atoms/buttons/AltPrimaryButton.tsx +31 -0
  52. package/src/atoms/buttons/EmptySelectorButton.stories.tsx +36 -0
  53. package/src/atoms/buttons/EmptySelectorButton.tsx +83 -0
  54. package/src/atoms/buttons/LargeButton.stories.tsx +99 -0
  55. package/src/atoms/buttons/LargeButton.tsx +320 -0
  56. package/src/atoms/buttons/PrimaryButton.tsx +36 -0
  57. package/src/atoms/buttons/RadioButton.stories.tsx +35 -0
  58. package/src/atoms/buttons/RadioButton.tsx +217 -0
  59. package/src/atoms/buttons/SecondaryButton.tsx +62 -0
  60. package/src/atoms/buttons/buttons.stories.tsx +78 -0
  61. package/src/atoms/buttons/index.ts +6 -0
  62. package/src/atoms/index.ts +20 -0
  63. package/src/barrel.ts +10 -0
  64. package/src/buttons/Button.tsx +96 -0
  65. package/src/buttons/DeprecatedPrimaryButton.tsx +24 -0
  66. package/src/buttons/FlatButton.tsx +21 -0
  67. package/src/buttons/IconButton.tsx +37 -0
  68. package/src/buttons/OutlineButton.tsx +24 -0
  69. package/src/buttons/index.ts +7 -0
  70. package/src/controls/ControlInfo.tsx +13 -0
  71. package/src/controls/LabeledButton.tsx +28 -0
  72. package/src/controls/LabeledCheckbox.tsx +35 -0
  73. package/src/controls/LabeledControl.tsx +24 -0
  74. package/src/controls/LabeledRadioGroup.tsx +27 -0
  75. package/src/controls/LabeledSelect.tsx +34 -0
  76. package/src/controls/LabeledToggle.tsx +35 -0
  77. package/src/controls/StackedLabeledControl.tsx +28 -0
  78. package/src/controls/ToggleButton.tsx +25 -0
  79. package/src/controls/index.ts +10 -0
  80. package/src/forms/DeprecatedCheckboxField.stories.tsx +31 -0
  81. package/src/forms/DeprecatedCheckboxField.tsx +94 -0
  82. package/src/forms/DropdownField.stories.tsx +44 -0
  83. package/src/forms/DropdownField.tsx +106 -0
  84. package/src/forms/FormGroup.stories.tsx +31 -0
  85. package/src/forms/FormGroup.tsx +53 -0
  86. package/src/forms/InputField.stories.tsx +41 -0
  87. package/src/forms/LegacyInputField.tsx +123 -0
  88. package/src/forms/RadioGroup.stories.tsx +44 -0
  89. package/src/forms/RadioGroup.tsx +87 -0
  90. package/src/forms/Select.stories.tsx +117 -0
  91. package/src/forms/Select.tsx +132 -0
  92. package/src/forms/SelectField.tsx +94 -0
  93. package/src/forms/ToggleField.stories.tsx +31 -0
  94. package/src/forms/ToggleField.tsx +59 -0
  95. package/src/forms/index.ts +8 -0
  96. package/src/hardware-sim/BaseDeck/BaseDeck.stories.tsx +94 -0
  97. package/src/hardware-sim/BaseDeck/BaseDeck.tsx +423 -0
  98. package/src/hardware-sim/BaseDeck/SingleSlotFixture.tsx +199 -0
  99. package/src/hardware-sim/BaseDeck/SlotBase.tsx +5 -0
  100. package/src/hardware-sim/BaseDeck/SlotClip.tsx +15 -0
  101. package/src/hardware-sim/BaseDeck/StagingAreaFixture.tsx +114 -0
  102. package/src/hardware-sim/BaseDeck/WasteChuteFixture.tsx +114 -0
  103. package/src/hardware-sim/BaseDeck/WasteChuteStagingAreaFixture.tsx +68 -0
  104. package/src/hardware-sim/BaseDeck/__fixtures__/index.ts +165 -0
  105. package/src/hardware-sim/BaseDeck/index.ts +5 -0
  106. package/src/hardware-sim/BaseDeck/something.test.tsx +7 -0
  107. package/src/hardware-sim/Deck/DeckFromLayers.tsx +58 -0
  108. package/src/hardware-sim/Deck/FlexTrash.tsx +128 -0
  109. package/src/hardware-sim/Deck/MoveLabwareOnDeck.stories.tsx +97 -0
  110. package/src/hardware-sim/Deck/MoveLabwareOnDeck.tsx +251 -0
  111. package/src/hardware-sim/Deck/OT2Layers.tsx +153 -0
  112. package/src/hardware-sim/Deck/RobotCoordsForeignDiv.tsx +46 -0
  113. package/src/hardware-sim/Deck/RobotCoordsForeignObject.tsx +42 -0
  114. package/src/hardware-sim/Deck/RobotCoordsText.tsx +32 -0
  115. package/src/hardware-sim/Deck/RobotWorkSpace.tsx +90 -0
  116. package/src/hardware-sim/Deck/SlotLabels.tsx +111 -0
  117. package/src/hardware-sim/Deck/__mocks__/getDeckDefinitions.ts +29 -0
  118. package/src/hardware-sim/Deck/constants.ts +12 -0
  119. package/src/hardware-sim/Deck/index.tsx +8 -0
  120. package/src/hardware-sim/DeckConfigurator/AbsorbanceReaderFixture.tsx +91 -0
  121. package/src/hardware-sim/DeckConfigurator/DeckConfigurator.stories.tsx +110 -0
  122. package/src/hardware-sim/DeckConfigurator/EmptyConfigFixture.tsx +131 -0
  123. package/src/hardware-sim/DeckConfigurator/HeaterShakerFixture.tsx +102 -0
  124. package/src/hardware-sim/DeckConfigurator/MagneticBlockFixture.tsx +130 -0
  125. package/src/hardware-sim/DeckConfigurator/StagingAreaConfigFixture.tsx +89 -0
  126. package/src/hardware-sim/DeckConfigurator/StaticFixture.tsx +54 -0
  127. package/src/hardware-sim/DeckConfigurator/TemperatureModuleFixture.tsx +103 -0
  128. package/src/hardware-sim/DeckConfigurator/ThermocyclerFixture.tsx +89 -0
  129. package/src/hardware-sim/DeckConfigurator/TrashBinConfigFixture.tsx +99 -0
  130. package/src/hardware-sim/DeckConfigurator/WasteChuteConfigFixture.tsx +96 -0
  131. package/src/hardware-sim/DeckConfigurator/constants.ts +81 -0
  132. package/src/hardware-sim/DeckConfigurator/index.tsx +285 -0
  133. package/src/hardware-sim/DeckSlotLocation/index.tsx +88 -0
  134. package/src/hardware-sim/Labware/Labware.tsx +173 -0
  135. package/src/hardware-sim/Labware/LabwareAdapter/Opentrons96DeepWellAdapter.tsx +23 -0
  136. package/src/hardware-sim/Labware/LabwareAdapter/Opentrons96FlatBottomAdapter.tsx +7 -0
  137. package/src/hardware-sim/Labware/LabwareAdapter/OpentronsAluminumFlatBottomPlate.tsx +13 -0
  138. package/src/hardware-sim/Labware/LabwareAdapter/OpentronsAutoclavableDeckRiser.tsx +100 -0
  139. package/src/hardware-sim/Labware/LabwareAdapter/OpentronsFlex96TiprackAdapter.tsx +13 -0
  140. package/src/hardware-sim/Labware/LabwareAdapter/OpentronsToughPCRAutoSealingLid.tsx +83 -0
  141. package/src/hardware-sim/Labware/LabwareAdapter/OpentronsUniversalFlatAdapter.tsx +13 -0
  142. package/src/hardware-sim/Labware/LabwareAdapter/index.tsx +73 -0
  143. package/src/hardware-sim/Labware/LabwareRender.stories.tsx +96 -0
  144. package/src/hardware-sim/Labware/LabwareRender.tsx +173 -0
  145. package/src/hardware-sim/Labware/LabwareStackRender.tsx +272 -0
  146. package/src/hardware-sim/Labware/index.ts +6 -0
  147. package/src/hardware-sim/Labware/labwareInternals/FilledWells.tsx +39 -0
  148. package/src/hardware-sim/Labware/labwareInternals/LabwareOutline.tsx +133 -0
  149. package/src/hardware-sim/Labware/labwareInternals/LabwareWellLabels.tsx +118 -0
  150. package/src/hardware-sim/Labware/labwareInternals/StaticLabware.tsx +121 -0
  151. package/src/hardware-sim/Labware/labwareInternals/StrokedWells.tsx +38 -0
  152. package/src/hardware-sim/Labware/labwareInternals/StyledWells.tsx +77 -0
  153. package/src/hardware-sim/Labware/labwareInternals/Well.tsx +74 -0
  154. package/src/hardware-sim/Labware/labwareInternals/WellLabels.tsx +121 -0
  155. package/src/hardware-sim/Labware/labwareInternals/index.ts +8 -0
  156. package/src/hardware-sim/Labware/labwareInternals/types.ts +18 -0
  157. package/src/hardware-sim/Module/HeaterShaker.tsx +83 -0
  158. package/src/hardware-sim/Module/MagneticBlock.tsx +49 -0
  159. package/src/hardware-sim/Module/MagneticModule.tsx +51 -0
  160. package/src/hardware-sim/Module/Module.stories.tsx +90 -0
  161. package/src/hardware-sim/Module/ModuleTag.tsx +38 -0
  162. package/src/hardware-sim/Module/PlateReader.tsx +208 -0
  163. package/src/hardware-sim/Module/Temperature.tsx +54 -0
  164. package/src/hardware-sim/Module/Thermocycler/ThermocyclerGEN1.tsx +248 -0
  165. package/src/hardware-sim/Module/Thermocycler/ThermocyclerGEN2.tsx +286 -0
  166. package/src/hardware-sim/Module/Thermocycler/index.tsx +49 -0
  167. package/src/hardware-sim/Module/index.tsx +227 -0
  168. package/src/hardware-sim/Pipette/EightEmanatingNozzles.tsx +23 -0
  169. package/src/hardware-sim/Pipette/EmanatingNozzle.tsx +52 -0
  170. package/src/hardware-sim/Pipette/PipetteRender.stories.tsx +71 -0
  171. package/src/hardware-sim/Pipette/PipetteRender.tsx +92 -0
  172. package/src/hardware-sim/Pipette/constants.ts +10 -0
  173. package/src/hardware-sim/Pipette/index.ts +1 -0
  174. package/src/hardware-sim/ProtocolDeck/LabwareInfo.tsx +68 -0
  175. package/src/hardware-sim/ProtocolDeck/ProtocolDeck.stories.tsx +25 -0
  176. package/src/hardware-sim/ProtocolDeck/__fixtures__/analysis_QIAseqFX24xv4_8.json +47145 -0
  177. package/src/hardware-sim/ProtocolDeck/index.tsx +174 -0
  178. package/src/hardware-sim/ProtocolDeck/types.ts +6 -0
  179. package/src/hardware-sim/ProtocolDeck/utils/getInitiallyLoadedLabwareByAdapter.ts +33 -0
  180. package/src/hardware-sim/ProtocolDeck/utils/getLabwareInSlots.ts +155 -0
  181. package/src/hardware-sim/ProtocolDeck/utils/getLabwareInfoByLiquidId.ts +42 -0
  182. package/src/hardware-sim/ProtocolDeck/utils/getModulesInSlots.ts +129 -0
  183. package/src/hardware-sim/ProtocolDeck/utils/getStandardDeckViewLayerBlockList.ts +29 -0
  184. package/src/hardware-sim/ProtocolDeck/utils/getWellFillFromLabwareId.ts +30 -0
  185. package/src/hardware-sim/ProtocolDeck/utils/index.ts +3 -0
  186. package/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpace.tsx +28 -0
  187. package/src/hardware-sim/RobotCoordinateSpace/RobotCoordinateSpaceWithRef.tsx +52 -0
  188. package/src/hardware-sim/RobotCoordinateSpace/index.ts +2 -0
  189. package/src/hardware-sim/index.ts +11 -0
  190. package/src/hardware-sim/utils.ts +18 -0
  191. package/src/helix-design-system/borders.ts +32 -0
  192. package/src/helix-design-system/colors.ts +100 -0
  193. package/src/helix-design-system/index.ts +4 -0
  194. package/src/helix-design-system/product/index.ts +1 -0
  195. package/src/helix-design-system/product/typography.ts +151 -0
  196. package/src/helix-design-system/style.ts +2 -0
  197. package/src/hooks/index.ts +15 -0
  198. package/src/hooks/useConditionalConfirm.ts +70 -0
  199. package/src/hooks/useDrag.ts +90 -0
  200. package/src/hooks/useIdle.ts +68 -0
  201. package/src/hooks/useInterval.ts +38 -0
  202. package/src/hooks/useLongPress.ts +83 -0
  203. package/src/hooks/useMenuHandleClickOutside.tsx +46 -0
  204. package/src/hooks/useMountEffect.ts +12 -0
  205. package/src/hooks/usePrevious.ts +19 -0
  206. package/src/hooks/useScrolling.ts +33 -0
  207. package/src/hooks/useSelectDeckLocation/SelectDeckLocation.stories.tsx +55 -0
  208. package/src/hooks/useSelectDeckLocation/index.tsx +331 -0
  209. package/src/hooks/useSwipe.ts +86 -0
  210. package/src/hooks/useTimeout.ts +33 -0
  211. package/src/hooks/useToggle.ts +27 -0
  212. package/src/icons/Icon.stories.tsx +37 -0
  213. package/src/icons/Icon.tsx +79 -0
  214. package/src/icons/IconList.stories.tsx +108 -0
  215. package/src/icons/ModuleIcon.tsx +48 -0
  216. package/src/icons/NotificationIcon.tsx +41 -0
  217. package/src/icons/icon-data.ts +821 -0
  218. package/src/icons/index.ts +6 -0
  219. package/src/images/index.ts +1 -0
  220. package/src/images/labware/index.ts +1 -0
  221. package/src/images/labware/measurement-guide/images/depth/depth-plate-flat@3x.png +0 -0
  222. package/src/images/labware/measurement-guide/images/depth/depth-plate-round@3x.png +0 -0
  223. package/src/images/labware/measurement-guide/images/depth/depth-plate-v@3x.png +0 -0
  224. package/src/images/labware/measurement-guide/images/depth/depth-reservoir-and-tubes-flat@3x.png +0 -0
  225. package/src/images/labware/measurement-guide/images/depth/depth-reservoir-and-tubes-round@3x.png +0 -0
  226. package/src/images/labware/measurement-guide/images/depth/depth-reservoir-and-tubes-v@3x.png +0 -0
  227. package/src/images/labware/measurement-guide/images/depth/length-tip-rack@3x.png +0 -0
  228. package/src/images/labware/measurement-guide/images/dimensions/footprint@3x.png +0 -0
  229. package/src/images/labware/measurement-guide/images/dimensions/height-alum-block-plate@3x.png +0 -0
  230. package/src/images/labware/measurement-guide/images/dimensions/height-alum-block-tubes@3x.png +0 -0
  231. package/src/images/labware/measurement-guide/images/dimensions/height-plate-and-reservoir@3x.png +0 -0
  232. package/src/images/labware/measurement-guide/images/dimensions/height-tip-rack@3x.png +0 -0
  233. package/src/images/labware/measurement-guide/images/dimensions/height-tube-rack-irregular@3x.png +0 -0
  234. package/src/images/labware/measurement-guide/images/dimensions/height-tube-rack@3x.png +0 -0
  235. package/src/images/labware/measurement-guide/images/offset/offset-reservoir@3x.png +0 -0
  236. package/src/images/labware/measurement-guide/images/offset/offset-well-circular@3x.png +0 -0
  237. package/src/images/labware/measurement-guide/images/offset/offset-well-rectangular@3x.png +0 -0
  238. package/src/images/labware/measurement-guide/images/shape/shape-circular@3x.png +0 -0
  239. package/src/images/labware/measurement-guide/images/shape/shape-rectangular@3x.png +0 -0
  240. package/src/images/labware/measurement-guide/images/spacing/spacing-reservoir-multi-row@3x.png +0 -0
  241. package/src/images/labware/measurement-guide/images/spacing/spacing-reservoir@3x.png +0 -0
  242. package/src/images/labware/measurement-guide/images/spacing/spacing-well-circular@3x.png +0 -0
  243. package/src/images/labware/measurement-guide/images/spacing/spacing-well-rectangular@3x.png +0 -0
  244. package/src/images/labware/measurement-guide/index.ts +272 -0
  245. package/src/index.ts +2 -0
  246. package/src/instrument/InstrumentDiagram.stories.tsx +42 -0
  247. package/src/instrument/InstrumentDiagram.tsx +58 -0
  248. package/src/instrument/InstrumentGroup.stories.tsx +88 -0
  249. package/src/instrument/InstrumentGroup.tsx +35 -0
  250. package/src/instrument/InstrumentInfo.tsx +107 -0
  251. package/src/instrument/PipetteSelect.stories.tsx +40 -0
  252. package/src/instrument/PipetteSelect.tsx +170 -0
  253. package/src/instrument/eight-channel-flex.png +0 -0
  254. package/src/instrument/index.ts +4 -0
  255. package/src/instrument/multi-channel_GEN1_800px.png +0 -0
  256. package/src/instrument/multi-channel_GEN2_800px.png +0 -0
  257. package/src/instrument/ninety-six-channel-gen1.png +0 -0
  258. package/src/instrument/pipetteGEN2Multi.png +0 -0
  259. package/src/instrument/pipetteGEN2Single.png +0 -0
  260. package/src/instrument/pipetteMulti.png +0 -0
  261. package/src/instrument/pipetteSingle.png +0 -0
  262. package/src/instrument/single-channel-flex.png +0 -0
  263. package/src/instrument/single-channel_GEN2_800px.png +0 -0
  264. package/src/instrument/single_channel_GEN1_800px.png +0 -0
  265. package/src/interaction-enhancers/ClickOutside.ts +57 -0
  266. package/src/interaction-enhancers/HandleKeypress.tsx +69 -0
  267. package/src/interaction-enhancers/index.ts +4 -0
  268. package/src/interaction-enhancers/useHover.ts +84 -0
  269. package/src/interaction-enhancers/useOnClickOutside.ts +42 -0
  270. package/src/legacy-hardware-sim/LabwareNameOverlay.tsx +22 -0
  271. package/src/legacy-hardware-sim/ModuleItem.tsx +145 -0
  272. package/src/legacy-hardware-sim/index.ts +2 -0
  273. package/src/lists/SidePanelGroup.tsx +48 -0
  274. package/src/lists/TitledList.tsx +155 -0
  275. package/src/lists/index.ts +3 -0
  276. package/src/modals/AlertModal.tsx +89 -0
  277. package/src/modals/ContinueModal.tsx +32 -0
  278. package/src/modals/LegacyModal.tsx +59 -0
  279. package/src/modals/Modal.stories.tsx +52 -0
  280. package/src/modals/Modal.tsx +96 -0
  281. package/src/modals/ModalHeader.tsx +100 -0
  282. package/src/modals/ModalShell.tsx +155 -0
  283. package/src/modals/Overlay.tsx +38 -0
  284. package/src/modals/SpinnerModal.tsx +35 -0
  285. package/src/modals/SpinnerModalPage.tsx +30 -0
  286. package/src/modals/index.ts +10 -0
  287. package/src/molecules/Banner/Banner.stories.tsx +41 -0
  288. package/src/molecules/Banner/index.tsx +147 -0
  289. package/src/molecules/DeckInfoLabel/DeckInfoLabel.stories.tsx +65 -0
  290. package/src/molecules/DeckInfoLabel/index.tsx +95 -0
  291. package/src/molecules/DeckLabel/DeckLabel.stories.tsx +31 -0
  292. package/src/molecules/DeckLabel/index.tsx +80 -0
  293. package/src/molecules/DropdownMenu/DropdownMenu.stories.tsx +30 -0
  294. package/src/molecules/DropdownMenu/index.tsx +343 -0
  295. package/src/molecules/InfoScreen/InfoScreen.stories.tsx +50 -0
  296. package/src/molecules/InfoScreen/index.tsx +54 -0
  297. package/src/molecules/LiquidIcon/LiquidIcon.stories.tsx +53 -0
  298. package/src/molecules/LiquidIcon/index.tsx +68 -0
  299. package/src/molecules/ParametersTable/ParametersTable.stories.tsx +172 -0
  300. package/src/molecules/ParametersTable/index.tsx +198 -0
  301. package/src/molecules/Tabs/Tabs.stories.tsx +74 -0
  302. package/src/molecules/Tabs/index.tsx +94 -0
  303. package/src/molecules/index.ts +8 -0
  304. package/src/nav/SidePanel.stories.tsx +29 -0
  305. package/src/nav/SidePanel.tsx +21 -0
  306. package/src/nav/index.ts +2 -0
  307. package/src/organisms/DeckLabelSet/DeckLabelSet.stories.tsx +46 -0
  308. package/src/organisms/DeckLabelSet/index.tsx +69 -0
  309. package/src/organisms/EndUserAgreementFooter/index.tsx +49 -0
  310. package/src/organisms/Toolbox/Toolbox.stories.tsx +23 -0
  311. package/src/organisms/Toolbox/index.tsx +160 -0
  312. package/src/organisms/index.ts +3 -0
  313. package/src/primitives/Box.stories.tsx +25 -0
  314. package/src/primitives/Box.tsx +17 -0
  315. package/src/primitives/Btn.stories.tsx +105 -0
  316. package/src/primitives/Btn.tsx +266 -0
  317. package/src/primitives/Flex.stories.tsx +50 -0
  318. package/src/primitives/Flex.tsx +17 -0
  319. package/src/primitives/ForeignObject.tsx +70 -0
  320. package/src/primitives/Link.stories.tsx +27 -0
  321. package/src/primitives/Link.tsx +32 -0
  322. package/src/primitives/README.md +188 -0
  323. package/src/primitives/Svg.stories.tsx +36 -0
  324. package/src/primitives/Svg.tsx +68 -0
  325. package/src/primitives/Text.stories.tsx +17 -0
  326. package/src/primitives/Text.tsx +18 -0
  327. package/src/primitives/index.ts +10 -0
  328. package/src/primitives/style-props.ts +197 -0
  329. package/src/primitives/types.ts +120 -0
  330. package/src/robot-types.ts +4 -0
  331. package/src/slotmap/OT2SlotMap.tsx +73 -0
  332. package/src/slotmap/index.ts +1 -0
  333. package/src/structure/Card.stories.tsx +28 -0
  334. package/src/structure/Card.tsx +64 -0
  335. package/src/structure/LabeledValue.stories.tsx +17 -0
  336. package/src/structure/LabeledValue.tsx +31 -0
  337. package/src/structure/Pill.tsx +43 -0
  338. package/src/structure/Splash.stories.tsx +24 -0
  339. package/src/structure/Splash.tsx +22 -0
  340. package/src/structure/TitleBar.stories.tsx +42 -0
  341. package/src/structure/TitleBar.tsx +81 -0
  342. package/src/structure/index.ts +7 -0
  343. package/src/styles/borders.ts +16 -0
  344. package/src/styles/colors.ts +58 -0
  345. package/src/styles/cursor.ts +12 -0
  346. package/src/styles/flexbox.ts +39 -0
  347. package/src/styles/index.ts +8 -0
  348. package/src/styles/layout.ts +31 -0
  349. package/src/styles/position.ts +5 -0
  350. package/src/styles/spacing.ts +11 -0
  351. package/src/styles/typography.ts +90 -0
  352. package/src/testing/utils/index.ts +2 -0
  353. package/src/testing/utils/matchers.ts +31 -0
  354. package/src/testing/utils/renderWithProviders.tsx +53 -0
  355. package/src/tooltips/DeprecatedTooltip.tsx +105 -0
  356. package/src/tooltips/HoverTooltip.tsx +83 -0
  357. package/src/tooltips/LegacyTooltip.stories.tsx +98 -0
  358. package/src/tooltips/LegacyTooltip.tsx +151 -0
  359. package/src/tooltips/constants.ts +28 -0
  360. package/src/tooltips/index.ts +10 -0
  361. package/src/tooltips/styles.ts +20 -0
  362. package/src/tooltips/types.ts +73 -0
  363. package/src/tooltips/useHoverTooltip.ts +47 -0
  364. package/src/tooltips/usePopper.ts +87 -0
  365. package/src/tooltips/useTooltip.ts +100 -0
  366. package/src/ui-style-constants/index.ts +4 -0
  367. package/src/ui-style-constants/responsiveness.ts +15 -0
  368. package/src/ui-style-constants/spacing.ts +18 -0
  369. package/src/ui-style-constants/typography.ts +258 -0
  370. package/src/ui-style-constants/viewport.ts +18 -0
  371. package/src/utils.ts +56 -0
  372. package/{vite.config.ts → vite.config.mts} +2 -0
  373. package/lib/index.mjs +0 -19869
@@ -0,0 +1,83 @@
1
+ import { useState, useEffect, useRef } from 'react'
2
+ import interact from 'interactjs'
3
+ import type PointerEvent from 'interactjs'
4
+ import type { CSSProperties, MutableRefObject } from 'react'
5
+
6
+ const HOLD_DURATION_MS = 1000
7
+
8
+ // Note kj 12/05/2022
9
+ // ODD needs setIsLongPressed since when a user use long press, ODD app needs to show overflow menu.
10
+ // Then if a user takes clicking outside action, the ODD app needs to reset the isLongPressed.
11
+ // In terms of setIsTapped, if the ODD app doesn't need it, it will be removed.
12
+ export interface UseLongPressResult {
13
+ ref: MutableRefObject<null>
14
+ style: CSSProperties
15
+ isEnabled: boolean
16
+ isLongPressed: boolean
17
+ isTapped: boolean
18
+ setIsLongPressed: (value: boolean) => void
19
+ setIsTapped: (value: boolean) => void
20
+ enable: () => void
21
+ disable: () => void
22
+ }
23
+
24
+ /**
25
+ * useLongPress provide two actions (tap and long press)
26
+ * useLongPress recognize 1 sec hold as long press: hold Duration
27
+ * interactjs recognize "hold" when an element is held down around 600ms(default)
28
+ * @returns {UseLongPressResult}
29
+ */
30
+ export const useLongPress = (): UseLongPressResult => {
31
+ const [isLongPressed, setIsLongPressed] = useState<boolean>(false)
32
+ const [isTapped, setIsTapped] = useState<boolean>(false)
33
+ const [isEnabled, setIsEnabled] = useState<boolean>(true)
34
+ const interactiveRef = useRef(null)
35
+
36
+ const enable = (): void => {
37
+ if (interactiveRef?.current != null) {
38
+ interact((interactiveRef.current as unknown) as HTMLElement)
39
+ .pointerEvents({
40
+ holdDuration: HOLD_DURATION_MS,
41
+ })
42
+ .on('hold', (_event: PointerEvent) => {
43
+ setIsLongPressed(isLongPressed => !isLongPressed)
44
+ })
45
+ .on('tap', (_event: PointerEvent) => {
46
+ setIsTapped(isTapped => !isTapped)
47
+ })
48
+ }
49
+ }
50
+ const disable = (): void => {
51
+ if (interactiveRef?.current != null) {
52
+ interact((interactiveRef.current as unknown) as HTMLElement).unset()
53
+ }
54
+ }
55
+
56
+ useEffect(() => {
57
+ if (isEnabled) {
58
+ enable()
59
+ } else {
60
+ disable()
61
+ }
62
+ return disable
63
+ // eslint-disable-next-line react-hooks/exhaustive-deps
64
+ }, [isEnabled])
65
+
66
+ return {
67
+ ref: interactiveRef,
68
+ style: {
69
+ touchAction: 'none',
70
+ },
71
+ isEnabled,
72
+ isLongPressed,
73
+ isTapped,
74
+ setIsLongPressed,
75
+ setIsTapped,
76
+ enable: () => {
77
+ setIsEnabled(true)
78
+ },
79
+ disable: () => {
80
+ setIsEnabled(false)
81
+ },
82
+ }
83
+ }
@@ -0,0 +1,46 @@
1
+ import { useState } from 'react'
2
+ import { COLORS } from '../helix-design-system'
3
+ import { Overlay } from '../modals'
4
+
5
+ import type { Dispatch, MouseEventHandler, SetStateAction } from 'react'
6
+
7
+ interface MenuHandleClickOutside {
8
+ menuOverlay: JSX.Element
9
+ handleOverflowClick: MouseEventHandler<HTMLButtonElement>
10
+ showOverflowMenu: boolean
11
+ setShowOverflowMenu: Dispatch<SetStateAction<boolean>>
12
+ }
13
+
14
+ export function useMenuHandleClickOutside(): MenuHandleClickOutside {
15
+ const [showOverflowMenu, setShowOverflowMenu] = useState<boolean>(false)
16
+
17
+ const handleOverflowClick: MouseEventHandler<HTMLButtonElement> = e => {
18
+ e.preventDefault()
19
+ e.stopPropagation()
20
+ setShowOverflowMenu(currentShowOverflowMenu => !currentShowOverflowMenu)
21
+ }
22
+
23
+ const handleClickOutside: MouseEventHandler<HTMLDivElement> = e => {
24
+ e.preventDefault()
25
+ e.stopPropagation()
26
+ setShowOverflowMenu(false)
27
+ }
28
+
29
+ const menuOverlay: JSX.Element = (
30
+ <>
31
+ {showOverflowMenu ? (
32
+ <Overlay
33
+ onClick={handleClickOutside}
34
+ backgroundColor={COLORS.transparent}
35
+ />
36
+ ) : null}
37
+ </>
38
+ )
39
+
40
+ return {
41
+ menuOverlay,
42
+ handleOverflowClick,
43
+ showOverflowMenu,
44
+ setShowOverflowMenu,
45
+ }
46
+ }
@@ -0,0 +1,12 @@
1
+ import { useEffect } from 'react'
2
+ import type { EffectCallback } from 'react'
3
+ /**
4
+ * React hook to call a function on component mount and unmount
5
+ *
6
+ * @param {EffectCallback} callback (function to call on mount that optionally returns a cleanup function to call on unmount)
7
+ * @returns {void}
8
+ */
9
+ export function useMountEffect(callback: EffectCallback): void {
10
+ // call useEffect with an empty dependency list so it's only called on mount
11
+ useEffect(callback, [])
12
+ }
@@ -0,0 +1,19 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ /**
4
+ * React hook to keep track of the previous value of a parameter
5
+ * https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
6
+ *
7
+ * @template T (type of the input value)
8
+ * @param {T} value (value to keep track of)
9
+ * @returns {(T | void)} (previous value or undefined if first render)
10
+ */
11
+ export function usePrevious<T>(value: T): T | undefined {
12
+ const prevRef = useRef<T | undefined>()
13
+
14
+ useEffect(() => {
15
+ prevRef.current = value
16
+ }, [value])
17
+
18
+ return prevRef.current
19
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * A custom hook that detects whether an HTMLElement is being scrolled.
3
+ *
4
+ * @param {HTMLElement | null} node - HTMLElement to monitor for scrolling.
5
+ * @returns {boolean} - A boolean indicating whether the HTMLElement is being scrolled.
6
+ */
7
+ import { useState, useEffect, useRef } from 'react'
8
+
9
+ export const useScrolling = (node: HTMLElement | null): boolean => {
10
+ const [isScrolling, setIsScrolling] = useState<boolean>(false)
11
+ const scrollTimeout = useRef<NodeJS.Timeout | null>(null)
12
+
13
+ useEffect(() => {
14
+ if (node != null) {
15
+ const handleScroll = (): void => {
16
+ setIsScrolling(true)
17
+ if (scrollTimeout.current != null) clearTimeout(scrollTimeout.current)
18
+ scrollTimeout.current = setTimeout(() => {
19
+ setIsScrolling(false)
20
+ }, 200)
21
+ }
22
+
23
+ node?.addEventListener('scroll', handleScroll)
24
+
25
+ return () => {
26
+ if (scrollTimeout.current != null) clearTimeout(scrollTimeout.current)
27
+ node?.removeEventListener('scroll', handleScroll)
28
+ }
29
+ }
30
+ }, [node])
31
+
32
+ return isScrolling
33
+ }
@@ -0,0 +1,55 @@
1
+ import * as React from 'react'
2
+ import { DeckLocationSelect as DeckLocationSelectComponent } from './'
3
+ import {
4
+ FLEX_ROBOT_TYPE,
5
+ getDeckDefFromRobotType,
6
+ OT2_ROBOT_TYPE,
7
+ } from '@opentrons/shared-data'
8
+
9
+ import type { Meta, StoryObj } from '@storybook/react'
10
+ import type { RobotType } from '@opentrons/shared-data'
11
+
12
+ const meta: Meta<React.ComponentProps<typeof DeckLocationSelectComponent>> = {
13
+ component: DeckLocationSelectComponent,
14
+ title: 'Library/Molecules/Simulation/SelectDeckLocation',
15
+ } as Meta
16
+
17
+ export default meta
18
+ type Story = StoryObj<{ disabledSlotNames: string[]; robotType: RobotType }>
19
+
20
+ export const FlexDeckLocationSelect: Story = {
21
+ render: args => {
22
+ return <Wrapper {...args} />
23
+ },
24
+ args: {
25
+ disabledSlotNames: ['A2'],
26
+ robotType: FLEX_ROBOT_TYPE,
27
+ },
28
+ }
29
+
30
+ export const OT2DeckLocationSelect: Story = {
31
+ render: args => {
32
+ return <Wrapper {...args} />
33
+ },
34
+ args: {
35
+ disabledSlotNames: ['2'],
36
+ robotType: OT2_ROBOT_TYPE,
37
+ },
38
+ }
39
+
40
+ function Wrapper(props: {
41
+ disabledSlotNames: string[]
42
+ robotType: RobotType
43
+ }): JSX.Element {
44
+ const [selectedLocation, setSelectedLocation] = React.useState({
45
+ slotName: props.robotType === FLEX_ROBOT_TYPE ? 'A1' : '1',
46
+ })
47
+
48
+ const deckDef = getDeckDefFromRobotType(props.robotType)
49
+ return (
50
+ <DeckLocationSelectComponent
51
+ {...{ selectedLocation, setSelectedLocation, deckDef }}
52
+ disabledLocations={props.disabledSlotNames.map(s => ({ slotName: s }))}
53
+ />
54
+ )
55
+ }
@@ -0,0 +1,331 @@
1
+ import { useState, Fragment } from 'react'
2
+ import isEqual from 'lodash/isEqual'
3
+ import { useTranslation } from 'react-i18next'
4
+ import {
5
+ FLEX_CUTOUT_BY_SLOT_ID,
6
+ FLEX_SINGLE_SLOT_BY_CUTOUT_ID,
7
+ FLEX_ROBOT_TYPE,
8
+ getDeckDefFromRobotType,
9
+ getPositionFromSlotId,
10
+ getFixtureDisplayName,
11
+ isAddressableAreaStandardSlot,
12
+ OT2_ROBOT_TYPE,
13
+ } from '@opentrons/shared-data'
14
+ import {
15
+ DeckFromLayers,
16
+ LegacyDeckSlotLocation,
17
+ OT2_FIXED_TRASH_X_DIMENSION,
18
+ OT2_FIXED_TRASH_Y_DIMENSION,
19
+ RobotCoordinateSpace,
20
+ RobotCoordsForeignDiv,
21
+ SingleSlotFixture,
22
+ SlotLabels,
23
+ } from '../../hardware-sim'
24
+ import { Icon } from '../../icons'
25
+ import { Text } from '../../primitives'
26
+ import { ALIGN_CENTER, JUSTIFY_CENTER } from '../../styles'
27
+ import { SPACING, TYPOGRAPHY } from '../../ui-style-constants'
28
+ import { COLORS } from '../../helix-design-system'
29
+
30
+ import type {
31
+ CutoutConfig,
32
+ AddressableArea,
33
+ CoordinateTuple,
34
+ CutoutFixtureId,
35
+ DeckDefinition,
36
+ ModuleLocation,
37
+ RobotType,
38
+ } from '@opentrons/shared-data'
39
+
40
+ export type DeckLocationSelectThemes = 'default' | 'grey'
41
+
42
+ const X_CROP_MM = 0
43
+ const X_ADJUSTMENT_FOR_TC = '-50'
44
+ const Y_ADJUSTMENT_FOR_TC = '214'
45
+
46
+ const OT2_DECK_LOCATION_SELECT_LAYER_BLOCK_LIST: string[] = [
47
+ 'calibrationMarkings',
48
+ 'fixedBase',
49
+ 'doorStops',
50
+ 'metalFrame',
51
+ 'removalHandle',
52
+ 'removableDeckOutline',
53
+ 'screwHoles',
54
+ 'slotNumbers',
55
+ ]
56
+
57
+ export function useDeckLocationSelect(
58
+ robotType: RobotType,
59
+ theme?: DeckLocationSelectThemes
60
+ ): { DeckLocationSelect: JSX.Element; selectedLocation: ModuleLocation } {
61
+ const deckDef = getDeckDefFromRobotType(robotType)
62
+ const [selectedLocation, setSelectedLocation] = useState<ModuleLocation>({
63
+ slotName: deckDef.locations.addressableAreas[0].id,
64
+ })
65
+ return {
66
+ DeckLocationSelect: (
67
+ <DeckLocationSelect
68
+ {...{ deckDef, selectedLocation, setSelectedLocation, theme }}
69
+ />
70
+ ),
71
+ selectedLocation,
72
+ }
73
+ }
74
+
75
+ interface DeckLocationSelectProps {
76
+ deckDef: DeckDefinition
77
+ selectedLocation: ModuleLocation
78
+ theme?: DeckLocationSelectThemes
79
+ setSelectedLocation?: (loc: ModuleLocation) => void
80
+ availableSlotNames?: string[]
81
+ occupiedCutouts?: CutoutConfig[]
82
+ isThermocycler?: boolean
83
+ showTooltipOnDisabled?: boolean
84
+ }
85
+
86
+ export function DeckLocationSelect({
87
+ deckDef,
88
+ selectedLocation,
89
+ setSelectedLocation,
90
+ availableSlotNames,
91
+ occupiedCutouts = [],
92
+ theme = 'default',
93
+ isThermocycler = false,
94
+ showTooltipOnDisabled = false,
95
+ }: DeckLocationSelectProps): JSX.Element {
96
+ const robotType = deckDef.robot.model
97
+
98
+ const { t } = useTranslation('module_wizard_flows')
99
+
100
+ const [hoveredData, setHoveredData] = useState<{
101
+ slot: AddressableArea
102
+ slotPosition: CoordinateTuple | null
103
+ isDisabled: boolean
104
+ disabledReason?: CutoutFixtureId | null
105
+ } | null>(null)
106
+
107
+ const handleMouseEnter = (
108
+ slot: AddressableArea,
109
+ slotPosition: CoordinateTuple | null,
110
+ isDisabled: boolean,
111
+ disabledReason?: CutoutFixtureId | null
112
+ ): void => {
113
+ if (isDisabled) {
114
+ setHoveredData({
115
+ slot,
116
+ slotPosition,
117
+ isDisabled,
118
+ disabledReason,
119
+ })
120
+ } else {
121
+ setHoveredData(null)
122
+ }
123
+ }
124
+
125
+ const handleMouseLeave = (): void => {
126
+ setHoveredData(null)
127
+ }
128
+
129
+ return (
130
+ <RobotCoordinateSpace
131
+ viewBox={`${deckDef.cornerOffsetFromOrigin[0] + X_CROP_MM} ${
132
+ deckDef.cornerOffsetFromOrigin[1]
133
+ } ${deckDef.dimensions[0] - X_CROP_MM * 2} ${deckDef.dimensions[1]}`}
134
+ >
135
+ {deckDef.locations.addressableAreas
136
+ // only render standard slot fixture components
137
+ .filter(
138
+ addressableArea =>
139
+ isAddressableAreaStandardSlot(addressableArea.id, deckDef) ||
140
+ // special case the OT-2 trash addressable area
141
+ addressableArea.id === 'fixedTrash'
142
+ )
143
+ .map(slot => {
144
+ const slotLocation = { slotName: slot.id }
145
+ const isDisabled =
146
+ availableSlotNames !== undefined
147
+ ? !availableSlotNames.some(slotName => slotName === slot.id)
148
+ : false
149
+
150
+ const disabledReason =
151
+ occupiedCutouts.find(
152
+ cutout =>
153
+ FLEX_SINGLE_SLOT_BY_CUTOUT_ID[cutout.cutoutId] === slot.id
154
+ )?.cutoutFixtureId ?? null
155
+ const isSelected = isEqual(selectedLocation, slotLocation)
156
+ let fill = theme === 'default' ? COLORS.purple35 : COLORS.grey35
157
+ if (isSelected)
158
+ fill = theme === 'default' ? COLORS.purple50 : COLORS.grey50
159
+ if (isDisabled) fill = COLORS.grey30
160
+ if (isSelected && slot.id === 'B1' && isThermocycler) {
161
+ return (
162
+ <g key="thermocyclerSelectionArea">
163
+ <path
164
+ fill={fill}
165
+ d="M-97.8,496.6h239c2.3,0,4.2-1.9,4.2-4.2v-282c0-2.3-1.9-4.2-4.2-4.2h-239c-2.3,0-4.2,1.9-4.2,4.2v282 C-102,494.7-100.1,496.6-97.8,496.6z"
166
+ />
167
+ <RobotCoordsForeignDiv
168
+ x={X_ADJUSTMENT_FOR_TC}
169
+ y={Y_ADJUSTMENT_FOR_TC}
170
+ width={slot.boundingBox.xDimension}
171
+ height="282"
172
+ innerDivProps={INNER_DIV_PROPS}
173
+ >
174
+ <Icon
175
+ name="check-circle"
176
+ size="1.5rem"
177
+ color={COLORS.white}
178
+ />
179
+ <Text color={COLORS.white} fontSize="1.5rem">
180
+ Selected
181
+ </Text>
182
+ </RobotCoordsForeignDiv>
183
+ </g>
184
+ )
185
+ } else if (slot.id === 'A1' && isThermocycler) {
186
+ return null
187
+ }
188
+
189
+ const slotPosition = getPositionFromSlotId(slot.id, deckDef)
190
+ const cutoutId = FLEX_CUTOUT_BY_SLOT_ID[slot.id]
191
+
192
+ return (
193
+ <Fragment key={slot.id}>
194
+ {robotType === FLEX_ROBOT_TYPE ? (
195
+ <>
196
+ <SingleSlotFixture
197
+ cutoutId={cutoutId}
198
+ fixtureBaseColor={fill}
199
+ slotClipColor={COLORS.white}
200
+ onClick={() => {
201
+ if (!isDisabled && setSelectedLocation != null)
202
+ setSelectedLocation(slotLocation)
203
+ }}
204
+ cursor={
205
+ setSelectedLocation == null || isDisabled || isSelected
206
+ ? 'default'
207
+ : 'pointer'
208
+ }
209
+ deckDefinition={deckDef}
210
+ onMouseEnter={() => {
211
+ handleMouseEnter(
212
+ slot,
213
+ slotPosition,
214
+ isDisabled,
215
+ disabledReason
216
+ )
217
+ }}
218
+ onMouseLeave={handleMouseLeave}
219
+ />
220
+ </>
221
+ ) : (
222
+ <LegacyDeckSlotLocation
223
+ robotType={robotType}
224
+ slotBaseColor={fill}
225
+ slotName={slot.id}
226
+ slotClipColor={COLORS.white}
227
+ onClick={() => {
228
+ if (!isDisabled && setSelectedLocation != null)
229
+ setSelectedLocation(slotLocation)
230
+ }}
231
+ cursor={
232
+ setSelectedLocation == null || isDisabled || isSelected
233
+ ? 'default'
234
+ : 'pointer'
235
+ }
236
+ />
237
+ )}
238
+ {isSelected && slotPosition != null ? (
239
+ <RobotCoordsForeignDiv
240
+ x={slotPosition[0] - slot.offsetFromCutoutFixture[0]}
241
+ y={slotPosition[1] - slot.offsetFromCutoutFixture[1]}
242
+ width={
243
+ slot.id === 'fixedTrash'
244
+ ? OT2_FIXED_TRASH_X_DIMENSION
245
+ : slot.boundingBox.xDimension
246
+ }
247
+ height={
248
+ slot.id === 'fixedTrash'
249
+ ? OT2_FIXED_TRASH_Y_DIMENSION
250
+ : slot.boundingBox.yDimension
251
+ }
252
+ innerDivProps={INNER_DIV_PROPS}
253
+ >
254
+ <Text
255
+ color={COLORS.white}
256
+ css={
257
+ robotType === FLEX_ROBOT_TYPE
258
+ ? TYPOGRAPHY.level4HeaderSemiBold
259
+ : TYPOGRAPHY.bodyTextSemiBold
260
+ }
261
+ >
262
+ Selected
263
+ </Text>
264
+ </RobotCoordsForeignDiv>
265
+ ) : null}
266
+ </Fragment>
267
+ )
268
+ })}
269
+ {robotType === OT2_ROBOT_TYPE ? (
270
+ <DeckFromLayers
271
+ robotType={robotType}
272
+ layerBlocklist={OT2_DECK_LOCATION_SELECT_LAYER_BLOCK_LIST}
273
+ />
274
+ ) : null}
275
+ <SlotLabels robotType={robotType} color={COLORS.grey50} />
276
+ {hoveredData != null &&
277
+ hoveredData.isDisabled &&
278
+ hoveredData.slotPosition != null &&
279
+ showTooltipOnDisabled && (
280
+ <RobotCoordsForeignDiv
281
+ x={
282
+ hoveredData.slot.id === 'A3'
283
+ ? hoveredData.slotPosition[0] - 50
284
+ : hoveredData.slotPosition[0] - 20
285
+ }
286
+ y={
287
+ hoveredData.slotPosition[1] +
288
+ hoveredData.slot.boundingBox.yDimension +
289
+ 10
290
+ }
291
+ innerDivProps={
292
+ hoveredData.slot.id[0] === 'A'
293
+ ? {
294
+ maxWidth: '25rem',
295
+ maxHeight: '10rem',
296
+ width: 'fit-content',
297
+ }
298
+ : {
299
+ maxWidth: '20rem',
300
+ width: 'fit-content',
301
+ }
302
+ }
303
+ >
304
+ <Text
305
+ color={COLORS.white}
306
+ fontSize="1.5rem"
307
+ backgroundColor={COLORS.black90}
308
+ padding={SPACING.spacing8}
309
+ borderRadius="3px"
310
+ >
311
+ {hoveredData.disabledReason != null
312
+ ? t('location_occupied', {
313
+ fixture: getFixtureDisplayName(
314
+ hoveredData.disabledReason
315
+ ).toLowerCase(),
316
+ })
317
+ : 'Slot unavailable'}
318
+ </Text>
319
+ </RobotCoordsForeignDiv>
320
+ )}
321
+ </RobotCoordinateSpace>
322
+ )
323
+ }
324
+
325
+ const INNER_DIV_PROPS = {
326
+ display: 'flex',
327
+ alignItems: ALIGN_CENTER,
328
+ justifyContent: JUSTIFY_CENTER,
329
+ height: '100%',
330
+ gridGap: SPACING.spacing4,
331
+ }
@@ -0,0 +1,86 @@
1
+ import { useState, useEffect, useRef } from 'react'
2
+ import interact from 'interactjs'
3
+ import type { MutableRefObject, CSSProperties } from 'react'
4
+
5
+ interface UseSwipeResult {
6
+ ref: MutableRefObject<null>
7
+ style: CSSProperties
8
+ isEnabled: boolean
9
+ setSwipeType: (value: string) => void
10
+ swipeType: string
11
+ enable: () => void
12
+ disable: () => void
13
+ }
14
+
15
+ export const useSwipe = (): UseSwipeResult => {
16
+ const [swipeType, setSwipeType] = useState<string>('')
17
+ const [isEnabled, setIsEnabled] = useState<boolean>(true)
18
+ const interactiveRef = useRef(null)
19
+ const THRESHOLD = 50
20
+ let startX = 0
21
+ let startY = 0
22
+
23
+ const enable = (): void => {
24
+ if (interactiveRef.current != null) {
25
+ interact(interactiveRef.current).draggable({
26
+ inertia: false,
27
+ modifiers: [],
28
+ autoScroll: false,
29
+ listeners: {
30
+ start(event) {
31
+ startX = event.clientX
32
+ startY = event.clientY
33
+ },
34
+ // Note (kk:07/11/2024) want to keep this for debugging
35
+ // move(event) {
36
+ // console.log('Drag move:', event.clientX, event.clientY)
37
+ // },
38
+ end(event) {
39
+ const dx = event.clientX - startX
40
+ const dy = event.clientY - startY
41
+ const absX = Math.abs(dx)
42
+ const absY = Math.abs(dy)
43
+
44
+ if (absX > absY && absX > THRESHOLD) {
45
+ setSwipeType(dx > 0 ? 'swipe-right' : 'swipe-left')
46
+ } else if (absY > absX && absY > THRESHOLD) {
47
+ setSwipeType(dy > 0 ? 'swipe-down' : 'swipe-up')
48
+ }
49
+ },
50
+ },
51
+ })
52
+ }
53
+ }
54
+
55
+ const disable = (): void => {
56
+ if (interactiveRef.current != null) {
57
+ interact((interactiveRef.current as unknown) as HTMLElement).unset()
58
+ }
59
+ }
60
+
61
+ useEffect(() => {
62
+ if (isEnabled) {
63
+ enable()
64
+ } else {
65
+ disable()
66
+ }
67
+ return disable
68
+ // eslint-disable-next-line react-hooks/exhaustive-deps
69
+ }, [isEnabled])
70
+
71
+ return {
72
+ ref: interactiveRef,
73
+ style: {
74
+ touchAction: 'none',
75
+ },
76
+ isEnabled,
77
+ setSwipeType,
78
+ swipeType,
79
+ enable: () => {
80
+ setIsEnabled(true)
81
+ },
82
+ disable: () => {
83
+ setIsEnabled(false)
84
+ },
85
+ }
86
+ }
@@ -0,0 +1,33 @@
1
+ import { useEffect, useRef } from 'react'
2
+
3
+ /**
4
+ * React hook to call a function after a delay; adapted from: useInterval
5
+ *
6
+ * @template T (type of the input value)
7
+ * @param {() => unknown} callback (function to call after timeout)
8
+ * @param {number | null} delay (timeout delay, or null to disable the timeout)
9
+ * @returns {void}
10
+ */
11
+ export function useTimeout(
12
+ callback: () => unknown,
13
+ delay: number | null
14
+ ): void {
15
+ const savedCallback = useRef<() => unknown>()
16
+
17
+ // remember the latest callback
18
+ useEffect(() => {
19
+ savedCallback.current = callback
20
+ }, [callback])
21
+
22
+ // set up the timeout
23
+ useEffect(() => {
24
+ const currentCallback = (): unknown =>
25
+ savedCallback.current != null && savedCallback.current()
26
+ if (delay !== null) {
27
+ const id = setTimeout(currentCallback, delay)
28
+ return () => {
29
+ clearTimeout(id)
30
+ }
31
+ }
32
+ }, [delay])
33
+ }