figure-modal-context.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { FC, createContext, useContext, useReducer } from 'react'
  2. import { PastedImageData } from '../../extensions/figure-modal'
  3. /* eslint-disable no-unused-vars */
  4. export enum FigureModalSource {
  5. NONE,
  6. FILE_UPLOAD,
  7. FILE_TREE,
  8. FROM_URL,
  9. OTHER_PROJECT,
  10. EDIT_FIGURE,
  11. }
  12. /* eslint-enable no-unused-vars */
  13. type FigureModalState = {
  14. source: FigureModalSource
  15. helpShown: boolean
  16. sourcePickerShown: boolean
  17. getPath?: () => Promise<string>
  18. width: number | undefined
  19. includeCaption: boolean
  20. includeLabel: boolean
  21. error?: string
  22. pastedImageData?: PastedImageData
  23. selectedItemId?: string
  24. }
  25. type FigureModalStateUpdate = Partial<FigureModalState>
  26. const FigureModalContext = createContext<
  27. | (FigureModalState & {
  28. dispatch: (update: FigureModalStateUpdate) => void
  29. })
  30. | undefined
  31. >(undefined)
  32. export const useFigureModalContext = () => {
  33. const context = useContext(FigureModalContext)
  34. if (!context) {
  35. throw new Error(
  36. 'useFigureModalContext is only available inside FigureModalProvider'
  37. )
  38. }
  39. return context
  40. }
  41. const reducer = (prev: FigureModalState, action: Partial<FigureModalState>) => {
  42. if ('source' in action && prev.source === FigureModalSource.NONE) {
  43. // Reset when showing modal
  44. return {
  45. ...prev,
  46. width: 0.5,
  47. includeLabel: true,
  48. includeCaption: true,
  49. helpShown: false,
  50. sourcePickerShown: false,
  51. getPath: undefined,
  52. error: undefined,
  53. pastedImageData: undefined,
  54. ...action,
  55. }
  56. }
  57. return { ...prev, ...action }
  58. }
  59. type FigureModalExistingFigureState = {
  60. name: string | undefined
  61. hasComplexGraphicsArgument?: boolean
  62. }
  63. type FigureModalExistingFigureStateUpdate =
  64. Partial<FigureModalExistingFigureState>
  65. const FigureModalExistingFigureContext = createContext<
  66. | (FigureModalExistingFigureState & {
  67. dispatch: (update: FigureModalExistingFigureStateUpdate) => void
  68. })
  69. | undefined
  70. >(undefined)
  71. export const FigureModalProvider: FC<React.PropsWithChildren> = ({
  72. children,
  73. }) => {
  74. const [state, dispatch] = useReducer(reducer, {
  75. source: FigureModalSource.NONE,
  76. helpShown: false,
  77. sourcePickerShown: false,
  78. getPath: undefined,
  79. includeLabel: true,
  80. includeCaption: true,
  81. width: 0.5,
  82. })
  83. const [existingFigureState, dispatchFigureState] = useReducer(
  84. (
  85. prev: FigureModalExistingFigureState,
  86. action: FigureModalExistingFigureStateUpdate
  87. ) => ({ ...prev, ...action }),
  88. {
  89. name: undefined,
  90. }
  91. )
  92. return (
  93. <FigureModalContext.Provider value={{ ...state, dispatch }}>
  94. <FigureModalExistingFigureContext.Provider
  95. value={{ ...existingFigureState, dispatch: dispatchFigureState }}
  96. >
  97. {children}
  98. </FigureModalExistingFigureContext.Provider>
  99. </FigureModalContext.Provider>
  100. )
  101. }
  102. export const useFigureModalExistingFigureContext = () => {
  103. const context = useContext(FigureModalExistingFigureContext)
  104. if (!context) {
  105. throw new Error(
  106. 'useFigureModalExistingFigureContext is only available inside FigureModalProvider'
  107. )
  108. }
  109. return context
  110. }