{"version":3,"file":"TimeRangeContext.mjs","sources":["../../../../src/components/DateTimePickers/TimeRangeContext.tsx"],"sourcesContent":["import { ReactNode, createContext, useEffect, useMemo, useState, useContext } from 'react';\n\nimport { TimeRange } from '@grafana/data';\n\ntype TimeRangeContextValue = TimeRangeContextHookValue & {\n  // These are to be used internally and aren't passed to the users of the hook.\n\n  // Called when picker is mounted to update the picker count.\n  addPicker(): void;\n\n  // Called when picker is unmounted to update the picker count.\n  removePicker(): void;\n};\n\nexport type TimeRangeContextHookValue = {\n  // If the time range is synced, this is the value that all pickers should show.\n  syncedValue?: TimeRange;\n\n  // If the time range is synced across all visible pickers.\n  synced: boolean;\n\n  // If it is possible to sync the time range. This is based just on the number of pickers that are visible so if\n  // there is only one, the sync button can be hidden.\n  syncPossible: boolean;\n\n  // Action passed to the picker to interact with the sync state.\n  // Sync the time range across all pickers with the provided value. Can be also used just to update a value when\n  // already synced.\n  sync(value: TimeRange): void;\n  unSync(): void;\n};\n\nconst TimeRangeContext = createContext<TimeRangeContextValue | undefined>(undefined);\n\nexport function TimeRangeProvider({ children }: { children: ReactNode }) {\n  // We simply keep the count of the pickers visible by letting them call the addPicker and removePicker functions.\n  const [pickersCount, setPickersCount] = useState(0);\n  const [syncedValue, setSyncedValue] = useState<TimeRange>();\n\n  const contextVal = useMemo(() => {\n    return {\n      sync: (value: TimeRange) => setSyncedValue(value),\n      unSync: () => setSyncedValue(undefined),\n      addPicker: () => setPickersCount((val) => val + 1),\n      removePicker: () => {\n        setPickersCount((val) => {\n          const newVal = val - 1;\n          if (newVal < 2) {\n            setSyncedValue(undefined);\n          }\n          return newVal;\n        });\n      },\n      syncPossible: pickersCount > 1,\n      synced: Boolean(syncedValue),\n      syncedValue,\n    };\n  }, [pickersCount, syncedValue]);\n\n  return <TimeRangeContext.Provider value={contextVal}>{children}</TimeRangeContext.Provider>;\n}\n\nexport function useTimeRangeContext(initialSyncValue?: TimeRange): TimeRangeContextHookValue | undefined {\n  const context = useContext(TimeRangeContext);\n\n  // Automatically add and remove the picker when the component mounts and unmounts or if context changes (but that\n  // should not happen). We ignore the initialSyncValue to make this value really just an initial value and isn't a\n  // prop by which you could control the picker.\n  useEffect(() => {\n    // We want the pickers to still function even if they are not used in a context. Not sure, this will be a common\n    // usecase, but it does not seem like it will cost us anything.\n    if (context) {\n      context.addPicker();\n      if (initialSyncValue) {\n        context.sync(initialSyncValue);\n      }\n      return () => {\n        context.removePicker();\n      };\n    }\n    return () => {};\n    // We want to do this only on mount and unmount.\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, []);\n\n  return useMemo(() => {\n    // We want the pickers to still function even if they are not used in a context. Not sure, this will be a common\n    // usecase, but it does not seem like it will cost us anything.\n    if (!context) {\n      return context;\n    }\n\n    // We just remove the addPicker/removePicker function as that is done automatically here and picker does not need\n    // them.\n    return {\n      sync: context.sync,\n      unSync: context.unSync,\n      syncPossible: context.syncPossible,\n      synced: context.synced,\n      syncedValue: context.syncedValue,\n    };\n  }, [context]);\n}\n"],"names":[],"mappings":";;;AAgCyB,cAAiD,KAAS,CAAA"}