direction-provider.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { createContext, useContext, useEffect, useState } from 'react'
  2. import { DirectionProvider as RdxDirProvider } from '@radix-ui/react-direction'
  3. import { getCookie, setCookie, removeCookie } from '@/lib/cookies'
  4. export type Direction = 'ltr' | 'rtl'
  5. const DEFAULT_DIRECTION = 'ltr'
  6. const DIRECTION_COOKIE_NAME = 'dir'
  7. const DIRECTION_COOKIE_MAX_AGE = 60 * 60 * 24 * 365 // 1 year
  8. type DirectionContextType = {
  9. defaultDir: Direction
  10. dir: Direction
  11. setDir: (dir: Direction) => void
  12. resetDir: () => void
  13. }
  14. const DirectionContext = createContext<DirectionContextType | null>(null)
  15. export function DirectionProvider({ children }: { children: React.ReactNode }) {
  16. const [dir, _setDir] = useState<Direction>(
  17. () => (getCookie(DIRECTION_COOKIE_NAME) as Direction) || DEFAULT_DIRECTION
  18. )
  19. useEffect(() => {
  20. const htmlElement = document.documentElement
  21. htmlElement.setAttribute('dir', dir)
  22. }, [dir])
  23. const setDir = (dir: Direction) => {
  24. _setDir(dir)
  25. setCookie(DIRECTION_COOKIE_NAME, dir, DIRECTION_COOKIE_MAX_AGE)
  26. }
  27. const resetDir = () => {
  28. _setDir(DEFAULT_DIRECTION)
  29. removeCookie(DIRECTION_COOKIE_NAME)
  30. }
  31. return (
  32. <DirectionContext
  33. value={{
  34. defaultDir: DEFAULT_DIRECTION,
  35. dir,
  36. setDir,
  37. resetDir,
  38. }}
  39. >
  40. <RdxDirProvider dir={dir}>{children}</RdxDirProvider>
  41. </DirectionContext>
  42. )
  43. }
  44. // eslint-disable-next-line react-refresh/only-export-components
  45. export function useDirection() {
  46. const context = useContext(DirectionContext)
  47. if (!context) {
  48. throw new Error('useDirection must be used within a DirectionProvider')
  49. }
  50. return context
  51. }