@chayns-components/core 5.0.0-beta.1180 → 5.0.0-beta.1182

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.
@@ -26,8 +26,12 @@ const DropdownBodyWrapper = ({
26
26
  minBodyWidth = 0,
27
27
  bodyWidth
28
28
  }) => {
29
+ const isInChaynsWalletRef = (0, _react.useRef)(false);
30
+ const [measuredContentHeight, setMeasuredContentHeight] = (0, _react.useState)(0);
29
31
  const [portal, setPortal] = (0, _react.useState)();
30
32
  const ref = (0, _react.useRef)(null);
33
+ const shouldPreventClickRef = (0, _react.useRef)(false);
34
+ const touchTimeoutRef = (0, _react.useRef)(undefined);
31
35
  const container = (0, _container.useContainer)({
32
36
  anchorElement,
33
37
  container: containerProp
@@ -53,24 +57,76 @@ const DropdownBodyWrapper = ({
53
57
  /**
54
58
  * This function closes the body
55
59
  */
56
- const handleOutsideClick = (0, _react.useCallback)(event => {
57
- if (!anchorElement.contains(event.target) && ref.current && !ref.current.contains(event.target)) {
60
+ const handleClick = (0, _react.useCallback)(event => {
61
+ if (!shouldPreventClickRef.current && !anchorElement.contains(event.target) && ref.current && !ref.current.contains(event.target)) {
58
62
  handleClose();
59
63
  }
64
+ shouldPreventClickRef.current = false;
60
65
  }, [anchorElement, handleClose]);
66
+ const handleContentMeasure = (0, _react.useCallback)(measurements => {
67
+ // Measurements are only needed if the content is shown in the chayns wallet. To prevent
68
+ // unnecessary renders, we only set the height if the content is shown in the wallet.
69
+ if (isInChaynsWalletRef.current) {
70
+ setMeasuredContentHeight(measurements.height);
71
+ }
72
+ if (typeof onMeasure === 'function') {
73
+ onMeasure(measurements);
74
+ }
75
+ }, [onMeasure]);
76
+ const handleTouchEnd = (0, _react.useCallback)(() => {
77
+ clearTimeout(touchTimeoutRef.current);
78
+ }, []);
79
+ const handleTouchStart = (0, _react.useCallback)(() => {
80
+ touchTimeoutRef.current = window.setTimeout(() => {
81
+ shouldPreventClickRef.current = true;
82
+ }, 500);
83
+ }, []);
61
84
 
62
85
  /**
63
86
  * This hook listens for clicks
64
87
  */
65
88
  (0, _dropdown2.useDropdownListener)({
66
- onOutsideClick: handleOutsideClick,
67
- onClose: handleClose
89
+ onClick: handleClick,
90
+ onClose: handleClose,
91
+ onTouchEnd: handleTouchEnd,
92
+ onTouchStart: handleTouchStart
68
93
  });
94
+ (0, _react.useEffect)(() => {
95
+ const isBottomDirection = [_dropdown.DropdownDirection.BOTTOM, _dropdown.DropdownDirection.BOTTOM_LEFT, _dropdown.DropdownDirection.BOTTOM_RIGHT].includes(direction);
96
+ const reservationWrapperElement = document.querySelector(_container.ContainerAnchor.RESERVATION_WRAPPER);
97
+ isInChaynsWalletRef.current = !!(reservationWrapperElement && reservationWrapperElement.contains(anchorElement)) || true;
98
+
99
+ // This effect checks if additional space is needed to show dropdown content in chayns cards.
100
+ if (isBottomDirection && isInChaynsWalletRef.current && measuredContentHeight > 0 && reservationWrapperElement && shouldShowDropdown) {
101
+ const availableHeight = window.innerHeight - anchorElement.getBoundingClientRect().bottom;
102
+
103
+ // If the content height is greater than the available height, we need to add additional space.
104
+ // This is to ensure that the dropdown content is fully visible. The 16 pixels are a buffer for shadows.
105
+ const additionalNeededSpace = measuredContentHeight + 16 - availableHeight;
106
+ if (additionalNeededSpace > 0) {
107
+ // Add margin bottom to the reservation wrapper to ensure the dropdown content is fully visible.
108
+ reservationWrapperElement.style.marginBottom = `${additionalNeededSpace}px`;
109
+ } else {
110
+ // Reset the margin bottom if no additional space is needed.
111
+ reservationWrapperElement.style.marginBottom = '0px';
112
+ }
113
+ }
114
+ if (isInChaynsWalletRef.current && reservationWrapperElement && !shouldShowDropdown) {
115
+ // Reset the margin bottom when the dropdown is closed.
116
+ reservationWrapperElement.style.marginBottom = '0px';
117
+ }
118
+ return () => {
119
+ if (reservationWrapperElement) {
120
+ reservationWrapperElement.style.marginBottom = '0px';
121
+ }
122
+ };
123
+ }, [anchorElement, direction, measuredContentHeight, shouldShowDropdown]);
69
124
  (0, _react.useEffect)(() => {
70
125
  if (!container) return;
71
126
  setPortal(() => /*#__PURE__*/(0, _reactDom.createPortal)(/*#__PURE__*/_react.default.createElement(_DelayedDropdownContent.default, {
72
- shouldShowContent: shouldShowDropdown,
73
127
  coordinates: coordinates,
128
+ onMeasure: handleContentMeasure,
129
+ shouldShowContent: shouldShowDropdown,
74
130
  transform: transform
75
131
  }, /*#__PURE__*/_react.default.createElement(_DropdownBodyWrapper.StyledDropdownBodyWrapperContent, {
76
132
  $width: width,
@@ -79,7 +135,7 @@ const DropdownBodyWrapper = ({
79
135
  $direction: direction,
80
136
  ref: ref
81
137
  }, children)), container));
82
- }, [direction, children, container, coordinates, maxHeight, shouldShowDropdown, width, minBodyWidth, transform, onMeasure]);
138
+ }, [children, container, coordinates, direction, handleContentMeasure, maxHeight, minBodyWidth, shouldShowDropdown, transform, width]);
83
139
  return /*#__PURE__*/_react.default.createElement(_DropdownBodyWrapper.StyledDropdownBodyWrapper, null, portal);
84
140
  };
85
141
  DropdownBodyWrapper.displayName = 'DropdownBodyWrapper';
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownBodyWrapper.js","names":["_react","_interopRequireWildcard","require","_DropdownBodyWrapper","_reactDom","_dropdown","_DelayedDropdownContent","_interopRequireDefault","_dropdown2","_container","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","DropdownBodyWrapper","direction","DropdownDirection","BOTTOM_RIGHT","children","container","containerProp","shouldShowDropdown","anchorElement","contentHeight","maxHeight","onClose","onMeasure","minBodyWidth","bodyWidth","portal","setPortal","useState","ref","useRef","useContainer","transform","width","coordinates","useDropdown","handleClose","useCallback","handleOutsideClick","event","contains","target","current","useDropdownListener","onOutsideClick","useEffect","createPortal","createElement","shouldShowContent","StyledDropdownBodyWrapperContent","$width","$minWidth","$maxHeight","$direction","StyledDropdownBodyWrapper","displayName","_default","exports"],"sources":["../../../../src/components/dropdown-body-wrapper/DropdownBodyWrapper.tsx"],"sourcesContent":["import React, { FC, ReactNode, ReactPortal, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n StyledDropdownBodyWrapper,\n StyledDropdownBodyWrapperContent,\n} from './DropdownBodyWrapper.styles';\nimport { createPortal } from 'react-dom';\nimport { DropdownDirection } from '../../types/dropdown';\nimport DelayedDropdownContent, {\n DelayedDropdownContentProps,\n} from './delayed-dropdown-content/DelayedDropdownContent';\nimport { useDropdown, useDropdownListener } from '../../hooks/dropdown';\nimport { useContainer } from '../../hooks/container';\n\ninterface DropdownBodyWrapperProps {\n /**\n * The anchor element of the dropdown.\n */\n anchorElement: Element;\n /**\n * The width of the Body.\n */\n bodyWidth?: number;\n /**\n * The content of the dropdown body.\n */\n children: ReactNode;\n /**\n * The element where the content should be rendered via React Portal.\n */\n container?: Element;\n /**\n * The height of the content\n */\n contentHeight?: number;\n /**\n * The direction of the dropdown.\n */\n direction?: DropdownDirection;\n /**\n * The max height of the dropdown.\n */\n maxHeight?: number;\n /**\n * The minimum width of the body.\n */\n minBodyWidth?: number;\n /**\n * Function to be executed when the body is closed.\n */\n onClose?: VoidFunction;\n /**\n * Function to be executed when the content is measured.\n */\n onMeasure?: DelayedDropdownContentProps['onMeasure'];\n /**\n * Whether the dropdown should be visible.\n */\n shouldShowDropdown: boolean;\n}\n\nconst DropdownBodyWrapper: FC<DropdownBodyWrapperProps> = ({\n direction = DropdownDirection.BOTTOM_RIGHT,\n children,\n container: containerProp,\n shouldShowDropdown,\n anchorElement,\n contentHeight = 0,\n maxHeight = 300,\n onClose,\n onMeasure,\n minBodyWidth = 0,\n bodyWidth,\n}) => {\n const [portal, setPortal] = useState<ReactPortal>();\n\n const ref = useRef<HTMLDivElement>(null);\n\n const container = useContainer({ anchorElement, container: containerProp });\n\n const { transform, width, coordinates } = useDropdown({\n direction,\n bodyWidth,\n contentHeight,\n container,\n anchorElement,\n shouldShowDropdown,\n });\n\n const handleClose = useCallback(() => {\n if (typeof onClose === 'function') {\n onClose();\n }\n }, [onClose]);\n\n /**\n * This function closes the body\n */\n const handleOutsideClick = useCallback(\n (event: MouseEvent) => {\n if (\n !anchorElement.contains(event.target as Node) &&\n ref.current &&\n !ref.current.contains(event.target as Node)\n ) {\n handleClose();\n }\n },\n [anchorElement, handleClose],\n );\n\n /**\n * This hook listens for clicks\n */\n useDropdownListener({\n onOutsideClick: handleOutsideClick,\n onClose: handleClose,\n });\n\n useEffect(() => {\n if (!container) return;\n\n setPortal(() =>\n createPortal(\n <DelayedDropdownContent\n shouldShowContent={shouldShowDropdown}\n coordinates={coordinates}\n transform={transform}\n >\n <StyledDropdownBodyWrapperContent\n $width={width}\n $minWidth={minBodyWidth}\n $maxHeight={maxHeight}\n $direction={direction}\n ref={ref}\n >\n {children}\n </StyledDropdownBodyWrapperContent>\n </DelayedDropdownContent>,\n container,\n ),\n );\n }, [\n direction,\n children,\n container,\n coordinates,\n maxHeight,\n shouldShowDropdown,\n width,\n minBodyWidth,\n transform,\n onMeasure,\n ]);\n\n return <StyledDropdownBodyWrapper>{portal}</StyledDropdownBodyWrapper>;\n};\n\nDropdownBodyWrapper.displayName = 'DropdownBodyWrapper';\n\nexport default DropdownBodyWrapper;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"DropdownBodyWrapper.js","names":["_react","_interopRequireWildcard","require","_DropdownBodyWrapper","_reactDom","_dropdown","_DelayedDropdownContent","_interopRequireDefault","_dropdown2","_container","e","__esModule","default","t","WeakMap","r","n","o","i","f","__proto__","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","DropdownBodyWrapper","direction","DropdownDirection","BOTTOM_RIGHT","children","container","containerProp","shouldShowDropdown","anchorElement","contentHeight","maxHeight","onClose","onMeasure","minBodyWidth","bodyWidth","isInChaynsWalletRef","useRef","measuredContentHeight","setMeasuredContentHeight","useState","portal","setPortal","ref","shouldPreventClickRef","touchTimeoutRef","undefined","useContainer","transform","width","coordinates","useDropdown","handleClose","useCallback","handleClick","event","current","contains","target","handleContentMeasure","measurements","height","handleTouchEnd","clearTimeout","handleTouchStart","window","setTimeout","useDropdownListener","onClick","onTouchEnd","onTouchStart","useEffect","isBottomDirection","BOTTOM","BOTTOM_LEFT","includes","reservationWrapperElement","document","querySelector","ContainerAnchor","RESERVATION_WRAPPER","availableHeight","innerHeight","getBoundingClientRect","bottom","additionalNeededSpace","style","marginBottom","createPortal","createElement","shouldShowContent","StyledDropdownBodyWrapperContent","$width","$minWidth","$maxHeight","$direction","StyledDropdownBodyWrapper","displayName","_default","exports"],"sources":["../../../../src/components/dropdown-body-wrapper/DropdownBodyWrapper.tsx"],"sourcesContent":["import React, { FC, ReactNode, ReactPortal, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n StyledDropdownBodyWrapper,\n StyledDropdownBodyWrapperContent,\n} from './DropdownBodyWrapper.styles';\nimport { createPortal } from 'react-dom';\nimport { DropdownDirection, DropdownMeasurements } from '../../types/dropdown';\nimport DelayedDropdownContent, {\n DelayedDropdownContentProps,\n} from './delayed-dropdown-content/DelayedDropdownContent';\nimport { useDropdown, useDropdownListener } from '../../hooks/dropdown';\nimport { ContainerAnchor, useContainer } from '../../hooks/container';\n\ninterface DropdownBodyWrapperProps {\n /**\n * The anchor element of the dropdown.\n */\n anchorElement: Element;\n /**\n * The width of the Body.\n */\n bodyWidth?: number;\n /**\n * The content of the dropdown body.\n */\n children: ReactNode;\n /**\n * The element where the content should be rendered via React Portal.\n */\n container?: Element;\n /**\n * The height of the content\n */\n contentHeight?: number;\n /**\n * The direction of the dropdown.\n */\n direction?: DropdownDirection;\n /**\n * The max height of the dropdown.\n */\n maxHeight?: number;\n /**\n * The minimum width of the body.\n */\n minBodyWidth?: number;\n /**\n * Function to be executed when the body is closed.\n */\n onClose?: VoidFunction;\n /**\n * Function to be executed when the content is measured.\n */\n onMeasure?: DelayedDropdownContentProps['onMeasure'];\n /**\n * Whether the dropdown should be visible.\n */\n shouldShowDropdown: boolean;\n}\n\nconst DropdownBodyWrapper: FC<DropdownBodyWrapperProps> = ({\n direction = DropdownDirection.BOTTOM_RIGHT,\n children,\n container: containerProp,\n shouldShowDropdown,\n anchorElement,\n contentHeight = 0,\n maxHeight = 300,\n onClose,\n onMeasure,\n minBodyWidth = 0,\n bodyWidth,\n}) => {\n const isInChaynsWalletRef = useRef(false);\n\n const [measuredContentHeight, setMeasuredContentHeight] = useState<number>(0);\n const [portal, setPortal] = useState<ReactPortal>();\n\n const ref = useRef<HTMLDivElement>(null);\n const shouldPreventClickRef = useRef<boolean>(false);\n const touchTimeoutRef = useRef<number | undefined>(undefined);\n\n const container = useContainer({ anchorElement, container: containerProp });\n\n const { transform, width, coordinates } = useDropdown({\n direction,\n bodyWidth,\n contentHeight,\n container,\n anchorElement,\n shouldShowDropdown,\n });\n\n const handleClose = useCallback(() => {\n if (typeof onClose === 'function') {\n onClose();\n }\n }, [onClose]);\n\n /**\n * This function closes the body\n */\n const handleClick = useCallback(\n (event: MouseEvent) => {\n if (\n !shouldPreventClickRef.current &&\n !anchorElement.contains(event.target as Node) &&\n ref.current &&\n !ref.current.contains(event.target as Node)\n ) {\n handleClose();\n }\n\n shouldPreventClickRef.current = false;\n },\n [anchorElement, handleClose],\n );\n\n const handleContentMeasure = useCallback(\n (measurements: DropdownMeasurements) => {\n // Measurements are only needed if the content is shown in the chayns wallet. To prevent\n // unnecessary renders, we only set the height if the content is shown in the wallet.\n if (isInChaynsWalletRef.current) {\n setMeasuredContentHeight(measurements.height);\n }\n\n if (typeof onMeasure === 'function') {\n onMeasure(measurements);\n }\n },\n [onMeasure],\n );\n\n const handleTouchEnd = useCallback(() => {\n clearTimeout(touchTimeoutRef.current);\n }, []);\n\n const handleTouchStart = useCallback(() => {\n touchTimeoutRef.current = window.setTimeout(() => {\n shouldPreventClickRef.current = true;\n }, 500);\n }, []);\n\n /**\n * This hook listens for clicks\n */\n useDropdownListener({\n onClick: handleClick,\n onClose: handleClose,\n onTouchEnd: handleTouchEnd,\n onTouchStart: handleTouchStart,\n });\n\n useEffect(() => {\n const isBottomDirection = [\n DropdownDirection.BOTTOM,\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.BOTTOM_RIGHT,\n ].includes(direction);\n\n const reservationWrapperElement = document.querySelector<HTMLDivElement>(\n ContainerAnchor.RESERVATION_WRAPPER,\n );\n\n isInChaynsWalletRef.current =\n !!(reservationWrapperElement && reservationWrapperElement.contains(anchorElement)) ||\n true;\n\n // This effect checks if additional space is needed to show dropdown content in chayns cards.\n if (\n isBottomDirection &&\n isInChaynsWalletRef.current &&\n measuredContentHeight > 0 &&\n reservationWrapperElement &&\n shouldShowDropdown\n ) {\n const availableHeight =\n window.innerHeight - anchorElement.getBoundingClientRect().bottom;\n\n // If the content height is greater than the available height, we need to add additional space.\n // This is to ensure that the dropdown content is fully visible. The 16 pixels are a buffer for shadows.\n const additionalNeededSpace = measuredContentHeight + 16 - availableHeight;\n\n if (additionalNeededSpace > 0) {\n // Add margin bottom to the reservation wrapper to ensure the dropdown content is fully visible.\n reservationWrapperElement.style.marginBottom = `${additionalNeededSpace}px`;\n } else {\n // Reset the margin bottom if no additional space is needed.\n reservationWrapperElement.style.marginBottom = '0px';\n }\n }\n\n if (isInChaynsWalletRef.current && reservationWrapperElement && !shouldShowDropdown) {\n // Reset the margin bottom when the dropdown is closed.\n reservationWrapperElement.style.marginBottom = '0px';\n }\n\n return () => {\n if (reservationWrapperElement) {\n reservationWrapperElement.style.marginBottom = '0px';\n }\n };\n }, [anchorElement, direction, measuredContentHeight, shouldShowDropdown]);\n\n useEffect(() => {\n if (!container) return;\n\n setPortal(() =>\n createPortal(\n <DelayedDropdownContent\n coordinates={coordinates}\n onMeasure={handleContentMeasure}\n shouldShowContent={shouldShowDropdown}\n transform={transform}\n >\n <StyledDropdownBodyWrapperContent\n $width={width}\n $minWidth={minBodyWidth}\n $maxHeight={maxHeight}\n $direction={direction}\n ref={ref}\n >\n {children}\n </StyledDropdownBodyWrapperContent>\n </DelayedDropdownContent>,\n container,\n ),\n );\n }, [\n children,\n container,\n coordinates,\n direction,\n handleContentMeasure,\n maxHeight,\n minBodyWidth,\n shouldShowDropdown,\n transform,\n width,\n ]);\n\n return <StyledDropdownBodyWrapper>{portal}</StyledDropdownBodyWrapper>;\n};\n\nDropdownBodyWrapper.displayName = 'DropdownBodyWrapper';\n\nexport default DropdownBodyWrapper;\n"],"mappings":"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","ignoreList":[]}
@@ -8,17 +8,23 @@ var _react = require("react");
8
8
  var _dropdown = require("../types/dropdown");
9
9
  const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? _react.useLayoutEffect : _react.useEffect;
10
10
  const useDropdownListener = ({
11
+ onClick,
11
12
  onClose,
12
- onOutsideClick
13
+ onTouchEnd,
14
+ onTouchStart
13
15
  }) => {
14
16
  (0, _react.useEffect)(() => {
15
- document.addEventListener('click', onOutsideClick);
17
+ document.addEventListener('click', onClick);
18
+ document.addEventListener('touchend', onTouchEnd);
19
+ document.addEventListener('touchstart', onTouchStart);
16
20
  window.addEventListener('blur', () => onClose());
17
21
  return () => {
18
- document.removeEventListener('click', onOutsideClick);
22
+ document.removeEventListener('click', onClick);
23
+ document.removeEventListener('touchend', onTouchEnd);
24
+ document.removeEventListener('touchstart', onTouchStart);
19
25
  window.addEventListener('blur', () => onClose());
20
26
  };
21
- }, [onOutsideClick, onClose]);
27
+ }, [onClick, onClose, onTouchEnd, onTouchStart]);
22
28
  };
23
29
  exports.useDropdownListener = useDropdownListener;
24
30
  const useDropdownAlignment = ({
@@ -92,12 +98,16 @@ const useDropdownPosition = ({
92
98
  }
93
99
  }, [anchorElement, container, contentHeight, direction]);
94
100
  useIsomorphicLayoutEffect(() => {
95
- calculateCoordinates();
101
+ const handleResize = () => {
102
+ calculateCoordinates();
103
+ setTimeout(calculateCoordinates, 300);
104
+ };
105
+ handleResize();
96
106
  if (shouldShowDropdown) {
97
- window.addEventListener('resize', calculateCoordinates);
107
+ window.addEventListener('resize', handleResize);
98
108
  }
99
109
  return () => {
100
- window.removeEventListener('resize', calculateCoordinates);
110
+ window.removeEventListener('resize', handleResize);
101
111
  };
102
112
  }, [calculateCoordinates, shouldShowDropdown]);
103
113
  return (0, _react.useMemo)(() => ({
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.js","names":["_react","require","_dropdown","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","useDropdownListener","onClose","onOutsideClick","document","addEventListener","removeEventListener","exports","useDropdownAlignment","direction","shouldUseTopAlignment","anchorElement","bodyWidth","translateX","setTranslateX","useState","translateY","setTranslateY","DropdownDirection","BOTTOM_LEFT","TOP_LEFT","LEFT","includes","difference","clientWidth","useTopAlignment","TOP","TOP_RIGHT","useMemo","x","y","useDropdownPosition","container","contentHeight","shouldShowDropdown","coordinates","setCoordinates","setShouldUseTopAlignment","calculateCoordinates","useCallback","left","anchorLeft","top","anchorTop","height","anchorHeight","getBoundingClientRect","scrollLeft","scrollTop","hasBottomAlignment","BOTTOM","BOTTOM_RIGHT","useDropdown","transform","width"],"sources":["../../../src/hooks/dropdown.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { DropdownCoordinates, DropdownDirection } from '../types/dropdown';\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\ninterface UseDropdownListenerOptions {\n onClose: () => void;\n onOutsideClick: (event: MouseEvent) => void;\n}\n\nexport const useDropdownListener = ({ onClose, onOutsideClick }: UseDropdownListenerOptions) => {\n useEffect(() => {\n document.addEventListener('click', onOutsideClick);\n window.addEventListener('blur', () => onClose());\n\n return () => {\n document.removeEventListener('click', onOutsideClick);\n window.addEventListener('blur', () => onClose());\n };\n }, [onOutsideClick, onClose]);\n};\n\ninterface UseDropdownAlignmentOptions {\n direction: DropdownDirection;\n shouldUseTopAlignment: boolean;\n bodyWidth?: number;\n anchorElement: Element;\n}\n\nexport const useDropdownAlignment = ({\n direction,\n shouldUseTopAlignment,\n anchorElement,\n bodyWidth,\n}: UseDropdownAlignmentOptions) => {\n const [translateX, setTranslateX] = useState<string>('0px');\n const [translateY, setTranslateY] = useState<string>('0px');\n\n useEffect(() => {\n if (\n [\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.LEFT,\n ].includes(direction) &&\n typeof bodyWidth === 'number'\n ) {\n const difference = anchorElement.clientWidth - bodyWidth;\n\n setTranslateX(`${difference}px`);\n } else {\n setTranslateX('0px');\n }\n }, [anchorElement.clientWidth, bodyWidth, direction]);\n\n useEffect(() => {\n const useTopAlignment =\n shouldUseTopAlignment ||\n [\n DropdownDirection.TOP,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.TOP_RIGHT,\n ].includes(direction);\n\n if (useTopAlignment) {\n setTranslateY('-100%');\n } else {\n setTranslateY('0px');\n }\n }, [direction, shouldUseTopAlignment]);\n\n return useMemo(() => ({ x: translateX, y: translateY }), [translateX, translateY]);\n};\n\ninterface UseDropdownPositionOptions {\n anchorElement: Element;\n container?: Element;\n contentHeight?: number;\n direction: DropdownDirection;\n shouldShowDropdown: boolean;\n}\n\nexport const useDropdownPosition = ({\n anchorElement,\n container,\n contentHeight = 0,\n direction,\n shouldShowDropdown,\n}: UseDropdownPositionOptions) => {\n const [coordinates, setCoordinates] = useState<DropdownCoordinates>({ x: 0, y: 0 });\n const [shouldUseTopAlignment, setShouldUseTopAlignment] = useState(false);\n\n const calculateCoordinates = useCallback(() => {\n if (container) {\n const {\n left: anchorLeft,\n top: anchorTop,\n height: anchorHeight,\n } = anchorElement.getBoundingClientRect();\n\n const { left, top, height } = container.getBoundingClientRect();\n\n const x = anchorLeft - left + container.scrollLeft;\n const y = anchorTop - top + container.scrollTop;\n\n let useTopAlignment = [\n DropdownDirection.TOP,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.TOP_RIGHT,\n ].includes(direction);\n\n const hasBottomAlignment = [\n DropdownDirection.BOTTOM,\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.BOTTOM_RIGHT,\n ].includes(direction);\n\n if (!hasBottomAlignment && y + anchorHeight + contentHeight > height) {\n useTopAlignment = true;\n\n setShouldUseTopAlignment(true);\n } else {\n setShouldUseTopAlignment(false);\n }\n\n setCoordinates({ x, y: useTopAlignment ? y : y + anchorHeight });\n }\n }, [anchorElement, container, contentHeight, direction]);\n\n useIsomorphicLayoutEffect(() => {\n calculateCoordinates();\n\n if (shouldShowDropdown) {\n window.addEventListener('resize', calculateCoordinates);\n }\n\n return () => {\n window.removeEventListener('resize', calculateCoordinates);\n };\n }, [calculateCoordinates, shouldShowDropdown]);\n\n return useMemo(\n () => ({ shouldUseTopAlignment, coordinates }),\n [coordinates, shouldUseTopAlignment],\n );\n};\n\ninterface UseDropdownOptions {\n anchorElement: Element;\n bodyWidth?: number;\n container?: Element;\n contentHeight?: number;\n direction: DropdownDirection;\n shouldShowDropdown: boolean;\n}\n\nexport const useDropdown = ({\n anchorElement,\n bodyWidth,\n container,\n contentHeight,\n direction,\n shouldShowDropdown,\n}: UseDropdownOptions) => {\n const { shouldUseTopAlignment, coordinates } = useDropdownPosition({\n anchorElement,\n container,\n contentHeight,\n direction,\n shouldShowDropdown,\n });\n\n const transform = useDropdownAlignment({\n shouldUseTopAlignment,\n bodyWidth,\n anchorElement,\n direction,\n });\n\n const width = useMemo(() => anchorElement.clientWidth, [anchorElement]);\n\n return useMemo(() => ({ coordinates, transform, width }), [coordinates, transform, width]);\n};\n"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,OAAA;AACA,IAAAC,SAAA,GAAAD,OAAA;AAEA,MAAME,yBAAyB,GAAG,OAAOC,MAAM,KAAK,WAAW,GAAGC,sBAAe,GAAGC,gBAAS;AAOtF,MAAMC,mBAAmB,GAAGA,CAAC;EAAEC,OAAO;EAAEC;AAA2C,CAAC,KAAK;EAC5F,IAAAH,gBAAS,EAAC,MAAM;IACZI,QAAQ,CAACC,gBAAgB,CAAC,OAAO,EAAEF,cAAc,CAAC;IAClDL,MAAM,CAACO,gBAAgB,CAAC,MAAM,EAAE,MAAMH,OAAO,CAAC,CAAC,CAAC;IAEhD,OAAO,MAAM;MACTE,QAAQ,CAACE,mBAAmB,CAAC,OAAO,EAAEH,cAAc,CAAC;MACrDL,MAAM,CAACO,gBAAgB,CAAC,MAAM,EAAE,MAAMH,OAAO,CAAC,CAAC,CAAC;IACpD,CAAC;EACL,CAAC,EAAE,CAACC,cAAc,EAAED,OAAO,CAAC,CAAC;AACjC,CAAC;AAACK,OAAA,CAAAN,mBAAA,GAAAA,mBAAA;AASK,MAAMO,oBAAoB,GAAGA,CAAC;EACjCC,SAAS;EACTC,qBAAqB;EACrBC,aAAa;EACbC;AACyB,CAAC,KAAK;EAC/B,MAAM,CAACC,UAAU,EAAEC,aAAa,CAAC,GAAG,IAAAC,eAAQ,EAAS,KAAK,CAAC;EAC3D,MAAM,CAACC,UAAU,EAAEC,aAAa,CAAC,GAAG,IAAAF,eAAQ,EAAS,KAAK,CAAC;EAE3D,IAAAf,gBAAS,EAAC,MAAM;IACZ,IACI,CACIkB,2BAAiB,CAACC,WAAW,EAC7BD,2BAAiB,CAACE,QAAQ,EAC1BF,2BAAiB,CAACG,IAAI,CACzB,CAACC,QAAQ,CAACb,SAAS,CAAC,IACrB,OAAOG,SAAS,KAAK,QAAQ,EAC/B;MACE,MAAMW,UAAU,GAAGZ,aAAa,CAACa,WAAW,GAAGZ,SAAS;MAExDE,aAAa,CAAC,GAAGS,UAAU,IAAI,CAAC;IACpC,CAAC,MAAM;MACHT,aAAa,CAAC,KAAK,CAAC;IACxB;EACJ,CAAC,EAAE,CAACH,aAAa,CAACa,WAAW,EAAEZ,SAAS,EAAEH,SAAS,CAAC,CAAC;EAErD,IAAAT,gBAAS,EAAC,MAAM;IACZ,MAAMyB,eAAe,GACjBf,qBAAqB,IACrB,CACIQ,2BAAiB,CAACQ,GAAG,EACrBR,2BAAiB,CAACE,QAAQ,EAC1BF,2BAAiB,CAACS,SAAS,CAC9B,CAACL,QAAQ,CAACb,SAAS,CAAC;IAEzB,IAAIgB,eAAe,EAAE;MACjBR,aAAa,CAAC,OAAO,CAAC;IAC1B,CAAC,MAAM;MACHA,aAAa,CAAC,KAAK,CAAC;IACxB;EACJ,CAAC,EAAE,CAACR,SAAS,EAAEC,qBAAqB,CAAC,CAAC;EAEtC,OAAO,IAAAkB,cAAO,EAAC,OAAO;IAAEC,CAAC,EAAEhB,UAAU;IAAEiB,CAAC,EAAEd;EAAW,CAAC,CAAC,EAAE,CAACH,UAAU,EAAEG,UAAU,CAAC,CAAC;AACtF,CAAC;AAACT,OAAA,CAAAC,oBAAA,GAAAA,oBAAA;AAUK,MAAMuB,mBAAmB,GAAGA,CAAC;EAChCpB,aAAa;EACbqB,SAAS;EACTC,aAAa,GAAG,CAAC;EACjBxB,SAAS;EACTyB;AACwB,CAAC,KAAK;EAC9B,MAAM,CAACC,WAAW,EAAEC,cAAc,CAAC,GAAG,IAAArB,eAAQ,EAAsB;IAAEc,CAAC,EAAE,CAAC;IAAEC,CAAC,EAAE;EAAE,CAAC,CAAC;EACnF,MAAM,CAACpB,qBAAqB,EAAE2B,wBAAwB,CAAC,GAAG,IAAAtB,eAAQ,EAAC,KAAK,CAAC;EAEzE,MAAMuB,oBAAoB,GAAG,IAAAC,kBAAW,EAAC,MAAM;IAC3C,IAAIP,SAAS,EAAE;MACX,MAAM;QACFQ,IAAI,EAAEC,UAAU;QAChBC,GAAG,EAAEC,SAAS;QACdC,MAAM,EAAEC;MACZ,CAAC,GAAGlC,aAAa,CAACmC,qBAAqB,CAAC,CAAC;MAEzC,MAAM;QAAEN,IAAI;QAAEE,GAAG;QAAEE;MAAO,CAAC,GAAGZ,SAAS,CAACc,qBAAqB,CAAC,CAAC;MAE/D,MAAMjB,CAAC,GAAGY,UAAU,GAAGD,IAAI,GAAGR,SAAS,CAACe,UAAU;MAClD,MAAMjB,CAAC,GAAGa,SAAS,GAAGD,GAAG,GAAGV,SAAS,CAACgB,SAAS;MAE/C,IAAIvB,eAAe,GAAG,CAClBP,2BAAiB,CAACQ,GAAG,EACrBR,2BAAiB,CAACE,QAAQ,EAC1BF,2BAAiB,CAACS,SAAS,CAC9B,CAACL,QAAQ,CAACb,SAAS,CAAC;MAErB,MAAMwC,kBAAkB,GAAG,CACvB/B,2BAAiB,CAACgC,MAAM,EACxBhC,2BAAiB,CAACC,WAAW,EAC7BD,2BAAiB,CAACiC,YAAY,CACjC,CAAC7B,QAAQ,CAACb,SAAS,CAAC;MAErB,IAAI,CAACwC,kBAAkB,IAAInB,CAAC,GAAGe,YAAY,GAAGZ,aAAa,GAAGW,MAAM,EAAE;QAClEnB,eAAe,GAAG,IAAI;QAEtBY,wBAAwB,CAAC,IAAI,CAAC;MAClC,CAAC,MAAM;QACHA,wBAAwB,CAAC,KAAK,CAAC;MACnC;MAEAD,cAAc,CAAC;QAAEP,CAAC;QAAEC,CAAC,EAAEL,eAAe,GAAGK,CAAC,GAAGA,CAAC,GAAGe;MAAa,CAAC,CAAC;IACpE;EACJ,CAAC,EAAE,CAAClC,aAAa,EAAEqB,SAAS,EAAEC,aAAa,EAAExB,SAAS,CAAC,CAAC;EAExDZ,yBAAyB,CAAC,MAAM;IAC5ByC,oBAAoB,CAAC,CAAC;IAEtB,IAAIJ,kBAAkB,EAAE;MACpBpC,MAAM,CAACO,gBAAgB,CAAC,QAAQ,EAAEiC,oBAAoB,CAAC;IAC3D;IAEA,OAAO,MAAM;MACTxC,MAAM,CAACQ,mBAAmB,CAAC,QAAQ,EAAEgC,oBAAoB,CAAC;IAC9D,CAAC;EACL,CAAC,EAAE,CAACA,oBAAoB,EAAEJ,kBAAkB,CAAC,CAAC;EAE9C,OAAO,IAAAN,cAAO,EACV,OAAO;IAAElB,qBAAqB;IAAEyB;EAAY,CAAC,CAAC,EAC9C,CAACA,WAAW,EAAEzB,qBAAqB,CACvC,CAAC;AACL,CAAC;AAACH,OAAA,CAAAwB,mBAAA,GAAAA,mBAAA;AAWK,MAAMqB,WAAW,GAAGA,CAAC;EACxBzC,aAAa;EACbC,SAAS;EACToB,SAAS;EACTC,aAAa;EACbxB,SAAS;EACTyB;AACgB,CAAC,KAAK;EACtB,MAAM;IAAExB,qBAAqB;IAAEyB;EAAY,CAAC,GAAGJ,mBAAmB,CAAC;IAC/DpB,aAAa;IACbqB,SAAS;IACTC,aAAa;IACbxB,SAAS;IACTyB;EACJ,CAAC,CAAC;EAEF,MAAMmB,SAAS,GAAG7C,oBAAoB,CAAC;IACnCE,qBAAqB;IACrBE,SAAS;IACTD,aAAa;IACbF;EACJ,CAAC,CAAC;EAEF,MAAM6C,KAAK,GAAG,IAAA1B,cAAO,EAAC,MAAMjB,aAAa,CAACa,WAAW,EAAE,CAACb,aAAa,CAAC,CAAC;EAEvE,OAAO,IAAAiB,cAAO,EAAC,OAAO;IAAEO,WAAW;IAAEkB,SAAS;IAAEC;EAAM,CAAC,CAAC,EAAE,CAACnB,WAAW,EAAEkB,SAAS,EAAEC,KAAK,CAAC,CAAC;AAC9F,CAAC;AAAC/C,OAAA,CAAA6C,WAAA,GAAAA,WAAA","ignoreList":[]}
1
+ {"version":3,"file":"dropdown.js","names":["_react","require","_dropdown","useIsomorphicLayoutEffect","window","useLayoutEffect","useEffect","useDropdownListener","onClick","onClose","onTouchEnd","onTouchStart","document","addEventListener","removeEventListener","exports","useDropdownAlignment","direction","shouldUseTopAlignment","anchorElement","bodyWidth","translateX","setTranslateX","useState","translateY","setTranslateY","DropdownDirection","BOTTOM_LEFT","TOP_LEFT","LEFT","includes","difference","clientWidth","useTopAlignment","TOP","TOP_RIGHT","useMemo","x","y","useDropdownPosition","container","contentHeight","shouldShowDropdown","coordinates","setCoordinates","setShouldUseTopAlignment","calculateCoordinates","useCallback","left","anchorLeft","top","anchorTop","height","anchorHeight","getBoundingClientRect","scrollLeft","scrollTop","hasBottomAlignment","BOTTOM","BOTTOM_RIGHT","handleResize","setTimeout","useDropdown","transform","width"],"sources":["../../../src/hooks/dropdown.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { DropdownCoordinates, DropdownDirection } from '../types/dropdown';\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\ninterface UseDropdownListenerOptions {\n onClick: (event: MouseEvent) => void;\n onClose: () => void;\n onTouchEnd: (event: TouchEvent) => void;\n onTouchStart: (event: TouchEvent) => void;\n}\n\nexport const useDropdownListener = ({\n onClick,\n onClose,\n onTouchEnd,\n onTouchStart,\n}: UseDropdownListenerOptions) => {\n useEffect(() => {\n document.addEventListener('click', onClick);\n document.addEventListener('touchend', onTouchEnd);\n document.addEventListener('touchstart', onTouchStart);\n\n window.addEventListener('blur', () => onClose());\n\n return () => {\n document.removeEventListener('click', onClick);\n document.removeEventListener('touchend', onTouchEnd);\n document.removeEventListener('touchstart', onTouchStart);\n\n window.addEventListener('blur', () => onClose());\n };\n }, [onClick, onClose, onTouchEnd, onTouchStart]);\n};\n\ninterface UseDropdownAlignmentOptions {\n direction: DropdownDirection;\n shouldUseTopAlignment: boolean;\n bodyWidth?: number;\n anchorElement: Element;\n}\n\nexport const useDropdownAlignment = ({\n direction,\n shouldUseTopAlignment,\n anchorElement,\n bodyWidth,\n}: UseDropdownAlignmentOptions) => {\n const [translateX, setTranslateX] = useState<string>('0px');\n const [translateY, setTranslateY] = useState<string>('0px');\n\n useEffect(() => {\n if (\n [\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.LEFT,\n ].includes(direction) &&\n typeof bodyWidth === 'number'\n ) {\n const difference = anchorElement.clientWidth - bodyWidth;\n\n setTranslateX(`${difference}px`);\n } else {\n setTranslateX('0px');\n }\n }, [anchorElement.clientWidth, bodyWidth, direction]);\n\n useEffect(() => {\n const useTopAlignment =\n shouldUseTopAlignment ||\n [\n DropdownDirection.TOP,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.TOP_RIGHT,\n ].includes(direction);\n\n if (useTopAlignment) {\n setTranslateY('-100%');\n } else {\n setTranslateY('0px');\n }\n }, [direction, shouldUseTopAlignment]);\n\n return useMemo(() => ({ x: translateX, y: translateY }), [translateX, translateY]);\n};\n\ninterface UseDropdownPositionOptions {\n anchorElement: Element;\n container?: Element;\n contentHeight?: number;\n direction: DropdownDirection;\n shouldShowDropdown: boolean;\n}\n\nexport const useDropdownPosition = ({\n anchorElement,\n container,\n contentHeight = 0,\n direction,\n shouldShowDropdown,\n}: UseDropdownPositionOptions) => {\n const [coordinates, setCoordinates] = useState<DropdownCoordinates>({ x: 0, y: 0 });\n const [shouldUseTopAlignment, setShouldUseTopAlignment] = useState(false);\n\n const calculateCoordinates = useCallback(() => {\n if (container) {\n const {\n left: anchorLeft,\n top: anchorTop,\n height: anchorHeight,\n } = anchorElement.getBoundingClientRect();\n\n const { left, top, height } = container.getBoundingClientRect();\n\n const x = anchorLeft - left + container.scrollLeft;\n const y = anchorTop - top + container.scrollTop;\n\n let useTopAlignment = [\n DropdownDirection.TOP,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.TOP_RIGHT,\n ].includes(direction);\n\n const hasBottomAlignment = [\n DropdownDirection.BOTTOM,\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.BOTTOM_RIGHT,\n ].includes(direction);\n\n if (!hasBottomAlignment && y + anchorHeight + contentHeight > height) {\n useTopAlignment = true;\n\n setShouldUseTopAlignment(true);\n } else {\n setShouldUseTopAlignment(false);\n }\n\n setCoordinates({ x, y: useTopAlignment ? y : y + anchorHeight });\n }\n }, [anchorElement, container, contentHeight, direction]);\n\n useIsomorphicLayoutEffect(() => {\n const handleResize = () => {\n calculateCoordinates();\n\n setTimeout(calculateCoordinates, 300);\n };\n\n handleResize();\n\n if (shouldShowDropdown) {\n window.addEventListener('resize', handleResize);\n }\n\n return () => {\n window.removeEventListener('resize', handleResize);\n };\n }, [calculateCoordinates, shouldShowDropdown]);\n\n return useMemo(\n () => ({ shouldUseTopAlignment, coordinates }),\n [coordinates, shouldUseTopAlignment],\n );\n};\n\ninterface UseDropdownOptions {\n anchorElement: Element;\n bodyWidth?: number;\n container?: Element;\n contentHeight?: number;\n direction: DropdownDirection;\n shouldShowDropdown: boolean;\n}\n\nexport const useDropdown = ({\n anchorElement,\n bodyWidth,\n container,\n contentHeight,\n direction,\n shouldShowDropdown,\n}: UseDropdownOptions) => {\n const { shouldUseTopAlignment, coordinates } = useDropdownPosition({\n anchorElement,\n container,\n contentHeight,\n direction,\n shouldShowDropdown,\n });\n\n const transform = useDropdownAlignment({\n shouldUseTopAlignment,\n bodyWidth,\n anchorElement,\n direction,\n });\n\n const width = useMemo(() => anchorElement.clientWidth, [anchorElement]);\n\n return useMemo(() => ({ coordinates, transform, width }), [coordinates, transform, width]);\n};\n"],"mappings":"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","ignoreList":[]}
@@ -4,7 +4,7 @@ import { createPortal } from 'react-dom';
4
4
  import { DropdownDirection } from '../../types/dropdown';
5
5
  import DelayedDropdownContent from './delayed-dropdown-content/DelayedDropdownContent';
6
6
  import { useDropdown, useDropdownListener } from '../../hooks/dropdown';
7
- import { useContainer } from '../../hooks/container';
7
+ import { ContainerAnchor, useContainer } from '../../hooks/container';
8
8
  const DropdownBodyWrapper = ({
9
9
  direction = DropdownDirection.BOTTOM_RIGHT,
10
10
  children,
@@ -18,8 +18,12 @@ const DropdownBodyWrapper = ({
18
18
  minBodyWidth = 0,
19
19
  bodyWidth
20
20
  }) => {
21
+ const isInChaynsWalletRef = useRef(false);
22
+ const [measuredContentHeight, setMeasuredContentHeight] = useState(0);
21
23
  const [portal, setPortal] = useState();
22
24
  const ref = useRef(null);
25
+ const shouldPreventClickRef = useRef(false);
26
+ const touchTimeoutRef = useRef(undefined);
23
27
  const container = useContainer({
24
28
  anchorElement,
25
29
  container: containerProp
@@ -45,24 +49,76 @@ const DropdownBodyWrapper = ({
45
49
  /**
46
50
  * This function closes the body
47
51
  */
48
- const handleOutsideClick = useCallback(event => {
49
- if (!anchorElement.contains(event.target) && ref.current && !ref.current.contains(event.target)) {
52
+ const handleClick = useCallback(event => {
53
+ if (!shouldPreventClickRef.current && !anchorElement.contains(event.target) && ref.current && !ref.current.contains(event.target)) {
50
54
  handleClose();
51
55
  }
56
+ shouldPreventClickRef.current = false;
52
57
  }, [anchorElement, handleClose]);
58
+ const handleContentMeasure = useCallback(measurements => {
59
+ // Measurements are only needed if the content is shown in the chayns wallet. To prevent
60
+ // unnecessary renders, we only set the height if the content is shown in the wallet.
61
+ if (isInChaynsWalletRef.current) {
62
+ setMeasuredContentHeight(measurements.height);
63
+ }
64
+ if (typeof onMeasure === 'function') {
65
+ onMeasure(measurements);
66
+ }
67
+ }, [onMeasure]);
68
+ const handleTouchEnd = useCallback(() => {
69
+ clearTimeout(touchTimeoutRef.current);
70
+ }, []);
71
+ const handleTouchStart = useCallback(() => {
72
+ touchTimeoutRef.current = window.setTimeout(() => {
73
+ shouldPreventClickRef.current = true;
74
+ }, 500);
75
+ }, []);
53
76
 
54
77
  /**
55
78
  * This hook listens for clicks
56
79
  */
57
80
  useDropdownListener({
58
- onOutsideClick: handleOutsideClick,
59
- onClose: handleClose
81
+ onClick: handleClick,
82
+ onClose: handleClose,
83
+ onTouchEnd: handleTouchEnd,
84
+ onTouchStart: handleTouchStart
60
85
  });
86
+ useEffect(() => {
87
+ const isBottomDirection = [DropdownDirection.BOTTOM, DropdownDirection.BOTTOM_LEFT, DropdownDirection.BOTTOM_RIGHT].includes(direction);
88
+ const reservationWrapperElement = document.querySelector(ContainerAnchor.RESERVATION_WRAPPER);
89
+ isInChaynsWalletRef.current = !!(reservationWrapperElement && reservationWrapperElement.contains(anchorElement)) || true;
90
+
91
+ // This effect checks if additional space is needed to show dropdown content in chayns cards.
92
+ if (isBottomDirection && isInChaynsWalletRef.current && measuredContentHeight > 0 && reservationWrapperElement && shouldShowDropdown) {
93
+ const availableHeight = window.innerHeight - anchorElement.getBoundingClientRect().bottom;
94
+
95
+ // If the content height is greater than the available height, we need to add additional space.
96
+ // This is to ensure that the dropdown content is fully visible. The 16 pixels are a buffer for shadows.
97
+ const additionalNeededSpace = measuredContentHeight + 16 - availableHeight;
98
+ if (additionalNeededSpace > 0) {
99
+ // Add margin bottom to the reservation wrapper to ensure the dropdown content is fully visible.
100
+ reservationWrapperElement.style.marginBottom = `${additionalNeededSpace}px`;
101
+ } else {
102
+ // Reset the margin bottom if no additional space is needed.
103
+ reservationWrapperElement.style.marginBottom = '0px';
104
+ }
105
+ }
106
+ if (isInChaynsWalletRef.current && reservationWrapperElement && !shouldShowDropdown) {
107
+ // Reset the margin bottom when the dropdown is closed.
108
+ reservationWrapperElement.style.marginBottom = '0px';
109
+ }
110
+ return () => {
111
+ if (reservationWrapperElement) {
112
+ reservationWrapperElement.style.marginBottom = '0px';
113
+ }
114
+ };
115
+ }, [anchorElement, direction, measuredContentHeight, shouldShowDropdown]);
61
116
  useEffect(() => {
62
117
  if (!container) return;
63
118
  setPortal(() => /*#__PURE__*/createPortal(/*#__PURE__*/React.createElement(DelayedDropdownContent, {
64
- shouldShowContent: shouldShowDropdown,
65
119
  coordinates: coordinates,
120
+ onMeasure: handleContentMeasure,
121
+ shouldShowContent: shouldShowDropdown,
66
122
  transform: transform
67
123
  }, /*#__PURE__*/React.createElement(StyledDropdownBodyWrapperContent, {
68
124
  $width: width,
@@ -71,7 +127,7 @@ const DropdownBodyWrapper = ({
71
127
  $direction: direction,
72
128
  ref: ref
73
129
  }, children)), container));
74
- }, [direction, children, container, coordinates, maxHeight, shouldShowDropdown, width, minBodyWidth, transform, onMeasure]);
130
+ }, [children, container, coordinates, direction, handleContentMeasure, maxHeight, minBodyWidth, shouldShowDropdown, transform, width]);
75
131
  return /*#__PURE__*/React.createElement(StyledDropdownBodyWrapper, null, portal);
76
132
  };
77
133
  DropdownBodyWrapper.displayName = 'DropdownBodyWrapper';
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownBodyWrapper.js","names":["React","useCallback","useEffect","useRef","useState","StyledDropdownBodyWrapper","StyledDropdownBodyWrapperContent","createPortal","DropdownDirection","DelayedDropdownContent","useDropdown","useDropdownListener","useContainer","DropdownBodyWrapper","direction","BOTTOM_RIGHT","children","container","containerProp","shouldShowDropdown","anchorElement","contentHeight","maxHeight","onClose","onMeasure","minBodyWidth","bodyWidth","portal","setPortal","ref","transform","width","coordinates","handleClose","handleOutsideClick","event","contains","target","current","onOutsideClick","createElement","shouldShowContent","$width","$minWidth","$maxHeight","$direction","displayName"],"sources":["../../../../src/components/dropdown-body-wrapper/DropdownBodyWrapper.tsx"],"sourcesContent":["import React, { FC, ReactNode, ReactPortal, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n StyledDropdownBodyWrapper,\n StyledDropdownBodyWrapperContent,\n} from './DropdownBodyWrapper.styles';\nimport { createPortal } from 'react-dom';\nimport { DropdownDirection } from '../../types/dropdown';\nimport DelayedDropdownContent, {\n DelayedDropdownContentProps,\n} from './delayed-dropdown-content/DelayedDropdownContent';\nimport { useDropdown, useDropdownListener } from '../../hooks/dropdown';\nimport { useContainer } from '../../hooks/container';\n\ninterface DropdownBodyWrapperProps {\n /**\n * The anchor element of the dropdown.\n */\n anchorElement: Element;\n /**\n * The width of the Body.\n */\n bodyWidth?: number;\n /**\n * The content of the dropdown body.\n */\n children: ReactNode;\n /**\n * The element where the content should be rendered via React Portal.\n */\n container?: Element;\n /**\n * The height of the content\n */\n contentHeight?: number;\n /**\n * The direction of the dropdown.\n */\n direction?: DropdownDirection;\n /**\n * The max height of the dropdown.\n */\n maxHeight?: number;\n /**\n * The minimum width of the body.\n */\n minBodyWidth?: number;\n /**\n * Function to be executed when the body is closed.\n */\n onClose?: VoidFunction;\n /**\n * Function to be executed when the content is measured.\n */\n onMeasure?: DelayedDropdownContentProps['onMeasure'];\n /**\n * Whether the dropdown should be visible.\n */\n shouldShowDropdown: boolean;\n}\n\nconst DropdownBodyWrapper: FC<DropdownBodyWrapperProps> = ({\n direction = DropdownDirection.BOTTOM_RIGHT,\n children,\n container: containerProp,\n shouldShowDropdown,\n anchorElement,\n contentHeight = 0,\n maxHeight = 300,\n onClose,\n onMeasure,\n minBodyWidth = 0,\n bodyWidth,\n}) => {\n const [portal, setPortal] = useState<ReactPortal>();\n\n const ref = useRef<HTMLDivElement>(null);\n\n const container = useContainer({ anchorElement, container: containerProp });\n\n const { transform, width, coordinates } = useDropdown({\n direction,\n bodyWidth,\n contentHeight,\n container,\n anchorElement,\n shouldShowDropdown,\n });\n\n const handleClose = useCallback(() => {\n if (typeof onClose === 'function') {\n onClose();\n }\n }, [onClose]);\n\n /**\n * This function closes the body\n */\n const handleOutsideClick = useCallback(\n (event: MouseEvent) => {\n if (\n !anchorElement.contains(event.target as Node) &&\n ref.current &&\n !ref.current.contains(event.target as Node)\n ) {\n handleClose();\n }\n },\n [anchorElement, handleClose],\n );\n\n /**\n * This hook listens for clicks\n */\n useDropdownListener({\n onOutsideClick: handleOutsideClick,\n onClose: handleClose,\n });\n\n useEffect(() => {\n if (!container) return;\n\n setPortal(() =>\n createPortal(\n <DelayedDropdownContent\n shouldShowContent={shouldShowDropdown}\n coordinates={coordinates}\n transform={transform}\n >\n <StyledDropdownBodyWrapperContent\n $width={width}\n $minWidth={minBodyWidth}\n $maxHeight={maxHeight}\n $direction={direction}\n ref={ref}\n >\n {children}\n </StyledDropdownBodyWrapperContent>\n </DelayedDropdownContent>,\n container,\n ),\n );\n }, [\n direction,\n children,\n container,\n coordinates,\n maxHeight,\n shouldShowDropdown,\n width,\n minBodyWidth,\n transform,\n onMeasure,\n ]);\n\n return <StyledDropdownBodyWrapper>{portal}</StyledDropdownBodyWrapper>;\n};\n\nDropdownBodyWrapper.displayName = 'DropdownBodyWrapper';\n\nexport default DropdownBodyWrapper;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"DropdownBodyWrapper.js","names":["React","useCallback","useEffect","useRef","useState","StyledDropdownBodyWrapper","StyledDropdownBodyWrapperContent","createPortal","DropdownDirection","DelayedDropdownContent","useDropdown","useDropdownListener","ContainerAnchor","useContainer","DropdownBodyWrapper","direction","BOTTOM_RIGHT","children","container","containerProp","shouldShowDropdown","anchorElement","contentHeight","maxHeight","onClose","onMeasure","minBodyWidth","bodyWidth","isInChaynsWalletRef","measuredContentHeight","setMeasuredContentHeight","portal","setPortal","ref","shouldPreventClickRef","touchTimeoutRef","undefined","transform","width","coordinates","handleClose","handleClick","event","current","contains","target","handleContentMeasure","measurements","height","handleTouchEnd","clearTimeout","handleTouchStart","window","setTimeout","onClick","onTouchEnd","onTouchStart","isBottomDirection","BOTTOM","BOTTOM_LEFT","includes","reservationWrapperElement","document","querySelector","RESERVATION_WRAPPER","availableHeight","innerHeight","getBoundingClientRect","bottom","additionalNeededSpace","style","marginBottom","createElement","shouldShowContent","$width","$minWidth","$maxHeight","$direction","displayName"],"sources":["../../../../src/components/dropdown-body-wrapper/DropdownBodyWrapper.tsx"],"sourcesContent":["import React, { FC, ReactNode, ReactPortal, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n StyledDropdownBodyWrapper,\n StyledDropdownBodyWrapperContent,\n} from './DropdownBodyWrapper.styles';\nimport { createPortal } from 'react-dom';\nimport { DropdownDirection, DropdownMeasurements } from '../../types/dropdown';\nimport DelayedDropdownContent, {\n DelayedDropdownContentProps,\n} from './delayed-dropdown-content/DelayedDropdownContent';\nimport { useDropdown, useDropdownListener } from '../../hooks/dropdown';\nimport { ContainerAnchor, useContainer } from '../../hooks/container';\n\ninterface DropdownBodyWrapperProps {\n /**\n * The anchor element of the dropdown.\n */\n anchorElement: Element;\n /**\n * The width of the Body.\n */\n bodyWidth?: number;\n /**\n * The content of the dropdown body.\n */\n children: ReactNode;\n /**\n * The element where the content should be rendered via React Portal.\n */\n container?: Element;\n /**\n * The height of the content\n */\n contentHeight?: number;\n /**\n * The direction of the dropdown.\n */\n direction?: DropdownDirection;\n /**\n * The max height of the dropdown.\n */\n maxHeight?: number;\n /**\n * The minimum width of the body.\n */\n minBodyWidth?: number;\n /**\n * Function to be executed when the body is closed.\n */\n onClose?: VoidFunction;\n /**\n * Function to be executed when the content is measured.\n */\n onMeasure?: DelayedDropdownContentProps['onMeasure'];\n /**\n * Whether the dropdown should be visible.\n */\n shouldShowDropdown: boolean;\n}\n\nconst DropdownBodyWrapper: FC<DropdownBodyWrapperProps> = ({\n direction = DropdownDirection.BOTTOM_RIGHT,\n children,\n container: containerProp,\n shouldShowDropdown,\n anchorElement,\n contentHeight = 0,\n maxHeight = 300,\n onClose,\n onMeasure,\n minBodyWidth = 0,\n bodyWidth,\n}) => {\n const isInChaynsWalletRef = useRef(false);\n\n const [measuredContentHeight, setMeasuredContentHeight] = useState<number>(0);\n const [portal, setPortal] = useState<ReactPortal>();\n\n const ref = useRef<HTMLDivElement>(null);\n const shouldPreventClickRef = useRef<boolean>(false);\n const touchTimeoutRef = useRef<number | undefined>(undefined);\n\n const container = useContainer({ anchorElement, container: containerProp });\n\n const { transform, width, coordinates } = useDropdown({\n direction,\n bodyWidth,\n contentHeight,\n container,\n anchorElement,\n shouldShowDropdown,\n });\n\n const handleClose = useCallback(() => {\n if (typeof onClose === 'function') {\n onClose();\n }\n }, [onClose]);\n\n /**\n * This function closes the body\n */\n const handleClick = useCallback(\n (event: MouseEvent) => {\n if (\n !shouldPreventClickRef.current &&\n !anchorElement.contains(event.target as Node) &&\n ref.current &&\n !ref.current.contains(event.target as Node)\n ) {\n handleClose();\n }\n\n shouldPreventClickRef.current = false;\n },\n [anchorElement, handleClose],\n );\n\n const handleContentMeasure = useCallback(\n (measurements: DropdownMeasurements) => {\n // Measurements are only needed if the content is shown in the chayns wallet. To prevent\n // unnecessary renders, we only set the height if the content is shown in the wallet.\n if (isInChaynsWalletRef.current) {\n setMeasuredContentHeight(measurements.height);\n }\n\n if (typeof onMeasure === 'function') {\n onMeasure(measurements);\n }\n },\n [onMeasure],\n );\n\n const handleTouchEnd = useCallback(() => {\n clearTimeout(touchTimeoutRef.current);\n }, []);\n\n const handleTouchStart = useCallback(() => {\n touchTimeoutRef.current = window.setTimeout(() => {\n shouldPreventClickRef.current = true;\n }, 500);\n }, []);\n\n /**\n * This hook listens for clicks\n */\n useDropdownListener({\n onClick: handleClick,\n onClose: handleClose,\n onTouchEnd: handleTouchEnd,\n onTouchStart: handleTouchStart,\n });\n\n useEffect(() => {\n const isBottomDirection = [\n DropdownDirection.BOTTOM,\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.BOTTOM_RIGHT,\n ].includes(direction);\n\n const reservationWrapperElement = document.querySelector<HTMLDivElement>(\n ContainerAnchor.RESERVATION_WRAPPER,\n );\n\n isInChaynsWalletRef.current =\n !!(reservationWrapperElement && reservationWrapperElement.contains(anchorElement)) ||\n true;\n\n // This effect checks if additional space is needed to show dropdown content in chayns cards.\n if (\n isBottomDirection &&\n isInChaynsWalletRef.current &&\n measuredContentHeight > 0 &&\n reservationWrapperElement &&\n shouldShowDropdown\n ) {\n const availableHeight =\n window.innerHeight - anchorElement.getBoundingClientRect().bottom;\n\n // If the content height is greater than the available height, we need to add additional space.\n // This is to ensure that the dropdown content is fully visible. The 16 pixels are a buffer for shadows.\n const additionalNeededSpace = measuredContentHeight + 16 - availableHeight;\n\n if (additionalNeededSpace > 0) {\n // Add margin bottom to the reservation wrapper to ensure the dropdown content is fully visible.\n reservationWrapperElement.style.marginBottom = `${additionalNeededSpace}px`;\n } else {\n // Reset the margin bottom if no additional space is needed.\n reservationWrapperElement.style.marginBottom = '0px';\n }\n }\n\n if (isInChaynsWalletRef.current && reservationWrapperElement && !shouldShowDropdown) {\n // Reset the margin bottom when the dropdown is closed.\n reservationWrapperElement.style.marginBottom = '0px';\n }\n\n return () => {\n if (reservationWrapperElement) {\n reservationWrapperElement.style.marginBottom = '0px';\n }\n };\n }, [anchorElement, direction, measuredContentHeight, shouldShowDropdown]);\n\n useEffect(() => {\n if (!container) return;\n\n setPortal(() =>\n createPortal(\n <DelayedDropdownContent\n coordinates={coordinates}\n onMeasure={handleContentMeasure}\n shouldShowContent={shouldShowDropdown}\n transform={transform}\n >\n <StyledDropdownBodyWrapperContent\n $width={width}\n $minWidth={minBodyWidth}\n $maxHeight={maxHeight}\n $direction={direction}\n ref={ref}\n >\n {children}\n </StyledDropdownBodyWrapperContent>\n </DelayedDropdownContent>,\n container,\n ),\n );\n }, [\n children,\n container,\n coordinates,\n direction,\n handleContentMeasure,\n maxHeight,\n minBodyWidth,\n shouldShowDropdown,\n transform,\n width,\n ]);\n\n return <StyledDropdownBodyWrapper>{portal}</StyledDropdownBodyWrapper>;\n};\n\nDropdownBodyWrapper.displayName = 'DropdownBodyWrapper';\n\nexport default DropdownBodyWrapper;\n"],"mappings":"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","ignoreList":[]}
@@ -2,17 +2,23 @@ import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'reac
2
2
  import { DropdownDirection } from '../types/dropdown';
3
3
  const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
4
4
  export const useDropdownListener = ({
5
+ onClick,
5
6
  onClose,
6
- onOutsideClick
7
+ onTouchEnd,
8
+ onTouchStart
7
9
  }) => {
8
10
  useEffect(() => {
9
- document.addEventListener('click', onOutsideClick);
11
+ document.addEventListener('click', onClick);
12
+ document.addEventListener('touchend', onTouchEnd);
13
+ document.addEventListener('touchstart', onTouchStart);
10
14
  window.addEventListener('blur', () => onClose());
11
15
  return () => {
12
- document.removeEventListener('click', onOutsideClick);
16
+ document.removeEventListener('click', onClick);
17
+ document.removeEventListener('touchend', onTouchEnd);
18
+ document.removeEventListener('touchstart', onTouchStart);
13
19
  window.addEventListener('blur', () => onClose());
14
20
  };
15
- }, [onOutsideClick, onClose]);
21
+ }, [onClick, onClose, onTouchEnd, onTouchStart]);
16
22
  };
17
23
  export const useDropdownAlignment = ({
18
24
  direction,
@@ -84,12 +90,16 @@ export const useDropdownPosition = ({
84
90
  }
85
91
  }, [anchorElement, container, contentHeight, direction]);
86
92
  useIsomorphicLayoutEffect(() => {
87
- calculateCoordinates();
93
+ const handleResize = () => {
94
+ calculateCoordinates();
95
+ setTimeout(calculateCoordinates, 300);
96
+ };
97
+ handleResize();
88
98
  if (shouldShowDropdown) {
89
- window.addEventListener('resize', calculateCoordinates);
99
+ window.addEventListener('resize', handleResize);
90
100
  }
91
101
  return () => {
92
- window.removeEventListener('resize', calculateCoordinates);
102
+ window.removeEventListener('resize', handleResize);
93
103
  };
94
104
  }, [calculateCoordinates, shouldShowDropdown]);
95
105
  return useMemo(() => ({
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.js","names":["useCallback","useEffect","useLayoutEffect","useMemo","useState","DropdownDirection","useIsomorphicLayoutEffect","window","useDropdownListener","onClose","onOutsideClick","document","addEventListener","removeEventListener","useDropdownAlignment","direction","shouldUseTopAlignment","anchorElement","bodyWidth","translateX","setTranslateX","translateY","setTranslateY","BOTTOM_LEFT","TOP_LEFT","LEFT","includes","difference","clientWidth","useTopAlignment","TOP","TOP_RIGHT","x","y","useDropdownPosition","container","contentHeight","shouldShowDropdown","coordinates","setCoordinates","setShouldUseTopAlignment","calculateCoordinates","left","anchorLeft","top","anchorTop","height","anchorHeight","getBoundingClientRect","scrollLeft","scrollTop","hasBottomAlignment","BOTTOM","BOTTOM_RIGHT","useDropdown","transform","width"],"sources":["../../../src/hooks/dropdown.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { DropdownCoordinates, DropdownDirection } from '../types/dropdown';\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\ninterface UseDropdownListenerOptions {\n onClose: () => void;\n onOutsideClick: (event: MouseEvent) => void;\n}\n\nexport const useDropdownListener = ({ onClose, onOutsideClick }: UseDropdownListenerOptions) => {\n useEffect(() => {\n document.addEventListener('click', onOutsideClick);\n window.addEventListener('blur', () => onClose());\n\n return () => {\n document.removeEventListener('click', onOutsideClick);\n window.addEventListener('blur', () => onClose());\n };\n }, [onOutsideClick, onClose]);\n};\n\ninterface UseDropdownAlignmentOptions {\n direction: DropdownDirection;\n shouldUseTopAlignment: boolean;\n bodyWidth?: number;\n anchorElement: Element;\n}\n\nexport const useDropdownAlignment = ({\n direction,\n shouldUseTopAlignment,\n anchorElement,\n bodyWidth,\n}: UseDropdownAlignmentOptions) => {\n const [translateX, setTranslateX] = useState<string>('0px');\n const [translateY, setTranslateY] = useState<string>('0px');\n\n useEffect(() => {\n if (\n [\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.LEFT,\n ].includes(direction) &&\n typeof bodyWidth === 'number'\n ) {\n const difference = anchorElement.clientWidth - bodyWidth;\n\n setTranslateX(`${difference}px`);\n } else {\n setTranslateX('0px');\n }\n }, [anchorElement.clientWidth, bodyWidth, direction]);\n\n useEffect(() => {\n const useTopAlignment =\n shouldUseTopAlignment ||\n [\n DropdownDirection.TOP,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.TOP_RIGHT,\n ].includes(direction);\n\n if (useTopAlignment) {\n setTranslateY('-100%');\n } else {\n setTranslateY('0px');\n }\n }, [direction, shouldUseTopAlignment]);\n\n return useMemo(() => ({ x: translateX, y: translateY }), [translateX, translateY]);\n};\n\ninterface UseDropdownPositionOptions {\n anchorElement: Element;\n container?: Element;\n contentHeight?: number;\n direction: DropdownDirection;\n shouldShowDropdown: boolean;\n}\n\nexport const useDropdownPosition = ({\n anchorElement,\n container,\n contentHeight = 0,\n direction,\n shouldShowDropdown,\n}: UseDropdownPositionOptions) => {\n const [coordinates, setCoordinates] = useState<DropdownCoordinates>({ x: 0, y: 0 });\n const [shouldUseTopAlignment, setShouldUseTopAlignment] = useState(false);\n\n const calculateCoordinates = useCallback(() => {\n if (container) {\n const {\n left: anchorLeft,\n top: anchorTop,\n height: anchorHeight,\n } = anchorElement.getBoundingClientRect();\n\n const { left, top, height } = container.getBoundingClientRect();\n\n const x = anchorLeft - left + container.scrollLeft;\n const y = anchorTop - top + container.scrollTop;\n\n let useTopAlignment = [\n DropdownDirection.TOP,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.TOP_RIGHT,\n ].includes(direction);\n\n const hasBottomAlignment = [\n DropdownDirection.BOTTOM,\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.BOTTOM_RIGHT,\n ].includes(direction);\n\n if (!hasBottomAlignment && y + anchorHeight + contentHeight > height) {\n useTopAlignment = true;\n\n setShouldUseTopAlignment(true);\n } else {\n setShouldUseTopAlignment(false);\n }\n\n setCoordinates({ x, y: useTopAlignment ? y : y + anchorHeight });\n }\n }, [anchorElement, container, contentHeight, direction]);\n\n useIsomorphicLayoutEffect(() => {\n calculateCoordinates();\n\n if (shouldShowDropdown) {\n window.addEventListener('resize', calculateCoordinates);\n }\n\n return () => {\n window.removeEventListener('resize', calculateCoordinates);\n };\n }, [calculateCoordinates, shouldShowDropdown]);\n\n return useMemo(\n () => ({ shouldUseTopAlignment, coordinates }),\n [coordinates, shouldUseTopAlignment],\n );\n};\n\ninterface UseDropdownOptions {\n anchorElement: Element;\n bodyWidth?: number;\n container?: Element;\n contentHeight?: number;\n direction: DropdownDirection;\n shouldShowDropdown: boolean;\n}\n\nexport const useDropdown = ({\n anchorElement,\n bodyWidth,\n container,\n contentHeight,\n direction,\n shouldShowDropdown,\n}: UseDropdownOptions) => {\n const { shouldUseTopAlignment, coordinates } = useDropdownPosition({\n anchorElement,\n container,\n contentHeight,\n direction,\n shouldShowDropdown,\n });\n\n const transform = useDropdownAlignment({\n shouldUseTopAlignment,\n bodyWidth,\n anchorElement,\n direction,\n });\n\n const width = useMemo(() => anchorElement.clientWidth, [anchorElement]);\n\n return useMemo(() => ({ coordinates, transform, width }), [coordinates, transform, width]);\n};\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"dropdown.js","names":["useCallback","useEffect","useLayoutEffect","useMemo","useState","DropdownDirection","useIsomorphicLayoutEffect","window","useDropdownListener","onClick","onClose","onTouchEnd","onTouchStart","document","addEventListener","removeEventListener","useDropdownAlignment","direction","shouldUseTopAlignment","anchorElement","bodyWidth","translateX","setTranslateX","translateY","setTranslateY","BOTTOM_LEFT","TOP_LEFT","LEFT","includes","difference","clientWidth","useTopAlignment","TOP","TOP_RIGHT","x","y","useDropdownPosition","container","contentHeight","shouldShowDropdown","coordinates","setCoordinates","setShouldUseTopAlignment","calculateCoordinates","left","anchorLeft","top","anchorTop","height","anchorHeight","getBoundingClientRect","scrollLeft","scrollTop","hasBottomAlignment","BOTTOM","BOTTOM_RIGHT","handleResize","setTimeout","useDropdown","transform","width"],"sources":["../../../src/hooks/dropdown.ts"],"sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useMemo, useState } from 'react';\nimport { DropdownCoordinates, DropdownDirection } from '../types/dropdown';\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\ninterface UseDropdownListenerOptions {\n onClick: (event: MouseEvent) => void;\n onClose: () => void;\n onTouchEnd: (event: TouchEvent) => void;\n onTouchStart: (event: TouchEvent) => void;\n}\n\nexport const useDropdownListener = ({\n onClick,\n onClose,\n onTouchEnd,\n onTouchStart,\n}: UseDropdownListenerOptions) => {\n useEffect(() => {\n document.addEventListener('click', onClick);\n document.addEventListener('touchend', onTouchEnd);\n document.addEventListener('touchstart', onTouchStart);\n\n window.addEventListener('blur', () => onClose());\n\n return () => {\n document.removeEventListener('click', onClick);\n document.removeEventListener('touchend', onTouchEnd);\n document.removeEventListener('touchstart', onTouchStart);\n\n window.addEventListener('blur', () => onClose());\n };\n }, [onClick, onClose, onTouchEnd, onTouchStart]);\n};\n\ninterface UseDropdownAlignmentOptions {\n direction: DropdownDirection;\n shouldUseTopAlignment: boolean;\n bodyWidth?: number;\n anchorElement: Element;\n}\n\nexport const useDropdownAlignment = ({\n direction,\n shouldUseTopAlignment,\n anchorElement,\n bodyWidth,\n}: UseDropdownAlignmentOptions) => {\n const [translateX, setTranslateX] = useState<string>('0px');\n const [translateY, setTranslateY] = useState<string>('0px');\n\n useEffect(() => {\n if (\n [\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.LEFT,\n ].includes(direction) &&\n typeof bodyWidth === 'number'\n ) {\n const difference = anchorElement.clientWidth - bodyWidth;\n\n setTranslateX(`${difference}px`);\n } else {\n setTranslateX('0px');\n }\n }, [anchorElement.clientWidth, bodyWidth, direction]);\n\n useEffect(() => {\n const useTopAlignment =\n shouldUseTopAlignment ||\n [\n DropdownDirection.TOP,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.TOP_RIGHT,\n ].includes(direction);\n\n if (useTopAlignment) {\n setTranslateY('-100%');\n } else {\n setTranslateY('0px');\n }\n }, [direction, shouldUseTopAlignment]);\n\n return useMemo(() => ({ x: translateX, y: translateY }), [translateX, translateY]);\n};\n\ninterface UseDropdownPositionOptions {\n anchorElement: Element;\n container?: Element;\n contentHeight?: number;\n direction: DropdownDirection;\n shouldShowDropdown: boolean;\n}\n\nexport const useDropdownPosition = ({\n anchorElement,\n container,\n contentHeight = 0,\n direction,\n shouldShowDropdown,\n}: UseDropdownPositionOptions) => {\n const [coordinates, setCoordinates] = useState<DropdownCoordinates>({ x: 0, y: 0 });\n const [shouldUseTopAlignment, setShouldUseTopAlignment] = useState(false);\n\n const calculateCoordinates = useCallback(() => {\n if (container) {\n const {\n left: anchorLeft,\n top: anchorTop,\n height: anchorHeight,\n } = anchorElement.getBoundingClientRect();\n\n const { left, top, height } = container.getBoundingClientRect();\n\n const x = anchorLeft - left + container.scrollLeft;\n const y = anchorTop - top + container.scrollTop;\n\n let useTopAlignment = [\n DropdownDirection.TOP,\n DropdownDirection.TOP_LEFT,\n DropdownDirection.TOP_RIGHT,\n ].includes(direction);\n\n const hasBottomAlignment = [\n DropdownDirection.BOTTOM,\n DropdownDirection.BOTTOM_LEFT,\n DropdownDirection.BOTTOM_RIGHT,\n ].includes(direction);\n\n if (!hasBottomAlignment && y + anchorHeight + contentHeight > height) {\n useTopAlignment = true;\n\n setShouldUseTopAlignment(true);\n } else {\n setShouldUseTopAlignment(false);\n }\n\n setCoordinates({ x, y: useTopAlignment ? y : y + anchorHeight });\n }\n }, [anchorElement, container, contentHeight, direction]);\n\n useIsomorphicLayoutEffect(() => {\n const handleResize = () => {\n calculateCoordinates();\n\n setTimeout(calculateCoordinates, 300);\n };\n\n handleResize();\n\n if (shouldShowDropdown) {\n window.addEventListener('resize', handleResize);\n }\n\n return () => {\n window.removeEventListener('resize', handleResize);\n };\n }, [calculateCoordinates, shouldShowDropdown]);\n\n return useMemo(\n () => ({ shouldUseTopAlignment, coordinates }),\n [coordinates, shouldUseTopAlignment],\n );\n};\n\ninterface UseDropdownOptions {\n anchorElement: Element;\n bodyWidth?: number;\n container?: Element;\n contentHeight?: number;\n direction: DropdownDirection;\n shouldShowDropdown: boolean;\n}\n\nexport const useDropdown = ({\n anchorElement,\n bodyWidth,\n container,\n contentHeight,\n direction,\n shouldShowDropdown,\n}: UseDropdownOptions) => {\n const { shouldUseTopAlignment, coordinates } = useDropdownPosition({\n anchorElement,\n container,\n contentHeight,\n direction,\n shouldShowDropdown,\n });\n\n const transform = useDropdownAlignment({\n shouldUseTopAlignment,\n bodyWidth,\n anchorElement,\n direction,\n });\n\n const width = useMemo(() => anchorElement.clientWidth, [anchorElement]);\n\n return useMemo(() => ({ coordinates, transform, width }), [coordinates, transform, width]);\n};\n"],"mappings":"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","ignoreList":[]}
@@ -1,9 +1,11 @@
1
1
  import { DropdownCoordinates, DropdownDirection } from '../types/dropdown';
2
2
  interface UseDropdownListenerOptions {
3
+ onClick: (event: MouseEvent) => void;
3
4
  onClose: () => void;
4
- onOutsideClick: (event: MouseEvent) => void;
5
+ onTouchEnd: (event: TouchEvent) => void;
6
+ onTouchStart: (event: TouchEvent) => void;
5
7
  }
6
- export declare const useDropdownListener: ({ onClose, onOutsideClick }: UseDropdownListenerOptions) => void;
8
+ export declare const useDropdownListener: ({ onClick, onClose, onTouchEnd, onTouchStart, }: UseDropdownListenerOptions) => void;
7
9
  interface UseDropdownAlignmentOptions {
8
10
  direction: DropdownDirection;
9
11
  shouldUseTopAlignment: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chayns-components/core",
3
- "version": "5.0.0-beta.1180",
3
+ "version": "5.0.0-beta.1182",
4
4
  "description": "A set of beautiful React components for developing your own applications with chayns.",
5
5
  "sideEffects": false,
6
6
  "browserslist": [
@@ -85,5 +85,5 @@
85
85
  "publishConfig": {
86
86
  "access": "public"
87
87
  },
88
- "gitHead": "ae02dfa6d677354ae892ac173512b1369824b780"
88
+ "gitHead": "8707be8081bf7b9a8a686045f2db3be5ac2337f8"
89
89
  }