ide-context.tsx 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import { createContext, FC, useContext, useEffect, useMemo } from 'react'
  2. import { ScopeValueStore } from '../../../../types/ide/scope-value-store'
  3. import { ScopeEventEmitter } from '../../../../types/ide/scope-event-emitter'
  4. export type Ide = {
  5. [key: string]: any // TODO: define the rest of the `ide` and `$scope` properties
  6. $scope: Record<string, any>
  7. }
  8. type IdeContextValue = Ide & {
  9. scopeStore: ScopeValueStore
  10. scopeEventEmitter: ScopeEventEmitter
  11. }
  12. export const IdeContext = createContext<IdeContextValue | undefined>(undefined)
  13. export const IdeProvider: FC<{
  14. ide: Ide
  15. scopeStore: ScopeValueStore
  16. scopeEventEmitter: ScopeEventEmitter
  17. }> = ({ ide, scopeStore, scopeEventEmitter, children }) => {
  18. /**
  19. * Expose scopeStore via `window.overleaf.unstable.store`, so it can be accessed by external extensions.
  20. *
  21. * These properties are expected to be available:
  22. * - `editor.view`
  23. * - `project.spellcheckLanguage`
  24. * - `editor.open_doc_name`,
  25. * - `editor.open_doc_id`,
  26. * - `settings.theme`
  27. * - `settings.keybindings`
  28. * - `settings.fontSize`
  29. */
  30. useEffect(() => {
  31. window.overleaf = {
  32. ...window.overleaf,
  33. unstable: {
  34. ...window.overleaf?.unstable,
  35. store: scopeStore,
  36. },
  37. }
  38. }, [scopeStore])
  39. const value = useMemo<IdeContextValue>(() => {
  40. return {
  41. ...ide,
  42. scopeStore,
  43. scopeEventEmitter,
  44. }
  45. }, [ide, scopeStore, scopeEventEmitter])
  46. return <IdeContext.Provider value={value}>{children}</IdeContext.Provider>
  47. }
  48. export function useIdeContext(): IdeContextValue {
  49. const context = useContext(IdeContext)
  50. if (!context) {
  51. throw new Error('useIdeContext is only available inside IdeProvider')
  52. }
  53. return context
  54. }