@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.
- package/README.md +30 -0
- package/dist/Alert/Alert.d.ts +20 -0
- package/dist/Alert/Alert.js +23 -0
- package/dist/Alert/index.d.ts +3 -0
- package/dist/Alert/index.js +1 -0
- package/dist/Autocomplete/Autocomplete.d.ts +21 -0
- package/dist/Autocomplete/Autocomplete.js +183 -0
- package/dist/Autocomplete/index.d.ts +3 -0
- package/dist/Autocomplete/index.js +1 -0
- package/dist/Badge/Badge.d.ts +14 -0
- package/dist/Badge/Badge.js +15 -0
- package/dist/Badge/index.d.ts +3 -0
- package/dist/Badge/index.js +1 -0
- package/dist/Button/Button.d.ts +30 -0
- package/dist/Button/Button.js +41 -0
- package/dist/Button/index.d.ts +3 -0
- package/dist/Button/index.js +1 -0
- package/dist/Checkbox/Checkbox.d.ts +19 -0
- package/dist/Checkbox/Checkbox.js +19 -0
- package/dist/Checkbox/index.d.ts +3 -0
- package/dist/Checkbox/index.js +1 -0
- package/dist/CheckboxButton/CheckboxButton.d.ts +12 -0
- package/dist/CheckboxButton/CheckboxButton.js +19 -0
- package/dist/CheckboxButton/index.d.ts +3 -0
- package/dist/CheckboxButton/index.js +1 -0
- package/dist/DownloadList/DownloadList.d.ts +15 -0
- package/dist/DownloadList/DownloadList.js +9 -0
- package/dist/DownloadList/index.d.ts +3 -0
- package/dist/DownloadList/index.js +2 -0
- package/dist/Draggable/Draggable.d.ts +9 -0
- package/dist/Draggable/Draggable.js +92 -0
- package/dist/Draggable/index.d.ts +3 -0
- package/dist/Draggable/index.js +2 -0
- package/dist/EntityItem/EntityItem.d.ts +46 -0
- package/dist/EntityItem/EntityItem.js +29 -0
- package/dist/EntityItem/index.d.ts +3 -0
- package/dist/EntityItem/index.js +1 -0
- package/dist/EventBadge/EventBadge.d.ts +13 -0
- package/dist/EventBadge/EventBadge.js +10 -0
- package/dist/EventBadge/index.d.ts +3 -0
- package/dist/EventBadge/index.js +1 -0
- package/dist/HeatmapLegend/HeatmapLegend.d.ts +15 -0
- package/dist/HeatmapLegend/HeatmapLegend.js +11 -0
- package/dist/HeatmapLegend/index.d.ts +3 -0
- package/dist/HeatmapLegend/index.js +2 -0
- package/dist/HighlightText/HighlightText.d.ts +7 -0
- package/dist/HighlightText/HighlightText.js +14 -0
- package/dist/HighlightText/index.d.ts +2 -0
- package/dist/HighlightText/index.js +1 -0
- package/dist/LevelBadge/LevelBadge.d.ts +9 -0
- package/dist/LevelBadge/LevelBadge.js +10 -0
- package/dist/LevelBadge/index.d.ts +3 -0
- package/dist/LevelBadge/index.js +2 -0
- package/dist/LevelSelector/LevelSelector.d.ts +19 -0
- package/dist/LevelSelector/LevelSelector.js +91 -0
- package/dist/LevelSelector/index.d.ts +3 -0
- package/dist/LevelSelector/index.js +2 -0
- package/dist/MapControls/MapControls.d.ts +33 -0
- package/dist/MapControls/MapControls.js +38 -0
- package/dist/MapControls/index.d.ts +3 -0
- package/dist/MapControls/index.js +2 -0
- package/dist/MobileToggleButton/MobileToggleButton.d.ts +12 -0
- package/dist/MobileToggleButton/MobileToggleButton.js +8 -0
- package/dist/MobileToggleButton/index.d.ts +3 -0
- package/dist/MobileToggleButton/index.js +1 -0
- package/dist/Modal/Modal.d.ts +34 -0
- package/dist/Modal/Modal.js +98 -0
- package/dist/Modal/index.d.ts +3 -0
- package/dist/Modal/index.js +1 -0
- package/dist/MultiSelectGroups/MultiSelectGroups.d.ts +37 -0
- package/dist/MultiSelectGroups/MultiSelectGroups.js +80 -0
- package/dist/MultiSelectGroups/index.d.ts +3 -0
- package/dist/MultiSelectGroups/index.js +1 -0
- package/dist/OverlayGrip/OverlayGrip.d.ts +11 -0
- package/dist/OverlayGrip/OverlayGrip.js +8 -0
- package/dist/OverlayGrip/index.d.ts +3 -0
- package/dist/OverlayGrip/index.js +2 -0
- package/dist/PermissionNotice/PermissionNotice.d.ts +16 -0
- package/dist/PermissionNotice/PermissionNotice.js +11 -0
- package/dist/PermissionNotice/index.d.ts +3 -0
- package/dist/PermissionNotice/index.js +2 -0
- package/dist/Radio/Radio.d.ts +15 -0
- package/dist/Radio/Radio.js +13 -0
- package/dist/Radio/index.d.ts +3 -0
- package/dist/Radio/index.js +1 -0
- package/dist/RebookingNotes/RebookingNotes.d.ts +11 -0
- package/dist/RebookingNotes/RebookingNotes.js +18 -0
- package/dist/RebookingNotes/index.d.ts +3 -0
- package/dist/RebookingNotes/index.js +1 -0
- package/dist/RebookingRadioGroup/RebookingRadioGroup.d.ts +17 -0
- package/dist/RebookingRadioGroup/RebookingRadioGroup.js +13 -0
- package/dist/RebookingRadioGroup/index.d.ts +3 -0
- package/dist/RebookingRadioGroup/index.js +1 -0
- package/dist/ScrollableRow/ScrollableRow.d.ts +21 -0
- package/dist/ScrollableRow/ScrollableRow.js +155 -0
- package/dist/ScrollableRow/index.d.ts +3 -0
- package/dist/ScrollableRow/index.js +2 -0
- package/dist/Share/Share.d.ts +22 -0
- package/dist/Share/Share.js +24 -0
- package/dist/Share/index.d.ts +3 -0
- package/dist/Share/index.js +1 -0
- package/dist/ShowMoreButton/ShowMoreButton.d.ts +11 -0
- package/dist/ShowMoreButton/ShowMoreButton.js +7 -0
- package/dist/ShowMoreButton/index.d.ts +3 -0
- package/dist/ShowMoreButton/index.js +1 -0
- package/dist/SidebarActions/SidebarActions.d.ts +26 -0
- package/dist/SidebarActions/SidebarActions.js +32 -0
- package/dist/SidebarActions/index.d.ts +3 -0
- package/dist/SidebarActions/index.js +2 -0
- package/dist/SimpleRow/SimpleRow.d.ts +15 -0
- package/dist/SimpleRow/SimpleRow.js +11 -0
- package/dist/SimpleRow/index.d.ts +3 -0
- package/dist/SimpleRow/index.js +2 -0
- package/dist/Spinner/Spinner.d.ts +9 -0
- package/dist/Spinner/Spinner.js +8 -0
- package/dist/Spinner/index.d.ts +3 -0
- package/dist/Spinner/index.js +1 -0
- package/dist/ToggleButton/ToggleButton.d.ts +17 -0
- package/dist/ToggleButton/ToggleButton.js +8 -0
- package/dist/ToggleButton/index.d.ts +3 -0
- package/dist/ToggleButton/index.js +1 -0
- package/dist/ToggleSwitch/ToggleSwitch.d.ts +12 -0
- package/dist/ToggleSwitch/ToggleSwitch.js +10 -0
- package/dist/ToggleSwitch/index.d.ts +3 -0
- package/dist/ToggleSwitch/index.js +1 -0
- package/dist/TouchHand/TouchHand.d.ts +5 -0
- package/dist/TouchHand/TouchHand.js +7 -0
- package/dist/TouchHand/index.d.ts +2 -0
- package/dist/TouchHand/index.js +1 -0
- package/dist/WayfindingFloorSelector/WayfindingFloorSelector.d.ts +24 -0
- package/dist/WayfindingFloorSelector/WayfindingFloorSelector.js +27 -0
- package/dist/WayfindingFloorSelector/index.d.ts +3 -0
- package/dist/WayfindingFloorSelector/index.js +1 -0
- package/dist/components/Alert/Alert.d.ts +20 -0
- package/dist/components/Alert/Alert.js +23 -0
- package/dist/components/Alert/index.d.ts +3 -0
- package/dist/components/Alert/index.js +1 -0
- package/dist/components/Autocomplete/Autocomplete.d.ts +21 -0
- package/dist/components/Autocomplete/Autocomplete.js +183 -0
- package/dist/components/Autocomplete/index.d.ts +3 -0
- package/dist/components/Autocomplete/index.js +1 -0
- package/dist/components/Badge/Badge.d.ts +14 -0
- package/dist/components/Badge/Badge.js +15 -0
- package/dist/components/Badge/index.d.ts +3 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Button/Button.d.ts +30 -0
- package/dist/components/Button/Button.js +41 -0
- package/dist/components/Button/index.d.ts +3 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Checkbox/Checkbox.d.ts +19 -0
- package/dist/components/Checkbox/Checkbox.js +19 -0
- package/dist/components/Checkbox/index.d.ts +3 -0
- package/dist/components/Checkbox/index.js +1 -0
- package/dist/components/CheckboxButton/CheckboxButton.d.ts +12 -0
- package/dist/components/CheckboxButton/CheckboxButton.js +19 -0
- package/dist/components/CheckboxButton/index.d.ts +3 -0
- package/dist/components/CheckboxButton/index.js +1 -0
- package/dist/components/DownloadList/DownloadList.d.ts +15 -0
- package/dist/components/DownloadList/DownloadList.js +9 -0
- package/dist/components/DownloadList/index.d.ts +3 -0
- package/dist/components/DownloadList/index.js +2 -0
- package/dist/components/Draggable/Draggable.d.ts +9 -0
- package/dist/components/Draggable/Draggable.js +92 -0
- package/dist/components/Draggable/index.d.ts +3 -0
- package/dist/components/Draggable/index.js +2 -0
- package/dist/components/EntityItem/EntityItem.d.ts +46 -0
- package/dist/components/EntityItem/EntityItem.js +29 -0
- package/dist/components/EntityItem/index.d.ts +3 -0
- package/dist/components/EntityItem/index.js +1 -0
- package/dist/components/EventBadge/EventBadge.d.ts +13 -0
- package/dist/components/EventBadge/EventBadge.js +10 -0
- package/dist/components/EventBadge/index.d.ts +3 -0
- package/dist/components/EventBadge/index.js +1 -0
- package/dist/components/Gallery/Gallery.d.ts +25 -0
- package/dist/components/Gallery/Gallery.js +25 -0
- package/dist/components/Gallery/GalleryBadges/GalleryBadges.d.ts +8 -0
- package/dist/components/Gallery/GalleryBadges/GalleryBadges.js +5 -0
- package/dist/components/Gallery/GalleryControls/GalleryControls.d.ts +11 -0
- package/dist/components/Gallery/GalleryControls/GalleryControls.js +5 -0
- package/dist/components/Gallery/GalleryImg/GalleryImg.d.ts +13 -0
- package/dist/components/Gallery/GalleryImg/GalleryImg.js +37 -0
- package/dist/components/Gallery/GalleryItem/GalleryItem.d.ts +14 -0
- package/dist/components/Gallery/GalleryItem/GalleryItem.js +6 -0
- package/dist/components/Gallery/GalleryModal/GalleryModal.d.ts +18 -0
- package/dist/components/Gallery/GalleryModal/GalleryModal.js +88 -0
- package/dist/components/Gallery/GalleryPreLoader.d.ts +7 -0
- package/dist/components/Gallery/GalleryPreLoader.js +29 -0
- package/dist/components/Gallery/TransformImg/TransformImg.d.ts +10 -0
- package/dist/components/Gallery/TransformImg/TransformImg.js +15 -0
- package/dist/components/Gallery/index.d.ts +3 -0
- package/dist/components/Gallery/index.js +1 -0
- package/dist/components/HeatmapLegend/HeatmapLegend.d.ts +15 -0
- package/dist/components/HeatmapLegend/HeatmapLegend.js +11 -0
- package/dist/components/HeatmapLegend/index.d.ts +3 -0
- package/dist/components/HeatmapLegend/index.js +2 -0
- package/dist/components/HighlightText/HighlightText.d.ts +7 -0
- package/dist/components/HighlightText/HighlightText.js +14 -0
- package/dist/components/HighlightText/index.d.ts +2 -0
- package/dist/components/HighlightText/index.js +1 -0
- package/dist/components/LevelBadge/LevelBadge.d.ts +9 -0
- package/dist/components/LevelBadge/LevelBadge.js +10 -0
- package/dist/components/LevelBadge/index.d.ts +3 -0
- package/dist/components/LevelBadge/index.js +2 -0
- package/dist/components/LevelSelector/LevelSelector.d.ts +19 -0
- package/dist/components/LevelSelector/LevelSelector.js +91 -0
- package/dist/components/LevelSelector/index.d.ts +3 -0
- package/dist/components/LevelSelector/index.js +2 -0
- package/dist/components/MapControls/MapControls.d.ts +33 -0
- package/dist/components/MapControls/MapControls.js +38 -0
- package/dist/components/MapControls/index.d.ts +3 -0
- package/dist/components/MapControls/index.js +2 -0
- package/dist/components/MobileToggleButton/MobileToggleButton.d.ts +12 -0
- package/dist/components/MobileToggleButton/MobileToggleButton.js +8 -0
- package/dist/components/MobileToggleButton/index.d.ts +3 -0
- package/dist/components/MobileToggleButton/index.js +1 -0
- package/dist/components/Modal/Modal.d.ts +34 -0
- package/dist/components/Modal/Modal.js +98 -0
- package/dist/components/Modal/index.d.ts +3 -0
- package/dist/components/Modal/index.js +1 -0
- package/dist/components/MultiSelectGroups/MultiSelectGroups.d.ts +37 -0
- package/dist/components/MultiSelectGroups/MultiSelectGroups.js +80 -0
- package/dist/components/MultiSelectGroups/index.d.ts +3 -0
- package/dist/components/MultiSelectGroups/index.js +1 -0
- package/dist/components/Overlay/Overlay.d.ts +29 -0
- package/dist/components/Overlay/Overlay.js +251 -0
- package/dist/components/Overlay/OverlayScrollContext.d.ts +7 -0
- package/dist/components/Overlay/OverlayScrollContext.js +7 -0
- package/dist/components/Overlay/index.d.ts +4 -0
- package/dist/components/Overlay/index.js +2 -0
- package/dist/components/OverlayGrip/OverlayGrip.d.ts +11 -0
- package/dist/components/OverlayGrip/OverlayGrip.js +8 -0
- package/dist/components/OverlayGrip/index.d.ts +3 -0
- package/dist/components/OverlayGrip/index.js +2 -0
- package/dist/components/PermissionNotice/PermissionNotice.d.ts +16 -0
- package/dist/components/PermissionNotice/PermissionNotice.js +11 -0
- package/dist/components/PermissionNotice/index.d.ts +3 -0
- package/dist/components/PermissionNotice/index.js +2 -0
- package/dist/components/Radio/Radio.d.ts +15 -0
- package/dist/components/Radio/Radio.js +13 -0
- package/dist/components/Radio/index.d.ts +3 -0
- package/dist/components/Radio/index.js +1 -0
- package/dist/components/RebookingNotes/RebookingNotes.d.ts +11 -0
- package/dist/components/RebookingNotes/RebookingNotes.js +18 -0
- package/dist/components/RebookingNotes/index.d.ts +3 -0
- package/dist/components/RebookingNotes/index.js +1 -0
- package/dist/components/RebookingRadioGroup/RebookingRadioGroup.d.ts +17 -0
- package/dist/components/RebookingRadioGroup/RebookingRadioGroup.js +13 -0
- package/dist/components/RebookingRadioGroup/index.d.ts +3 -0
- package/dist/components/RebookingRadioGroup/index.js +1 -0
- package/dist/components/ScrollableRow/ScrollableRow.d.ts +21 -0
- package/dist/components/ScrollableRow/ScrollableRow.js +155 -0
- package/dist/components/ScrollableRow/index.d.ts +3 -0
- package/dist/components/ScrollableRow/index.js +2 -0
- package/dist/components/Share/Share.d.ts +22 -0
- package/dist/components/Share/Share.js +24 -0
- package/dist/components/Share/index.d.ts +3 -0
- package/dist/components/Share/index.js +1 -0
- package/dist/components/ShowMoreButton/ShowMoreButton.d.ts +11 -0
- package/dist/components/ShowMoreButton/ShowMoreButton.js +7 -0
- package/dist/components/ShowMoreButton/index.d.ts +3 -0
- package/dist/components/ShowMoreButton/index.js +1 -0
- package/dist/components/SidebarActions/SidebarActions.d.ts +26 -0
- package/dist/components/SidebarActions/SidebarActions.js +32 -0
- package/dist/components/SidebarActions/index.d.ts +3 -0
- package/dist/components/SidebarActions/index.js +2 -0
- package/dist/components/SimpleRow/SimpleRow.d.ts +15 -0
- package/dist/components/SimpleRow/SimpleRow.js +11 -0
- package/dist/components/SimpleRow/index.d.ts +3 -0
- package/dist/components/SimpleRow/index.js +2 -0
- package/dist/components/Spinner/Spinner.d.ts +9 -0
- package/dist/components/Spinner/Spinner.js +8 -0
- package/dist/components/Spinner/index.d.ts +3 -0
- package/dist/components/Spinner/index.js +1 -0
- package/dist/components/ToggleButton/ToggleButton.d.ts +17 -0
- package/dist/components/ToggleButton/ToggleButton.js +8 -0
- package/dist/components/ToggleButton/index.d.ts +3 -0
- package/dist/components/ToggleButton/index.js +1 -0
- package/dist/components/ToggleSwitch/ToggleSwitch.d.ts +12 -0
- package/dist/components/ToggleSwitch/ToggleSwitch.js +10 -0
- package/dist/components/ToggleSwitch/index.d.ts +3 -0
- package/dist/components/ToggleSwitch/index.js +1 -0
- package/dist/components/TouchHand/TouchHand.d.ts +5 -0
- package/dist/components/TouchHand/TouchHand.js +7 -0
- package/dist/components/TouchHand/index.d.ts +2 -0
- package/dist/components/TouchHand/index.js +1 -0
- package/dist/components/WayfindingFloorSelector/WayfindingFloorSelector.d.ts +24 -0
- package/dist/components/WayfindingFloorSelector/WayfindingFloorSelector.js +27 -0
- package/dist/components/WayfindingFloorSelector/index.d.ts +3 -0
- package/dist/components/WayfindingFloorSelector/index.js +1 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +69 -0
- package/dist/shared/debounce.d.ts +2 -0
- package/dist/shared/debounce.js +9 -0
- package/dist/shared/hooks/useDragGesture.d.ts +19 -0
- package/dist/shared/hooks/useDragGesture.js +45 -0
- package/dist/shared/hooks/useOnClickOutside.d.ts +14 -0
- package/dist/shared/hooks/useOnClickOutside.js +43 -0
- package/dist/shared/hooks/useOnEscape.d.ts +14 -0
- package/dist/shared/hooks/useOnEscape.js +31 -0
- package/dist/shared/hooks/useWindowSize.d.ts +5 -0
- package/dist/shared/hooks/useWindowSize.js +40 -0
- package/dist/shared/interactive.d.ts +2 -0
- package/dist/shared/interactive.js +4 -0
- 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,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,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,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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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;
|