direction-context.tsx 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  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. interface DirectionContextType {
  9. defaultDir: Direction
  10. dir: Direction
  11. setDir: (dir: Direction) => void
  12. resetDir: () => void
  13. }
  14. const DirectionContext = createContext<DirectionContextType>({
  15. defaultDir: DEFAULT_DIRECTION,
  16. dir: DEFAULT_DIRECTION,
  17. setDir: () => {},
  18. resetDir: () => {},
  19. })
  20. export function DirectionProvider({ children }: { children: React.ReactNode }) {
  21. const [dir, _setDir] = useState<Direction>(
  22. () => (getCookie(DIRECTION_COOKIE_NAME) as Direction) || DEFAULT_DIRECTION
  23. )
  24. useEffect(() => {
  25. const htmlElement = document.documentElement
  26. htmlElement.setAttribute('dir', dir)
  27. }, [dir])
  28. const setDir = (dir: Direction) => {
  29. _setDir(dir)
  30. setCookie(DIRECTION_COOKIE_NAME, dir, DIRECTION_COOKIE_MAX_AGE)
  31. }
  32. const resetDir = () => {
  33. _setDir(DEFAULT_DIRECTION)
  34. removeCookie(DIRECTION_COOKIE_NAME)
  35. }
  36. return (
  37. <DirectionContext
  38. value={{
  39. defaultDir: DEFAULT_DIRECTION,
  40. dir,
  41. setDir,
  42. resetDir,
  43. }}
  44. >
  45. <RdxDirProvider dir={dir}>{children}</RdxDirProvider>
  46. </DirectionContext>
  47. )
  48. }
  49. // eslint-disable-next-line react-refresh/only-export-components
  50. export function useDirection() {
  51. const context = useContext(DirectionContext)
  52. if (!context) {
  53. throw new Error('useDirection must be used within a DirectionProvider')
  54. }
  55. return context
  56. }