rail-context.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import useCollapsiblePanel from '@/features/ide-react/hooks/use-collapsible-panel'
  2. import {
  3. createContext,
  4. Dispatch,
  5. FC,
  6. SetStateAction,
  7. useCallback,
  8. useContext,
  9. useMemo,
  10. useRef,
  11. useState,
  12. } from 'react'
  13. import { ImperativePanelHandle } from 'react-resizable-panels'
  14. export type RailTabKey =
  15. | 'file-tree'
  16. | 'integrations'
  17. | 'review-panel'
  18. | 'chat'
  19. | 'errors'
  20. export type RailModalKey = 'keyboard-shortcuts' | 'contact-us' | 'dictionary'
  21. const RailContext = createContext<
  22. | {
  23. selectedTab: RailTabKey
  24. isOpen: boolean
  25. setIsOpen: Dispatch<SetStateAction<boolean>>
  26. panelRef: React.RefObject<ImperativePanelHandle>
  27. togglePane: () => void
  28. handlePaneExpand: () => void
  29. handlePaneCollapse: () => void
  30. resizing: boolean
  31. setResizing: Dispatch<SetStateAction<boolean>>
  32. activeModal: RailModalKey | null
  33. setActiveModal: Dispatch<SetStateAction<RailModalKey | null>>
  34. openTab: (tab: RailTabKey) => void
  35. }
  36. | undefined
  37. >(undefined)
  38. export const RailProvider: FC = ({ children }) => {
  39. const [isOpen, setIsOpen] = useState(true)
  40. const [resizing, setResizing] = useState(false)
  41. const [activeModal, setActiveModalInternal] = useState<RailModalKey | null>(
  42. null
  43. )
  44. const setActiveModal: Dispatch<SetStateAction<RailModalKey | null>> =
  45. useCallback(modalKey => {
  46. setActiveModalInternal(modalKey)
  47. }, [])
  48. const panelRef = useRef<ImperativePanelHandle>(null)
  49. useCollapsiblePanel(isOpen, panelRef)
  50. const togglePane = useCallback(() => {
  51. setIsOpen(value => !value)
  52. }, [])
  53. const handlePaneExpand = useCallback(() => {
  54. setIsOpen(true)
  55. }, [])
  56. const handlePaneCollapse = useCallback(() => {
  57. setIsOpen(false)
  58. }, [])
  59. // NOTE: The file tree **MUST** be the first tab to be opened
  60. // since it is responsible for opening the initial document.
  61. const [selectedTab, setSelectedTab] = useState<RailTabKey>('file-tree')
  62. const openTab = useCallback(
  63. (tab: RailTabKey) => {
  64. setSelectedTab(tab)
  65. setIsOpen(true)
  66. },
  67. [setIsOpen, setSelectedTab]
  68. )
  69. const value = useMemo(
  70. () => ({
  71. selectedTab,
  72. isOpen,
  73. setIsOpen,
  74. panelRef,
  75. togglePane,
  76. handlePaneExpand,
  77. handlePaneCollapse,
  78. resizing,
  79. setResizing,
  80. activeModal,
  81. setActiveModal,
  82. openTab,
  83. }),
  84. [
  85. selectedTab,
  86. isOpen,
  87. setIsOpen,
  88. panelRef,
  89. togglePane,
  90. handlePaneExpand,
  91. handlePaneCollapse,
  92. resizing,
  93. setResizing,
  94. activeModal,
  95. setActiveModal,
  96. openTab,
  97. ]
  98. )
  99. return <RailContext.Provider value={value}>{children}</RailContext.Provider>
  100. }
  101. export const useRailContext = () => {
  102. const context = useContext(RailContext)
  103. if (!context) {
  104. throw new Error('useRailContext is only available inside RailProvider')
  105. }
  106. return context
  107. }