UNPKG

@grafana/ui

Version:
1 lines 4.08 kB
{"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"}