@expofp/ui 3.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/README.md +30 -0
  2. package/dist/Alert/Alert.d.ts +20 -0
  3. package/dist/Alert/Alert.js +23 -0
  4. package/dist/Alert/index.d.ts +3 -0
  5. package/dist/Alert/index.js +1 -0
  6. package/dist/Autocomplete/Autocomplete.d.ts +21 -0
  7. package/dist/Autocomplete/Autocomplete.js +183 -0
  8. package/dist/Autocomplete/index.d.ts +3 -0
  9. package/dist/Autocomplete/index.js +1 -0
  10. package/dist/Badge/Badge.d.ts +14 -0
  11. package/dist/Badge/Badge.js +15 -0
  12. package/dist/Badge/index.d.ts +3 -0
  13. package/dist/Badge/index.js +1 -0
  14. package/dist/Button/Button.d.ts +30 -0
  15. package/dist/Button/Button.js +41 -0
  16. package/dist/Button/index.d.ts +3 -0
  17. package/dist/Button/index.js +1 -0
  18. package/dist/Checkbox/Checkbox.d.ts +19 -0
  19. package/dist/Checkbox/Checkbox.js +19 -0
  20. package/dist/Checkbox/index.d.ts +3 -0
  21. package/dist/Checkbox/index.js +1 -0
  22. package/dist/CheckboxButton/CheckboxButton.d.ts +12 -0
  23. package/dist/CheckboxButton/CheckboxButton.js +19 -0
  24. package/dist/CheckboxButton/index.d.ts +3 -0
  25. package/dist/CheckboxButton/index.js +1 -0
  26. package/dist/DownloadList/DownloadList.d.ts +15 -0
  27. package/dist/DownloadList/DownloadList.js +9 -0
  28. package/dist/DownloadList/index.d.ts +3 -0
  29. package/dist/DownloadList/index.js +2 -0
  30. package/dist/Draggable/Draggable.d.ts +9 -0
  31. package/dist/Draggable/Draggable.js +92 -0
  32. package/dist/Draggable/index.d.ts +3 -0
  33. package/dist/Draggable/index.js +2 -0
  34. package/dist/EntityItem/EntityItem.d.ts +46 -0
  35. package/dist/EntityItem/EntityItem.js +29 -0
  36. package/dist/EntityItem/index.d.ts +3 -0
  37. package/dist/EntityItem/index.js +1 -0
  38. package/dist/EventBadge/EventBadge.d.ts +13 -0
  39. package/dist/EventBadge/EventBadge.js +10 -0
  40. package/dist/EventBadge/index.d.ts +3 -0
  41. package/dist/EventBadge/index.js +1 -0
  42. package/dist/HeatmapLegend/HeatmapLegend.d.ts +15 -0
  43. package/dist/HeatmapLegend/HeatmapLegend.js +11 -0
  44. package/dist/HeatmapLegend/index.d.ts +3 -0
  45. package/dist/HeatmapLegend/index.js +2 -0
  46. package/dist/HighlightText/HighlightText.d.ts +7 -0
  47. package/dist/HighlightText/HighlightText.js +14 -0
  48. package/dist/HighlightText/index.d.ts +2 -0
  49. package/dist/HighlightText/index.js +1 -0
  50. package/dist/LevelBadge/LevelBadge.d.ts +9 -0
  51. package/dist/LevelBadge/LevelBadge.js +10 -0
  52. package/dist/LevelBadge/index.d.ts +3 -0
  53. package/dist/LevelBadge/index.js +2 -0
  54. package/dist/LevelSelector/LevelSelector.d.ts +19 -0
  55. package/dist/LevelSelector/LevelSelector.js +91 -0
  56. package/dist/LevelSelector/index.d.ts +3 -0
  57. package/dist/LevelSelector/index.js +2 -0
  58. package/dist/MapControls/MapControls.d.ts +33 -0
  59. package/dist/MapControls/MapControls.js +38 -0
  60. package/dist/MapControls/index.d.ts +3 -0
  61. package/dist/MapControls/index.js +2 -0
  62. package/dist/MobileToggleButton/MobileToggleButton.d.ts +12 -0
  63. package/dist/MobileToggleButton/MobileToggleButton.js +8 -0
  64. package/dist/MobileToggleButton/index.d.ts +3 -0
  65. package/dist/MobileToggleButton/index.js +1 -0
  66. package/dist/Modal/Modal.d.ts +34 -0
  67. package/dist/Modal/Modal.js +98 -0
  68. package/dist/Modal/index.d.ts +3 -0
  69. package/dist/Modal/index.js +1 -0
  70. package/dist/MultiSelectGroups/MultiSelectGroups.d.ts +37 -0
  71. package/dist/MultiSelectGroups/MultiSelectGroups.js +80 -0
  72. package/dist/MultiSelectGroups/index.d.ts +3 -0
  73. package/dist/MultiSelectGroups/index.js +1 -0
  74. package/dist/OverlayGrip/OverlayGrip.d.ts +11 -0
  75. package/dist/OverlayGrip/OverlayGrip.js +8 -0
  76. package/dist/OverlayGrip/index.d.ts +3 -0
  77. package/dist/OverlayGrip/index.js +2 -0
  78. package/dist/PermissionNotice/PermissionNotice.d.ts +16 -0
  79. package/dist/PermissionNotice/PermissionNotice.js +11 -0
  80. package/dist/PermissionNotice/index.d.ts +3 -0
  81. package/dist/PermissionNotice/index.js +2 -0
  82. package/dist/Radio/Radio.d.ts +15 -0
  83. package/dist/Radio/Radio.js +13 -0
  84. package/dist/Radio/index.d.ts +3 -0
  85. package/dist/Radio/index.js +1 -0
  86. package/dist/RebookingNotes/RebookingNotes.d.ts +11 -0
  87. package/dist/RebookingNotes/RebookingNotes.js +18 -0
  88. package/dist/RebookingNotes/index.d.ts +3 -0
  89. package/dist/RebookingNotes/index.js +1 -0
  90. package/dist/RebookingRadioGroup/RebookingRadioGroup.d.ts +17 -0
  91. package/dist/RebookingRadioGroup/RebookingRadioGroup.js +13 -0
  92. package/dist/RebookingRadioGroup/index.d.ts +3 -0
  93. package/dist/RebookingRadioGroup/index.js +1 -0
  94. package/dist/ScrollableRow/ScrollableRow.d.ts +21 -0
  95. package/dist/ScrollableRow/ScrollableRow.js +155 -0
  96. package/dist/ScrollableRow/index.d.ts +3 -0
  97. package/dist/ScrollableRow/index.js +2 -0
  98. package/dist/Share/Share.d.ts +22 -0
  99. package/dist/Share/Share.js +24 -0
  100. package/dist/Share/index.d.ts +3 -0
  101. package/dist/Share/index.js +1 -0
  102. package/dist/ShowMoreButton/ShowMoreButton.d.ts +11 -0
  103. package/dist/ShowMoreButton/ShowMoreButton.js +7 -0
  104. package/dist/ShowMoreButton/index.d.ts +3 -0
  105. package/dist/ShowMoreButton/index.js +1 -0
  106. package/dist/SidebarActions/SidebarActions.d.ts +26 -0
  107. package/dist/SidebarActions/SidebarActions.js +32 -0
  108. package/dist/SidebarActions/index.d.ts +3 -0
  109. package/dist/SidebarActions/index.js +2 -0
  110. package/dist/SimpleRow/SimpleRow.d.ts +15 -0
  111. package/dist/SimpleRow/SimpleRow.js +11 -0
  112. package/dist/SimpleRow/index.d.ts +3 -0
  113. package/dist/SimpleRow/index.js +2 -0
  114. package/dist/Spinner/Spinner.d.ts +9 -0
  115. package/dist/Spinner/Spinner.js +8 -0
  116. package/dist/Spinner/index.d.ts +3 -0
  117. package/dist/Spinner/index.js +1 -0
  118. package/dist/ToggleButton/ToggleButton.d.ts +17 -0
  119. package/dist/ToggleButton/ToggleButton.js +8 -0
  120. package/dist/ToggleButton/index.d.ts +3 -0
  121. package/dist/ToggleButton/index.js +1 -0
  122. package/dist/ToggleSwitch/ToggleSwitch.d.ts +12 -0
  123. package/dist/ToggleSwitch/ToggleSwitch.js +10 -0
  124. package/dist/ToggleSwitch/index.d.ts +3 -0
  125. package/dist/ToggleSwitch/index.js +1 -0
  126. package/dist/TouchHand/TouchHand.d.ts +5 -0
  127. package/dist/TouchHand/TouchHand.js +7 -0
  128. package/dist/TouchHand/index.d.ts +2 -0
  129. package/dist/TouchHand/index.js +1 -0
  130. package/dist/WayfindingFloorSelector/WayfindingFloorSelector.d.ts +24 -0
  131. package/dist/WayfindingFloorSelector/WayfindingFloorSelector.js +27 -0
  132. package/dist/WayfindingFloorSelector/index.d.ts +3 -0
  133. package/dist/WayfindingFloorSelector/index.js +1 -0
  134. package/dist/components/Alert/Alert.d.ts +20 -0
  135. package/dist/components/Alert/Alert.js +23 -0
  136. package/dist/components/Alert/index.d.ts +3 -0
  137. package/dist/components/Alert/index.js +1 -0
  138. package/dist/components/Autocomplete/Autocomplete.d.ts +21 -0
  139. package/dist/components/Autocomplete/Autocomplete.js +183 -0
  140. package/dist/components/Autocomplete/index.d.ts +3 -0
  141. package/dist/components/Autocomplete/index.js +1 -0
  142. package/dist/components/Badge/Badge.d.ts +14 -0
  143. package/dist/components/Badge/Badge.js +15 -0
  144. package/dist/components/Badge/index.d.ts +3 -0
  145. package/dist/components/Badge/index.js +1 -0
  146. package/dist/components/Button/Button.d.ts +30 -0
  147. package/dist/components/Button/Button.js +41 -0
  148. package/dist/components/Button/index.d.ts +3 -0
  149. package/dist/components/Button/index.js +1 -0
  150. package/dist/components/Checkbox/Checkbox.d.ts +19 -0
  151. package/dist/components/Checkbox/Checkbox.js +19 -0
  152. package/dist/components/Checkbox/index.d.ts +3 -0
  153. package/dist/components/Checkbox/index.js +1 -0
  154. package/dist/components/CheckboxButton/CheckboxButton.d.ts +12 -0
  155. package/dist/components/CheckboxButton/CheckboxButton.js +19 -0
  156. package/dist/components/CheckboxButton/index.d.ts +3 -0
  157. package/dist/components/CheckboxButton/index.js +1 -0
  158. package/dist/components/DownloadList/DownloadList.d.ts +15 -0
  159. package/dist/components/DownloadList/DownloadList.js +9 -0
  160. package/dist/components/DownloadList/index.d.ts +3 -0
  161. package/dist/components/DownloadList/index.js +2 -0
  162. package/dist/components/Draggable/Draggable.d.ts +9 -0
  163. package/dist/components/Draggable/Draggable.js +92 -0
  164. package/dist/components/Draggable/index.d.ts +3 -0
  165. package/dist/components/Draggable/index.js +2 -0
  166. package/dist/components/EntityItem/EntityItem.d.ts +46 -0
  167. package/dist/components/EntityItem/EntityItem.js +29 -0
  168. package/dist/components/EntityItem/index.d.ts +3 -0
  169. package/dist/components/EntityItem/index.js +1 -0
  170. package/dist/components/EventBadge/EventBadge.d.ts +13 -0
  171. package/dist/components/EventBadge/EventBadge.js +10 -0
  172. package/dist/components/EventBadge/index.d.ts +3 -0
  173. package/dist/components/EventBadge/index.js +1 -0
  174. package/dist/components/Gallery/Gallery.d.ts +25 -0
  175. package/dist/components/Gallery/Gallery.js +25 -0
  176. package/dist/components/Gallery/GalleryBadges/GalleryBadges.d.ts +8 -0
  177. package/dist/components/Gallery/GalleryBadges/GalleryBadges.js +5 -0
  178. package/dist/components/Gallery/GalleryControls/GalleryControls.d.ts +11 -0
  179. package/dist/components/Gallery/GalleryControls/GalleryControls.js +5 -0
  180. package/dist/components/Gallery/GalleryImg/GalleryImg.d.ts +13 -0
  181. package/dist/components/Gallery/GalleryImg/GalleryImg.js +37 -0
  182. package/dist/components/Gallery/GalleryItem/GalleryItem.d.ts +14 -0
  183. package/dist/components/Gallery/GalleryItem/GalleryItem.js +6 -0
  184. package/dist/components/Gallery/GalleryModal/GalleryModal.d.ts +18 -0
  185. package/dist/components/Gallery/GalleryModal/GalleryModal.js +88 -0
  186. package/dist/components/Gallery/GalleryPreLoader.d.ts +7 -0
  187. package/dist/components/Gallery/GalleryPreLoader.js +29 -0
  188. package/dist/components/Gallery/TransformImg/TransformImg.d.ts +10 -0
  189. package/dist/components/Gallery/TransformImg/TransformImg.js +15 -0
  190. package/dist/components/Gallery/index.d.ts +3 -0
  191. package/dist/components/Gallery/index.js +1 -0
  192. package/dist/components/HeatmapLegend/HeatmapLegend.d.ts +15 -0
  193. package/dist/components/HeatmapLegend/HeatmapLegend.js +11 -0
  194. package/dist/components/HeatmapLegend/index.d.ts +3 -0
  195. package/dist/components/HeatmapLegend/index.js +2 -0
  196. package/dist/components/HighlightText/HighlightText.d.ts +7 -0
  197. package/dist/components/HighlightText/HighlightText.js +14 -0
  198. package/dist/components/HighlightText/index.d.ts +2 -0
  199. package/dist/components/HighlightText/index.js +1 -0
  200. package/dist/components/LevelBadge/LevelBadge.d.ts +9 -0
  201. package/dist/components/LevelBadge/LevelBadge.js +10 -0
  202. package/dist/components/LevelBadge/index.d.ts +3 -0
  203. package/dist/components/LevelBadge/index.js +2 -0
  204. package/dist/components/LevelSelector/LevelSelector.d.ts +19 -0
  205. package/dist/components/LevelSelector/LevelSelector.js +91 -0
  206. package/dist/components/LevelSelector/index.d.ts +3 -0
  207. package/dist/components/LevelSelector/index.js +2 -0
  208. package/dist/components/MapControls/MapControls.d.ts +33 -0
  209. package/dist/components/MapControls/MapControls.js +38 -0
  210. package/dist/components/MapControls/index.d.ts +3 -0
  211. package/dist/components/MapControls/index.js +2 -0
  212. package/dist/components/MobileToggleButton/MobileToggleButton.d.ts +12 -0
  213. package/dist/components/MobileToggleButton/MobileToggleButton.js +8 -0
  214. package/dist/components/MobileToggleButton/index.d.ts +3 -0
  215. package/dist/components/MobileToggleButton/index.js +1 -0
  216. package/dist/components/Modal/Modal.d.ts +34 -0
  217. package/dist/components/Modal/Modal.js +98 -0
  218. package/dist/components/Modal/index.d.ts +3 -0
  219. package/dist/components/Modal/index.js +1 -0
  220. package/dist/components/MultiSelectGroups/MultiSelectGroups.d.ts +37 -0
  221. package/dist/components/MultiSelectGroups/MultiSelectGroups.js +80 -0
  222. package/dist/components/MultiSelectGroups/index.d.ts +3 -0
  223. package/dist/components/MultiSelectGroups/index.js +1 -0
  224. package/dist/components/Overlay/Overlay.d.ts +29 -0
  225. package/dist/components/Overlay/Overlay.js +251 -0
  226. package/dist/components/Overlay/OverlayScrollContext.d.ts +7 -0
  227. package/dist/components/Overlay/OverlayScrollContext.js +7 -0
  228. package/dist/components/Overlay/index.d.ts +4 -0
  229. package/dist/components/Overlay/index.js +2 -0
  230. package/dist/components/OverlayGrip/OverlayGrip.d.ts +11 -0
  231. package/dist/components/OverlayGrip/OverlayGrip.js +8 -0
  232. package/dist/components/OverlayGrip/index.d.ts +3 -0
  233. package/dist/components/OverlayGrip/index.js +2 -0
  234. package/dist/components/PermissionNotice/PermissionNotice.d.ts +16 -0
  235. package/dist/components/PermissionNotice/PermissionNotice.js +11 -0
  236. package/dist/components/PermissionNotice/index.d.ts +3 -0
  237. package/dist/components/PermissionNotice/index.js +2 -0
  238. package/dist/components/Radio/Radio.d.ts +15 -0
  239. package/dist/components/Radio/Radio.js +13 -0
  240. package/dist/components/Radio/index.d.ts +3 -0
  241. package/dist/components/Radio/index.js +1 -0
  242. package/dist/components/RebookingNotes/RebookingNotes.d.ts +11 -0
  243. package/dist/components/RebookingNotes/RebookingNotes.js +18 -0
  244. package/dist/components/RebookingNotes/index.d.ts +3 -0
  245. package/dist/components/RebookingNotes/index.js +1 -0
  246. package/dist/components/RebookingRadioGroup/RebookingRadioGroup.d.ts +17 -0
  247. package/dist/components/RebookingRadioGroup/RebookingRadioGroup.js +13 -0
  248. package/dist/components/RebookingRadioGroup/index.d.ts +3 -0
  249. package/dist/components/RebookingRadioGroup/index.js +1 -0
  250. package/dist/components/ScrollableRow/ScrollableRow.d.ts +21 -0
  251. package/dist/components/ScrollableRow/ScrollableRow.js +155 -0
  252. package/dist/components/ScrollableRow/index.d.ts +3 -0
  253. package/dist/components/ScrollableRow/index.js +2 -0
  254. package/dist/components/Share/Share.d.ts +22 -0
  255. package/dist/components/Share/Share.js +24 -0
  256. package/dist/components/Share/index.d.ts +3 -0
  257. package/dist/components/Share/index.js +1 -0
  258. package/dist/components/ShowMoreButton/ShowMoreButton.d.ts +11 -0
  259. package/dist/components/ShowMoreButton/ShowMoreButton.js +7 -0
  260. package/dist/components/ShowMoreButton/index.d.ts +3 -0
  261. package/dist/components/ShowMoreButton/index.js +1 -0
  262. package/dist/components/SidebarActions/SidebarActions.d.ts +26 -0
  263. package/dist/components/SidebarActions/SidebarActions.js +32 -0
  264. package/dist/components/SidebarActions/index.d.ts +3 -0
  265. package/dist/components/SidebarActions/index.js +2 -0
  266. package/dist/components/SimpleRow/SimpleRow.d.ts +15 -0
  267. package/dist/components/SimpleRow/SimpleRow.js +11 -0
  268. package/dist/components/SimpleRow/index.d.ts +3 -0
  269. package/dist/components/SimpleRow/index.js +2 -0
  270. package/dist/components/Spinner/Spinner.d.ts +9 -0
  271. package/dist/components/Spinner/Spinner.js +8 -0
  272. package/dist/components/Spinner/index.d.ts +3 -0
  273. package/dist/components/Spinner/index.js +1 -0
  274. package/dist/components/ToggleButton/ToggleButton.d.ts +17 -0
  275. package/dist/components/ToggleButton/ToggleButton.js +8 -0
  276. package/dist/components/ToggleButton/index.d.ts +3 -0
  277. package/dist/components/ToggleButton/index.js +1 -0
  278. package/dist/components/ToggleSwitch/ToggleSwitch.d.ts +12 -0
  279. package/dist/components/ToggleSwitch/ToggleSwitch.js +10 -0
  280. package/dist/components/ToggleSwitch/index.d.ts +3 -0
  281. package/dist/components/ToggleSwitch/index.js +1 -0
  282. package/dist/components/TouchHand/TouchHand.d.ts +5 -0
  283. package/dist/components/TouchHand/TouchHand.js +7 -0
  284. package/dist/components/TouchHand/index.d.ts +2 -0
  285. package/dist/components/TouchHand/index.js +1 -0
  286. package/dist/components/WayfindingFloorSelector/WayfindingFloorSelector.d.ts +24 -0
  287. package/dist/components/WayfindingFloorSelector/WayfindingFloorSelector.js +27 -0
  288. package/dist/components/WayfindingFloorSelector/index.d.ts +3 -0
  289. package/dist/components/WayfindingFloorSelector/index.js +1 -0
  290. package/dist/index.d.ts +65 -0
  291. package/dist/index.js +69 -0
  292. package/dist/shared/debounce.d.ts +2 -0
  293. package/dist/shared/debounce.js +9 -0
  294. package/dist/shared/hooks/useDragGesture.d.ts +19 -0
  295. package/dist/shared/hooks/useDragGesture.js +45 -0
  296. package/dist/shared/hooks/useOnClickOutside.d.ts +14 -0
  297. package/dist/shared/hooks/useOnClickOutside.js +43 -0
  298. package/dist/shared/hooks/useOnEscape.d.ts +14 -0
  299. package/dist/shared/hooks/useOnEscape.js +31 -0
  300. package/dist/shared/hooks/useWindowSize.d.ts +5 -0
  301. package/dist/shared/hooks/useWindowSize.js +40 -0
  302. package/dist/shared/interactive.d.ts +2 -0
  303. package/dist/shared/interactive.js +4 -0
  304. package/package.json +70 -0
@@ -0,0 +1,251 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import './Overlay.scss';
3
+ import cn from 'classnames';
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
+ import debounce from '../../shared/debounce';
6
+ import { useDragGesture } from '../../shared/hooks/useDragGesture';
7
+ import { useWindowSize } from '../../shared/hooks/useWindowSize';
8
+ import { OverlayScrollContext } from './OverlayScrollContext';
9
+ const GAP = 70;
10
+ const TRANSITION_DURATION = '0.3s';
11
+ const DEFAULT_SCROLL_THRESHOLD = 10;
12
+ const DEFAULT_MOBILE_BREAKPOINT = 768;
13
+ const getActualViewportHeight = () => {
14
+ const isInIframe = window !== window.top;
15
+ if (isInIframe) {
16
+ return (document.documentElement.clientHeight || document.body.clientHeight || window.innerHeight);
17
+ }
18
+ return window.innerHeight;
19
+ };
20
+ const generateSizes = (height = getActualViewportHeight(), smallMultiplier, mediumMultiplier, fullSizeOffset) => ({
21
+ small: height / smallMultiplier,
22
+ medium: height / mediumMultiplier,
23
+ full: height - fullSizeOffset,
24
+ });
25
+ const Overlay = ({ children, open, size = 'medium', particles, className, onChangeSize, onScrollStateChange, onScrollActivity, smallSizeMultiplier = 12.6, mediumSizeMultiplier = 2.6, fullSizeOffset = 0, scrollThreshold = DEFAULT_SCROLL_THRESHOLD, disableDrag = false, forceFull = false, scrollResetKey, mobileBreakpoint = DEFAULT_MOBILE_BREAKPOINT, noContentLabel, }) => {
26
+ const { width: windowWidth, height: windowHeight } = useWindowSize();
27
+ // Pure derivations of the window size — computed in render, not stored/synced via an effect.
28
+ const mobile = windowWidth <= mobileBreakpoint;
29
+ const sizes = useMemo(() => generateSizes(windowHeight, smallSizeMultiplier, mediumSizeMultiplier, fullSizeOffset), [windowHeight, smallSizeMultiplier, mediumSizeMultiplier, fullSizeOffset]);
30
+ const [dragging, setDragging] = useState(false);
31
+ const [panelHeight, setPanelHeight] = useState(() => sizes[size]);
32
+ const [overlayHeight, setOverlayHeight] = useState(() => sizes[size]);
33
+ const [isAnimating, setIsAnimating] = useState(false);
34
+ const [shouldRender, setShouldRender] = useState(open);
35
+ const [isScrolled, setIsScrolled] = useState(false);
36
+ const touchStartRef = useRef(undefined);
37
+ const dragOffsetRef = useRef(undefined);
38
+ const overlayPanelRef = useRef(null);
39
+ const triggerRef = useRef(null);
40
+ const scrollRef = useRef(null);
41
+ // Mirror frequently-changing values into refs so the drag callbacks can stay
42
+ // identity-stable and the listener effect subscribes only when mobile/disableDrag change.
43
+ const sizesRef = useRef(sizes);
44
+ const panelHeightRef = useRef(panelHeight);
45
+ const overlayHeightRef = useRef(overlayHeight);
46
+ const draggingRef = useRef(dragging);
47
+ const sizeRef = useRef(size);
48
+ useEffect(() => {
49
+ sizesRef.current = sizes;
50
+ panelHeightRef.current = panelHeight;
51
+ overlayHeightRef.current = overlayHeight;
52
+ draggingRef.current = dragging;
53
+ sizeRef.current = size;
54
+ });
55
+ const setSize = useCallback((newSize) => {
56
+ const height = sizesRef.current[newSize];
57
+ setPanelHeight(height);
58
+ setOverlayHeight(height);
59
+ onChangeSize?.(newSize);
60
+ }, [onChangeSize]);
61
+ const positioningStyles = useMemo(() => {
62
+ if (mobile) {
63
+ if (forceFull && open) {
64
+ return { height: getActualViewportHeight() };
65
+ }
66
+ return {
67
+ height: open || isAnimating ? overlayHeight : 0,
68
+ };
69
+ }
70
+ return {
71
+ height: open ? 'auto' : undefined,
72
+ };
73
+ }, [mobile, open, overlayHeight, isAnimating, forceFull]);
74
+ const setSizeByValue = useCallback((heightVal) => {
75
+ const sizes = sizesRef.current;
76
+ const sizesArray = [sizes.small, sizes.medium, sizes.full].sort();
77
+ if (heightVal >= sizes.full) {
78
+ setSize('full');
79
+ return;
80
+ }
81
+ if (heightVal <= sizes.small) {
82
+ setSize('small');
83
+ return;
84
+ }
85
+ const currentHeight = panelHeightRef.current || sizes.medium;
86
+ const targetSize = heightVal > currentHeight
87
+ ? (sizesArray.find((val) => val + GAP >= heightVal) ?? sizes.full)
88
+ : (sizesArray.reverse().find((val) => val - GAP <= heightVal) ?? sizes.small);
89
+ if (targetSize === sizes.full) {
90
+ setSize('full');
91
+ }
92
+ else if (targetSize === sizes.medium) {
93
+ setSize('medium');
94
+ }
95
+ else {
96
+ setSize('small');
97
+ }
98
+ }, [setSize]);
99
+ const handleDragStart = useCallback((clientY) => {
100
+ setDragging(true);
101
+ touchStartRef.current = clientY;
102
+ }, []);
103
+ const handleDragMove = useCallback((clientY) => {
104
+ const touchStart = touchStartRef.current;
105
+ if (touchStart === undefined)
106
+ return;
107
+ const sizes = sizesRef.current;
108
+ const panelHeight = panelHeightRef.current;
109
+ const scrollEl = scrollRef.current;
110
+ if ((scrollEl?.scrollTop ?? 0) > 0 && panelHeight === sizes.full)
111
+ return;
112
+ const offset = touchStart - clientY;
113
+ const currentHeight = panelHeight || sizes.medium;
114
+ let nextHeight = currentHeight + offset;
115
+ if (scrollEl && panelHeight === sizes.full && nextHeight < panelHeight) {
116
+ scrollEl.style.overflow = 'hidden';
117
+ }
118
+ nextHeight = Math.min(Math.max(nextHeight, sizes.small), sizes.full);
119
+ dragOffsetRef.current = offset;
120
+ overlayHeightRef.current = nextHeight;
121
+ setOverlayHeight(nextHeight);
122
+ }, []);
123
+ const handleDragEnd = useCallback(() => {
124
+ setDragging(false);
125
+ touchStartRef.current = undefined;
126
+ const scrollEl = scrollRef.current;
127
+ if (scrollEl) {
128
+ scrollEl.style.removeProperty('overflow');
129
+ }
130
+ const dragOffset = dragOffsetRef.current;
131
+ dragOffsetRef.current = undefined;
132
+ const finalHeight = overlayHeightRef.current;
133
+ if (dragOffset !== undefined && finalHeight !== undefined) {
134
+ setSizeByValue(finalHeight);
135
+ }
136
+ }, [setSizeByValue]);
137
+ const handleTriggerClick = useCallback(() => {
138
+ if (draggingRef.current)
139
+ return;
140
+ const currentSize = sizeRef.current;
141
+ const nextSize = currentSize === 'small' ? 'medium' : currentSize === 'medium' ? 'full' : 'small';
142
+ setSize(nextSize);
143
+ }, [setSize]);
144
+ const { touchHandlers, mouseHandlers } = useDragGesture({
145
+ onDragStart: handleDragStart,
146
+ onDragMove: handleDragMove,
147
+ onDragEnd: handleDragEnd,
148
+ });
149
+ const handleScroll = useCallback(() => {
150
+ const scrollEl = scrollRef.current;
151
+ if (!scrollEl)
152
+ return;
153
+ const scrollTop = scrollEl.scrollTop;
154
+ const shouldAddClass = scrollTop >= scrollThreshold;
155
+ if (isScrolled !== shouldAddClass) {
156
+ setIsScrolled(shouldAddClass);
157
+ onScrollStateChange?.(shouldAddClass);
158
+ }
159
+ }, [scrollThreshold, isScrolled, onScrollStateChange]);
160
+ const debouncedScrollActivity = useMemo(() => debounce(() => {
161
+ onScrollActivity?.();
162
+ }, 250), [onScrollActivity]);
163
+ useEffect(() => {
164
+ if (!mobile || disableDrag)
165
+ return;
166
+ const overlayEl = overlayPanelRef.current;
167
+ const triggerEl = triggerRef.current;
168
+ const scrollEl = scrollRef.current;
169
+ const preventOverscroll = () => {
170
+ const panelHeight = panelHeightRef.current;
171
+ if (panelHeight && panelHeight < sizesRef.current.full && scrollEl) {
172
+ scrollEl.style.overflow = 'hidden';
173
+ }
174
+ };
175
+ if (overlayEl) {
176
+ overlayEl.addEventListener('touchstart', touchHandlers.onTouchStart);
177
+ overlayEl.addEventListener('touchend', touchHandlers.onTouchEnd);
178
+ window.addEventListener('touchmove', touchHandlers.onTouchMove);
179
+ overlayEl.addEventListener('mousedown', mouseHandlers.onMouseDown);
180
+ overlayEl.addEventListener('mouseup', mouseHandlers.onMouseUp);
181
+ window.addEventListener('mousemove', mouseHandlers.onMouseMove);
182
+ }
183
+ if (triggerEl) {
184
+ triggerEl.addEventListener('mouseup', handleTriggerClick);
185
+ }
186
+ if (scrollEl) {
187
+ scrollEl.addEventListener('touchstart', preventOverscroll);
188
+ }
189
+ return () => {
190
+ if (overlayEl) {
191
+ overlayEl.removeEventListener('touchstart', touchHandlers.onTouchStart);
192
+ overlayEl.removeEventListener('touchend', touchHandlers.onTouchEnd);
193
+ window.removeEventListener('touchmove', touchHandlers.onTouchMove);
194
+ overlayEl.removeEventListener('mousedown', mouseHandlers.onMouseDown);
195
+ overlayEl.removeEventListener('mouseup', mouseHandlers.onMouseUp);
196
+ window.removeEventListener('mousemove', mouseHandlers.onMouseMove);
197
+ }
198
+ if (triggerEl) {
199
+ triggerEl.removeEventListener('mouseup', handleTriggerClick);
200
+ }
201
+ if (scrollEl) {
202
+ scrollEl.removeEventListener('touchstart', preventOverscroll);
203
+ }
204
+ };
205
+ }, [mobile, disableDrag, touchHandlers, mouseHandlers, handleTriggerClick]);
206
+ useEffect(() => {
207
+ if (open) {
208
+ setShouldRender(true);
209
+ setIsAnimating(true);
210
+ const timer = setTimeout(() => {
211
+ setSize(size);
212
+ setIsAnimating(false);
213
+ }, 10);
214
+ return () => clearTimeout(timer);
215
+ }
216
+ else {
217
+ setIsAnimating(true);
218
+ if (mobile) {
219
+ setOverlayHeight(0);
220
+ }
221
+ const timer = setTimeout(() => {
222
+ setShouldRender(false);
223
+ setIsAnimating(false);
224
+ setIsScrolled(false);
225
+ }, parseFloat(TRANSITION_DURATION) * 1000);
226
+ return () => clearTimeout(timer);
227
+ }
228
+ }, [open, size, setSize, mobile]);
229
+ useEffect(() => {
230
+ if (open && !isAnimating) {
231
+ scrollRef.current?.scrollTo({ top: 0 });
232
+ setIsScrolled(false);
233
+ onScrollStateChange?.(false);
234
+ }
235
+ }, [open, isAnimating, onScrollStateChange, scrollResetKey]);
236
+ if (!shouldRender)
237
+ return null;
238
+ return (_jsx(OverlayScrollContext, { value: scrollRef.current, children: _jsxs("div", { className: cn('efp-overlay', {
239
+ 'efp-overlay--draggable': dragging,
240
+ 'efp-overlay--full': size === 'full',
241
+ 'efp-overlay--mobile': mobile,
242
+ 'efp-overlay--desktop': !mobile,
243
+ 'efp-overlay--hidden': !mobile && !open,
244
+ 'efp-overlay--scrolled': isScrolled,
245
+ 'efp-overlay--forced-full': forceFull && mobile,
246
+ }, className), style: positioningStyles, ref: overlayPanelRef, children: [!disableDrag && _jsx("div", { className: "efp-overlay__draghandle", ref: triggerRef }), _jsxs("div", { className: "efp-overlay__scroll", ref: scrollRef, onScroll: () => {
247
+ handleScroll();
248
+ debouncedScrollActivity();
249
+ }, children: [particles, _jsx("div", { className: "efp-overlay__content", children: children ? children : noContentLabel })] })] }) }));
250
+ };
251
+ export default Overlay;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Exposes the overlay's inner scroll container to descendants so they can
3
+ * observe / drive it (e.g. a virtualized list syncing its scroll position).
4
+ * Provided by {@link Overlay}; `null` when rendered outside an overlay.
5
+ */
6
+ export declare const OverlayScrollContext: import("react").Context<HTMLDivElement | null>;
7
+ //# sourceMappingURL=OverlayScrollContext.d.ts.map
@@ -0,0 +1,7 @@
1
+ import { createContext } from 'react';
2
+ /**
3
+ * Exposes the overlay's inner scroll container to descendants so they can
4
+ * observe / drive it (e.g. a virtualized list syncing its scroll position).
5
+ * Provided by {@link Overlay}; `null` when rendered outside an overlay.
6
+ */
7
+ export const OverlayScrollContext = createContext(null);
@@ -0,0 +1,4 @@
1
+ export type { OverlayProps, Size } from './Overlay';
2
+ export { default } from './Overlay';
3
+ export { OverlayScrollContext } from './OverlayScrollContext';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ export { default } from './Overlay';
2
+ export { OverlayScrollContext } from './OverlayScrollContext';
@@ -0,0 +1,11 @@
1
+ import './OverlayGrip.scss';
2
+ import React from 'react';
3
+ export interface OverlayGripProps {
4
+ isFull: boolean;
5
+ onToggle: () => void;
6
+ ariaLabel: string;
7
+ className?: string;
8
+ }
9
+ declare const OverlayGrip: ({ isFull, onToggle, ariaLabel, className }: OverlayGripProps) => React.JSX.Element;
10
+ export default OverlayGrip;
11
+ //# sourceMappingURL=OverlayGrip.d.ts.map
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // @ts-nocheck
3
+ import './OverlayGrip.scss';
4
+ import cn from 'classnames';
5
+ const OverlayGrip = ({ isFull, onToggle, ariaLabel, className }) => {
6
+ return (_jsx("button", { type: "button", className: cn('efp-overlay-grip', { 'efp-overlay-grip--full': isFull }, className), onClick: onToggle, "aria-label": ariaLabel, "aria-expanded": isFull, children: _jsxs("svg", { viewBox: "0 0 1200 200", preserveAspectRatio: "xMidYMid meet", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [_jsx("path", { d: "M100,100 l 500 100 L 1100 100" }), _jsx("path", { d: "M100,150 l 500 0 L 1100 150" })] }) }));
7
+ };
8
+ export default OverlayGrip;
@@ -0,0 +1,3 @@
1
+ export { default } from './OverlayGrip';
2
+ export type { OverlayGripProps } from './OverlayGrip';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ /* eslint-disable simple-import-sort/exports */
2
+ export { default } from './OverlayGrip';
@@ -0,0 +1,16 @@
1
+ import './PermissionNotice.scss';
2
+ import React from 'react';
3
+ export type PermissionNoticePlacement = 'bottom-right' | 'bottom-left';
4
+ export interface PermissionNoticeProps {
5
+ title: string;
6
+ acceptText: string;
7
+ rejectText: string;
8
+ children: React.ReactNode;
9
+ placement?: PermissionNoticePlacement;
10
+ onAccept?: () => void;
11
+ onReject?: () => void;
12
+ className?: string;
13
+ }
14
+ declare const PermissionNotice: ({ title, acceptText, rejectText, children, placement, onAccept, onReject, className, }: PermissionNoticeProps) => React.JSX.Element;
15
+ export default PermissionNotice;
16
+ //# sourceMappingURL=PermissionNotice.d.ts.map
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import './PermissionNotice.scss';
3
+ import cn from 'classnames';
4
+ import { useId } from 'react';
5
+ import Button from '../Button';
6
+ const PermissionNotice = ({ title, acceptText, rejectText, children, placement = 'bottom-right', onAccept, onReject, className, }) => {
7
+ const titleId = useId();
8
+ const descId = useId();
9
+ return (_jsxs("div", { className: cn('efp-permission-notice', `efp-permission-notice--${placement}`, className), role: "dialog", "aria-labelledby": titleId, "aria-describedby": descId, children: [_jsx("div", { className: "efp-permission-notice__title", id: titleId, children: title }), _jsx("div", { className: "efp-permission-notice__text", id: descId, children: children }), _jsxs("div", { className: "efp-permission-notice__bottom", children: [_jsx(Button, { size: "md", onClick: onAccept, children: acceptText }), _jsx(Button, { size: "md", variant: "gray", onClick: onReject, children: rejectText })] })] }));
10
+ };
11
+ export default PermissionNotice;
@@ -0,0 +1,3 @@
1
+ export { default } from './PermissionNotice';
2
+ export type { PermissionNoticeProps } from './PermissionNotice';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ /* eslint-disable simple-import-sort/exports */
2
+ export { default } from './PermissionNotice';
@@ -0,0 +1,15 @@
1
+ import './Radio.scss';
2
+ import React from 'react';
3
+ export interface RadioProps {
4
+ name: string;
5
+ label: string;
6
+ value: string | number;
7
+ checked?: boolean;
8
+ disabled?: boolean;
9
+ className?: string;
10
+ ariaLabel?: string;
11
+ onChange?: () => void;
12
+ }
13
+ declare const Radio: ({ name, label, value, checked, disabled, className, ariaLabel, onChange, }: RadioProps) => React.JSX.Element;
14
+ export default Radio;
15
+ //# sourceMappingURL=Radio.d.ts.map
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // @ts-nocheck
3
+ import './Radio.scss';
4
+ import classNames from 'classnames';
5
+ import { useId } from 'react';
6
+ const Radio = ({ name, label, value, checked, disabled, className, ariaLabel, onChange, }) => {
7
+ const id = useId();
8
+ return (_jsxs("label", { htmlFor: id, className: classNames('efp-radio', className, {
9
+ 'efp-radio--checked': checked,
10
+ 'efp-radio--disabled': disabled,
11
+ }), children: [_jsx("input", { type: "radio", className: "efp-radio__input", id: id, name: name, value: value, checked: checked, disabled: disabled, "aria-label": ariaLabel, onChange: onChange }), _jsx("span", { className: "efp-radio__control", "aria-hidden": "true" }), _jsx("span", { className: "efp-radio__label", children: label })] }));
12
+ };
13
+ export default Radio;
@@ -0,0 +1,3 @@
1
+ export type { RadioProps } from './Radio';
2
+ export { default } from './Radio';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export { default } from './Radio';
@@ -0,0 +1,11 @@
1
+ import './RebookingNotes.scss';
2
+ export interface RebookingNotesProps {
3
+ value?: string;
4
+ noteLabel: string;
5
+ saveButtonLabel: string;
6
+ saveButtonAriaLabel: string;
7
+ onSave: (value: string) => void;
8
+ }
9
+ declare const RebookingNotes: ({ value, noteLabel, saveButtonLabel, saveButtonAriaLabel, onSave, }: RebookingNotesProps) => import("react").JSX.Element;
10
+ export default RebookingNotes;
11
+ //# sourceMappingURL=RebookingNotes.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import './RebookingNotes.scss';
3
+ import { useId, useState } from 'react';
4
+ import Button from '../Button';
5
+ const RebookingNotes = ({ value, noteLabel, saveButtonLabel, saveButtonAriaLabel, onSave, }) => {
6
+ const id = useId();
7
+ const labelId = `${id}-label`;
8
+ const textareaId = `${id}-textarea`;
9
+ // Uncontrolled editing buffer seeded from `value`; consumers reset it by remounting via `key`
10
+ // (see RebookingNotesContainer usage). Committed to the parent only on save.
11
+ const [internalValue, setInternalValue] = useState(value ?? '');
12
+ const handleChange = (event) => setInternalValue(event.target.value);
13
+ const handleSave = () => {
14
+ onSave(internalValue);
15
+ };
16
+ return (_jsxs("div", { className: "rebooking-notes", children: [_jsx("div", { className: "rebooking-notes__view-header", children: _jsx("strong", { id: labelId, children: noteLabel }) }), _jsxs("div", { className: "rebooking-notes__edit", children: [_jsx("div", { className: "rebooking-notes__val", children: _jsx("textarea", { id: textareaId, value: internalValue, onChange: handleChange, "aria-labelledby": labelId }) }), _jsx("div", { className: "rebooking-notes__buttons", children: _jsx(Button, { inline: true, onClick: handleSave, disabled: (value ?? '') === internalValue, "aria-label": saveButtonAriaLabel, children: saveButtonLabel }) })] })] }));
17
+ };
18
+ export default RebookingNotes;
@@ -0,0 +1,3 @@
1
+ export type { RebookingNotesProps } from './RebookingNotes';
2
+ export { default } from './RebookingNotes';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export { default } from './RebookingNotes';
@@ -0,0 +1,17 @@
1
+ import './RebookingRadioGroup.scss';
2
+ export interface RebookingOption {
3
+ value: string;
4
+ label: string;
5
+ iconName?: string;
6
+ disabled?: boolean;
7
+ color: string;
8
+ }
9
+ export interface RebookingRadioGroupProps {
10
+ options: RebookingOption[];
11
+ value: string;
12
+ title?: string;
13
+ onChange: (value: string) => void;
14
+ }
15
+ declare const RebookingRadioGroup: ({ options, value, title, onChange }: RebookingRadioGroupProps) => import("react").JSX.Element;
16
+ export default RebookingRadioGroup;
17
+ //# sourceMappingURL=RebookingRadioGroup.d.ts.map
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import './RebookingRadioGroup.scss';
3
+ import { useId } from 'react';
4
+ const RebookingRadioGroup = ({ options, value, title, onChange }) => {
5
+ const idPrefix = useId();
6
+ return (_jsxs("div", { className: "rebooking-radio-group", children: [title && _jsx("div", { className: "rebooking-radio-group__title", children: title }), _jsx("div", { className: "rebooking-radio-group__options", children: options.map((option) => {
7
+ const optionId = `${idPrefix}-${option.value}`;
8
+ return (_jsxs("div", { className: "rebooking-radio", style: {
9
+ '--rebooking-color-primary': option.color,
10
+ }, children: [_jsx("input", { type: "radio", name: idPrefix, value: option.value, id: optionId, checked: option.value === value, disabled: option.disabled, onChange: () => onChange(option.value) }), _jsxs("label", { htmlFor: optionId, children: [_jsx("div", { className: "rebooking-radio__label", children: option.label }), _jsx("div", { className: "rebooking-radio__icon", children: _jsx("i", { className: option.iconName, "aria-hidden": "true" }) })] })] }, option.value));
11
+ }) })] }));
12
+ };
13
+ export default RebookingRadioGroup;
@@ -0,0 +1,3 @@
1
+ export type { RebookingOption, RebookingRadioGroupProps } from './RebookingRadioGroup';
2
+ export { default } from './RebookingRadioGroup';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ export { default } from './RebookingRadioGroup';
@@ -0,0 +1,21 @@
1
+ import './ScrollableRow.scss';
2
+ import React, { ReactNode } from 'react';
3
+ export interface ScrollableRowProps {
4
+ children: ReactNode;
5
+ ariaLabel: string;
6
+ leftAriaLabel: string;
7
+ rightAriaLabel: string;
8
+ className?: string;
9
+ scrollAmount?: number;
10
+ mobileBreakpoint?: number;
11
+ showArrowsOnMobile?: boolean;
12
+ arrowPosition?: 'inside' | 'outside';
13
+ scrollBehavior?: 'smooth' | 'auto';
14
+ isRtl?: boolean;
15
+ enableDragScroll?: boolean;
16
+ dragScrollSensitivity?: number;
17
+ onScroll?: (scrollLeft: number) => void;
18
+ }
19
+ declare const ScrollableRow: ({ children, ariaLabel, leftAriaLabel, rightAriaLabel, className, scrollAmount, mobileBreakpoint, showArrowsOnMobile, arrowPosition, scrollBehavior, isRtl, enableDragScroll, dragScrollSensitivity, onScroll, }: ScrollableRowProps) => React.JSX.Element;
20
+ export default ScrollableRow;
21
+ //# sourceMappingURL=ScrollableRow.d.ts.map
@@ -0,0 +1,155 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable @typescript-eslint/consistent-type-imports, @eslint-react/set-state-in-effect */
3
+ import './ScrollableRow.scss';
4
+ import cn from 'classnames';
5
+ import { useCallback, useEffect, useRef, useState } from 'react';
6
+ import { ResizeObserver } from 'resize-observer';
7
+ import { isInteractiveTarget } from '../../shared/interactive';
8
+ const SCROLL_THRESHOLD = 5;
9
+ const DEFAULT_MOBILE_BREAKPOINT = 768;
10
+ const ScrollableRow = ({ children, ariaLabel, leftAriaLabel, rightAriaLabel, className, scrollAmount = 150, mobileBreakpoint = DEFAULT_MOBILE_BREAKPOINT, showArrowsOnMobile = false, arrowPosition = 'inside', scrollBehavior = 'smooth', isRtl = false, enableDragScroll = true, dragScrollSensitivity = 1, onScroll, }) => {
11
+ const containerRef = useRef(null);
12
+ const scrollRef = useRef(null);
13
+ const resizeObserverRef = useRef(null);
14
+ const [showLeftArrow, setShowLeftArrow] = useState(false);
15
+ const [showRightArrow, setShowRightArrow] = useState(false);
16
+ const [isDragging, setIsDragging] = useState(false);
17
+ const [startX, setStartX] = useState(0);
18
+ const [dragStartScrollLeft, setDragStartScrollLeft] = useState(0);
19
+ const isDesktop = useCallback(() => {
20
+ return (window.innerWidth > mobileBreakpoint &&
21
+ !('ontouchstart' in window || navigator.maxTouchPoints > 0));
22
+ }, [mobileBreakpoint]);
23
+ const normalizeRTLScroll = useCallback((scrollLeft, scrollWidth, clientWidth) => {
24
+ const maxScroll = scrollWidth - clientWidth;
25
+ if (scrollLeft < 0) {
26
+ return Math.abs(scrollLeft);
27
+ }
28
+ else if (scrollLeft > maxScroll / 2) {
29
+ return maxScroll - scrollLeft;
30
+ }
31
+ return scrollLeft;
32
+ }, []);
33
+ const checkArrows = useCallback(() => {
34
+ const scrollEl = scrollRef.current;
35
+ if (!scrollEl)
36
+ return;
37
+ const isMobile = window.innerWidth <= mobileBreakpoint;
38
+ if (isMobile && !showArrowsOnMobile) {
39
+ setShowLeftArrow(false);
40
+ setShowRightArrow(false);
41
+ return;
42
+ }
43
+ const { scrollLeft, scrollWidth, clientWidth } = scrollEl;
44
+ const hasOverflow = scrollWidth > clientWidth;
45
+ if (!hasOverflow) {
46
+ setShowLeftArrow(false);
47
+ setShowRightArrow(false);
48
+ return;
49
+ }
50
+ if (isRtl) {
51
+ const maxScroll = scrollWidth - clientWidth;
52
+ const normalizedScroll = normalizeRTLScroll(scrollLeft, scrollWidth, clientWidth);
53
+ setShowLeftArrow(normalizedScroll > SCROLL_THRESHOLD);
54
+ setShowRightArrow(normalizedScroll < maxScroll - SCROLL_THRESHOLD);
55
+ }
56
+ else {
57
+ setShowLeftArrow(scrollLeft > SCROLL_THRESHOLD);
58
+ setShowRightArrow(scrollLeft < scrollWidth - clientWidth - SCROLL_THRESHOLD);
59
+ }
60
+ }, [mobileBreakpoint, showArrowsOnMobile, normalizeRTLScroll, isRtl]);
61
+ const handleScroll = useCallback(() => {
62
+ checkArrows();
63
+ if (onScroll && scrollRef.current) {
64
+ onScroll(scrollRef.current.scrollLeft);
65
+ }
66
+ }, [checkArrows, onScroll]);
67
+ const scroll = useCallback((direction) => {
68
+ const scrollEl = scrollRef.current;
69
+ if (!scrollEl)
70
+ return;
71
+ const currentScroll = scrollEl.scrollLeft;
72
+ let newScroll;
73
+ if (isRtl) {
74
+ const maxScrollLeft = -(scrollEl.scrollWidth - scrollEl.clientWidth);
75
+ newScroll =
76
+ direction === 'left'
77
+ ? Math.min(0, currentScroll + scrollAmount)
78
+ : Math.max(maxScrollLeft, currentScroll - scrollAmount);
79
+ }
80
+ else {
81
+ newScroll =
82
+ direction === 'left'
83
+ ? Math.max(0, currentScroll - scrollAmount)
84
+ : currentScroll + scrollAmount;
85
+ }
86
+ scrollEl.scrollTo({
87
+ left: newScroll,
88
+ behavior: scrollBehavior,
89
+ });
90
+ }, [scrollAmount, scrollBehavior, isRtl]);
91
+ const handleMouseDown = useCallback((e) => {
92
+ if (!enableDragScroll || !isDesktop() || !scrollRef.current)
93
+ return;
94
+ if (isInteractiveTarget(e.target))
95
+ return;
96
+ setIsDragging(true);
97
+ setStartX(e.pageX - scrollRef.current.offsetLeft);
98
+ setDragStartScrollLeft(scrollRef.current.scrollLeft);
99
+ e.preventDefault();
100
+ }, [enableDragScroll, isDesktop]);
101
+ const handleMouseMove = useCallback((e) => {
102
+ if (!isDragging || !scrollRef.current)
103
+ return;
104
+ e.preventDefault();
105
+ const x = e.pageX - scrollRef.current.offsetLeft;
106
+ const walk = (x - startX) * dragScrollSensitivity;
107
+ scrollRef.current.scrollLeft = dragStartScrollLeft - walk;
108
+ }, [isDragging, startX, dragStartScrollLeft, dragScrollSensitivity]);
109
+ const endDrag = useCallback(() => {
110
+ setIsDragging(false);
111
+ }, []);
112
+ useEffect(() => {
113
+ if (!isDragging)
114
+ return;
115
+ document.addEventListener('mousemove', handleMouseMove);
116
+ document.addEventListener('mouseup', endDrag);
117
+ document.addEventListener('mouseleave', endDrag);
118
+ return () => {
119
+ document.removeEventListener('mousemove', handleMouseMove);
120
+ document.removeEventListener('mouseup', endDrag);
121
+ document.removeEventListener('mouseleave', endDrag);
122
+ };
123
+ }, [isDragging, handleMouseMove, endDrag]);
124
+ useEffect(() => {
125
+ checkArrows();
126
+ const handleResize = () => checkArrows();
127
+ window.addEventListener('resize', handleResize);
128
+ if (containerRef.current && !resizeObserverRef.current) {
129
+ resizeObserverRef.current = new ResizeObserver(checkArrows);
130
+ resizeObserverRef.current.observe(containerRef.current);
131
+ }
132
+ return () => {
133
+ window.removeEventListener('resize', handleResize);
134
+ if (resizeObserverRef.current) {
135
+ resizeObserverRef.current.disconnect();
136
+ resizeObserverRef.current = null;
137
+ }
138
+ };
139
+ }, [checkArrows]);
140
+ const showDragCursor = enableDragScroll && isDesktop();
141
+ const cursorStyle = showDragCursor ? (isDragging ? 'grabbing' : 'grab') : undefined;
142
+ return (_jsx("div", { ref: containerRef, className: cn('efp-scrollable-row', className), role: "group", "aria-label": ariaLabel, children: _jsxs("div", { className: cn('efp-scrollable-row__container', {
143
+ [`efp-scrollable-row__container--${arrowPosition}`]: arrowPosition,
144
+ }), children: [showLeftArrow && (_jsx("button", { type: "button", className: cn('efp-scrollable-row__arrow', 'efp-scrollable-row__arrow--left', {
145
+ 'efp-scrollable-row__arrow--rtl': isRtl,
146
+ }), onClick: () => scroll('left'), "aria-label": leftAriaLabel, children: _jsx("i", { className: "icon-chevron-left" }) })), _jsx("div", { ref: scrollRef, className: cn('efp-scrollable-row__scroll-wrapper', {
147
+ 'efp-scrollable-row__scroll-wrapper--dragging': isDragging,
148
+ }), onScroll: handleScroll, onMouseDown: handleMouseDown, style: {
149
+ cursor: cursorStyle,
150
+ userSelect: isDragging ? 'none' : undefined,
151
+ }, children: _jsx("div", { className: "efp-scrollable-row__content", children: children }) }), showRightArrow && (_jsx("button", { type: "button", className: cn('efp-scrollable-row__arrow', 'efp-scrollable-row__arrow--right', {
152
+ 'efp-scrollable-row__arrow--rtl': isRtl,
153
+ }), onClick: () => scroll('right'), "aria-label": rightAriaLabel, children: _jsx("i", { className: "icon-chevron-right" }) }))] }) }));
154
+ };
155
+ export default ScrollableRow;