{"version":3,"file":"useSidebar.mjs","sources":["../../../../src/components/Sidebar/useSidebar.tsx"],"sourcesContent":["import React, { useCallback, useContext, useEffect } from 'react';\nimport { useMedia } from 'react-use';\n\nimport { store } from '@grafana/data';\n\nimport { useTheme2 } from '../../themes/ThemeContext';\nimport { clamp } from '../../utils/clamp';\n\nexport type SidebarPosition = 'left' | 'right';\n\nexport interface SidebarContextValue {\n  isDocked: boolean;\n  position: SidebarPosition;\n  compact: boolean;\n  hasOpenPane?: boolean;\n  tabsMode?: boolean;\n  outerWrapperProps: React.HTMLAttributes<HTMLDivElement>;\n  paneWidth: number;\n  bottomMargin: number;\n  edgeMargin: number;\n  contentMargin: number;\n  isHidden: boolean;\n  isHiddenPreference: boolean;\n  canGoBack?: boolean;\n  onToggleDock?: () => void;\n  onResize: (diff: number) => void;\n  /** Called when pane is closed or clicked outside of (in undocked mode) */\n  onClosePane?: () => void;\n  /** Open previous pane */\n  onGoBack?: () => void;\n  onToggleIsHidden: () => void;\n  setIsHidden: (value: boolean) => void;\n}\n\nexport const SidebarContext: React.Context<SidebarContextValue | undefined> = React.createContext<\n  SidebarContextValue | undefined\n>(undefined);\n\nexport const useSidebarContext = () => useContext(SidebarContext);\n\nexport interface UseSideBarOptions {\n  hasOpenPane?: boolean;\n  position?: SidebarPosition;\n  tabsMode?: boolean;\n  /** Initial state for compact mode */\n  defaultToCompact?: boolean;\n  /** Initial state for docked mode */\n  defaultToDocked?: boolean;\n  /** defaults to 2 grid units (16px) */\n  bottomMargin?: number;\n  /** defaults to 2 grid units (16px) */\n  edgeMargin?: number;\n  /** defaults to 2 grid units (16px) */\n  contentMargin?: number;\n  /** Called when pane is closed or clicked outside of (in undocked mode) */\n  onClosePane?: () => void;\n  /** Disables go back button */\n  canGoBack?: boolean;\n  /** Open previous pane */\n  onGoBack?: () => void;\n  /**\n   * Optional key to use for persisting sidebar state (docked / compact / size)\n   * Can only be app name as the final local storag key will be `grafana.ui.sidebar.{persistenceKey}.{docked|compact|size}`\n   */\n  persistenceKey?: string;\n  /** Whether the sidebar is hidden by default */\n  defaultIsHidden?: boolean;\n  /**\n   * Optional override for the persistance key used to store the hidden state.\n   * Allows the hidden preference to be shared across consumers that otherwise use different\n   * persistenceKeys (e.g. dashboard view vs edit mode share a single hide preference).\n   */\n  hiddenPersistenceKey?: string;\n}\n\nexport const SIDE_BAR_WIDTH_ICON_ONLY = 5;\nexport const SIDE_BAR_WIDTH_WITH_TEXT = 8;\n\nexport function useSidebar({\n  hasOpenPane,\n  position = 'right',\n  tabsMode,\n  defaultToCompact = true,\n  defaultToDocked = false,\n  bottomMargin = 2,\n  edgeMargin = 2,\n  contentMargin = 2,\n  persistenceKey,\n  onClosePane,\n  onGoBack,\n  canGoBack,\n  defaultIsHidden = false,\n  hiddenPersistenceKey,\n}: UseSideBarOptions): SidebarContextValue {\n  const theme = useTheme2();\n  const [isDocked, setIsDocked] = useSidebarSavedState(persistenceKey, 'docked', defaultToDocked);\n  const [compact, setCompact] = useSidebarSavedState(persistenceKey, 'compact', defaultToCompact);\n  const [paneWidth, setPaneWidth] = useSidebarSavedState(persistenceKey, 'size', 240);\n  const [isHidden, setIsHidden] = useSidebarSavedState(\n    hiddenPersistenceKey ?? persistenceKey,\n    'hidden',\n    defaultIsHidden\n  );\n  const isMobile = useMedia(`(max-width: ${theme.breakpoints.values.sm}px)`);\n  const isTemporarilyShown = isHidden && Boolean(hasOpenPane);\n  const effectiveIsHidden = isHidden && !isTemporarilyShown;\n  // On small viewports the sidebar is always rendered as an undocked overlay so it doesn't\n  // permanently steal horizontal space — docking only applies on larger viewports.\n  const effectiveIsDocked = !isTemporarilyShown && !isMobile && isDocked;\n\n  // Used to accumulate drag distance to know when to change compact mode\n  const [_, setCompactDrag] = React.useState(0);\n\n  const onToggleDock = useCallback(() => {\n    setIsDocked((prev) => !prev);\n  }, [setIsDocked]);\n\n  // Calculate how much space the outer wrapper needs to reserve for the sidebar toolbar + pane (if docked)\n  const prop = position === 'right' ? 'paddingRight' : 'paddingLeft';\n  const toolbarWidth =\n    ((compact ? SIDE_BAR_WIDTH_ICON_ONLY : SIDE_BAR_WIDTH_WITH_TEXT) + edgeMargin + contentMargin) *\n    theme.spacing.gridSize;\n\n  const outerWrapperProps =\n    effectiveIsHidden || isTemporarilyShown\n      ? {}\n      : {\n          style: {\n            [prop]: effectiveIsDocked && hasOpenPane ? paneWidth + toolbarWidth : toolbarWidth,\n          },\n        };\n\n  const onResize = useCallback(\n    (diff: number) => {\n      setPaneWidth((prevWidth) => {\n        // If no pane is open we use the resize action to toggle compact mode (button text visibility)\n        if (!hasOpenPane) {\n          setCompactDrag((prevDrag) => {\n            const newDrag = prevDrag + diff;\n            if (newDrag < -20 && !compact) {\n              setCompact(() => true);\n              return 0;\n            } else if (newDrag > 20 && compact) {\n              setCompact(() => false);\n              return 0;\n            }\n\n            return newDrag;\n          });\n\n          return prevWidth;\n        }\n\n        const maxWidth = Math.max(window.innerWidth * 0.5, 500);\n        return clamp(prevWidth + diff, 100, maxWidth);\n      });\n    },\n    [hasOpenPane, setCompact, setPaneWidth, compact]\n  );\n\n  const onToggleIsHidden = useCallback(() => setIsHidden((prev) => !prev), [setIsHidden]);\n  const setIsHiddenValue = useCallback((value: boolean) => setIsHidden(() => value), [setIsHidden]);\n\n  return {\n    isDocked: effectiveIsDocked,\n    onToggleDock: isMobile || isTemporarilyShown ? undefined : onToggleDock,\n    onResize,\n    outerWrapperProps,\n    position,\n    compact,\n    hasOpenPane,\n    tabsMode,\n    paneWidth,\n    edgeMargin,\n    bottomMargin,\n    contentMargin,\n    isHidden: effectiveIsHidden,\n    isHiddenPreference: isHidden,\n    onClosePane,\n    onGoBack,\n    canGoBack,\n    onToggleIsHidden,\n    setIsHidden: setIsHiddenValue,\n  };\n}\n\nfunction readFromStore<T>(persistenceKey: string | undefined, subKey: string, defaultValue: T): T {\n  if (!persistenceKey) {\n    return defaultValue;\n  }\n\n  if (typeof defaultValue === 'boolean') {\n    // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n    return store.getBool(`grafana.ui.sidebar.${persistenceKey}.${subKey}`, defaultValue) as T;\n  }\n\n  if (typeof defaultValue === 'number') {\n    const value = Number.parseInt(store.get(`grafana.ui.sidebar.${persistenceKey}.${subKey}`), 10);\n    // eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n    return Number.isNaN(value) ? defaultValue : (value as T);\n  }\n\n  return defaultValue;\n}\n\nexport function useSidebarSavedState<T = number | boolean>(\n  persistenceKey: string | undefined,\n  subKey: string,\n  defaultValue: T\n) {\n  const [state, setState] = React.useState<T>(() => readFromStore(persistenceKey, subKey, defaultValue));\n\n  useEffect(() => {\n    setState(readFromStore(persistenceKey, subKey, defaultValue));\n    // Re-read from storage when the persistence key changes, but not when defaultValue changes\n    // to avoid overriding a user-persisted value.\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [persistenceKey, subKey]);\n\n  const setPersisted = useCallback(\n    (cb: (prevState: T) => T) => {\n      setState((prevState) => {\n        const newState = cb(prevState);\n\n        if (!persistenceKey) {\n          return newState;\n        }\n\n        if (persistenceKey) {\n          store.set(`grafana.ui.sidebar.${persistenceKey}.${subKey}`, String(newState));\n        }\n\n        return newState;\n      });\n    },\n    [persistenceKey, subKey]\n  );\n\n  return [state, setPersisted] as const;\n}\n"],"names":["React"],"mappings":"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"}