{"version":3,"file":"useTimeSync.mjs","sources":["../../../../../src/components/DateTimePickers/utils/useTimeSync.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { usePrevious } from 'react-use';\n\nimport { TimeRange } from '@grafana/data';\n\nimport { useTimeRangeContext } from '../TimeRangeContext';\nimport { TimeSyncButton } from '../TimeSyncButton';\n\n/**\n * Handle the behaviour of the time sync button and syncing the time range between pickers. It also takes care of\n * backward compatibility with the manually controlled isSynced prop.\n * @param options\n */\nexport function useTimeSync(options: {\n  initialIsSynced?: boolean;\n  value: TimeRange;\n  isSyncedProp?: boolean;\n  timeSyncButtonProp?: JSX.Element;\n  onChangeProp: (value: TimeRange) => void;\n}) {\n  const { value, onChangeProp, isSyncedProp, initialIsSynced, timeSyncButtonProp } = options;\n  const timeRangeContext = useTimeRangeContext(initialIsSynced && value ? value : undefined);\n\n  // Destructure to make it easier to use in hook deps.\n  const timeRangeContextSynced = timeRangeContext?.synced;\n  const timeRangeContextSyncedValue = timeRangeContext?.syncedValue;\n  const timeRangeContextSyncFunc = timeRangeContext?.sync;\n\n  // This is to determine if we should use the context to sync or not. This is for backward compatibility so that\n  // Explore with multiple panes still works as it is controlling the sync state itself for now.\n  const usingTimeRangeContext = Boolean(options.isSyncedProp === undefined && timeRangeContext);\n\n  // Create new onChange that handles propagating the value to the context if possible and synced is true.\n  const onChangeWithSync = useCallback(\n    (timeRange: TimeRange) => {\n      onChangeProp(timeRange);\n      if (usingTimeRangeContext && timeRangeContextSynced) {\n        timeRangeContextSyncFunc?.(timeRange);\n      }\n    },\n    [onChangeProp, usingTimeRangeContext, timeRangeContextSyncFunc, timeRangeContextSynced]\n  );\n\n  const prevValue = usePrevious(value);\n  const prevSyncedValue = usePrevious(timeRangeContext?.syncedValue);\n\n  // As timepicker is controlled component we need to sync the global sync value back to the parent with onChange\n  // handler whenever the outside global value changes. We do it here while checking if we are actually supposed\n  // to and making sure we don't go into a loop.\n  useEffect(() => {\n    // only react if we are actually synced\n    if (usingTimeRangeContext && timeRangeContextSynced) {\n      if (value !== prevValue && value !== timeRangeContextSyncedValue) {\n        // The value changed outside the picker. To keep the sync working we need to update the synced value.\n        timeRangeContextSyncFunc?.(value);\n      } else if (\n        timeRangeContextSyncedValue &&\n        timeRangeContextSyncedValue !== prevSyncedValue &&\n        timeRangeContextSyncedValue !== value\n      ) {\n        // The global synced value changed, so we need to update the picker value.\n        onChangeProp(timeRangeContextSyncedValue);\n      }\n    }\n  }, [\n    usingTimeRangeContext,\n    timeRangeContextSynced,\n    timeRangeContextSyncedValue,\n    timeRangeContextSyncFunc,\n    prevSyncedValue,\n    value,\n    prevValue,\n    onChangeProp,\n  ]);\n\n  // Decide if we are in synced state or not. This is complicated by the manual controlled isSynced prop that is used\n  // in Explore for now.\n  const isSynced = usingTimeRangeContext ? timeRangeContext?.synced : isSyncedProp;\n\n  // Again in Explore the sync button is controlled prop so here we also decide what kind of button to use.\n  const button = usingTimeRangeContext\n    ? timeRangeContext?.syncPossible && (\n        <TimeSyncButton\n          isSynced={timeRangeContext?.synced}\n          onClick={() => (timeRangeContext?.synced ? timeRangeContext.unSync() : timeRangeContext.sync(value))}\n        />\n      )\n    : timeSyncButtonProp;\n\n  return {\n    onChangeWithSync,\n    isSynced,\n    timeSyncButton: button,\n  };\n}\n"],"names":[],"mappings":";;;;;;AAaO,SAAS,YAAY,OAMzB,EAAA;AACD,EAAA,MAAM,EAAE,KAAO,EAAA,YAAA,EAAc,YAAc,EAAA,eAAA,EAAiB,oBAAuB,GAAA,OAAA;AACnF,EAAA,MAAM,gBAAmB,GAAA,mBAAA,CAAoB,eAAmB,IAAA,KAAA,GAAQ,QAAQ,KAAS,CAAA,CAAA;AAGzF,EAAA,MAAM,yBAAyB,gBAAkB,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAA,MAAA;AACjD,EAAA,MAAM,8BAA8B,gBAAkB,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAA,WAAA;AACtD,EAAA,MAAM,2BAA2B,gBAAkB,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAA,IAAA;AAInD,EAAA,MAAM,qBAAwB,GAAA,OAAA,CAAQ,OAAQ,CAAA,YAAA,KAAiB,UAAa,gBAAgB,CAAA;AAG5F,EAAA,MAAM,gBAAmB,GAAA,WAAA;AAAA,IACvB,CAAC,SAAyB,KAAA;AACxB,MAAA,YAAA,CAAa,SAAS,CAAA;AACtB,MAAA,IAAI,yBAAyB,sBAAwB,EAAA;AACnD,QAA2B,wBAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,wBAAA,CAAA,SAAA,CAAA;AAAA;AAC7B,KACF;AAAA,IACA,CAAC,YAAA,EAAc,qBAAuB,EAAA,wBAAA,EAA0B,sBAAsB;AAAA,GACxF;AAEA,EAAM,MAAA,SAAA,GAAY,YAAY,KAAK,CAAA;AACnC,EAAM,MAAA,eAAA,GAAkB,WAAY,CAAA,gBAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAkB,WAAW,CAAA;AAKjE,EAAA,SAAA,CAAU,MAAM;AAEd,IAAA,IAAI,yBAAyB,sBAAwB,EAAA;AACnD,MAAI,IAAA,KAAA,KAAU,SAAa,IAAA,KAAA,KAAU,2BAA6B,EAAA;AAEhE,QAA2B,wBAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,wBAAA,CAAA,KAAA,CAAA;AAAA,OAE3B,MAAA,IAAA,2BAAA,IACA,2BAAgC,KAAA,eAAA,IAChC,gCAAgC,KAChC,EAAA;AAEA,QAAA,YAAA,CAAa,2BAA2B,CAAA;AAAA;AAC1C;AACF,GACC,EAAA;AAAA,IACD,qBAAA;AAAA,IACA,sBAAA;AAAA,IACA,2BAAA;AAAA,IACA,wBAAA;AAAA,IACA,eAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACD,CAAA;AAID,EAAM,MAAA,QAAA,GAAW,qBAAwB,GAAA,gBAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAkB,MAAS,GAAA,YAAA;AAGpE,EAAM,MAAA,MAAA,GAAS,qBACX,GAAA,CAAA,gBAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAkB,YAChB,qBAAA,GAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,UAAU,gBAAkB,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAA,MAAA;AAAA,MAC5B,OAAA,EAAS,OAAO,gBAAkB,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,gBAAA,CAAA,MAAA,IAAS,iBAAiB,MAAO,EAAA,GAAI,gBAAiB,CAAA,IAAA,CAAK,KAAK;AAAA;AAAA,GAGtG,GAAA,kBAAA;AAEJ,EAAO,OAAA;AAAA,IACL,gBAAA;AAAA,IACA,QAAA;AAAA,IACA,cAAgB,EAAA;AAAA,GAClB;AACF;;;;"}