@openedx/paragon 22.11.2 → 22.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +8 -0
  2. package/dist/Card/CardFallbackDefaultImage.js +1 -0
  3. package/dist/Card/CardImageCap.js +1 -1
  4. package/dist/Card/CardImageCap.js.map +1 -1
  5. package/dist/hooks/useArrowKeyNavigation.d.ts +10 -0
  6. package/dist/hooks/useArrowKeyNavigation.js +8 -10
  7. package/dist/hooks/useArrowKeyNavigation.js.map +1 -1
  8. package/dist/hooks/useIndexOfLastVisibleChild.d.ts +12 -0
  9. package/dist/hooks/useIndexOfLastVisibleChild.js +11 -11
  10. package/dist/hooks/useIndexOfLastVisibleChild.js.map +1 -1
  11. package/dist/hooks/useIsVisible.d.ts +3 -0
  12. package/dist/hooks/useIsVisible.js +1 -1
  13. package/dist/hooks/useIsVisible.js.map +1 -1
  14. package/dist/hooks/useToggle.d.ts +12 -0
  15. package/dist/hooks/useToggle.js +7 -18
  16. package/dist/hooks/useToggle.js.map +1 -1
  17. package/dist/hooks/useWindowSize.d.ts +6 -0
  18. package/dist/hooks/useWindowSize.js.map +1 -1
  19. package/dist/index.d.ts +5 -5
  20. package/dist/index.js +5 -5
  21. package/package.json +1 -1
  22. package/src/Card/CardFallbackDefaultImage.js +1 -0
  23. package/src/Card/CardImageCap.jsx +1 -1
  24. package/src/Card/tests/CardImageCap.test.jsx +3 -3
  25. package/src/hooks/tests/{useIndexOfLastVisibleChild.test.jsx → useIndexOfLastVisibleChild.test.tsx} +2 -2
  26. package/src/hooks/tests/{useToggle.test.jsx → useToggle.test.tsx} +2 -1
  27. package/src/hooks/{useArrowKeyNavigation.jsx → useArrowKeyNavigation.tsx} +37 -13
  28. package/src/hooks/{useIndexOfLastVisibleChild.jsx → useIndexOfLastVisibleChild.tsx} +18 -16
  29. package/src/hooks/{useIsVisible.jsx → useIsVisible.tsx} +6 -3
  30. package/src/hooks/useToggle.tsx +38 -0
  31. package/src/hooks/{useWindowSize.jsx → useWindowSize.tsx} +7 -2
  32. package/src/index.d.ts +5 -5
  33. package/src/index.js +5 -5
  34. package/dist/Card/fallback-default.png +0 -0
  35. package/src/Card/fallback-default.png +0 -0
  36. package/src/hooks/useToggle.jsx +0 -37
  37. /package/src/hooks/tests/{useWindowSize.test.jsx → useWindowSize.test.tsx} +0 -0
package/README.md CHANGED
@@ -123,6 +123,14 @@ Note that if you are using ``@edx/frontend-platform``'s ``AppProvider`` componen
123
123
 
124
124
  ## Contributing
125
125
 
126
+ The branch to target with your PR depends on the type of change you are contributing to Paragon.
127
+
128
+ | Branch to Target | Type of Change | Documentation Site |
129
+ | - | - | - |
130
+ | [`release-22.x`](https://github.com/openedx/paragon/tree/release-22.x) | Bug fix/security patch | https://paragon-openedx-v22.netlify.app/ |
131
+ | [`release-23.x`](https://github.com/openedx/paragon/tree/release-23.x) | Bug fix/security patch/new (non-breaking) feature | https://paragon-openedx-v23.netlify.app/ |
132
+ | [`next`](https://github.com/openedx/paragon/tree/next) | Breaking change | https://paragon-openedx.netlify.app/ |
133
+
126
134
  Please refer to the ["How to Contribute"](https://openedx.org/r/how-to-contribute) documentation and [Code of Conduct](https://openedx.org/code-of-conduct/) from Open edX.
127
135
 
128
136
  The Paragon Working Group accepts bug fixes, new features, documentation, and security patches. You may find open issues [here](https://github.com/openedx/paragon/issues) or by visiting the Paragon Working Group [project board](https://github.com/orgs/openedx/projects/43/views/15).
@@ -0,0 +1 @@
1
+ export const cardSrcFallbackImg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXwAAACMCAYAAAB/AhJnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAH6SURBVHgB7dRBEYBADACxwuDf5j0QUXywiYhc7zk7APzd3gNAgvABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIp4BaNpp2Q/3/wfPkGyXOQAAAABJRU5ErkJggg==';
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import classNames from 'classnames';
4
4
  import Skeleton from 'react-loading-skeleton';
5
5
  import CardContext from './CardContext';
6
- import cardSrcFallbackImg from './fallback-default.png';
6
+ import { cardSrcFallbackImg } from './CardFallbackDefaultImage';
7
7
  const SKELETON_HEIGHT_VALUE = 140;
8
8
  const LOGO_SKELETON_HEIGHT_VALUE = 41;
9
9
  const CardImageCap = /*#__PURE__*/React.forwardRef((_ref, ref) => {
@@ -1 +1 @@
1
- {"version":3,"file":"CardImageCap.js","names":["React","useContext","useState","PropTypes","classNames","Skeleton","CardContext","cardSrcFallbackImg","SKELETON_HEIGHT_VALUE","LOGO_SKELETON_HEIGHT_VALUE","CardImageCap","forwardRef","_ref","ref","src","fallbackSrc","srcAlt","logoSrc","fallbackLogoSrc","logoAlt","skeletonHeight","skeletonWidth","logoSkeleton","logoSkeletonHeight","logoSkeletonWidth","className","imageLoadingType","orientation","isLoading","showImageCap","setShowImageCap","showLogoCap","setShowLogoCap","wrapperClassName","createElement","containerClassName","height","width","handleSrcFallback","event","altSrc","imageKey","currentTarget","endsWith","show","onError","onLoad","alt","loading","propTypes","string","number","bool","oneOf","defaultProps","undefined"],"sources":["../../src/Card/CardImageCap.jsx"],"sourcesContent":["import React, { useContext, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport Skeleton from 'react-loading-skeleton';\nimport CardContext from './CardContext';\nimport cardSrcFallbackImg from './fallback-default.png';\n\nconst SKELETON_HEIGHT_VALUE = 140;\nconst LOGO_SKELETON_HEIGHT_VALUE = 41;\n\nconst CardImageCap = React.forwardRef(({\n src,\n fallbackSrc,\n srcAlt,\n logoSrc,\n fallbackLogoSrc,\n logoAlt,\n skeletonHeight,\n skeletonWidth,\n logoSkeleton,\n logoSkeletonHeight,\n logoSkeletonWidth,\n className,\n imageLoadingType,\n}, ref) => {\n const { orientation, isLoading } = useContext(CardContext);\n const [showImageCap, setShowImageCap] = useState(false);\n const [showLogoCap, setShowLogoCap] = useState(false);\n\n const wrapperClassName = `pgn__card-wrapper-image-cap ${orientation}`;\n\n if (isLoading) {\n return (\n <div\n className={classNames(wrapperClassName, className)}\n data-testid=\"image-loader-wrapper\"\n >\n <Skeleton\n containerClassName=\"pgn__card-image-cap-loader\"\n height={orientation === 'horizontal' ? '100%' : skeletonHeight}\n width={skeletonWidth}\n />\n {logoSkeleton && (\n <Skeleton\n containerClassName=\"pgn__card-logo-cap\"\n height={logoSkeletonHeight}\n width={logoSkeletonWidth}\n />\n )}\n </div>\n );\n }\n\n const handleSrcFallback = (event, altSrc, imageKey) => {\n const { currentTarget } = event;\n\n if (!altSrc || currentTarget.src.endsWith(altSrc)) {\n if (imageKey === 'imageCap') {\n currentTarget.src = cardSrcFallbackImg;\n } else {\n setShowLogoCap(false);\n }\n\n return;\n }\n\n currentTarget.src = altSrc;\n };\n\n return (\n <div className={classNames(className, wrapperClassName)} ref={ref}>\n {!!src && (\n <img\n className={classNames('pgn__card-image-cap', { show: showImageCap })}\n src={src}\n onError={(event) => handleSrcFallback(event, fallbackSrc, 'imageCap')}\n onLoad={() => setShowImageCap(true)}\n alt={srcAlt}\n loading={imageLoadingType}\n />\n )}\n {!!logoSrc && (\n <img\n className={classNames('pgn__card-logo-cap', { show: showLogoCap })}\n src={logoSrc}\n onError={(event) => handleSrcFallback(event, fallbackLogoSrc, 'logoCap')}\n onLoad={() => setShowLogoCap(true)}\n alt={logoAlt}\n loading={imageLoadingType}\n />\n )}\n </div>\n );\n});\n\nCardImageCap.propTypes = {\n /** Specifies class name to append to the base element. */\n className: PropTypes.string,\n /** Specifies image src. */\n src: PropTypes.string,\n /** Specifies fallback image src. */\n fallbackSrc: PropTypes.string,\n /** Specifies image alt text. */\n srcAlt: PropTypes.string,\n /** Specifies logo src to put on top of the image. */\n logoSrc: PropTypes.string,\n /** Specifies fallback image logo src. */\n fallbackLogoSrc: PropTypes.string,\n /** Specifies logo image alt text. */\n logoAlt: PropTypes.string,\n /** Specifies height of Image skeleton in loading state. */\n skeletonHeight: PropTypes.number,\n /** Specifies width of Image skeleton in loading state. */\n skeletonWidth: PropTypes.number,\n /** Specifies whether the cap should be displayed during loading. */\n logoSkeleton: PropTypes.bool,\n /** Specifies height of Logo skeleton in loading state. */\n logoSkeletonHeight: PropTypes.number,\n /** Specifies width of Logo skeleton in loading state. */\n logoSkeletonWidth: PropTypes.number,\n /** Specifies loading type for images */\n imageLoadingType: PropTypes.oneOf(['eager', 'lazy']),\n};\n\nCardImageCap.defaultProps = {\n src: undefined,\n fallbackSrc: cardSrcFallbackImg,\n logoSrc: undefined,\n fallbackLogoSrc: undefined,\n className: undefined,\n srcAlt: undefined,\n logoAlt: undefined,\n skeletonHeight: SKELETON_HEIGHT_VALUE,\n logoSkeleton: false,\n logoSkeletonHeight: LOGO_SKELETON_HEIGHT_VALUE,\n skeletonWidth: undefined,\n logoSkeletonWidth: undefined,\n imageLoadingType: 'eager',\n};\n\nexport default CardImageCap;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"CardImageCap.js","names":["React","useContext","useState","PropTypes","classNames","Skeleton","CardContext","cardSrcFallbackImg","SKELETON_HEIGHT_VALUE","LOGO_SKELETON_HEIGHT_VALUE","CardImageCap","forwardRef","_ref","ref","src","fallbackSrc","srcAlt","logoSrc","fallbackLogoSrc","logoAlt","skeletonHeight","skeletonWidth","logoSkeleton","logoSkeletonHeight","logoSkeletonWidth","className","imageLoadingType","orientation","isLoading","showImageCap","setShowImageCap","showLogoCap","setShowLogoCap","wrapperClassName","createElement","containerClassName","height","width","handleSrcFallback","event","altSrc","imageKey","currentTarget","endsWith","show","onError","onLoad","alt","loading","propTypes","string","number","bool","oneOf","defaultProps","undefined"],"sources":["../../src/Card/CardImageCap.jsx"],"sourcesContent":["import React, { useContext, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport Skeleton from 'react-loading-skeleton';\nimport CardContext from './CardContext';\nimport { cardSrcFallbackImg } from './CardFallbackDefaultImage';\n\nconst SKELETON_HEIGHT_VALUE = 140;\nconst LOGO_SKELETON_HEIGHT_VALUE = 41;\n\nconst CardImageCap = React.forwardRef(({\n src,\n fallbackSrc,\n srcAlt,\n logoSrc,\n fallbackLogoSrc,\n logoAlt,\n skeletonHeight,\n skeletonWidth,\n logoSkeleton,\n logoSkeletonHeight,\n logoSkeletonWidth,\n className,\n imageLoadingType,\n}, ref) => {\n const { orientation, isLoading } = useContext(CardContext);\n const [showImageCap, setShowImageCap] = useState(false);\n const [showLogoCap, setShowLogoCap] = useState(false);\n\n const wrapperClassName = `pgn__card-wrapper-image-cap ${orientation}`;\n\n if (isLoading) {\n return (\n <div\n className={classNames(wrapperClassName, className)}\n data-testid=\"image-loader-wrapper\"\n >\n <Skeleton\n containerClassName=\"pgn__card-image-cap-loader\"\n height={orientation === 'horizontal' ? '100%' : skeletonHeight}\n width={skeletonWidth}\n />\n {logoSkeleton && (\n <Skeleton\n containerClassName=\"pgn__card-logo-cap\"\n height={logoSkeletonHeight}\n width={logoSkeletonWidth}\n />\n )}\n </div>\n );\n }\n\n const handleSrcFallback = (event, altSrc, imageKey) => {\n const { currentTarget } = event;\n\n if (!altSrc || currentTarget.src.endsWith(altSrc)) {\n if (imageKey === 'imageCap') {\n currentTarget.src = cardSrcFallbackImg;\n } else {\n setShowLogoCap(false);\n }\n\n return;\n }\n\n currentTarget.src = altSrc;\n };\n\n return (\n <div className={classNames(className, wrapperClassName)} ref={ref}>\n {!!src && (\n <img\n className={classNames('pgn__card-image-cap', { show: showImageCap })}\n src={src}\n onError={(event) => handleSrcFallback(event, fallbackSrc, 'imageCap')}\n onLoad={() => setShowImageCap(true)}\n alt={srcAlt}\n loading={imageLoadingType}\n />\n )}\n {!!logoSrc && (\n <img\n className={classNames('pgn__card-logo-cap', { show: showLogoCap })}\n src={logoSrc}\n onError={(event) => handleSrcFallback(event, fallbackLogoSrc, 'logoCap')}\n onLoad={() => setShowLogoCap(true)}\n alt={logoAlt}\n loading={imageLoadingType}\n />\n )}\n </div>\n );\n});\n\nCardImageCap.propTypes = {\n /** Specifies class name to append to the base element. */\n className: PropTypes.string,\n /** Specifies image src. */\n src: PropTypes.string,\n /** Specifies fallback image src. */\n fallbackSrc: PropTypes.string,\n /** Specifies image alt text. */\n srcAlt: PropTypes.string,\n /** Specifies logo src to put on top of the image. */\n logoSrc: PropTypes.string,\n /** Specifies fallback image logo src. */\n fallbackLogoSrc: PropTypes.string,\n /** Specifies logo image alt text. */\n logoAlt: PropTypes.string,\n /** Specifies height of Image skeleton in loading state. */\n skeletonHeight: PropTypes.number,\n /** Specifies width of Image skeleton in loading state. */\n skeletonWidth: PropTypes.number,\n /** Specifies whether the cap should be displayed during loading. */\n logoSkeleton: PropTypes.bool,\n /** Specifies height of Logo skeleton in loading state. */\n logoSkeletonHeight: PropTypes.number,\n /** Specifies width of Logo skeleton in loading state. */\n logoSkeletonWidth: PropTypes.number,\n /** Specifies loading type for images */\n imageLoadingType: PropTypes.oneOf(['eager', 'lazy']),\n};\n\nCardImageCap.defaultProps = {\n src: undefined,\n fallbackSrc: cardSrcFallbackImg,\n logoSrc: undefined,\n fallbackLogoSrc: undefined,\n className: undefined,\n srcAlt: undefined,\n logoAlt: undefined,\n skeletonHeight: SKELETON_HEIGHT_VALUE,\n logoSkeleton: false,\n logoSkeletonHeight: LOGO_SKELETON_HEIGHT_VALUE,\n skeletonWidth: undefined,\n logoSkeletonWidth: undefined,\n imageLoadingType: 'eager',\n};\n\nexport default CardImageCap;\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,10 @@
1
+ /// <reference types="react" />
2
+ export interface ArrowKeyNavProps {
3
+ /** e.g. 'a,button,input' */
4
+ selectors?: string;
5
+ ignoredKeys?: string[];
6
+ }
7
+ /**
8
+ * A React hook to enable arrow key navigation on a component.
9
+ */
10
+ export default function useArrowKeyNavigation(props?: ArrowKeyNavProps): import("react").MutableRefObject<HTMLElement | undefined>;
@@ -1,9 +1,4 @@
1
1
  import { useRef, useEffect } from 'react';
2
-
3
- /**
4
- * A React hook to enable arrow key navigation on a component.
5
- */
6
-
7
2
  function handleEnter(_ref) {
8
3
  let {
9
4
  event,
@@ -44,7 +39,6 @@ function handleArrowKey(_ref2) {
44
39
  nextElement?.focus();
45
40
  event.preventDefault();
46
41
  }
47
-
48
42
  /**
49
43
  * Implement arrow key navigation for the given parentNode
50
44
  */
@@ -83,11 +77,11 @@ function handleEvents(_ref3) {
83
77
 
84
78
  // Which index is currently selected
85
79
  const currentIndex = Array.from(availableElements).findIndex(availableElement => availableElement === activeElement);
86
- if (key === 'Enter') {
80
+ if (key === 'Enter' && activeElement) {
87
81
  handleEnter({
88
82
  event,
89
83
  currentIndex,
90
- activeElement
84
+ activeElement: activeElement
91
85
  });
92
86
  }
93
87
  handleArrowKey({
@@ -96,11 +90,15 @@ function handleEvents(_ref3) {
96
90
  availableElements
97
91
  });
98
92
  }
99
- export default function useArrowKeyNavigation(props) {
93
+ /**
94
+ * A React hook to enable arrow key navigation on a component.
95
+ */
96
+ export default function useArrowKeyNavigation() {
97
+ let props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
100
98
  const {
101
99
  selectors,
102
100
  ignoredKeys
103
- } = props || {};
101
+ } = props;
104
102
  const parentNode = useRef();
105
103
  useEffect(() => {
106
104
  const eventHandler = event => {
@@ -1 +1 @@
1
- {"version":3,"file":"useArrowKeyNavigation.js","names":["useRef","useEffect","handleEnter","_ref","event","currentIndex","activeElement","click","preventDefault","handleArrowKey","_ref2","availableElements","focus","nextElement","key","length","handleEvents","_ref3","ignoredKeys","parentNode","selectors","includes","document","contains","querySelectorAll","Array","from","findIndex","availableElement","useArrowKeyNavigation","props","eventHandler","current","addEventListener","removeEventListener"],"sources":["../../src/hooks/useArrowKeyNavigation.jsx"],"sourcesContent":["import { useRef, useEffect } from 'react';\n\n/**\n * A React hook to enable arrow key navigation on a component.\n */\n\nfunction handleEnter({ event, currentIndex, activeElement }) {\n if (currentIndex === -1) { return; }\n activeElement.click();\n event.preventDefault();\n}\n\nfunction handleArrowKey({ event, currentIndex, availableElements }) {\n // If the focus isn't in the container, focus on the first thing\n if (currentIndex === -1) { availableElements[0].focus(); }\n\n // Move the focus up or down. Wrap around ends of list.\n let nextElement;\n\n if (event.key === 'ArrowDown' || event.key === 'ArrowRight') {\n nextElement = availableElements[(currentIndex + 1) % availableElements.length];\n }\n if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') {\n nextElement = currentIndex - 1 < 0\n ? availableElements[currentIndex - 1 + availableElements.length]\n : availableElements[currentIndex - 1];\n }\n if (event.key === 'End') {\n nextElement = availableElements[availableElements.length - 1];\n }\n if (event.key === 'Home') {\n [nextElement] = availableElements;\n }\n\n nextElement?.focus();\n event.preventDefault();\n}\n\n/**\n * Implement arrow key navigation for the given parentNode\n */\nfunction handleEvents({\n event,\n ignoredKeys = [],\n parentNode,\n selectors = 'a,button,input',\n}) {\n if (!parentNode) { return; }\n\n const { key } = event;\n\n if (!['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft', 'Enter', 'Home', 'End'].includes(key)\n || ignoredKeys.includes(key)) {\n return;\n }\n\n const { activeElement } = document;\n\n // If we're not inside the container, don't do anything\n if (!parentNode.contains(activeElement)) { return; }\n\n // Get the list of elements we're allowed to scroll through\n const availableElements = parentNode.querySelectorAll(selectors);\n\n // No elements are available to loop through.\n if (!availableElements.length) { return; }\n\n // Which index is currently selected\n const currentIndex = Array.from(availableElements).findIndex(\n (availableElement) => availableElement === activeElement,\n );\n\n if (key === 'Enter') {\n handleEnter({ event, currentIndex, activeElement });\n }\n handleArrowKey({ event, currentIndex, availableElements });\n}\n\nexport default function useArrowKeyNavigation(props) {\n const { selectors, ignoredKeys } = props || {};\n const parentNode = useRef();\n\n useEffect(() => {\n const eventHandler = (event) => {\n handleEvents({\n event, ignoredKeys, parentNode: parentNode.current, selectors,\n });\n };\n\n document.addEventListener('keydown', eventHandler);\n\n return () => document.removeEventListener('keydown', eventHandler);\n }, [ignoredKeys, selectors]);\n\n return parentNode;\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"useArrowKeyNavigation.js","names":["useRef","useEffect","handleEnter","_ref","event","currentIndex","activeElement","click","preventDefault","handleArrowKey","_ref2","availableElements","focus","nextElement","key","length","handleEvents","_ref3","ignoredKeys","parentNode","selectors","includes","document","contains","querySelectorAll","Array","from","findIndex","availableElement","useArrowKeyNavigation","props","arguments","undefined","eventHandler","current","addEventListener","removeEventListener"],"sources":["../../src/hooks/useArrowKeyNavigation.tsx"],"sourcesContent":["import { useRef, useEffect } from 'react';\n\ninterface HandleEnterArgs {\n event: KeyboardEvent;\n currentIndex: number;\n activeElement: HTMLElement;\n}\n\nfunction handleEnter({ event, currentIndex, activeElement }: HandleEnterArgs) {\n if (currentIndex === -1) { return; }\n activeElement.click();\n event.preventDefault();\n}\n\ninterface HandleArrowKeyArgs {\n event: KeyboardEvent;\n currentIndex: number;\n availableElements: NodeListOf<HTMLElement>;\n}\n\nfunction handleArrowKey({ event, currentIndex, availableElements }: HandleArrowKeyArgs) {\n // If the focus isn't in the container, focus on the first thing\n if (currentIndex === -1) { availableElements[0].focus(); }\n\n // Move the focus up or down. Wrap around ends of list.\n let nextElement;\n\n if (event.key === 'ArrowDown' || event.key === 'ArrowRight') {\n nextElement = availableElements[(currentIndex + 1) % availableElements.length];\n }\n if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') {\n nextElement = currentIndex - 1 < 0\n ? availableElements[currentIndex - 1 + availableElements.length]\n : availableElements[currentIndex - 1];\n }\n if (event.key === 'End') {\n nextElement = availableElements[availableElements.length - 1];\n }\n if (event.key === 'Home') {\n [nextElement] = availableElements;\n }\n\n nextElement?.focus();\n event.preventDefault();\n}\n\ninterface HandleEventsArgs {\n event: KeyboardEvent;\n ignoredKeys?: string[];\n parentNode: HTMLElement | undefined;\n selectors?: string;\n}\n\n/**\n * Implement arrow key navigation for the given parentNode\n */\nfunction handleEvents({\n event,\n ignoredKeys = [],\n parentNode,\n selectors = 'a,button,input',\n}: HandleEventsArgs) {\n if (!parentNode) { return; }\n\n const { key } = event;\n\n if (!['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft', 'Enter', 'Home', 'End'].includes(key)\n || ignoredKeys.includes(key)) {\n return;\n }\n\n const { activeElement } = document;\n\n // If we're not inside the container, don't do anything\n if (!parentNode.contains(activeElement)) { return; }\n\n // Get the list of elements we're allowed to scroll through\n const availableElements = parentNode.querySelectorAll<HTMLElement>(selectors);\n\n // No elements are available to loop through.\n if (!availableElements.length) { return; }\n\n // Which index is currently selected\n const currentIndex = Array.from(availableElements).findIndex(\n (availableElement) => availableElement === activeElement,\n );\n\n if (key === 'Enter' && activeElement) {\n handleEnter({ event, currentIndex, activeElement: activeElement as HTMLElement });\n }\n handleArrowKey({ event, currentIndex, availableElements });\n}\n\nexport interface ArrowKeyNavProps {\n /** e.g. 'a,button,input' */\n selectors?: string;\n ignoredKeys?: string[];\n}\n\n/**\n * A React hook to enable arrow key navigation on a component.\n */\nexport default function useArrowKeyNavigation(props: ArrowKeyNavProps = {}) {\n const { selectors, ignoredKeys } = props;\n const parentNode = useRef<HTMLElement>();\n\n useEffect(() => {\n const eventHandler = (event: KeyboardEvent) => {\n handleEvents({\n event, ignoredKeys, parentNode: parentNode.current, selectors,\n });\n };\n\n document.addEventListener('keydown', eventHandler);\n\n return () => document.removeEventListener('keydown', eventHandler);\n }, [ignoredKeys, selectors]);\n\n return parentNode;\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * This hook will find the index of the last child of a containing element
3
+ * that fits within its bounding rectangle. This is done by summing the widths
4
+ * of the children until they exceed the width of the container.
5
+ *
6
+ * The hook returns the index of the last visible child.
7
+ *
8
+ * @param containerElementRef - container element
9
+ * @param overflowElementRef - overflow element
10
+ */
11
+ declare const useIndexOfLastVisibleChild: (containerElementRef: HTMLElement | null, overflowElementRef: HTMLElement | null) => number;
12
+ export default useIndexOfLastVisibleChild;
@@ -5,14 +5,17 @@ import { useLayoutEffect, useState } from 'react';
5
5
  * that fits within its bounding rectangle. This is done by summing the widths
6
6
  * of the children until they exceed the width of the container.
7
7
  *
8
- * @param {Element} containerElementRef - container element
9
- * @param {Element} overflowElementRef - overflow element
10
- *
11
8
  * The hook returns the index of the last visible child.
9
+ *
10
+ * @param containerElementRef - container element
11
+ * @param overflowElementRef - overflow element
12
12
  */
13
13
  const useIndexOfLastVisibleChild = (containerElementRef, overflowElementRef) => {
14
14
  const [indexOfLastVisibleChild, setIndexOfLastVisibleChild] = useState(-1);
15
15
  useLayoutEffect(() => {
16
+ if (!containerElementRef) {
17
+ return undefined;
18
+ }
16
19
  function updateLastVisibleChildIndex() {
17
20
  // Get array of child nodes from NodeList form
18
21
  const childNodesArr = Array.prototype.slice.call(containerElementRef.children);
@@ -33,18 +36,15 @@ const useIndexOfLastVisibleChild = (containerElementRef, overflowElementRef) =>
33
36
  // sometimes we'll show a dropdown with one item in it when it would fit,
34
37
  // but allowing this case dramatically simplifies the calculations we need
35
38
  // to do above.
36
- sumWidth: overflowElementRef ? overflowElementRef.getBoundingClientRect().width : 0,
39
+ sumWidth: overflowElementRef?.getBoundingClientRect().width ?? 0,
37
40
  nextIndexOfLastVisibleChild: -1
38
41
  });
39
42
  setIndexOfLastVisibleChild(nextIndexOfLastVisibleChild);
40
43
  }
41
- if (containerElementRef) {
42
- updateLastVisibleChildIndex();
43
- const resizeObserver = new ResizeObserver(() => updateLastVisibleChildIndex());
44
- resizeObserver.observe(containerElementRef);
45
- return () => resizeObserver.disconnect();
46
- }
47
- return undefined;
44
+ updateLastVisibleChildIndex();
45
+ const resizeObserver = new ResizeObserver(() => updateLastVisibleChildIndex());
46
+ resizeObserver.observe(containerElementRef);
47
+ return () => resizeObserver.disconnect();
48
48
  }, [containerElementRef, overflowElementRef]);
49
49
  return indexOfLastVisibleChild;
50
50
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useIndexOfLastVisibleChild.js","names":["useLayoutEffect","useState","useIndexOfLastVisibleChild","containerElementRef","overflowElementRef","indexOfLastVisibleChild","setIndexOfLastVisibleChild","updateLastVisibleChildIndex","childNodesArr","Array","prototype","slice","call","children","nextIndexOfLastVisibleChild","filter","childNode","reduce","acc","index","sumWidth","getBoundingClientRect","width","resizeObserver","ResizeObserver","observe","disconnect","undefined"],"sources":["../../src/hooks/useIndexOfLastVisibleChild.jsx"],"sourcesContent":["import { useLayoutEffect, useState } from 'react';\n\n/**\n * This hook will find the index of the last child of a containing element\n * that fits within its bounding rectangle. This is done by summing the widths\n * of the children until they exceed the width of the container.\n *\n * @param {Element} containerElementRef - container element\n * @param {Element} overflowElementRef - overflow element\n *\n * The hook returns the index of the last visible child.\n */\nconst useIndexOfLastVisibleChild = (containerElementRef, overflowElementRef) => {\n const [indexOfLastVisibleChild, setIndexOfLastVisibleChild] = useState(-1);\n\n useLayoutEffect(() => {\n function updateLastVisibleChildIndex() {\n // Get array of child nodes from NodeList form\n const childNodesArr = Array.prototype.slice.call(containerElementRef.children);\n const { nextIndexOfLastVisibleChild } = childNodesArr\n // filter out the overflow element\n .filter(childNode => childNode !== overflowElementRef)\n // sum the widths to find the last visible element's index\n .reduce((acc, childNode, index) => {\n acc.sumWidth += childNode.getBoundingClientRect().width;\n if (acc.sumWidth <= containerElementRef.getBoundingClientRect().width) {\n acc.nextIndexOfLastVisibleChild = index;\n }\n return acc;\n }, {\n // Include the overflow element's width to begin with. Doing this means\n // sometimes we'll show a dropdown with one item in it when it would fit,\n // but allowing this case dramatically simplifies the calculations we need\n // to do above.\n sumWidth: overflowElementRef ? overflowElementRef.getBoundingClientRect().width : 0,\n nextIndexOfLastVisibleChild: -1,\n });\n\n setIndexOfLastVisibleChild(nextIndexOfLastVisibleChild);\n }\n\n if (containerElementRef) {\n updateLastVisibleChildIndex();\n\n const resizeObserver = new ResizeObserver(() => updateLastVisibleChildIndex());\n resizeObserver.observe(containerElementRef);\n\n return () => resizeObserver.disconnect();\n }\n\n return undefined;\n }, [containerElementRef, overflowElementRef]);\n\n return indexOfLastVisibleChild;\n};\n\nexport default useIndexOfLastVisibleChild;\n"],"mappings":"AAAA,SAASA,eAAe,EAAEC,QAAQ,QAAQ,OAAO;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,0BAA0B,GAAGA,CAACC,mBAAmB,EAAEC,kBAAkB,KAAK;EAC9E,MAAM,CAACC,uBAAuB,EAAEC,0BAA0B,CAAC,GAAGL,QAAQ,CAAC,CAAC,CAAC,CAAC;EAE1ED,eAAe,CAAC,MAAM;IACpB,SAASO,2BAA2BA,CAAA,EAAG;MACrC;MACA,MAAMC,aAAa,GAAGC,KAAK,CAACC,SAAS,CAACC,KAAK,CAACC,IAAI,CAACT,mBAAmB,CAACU,QAAQ,CAAC;MAC9E,MAAM;QAAEC;MAA4B,CAAC,GAAGN;MACtC;MAAA,CACCO,MAAM,CAACC,SAAS,IAAIA,SAAS,KAAKZ,kBAAkB;MACrD;MAAA,CACCa,MAAM,CAAC,CAACC,GAAG,EAAEF,SAAS,EAAEG,KAAK,KAAK;QACjCD,GAAG,CAACE,QAAQ,IAAIJ,SAAS,CAACK,qBAAqB,CAAC,CAAC,CAACC,KAAK;QACvD,IAAIJ,GAAG,CAACE,QAAQ,IAAIjB,mBAAmB,CAACkB,qBAAqB,CAAC,CAAC,CAACC,KAAK,EAAE;UACrEJ,GAAG,CAACJ,2BAA2B,GAAGK,KAAK;QACzC;QACA,OAAOD,GAAG;MACZ,CAAC,EAAE;QACD;QACA;QACA;QACA;QACAE,QAAQ,EAAEhB,kBAAkB,GAAGA,kBAAkB,CAACiB,qBAAqB,CAAC,CAAC,CAACC,KAAK,GAAG,CAAC;QACnFR,2BAA2B,EAAE,CAAC;MAChC,CAAC,CAAC;MAEJR,0BAA0B,CAACQ,2BAA2B,CAAC;IACzD;IAEA,IAAIX,mBAAmB,EAAE;MACvBI,2BAA2B,CAAC,CAAC;MAE7B,MAAMgB,cAAc,GAAG,IAAIC,cAAc,CAAC,MAAMjB,2BAA2B,CAAC,CAAC,CAAC;MAC9EgB,cAAc,CAACE,OAAO,CAACtB,mBAAmB,CAAC;MAE3C,OAAO,MAAMoB,cAAc,CAACG,UAAU,CAAC,CAAC;IAC1C;IAEA,OAAOC,SAAS;EAClB,CAAC,EAAE,CAACxB,mBAAmB,EAAEC,kBAAkB,CAAC,CAAC;EAE7C,OAAOC,uBAAuB;AAChC,CAAC;AAED,eAAeH,0BAA0B","ignoreList":[]}
1
+ {"version":3,"file":"useIndexOfLastVisibleChild.js","names":["useLayoutEffect","useState","useIndexOfLastVisibleChild","containerElementRef","overflowElementRef","indexOfLastVisibleChild","setIndexOfLastVisibleChild","undefined","updateLastVisibleChildIndex","childNodesArr","Array","prototype","slice","call","children","nextIndexOfLastVisibleChild","filter","childNode","reduce","acc","index","sumWidth","getBoundingClientRect","width","resizeObserver","ResizeObserver","observe","disconnect"],"sources":["../../src/hooks/useIndexOfLastVisibleChild.tsx"],"sourcesContent":["import { useLayoutEffect, useState } from 'react';\n\n/**\n * This hook will find the index of the last child of a containing element\n * that fits within its bounding rectangle. This is done by summing the widths\n * of the children until they exceed the width of the container.\n *\n * The hook returns the index of the last visible child.\n *\n * @param containerElementRef - container element\n * @param overflowElementRef - overflow element\n */\nconst useIndexOfLastVisibleChild = (\n containerElementRef: HTMLElement | null,\n overflowElementRef: HTMLElement | null,\n): number => {\n const [indexOfLastVisibleChild, setIndexOfLastVisibleChild] = useState(-1);\n\n useLayoutEffect(() => {\n if (!containerElementRef) {\n return undefined;\n }\n\n function updateLastVisibleChildIndex() {\n // Get array of child nodes from NodeList form\n const childNodesArr = Array.prototype.slice.call(containerElementRef!.children);\n const { nextIndexOfLastVisibleChild } = childNodesArr\n // filter out the overflow element\n .filter(childNode => childNode !== overflowElementRef)\n // sum the widths to find the last visible element's index\n .reduce((acc, childNode, index) => {\n acc.sumWidth += childNode.getBoundingClientRect().width;\n if (acc.sumWidth <= containerElementRef!.getBoundingClientRect().width) {\n acc.nextIndexOfLastVisibleChild = index;\n }\n return acc;\n }, {\n // Include the overflow element's width to begin with. Doing this means\n // sometimes we'll show a dropdown with one item in it when it would fit,\n // but allowing this case dramatically simplifies the calculations we need\n // to do above.\n sumWidth: overflowElementRef?.getBoundingClientRect().width ?? 0,\n nextIndexOfLastVisibleChild: -1,\n });\n\n setIndexOfLastVisibleChild(nextIndexOfLastVisibleChild);\n }\n\n updateLastVisibleChildIndex();\n\n const resizeObserver = new ResizeObserver(() => updateLastVisibleChildIndex());\n resizeObserver.observe(containerElementRef);\n return () => resizeObserver.disconnect();\n }, [containerElementRef, overflowElementRef]);\n\n return indexOfLastVisibleChild;\n};\n\nexport default useIndexOfLastVisibleChild;\n"],"mappings":"AAAA,SAASA,eAAe,EAAEC,QAAQ,QAAQ,OAAO;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,0BAA0B,GAAGA,CACjCC,mBAAuC,EACvCC,kBAAsC,KAC3B;EACX,MAAM,CAACC,uBAAuB,EAAEC,0BAA0B,CAAC,GAAGL,QAAQ,CAAC,CAAC,CAAC,CAAC;EAE1ED,eAAe,CAAC,MAAM;IACpB,IAAI,CAACG,mBAAmB,EAAE;MACxB,OAAOI,SAAS;IAClB;IAEA,SAASC,2BAA2BA,CAAA,EAAG;MACrC;MACA,MAAMC,aAAa,GAAGC,KAAK,CAACC,SAAS,CAACC,KAAK,CAACC,IAAI,CAACV,mBAAmB,CAAEW,QAAQ,CAAC;MAC/E,MAAM;QAAEC;MAA4B,CAAC,GAAGN;MACtC;MAAA,CACCO,MAAM,CAACC,SAAS,IAAIA,SAAS,KAAKb,kBAAkB;MACrD;MAAA,CACCc,MAAM,CAAC,CAACC,GAAG,EAAEF,SAAS,EAAEG,KAAK,KAAK;QACjCD,GAAG,CAACE,QAAQ,IAAIJ,SAAS,CAACK,qBAAqB,CAAC,CAAC,CAACC,KAAK;QACvD,IAAIJ,GAAG,CAACE,QAAQ,IAAIlB,mBAAmB,CAAEmB,qBAAqB,CAAC,CAAC,CAACC,KAAK,EAAE;UACtEJ,GAAG,CAACJ,2BAA2B,GAAGK,KAAK;QACzC;QACA,OAAOD,GAAG;MACZ,CAAC,EAAE;QACD;QACA;QACA;QACA;QACAE,QAAQ,EAAEjB,kBAAkB,EAAEkB,qBAAqB,CAAC,CAAC,CAACC,KAAK,IAAI,CAAC;QAChER,2BAA2B,EAAE,CAAC;MAChC,CAAC,CAAC;MAEJT,0BAA0B,CAACS,2BAA2B,CAAC;IACzD;IAEAP,2BAA2B,CAAC,CAAC;IAE7B,MAAMgB,cAAc,GAAG,IAAIC,cAAc,CAAC,MAAMjB,2BAA2B,CAAC,CAAC,CAAC;IAC9EgB,cAAc,CAACE,OAAO,CAACvB,mBAAmB,CAAC;IAC3C,OAAO,MAAMqB,cAAc,CAACG,UAAU,CAAC,CAAC;EAC1C,CAAC,EAAE,CAACxB,mBAAmB,EAAEC,kBAAkB,CAAC,CAAC;EAE7C,OAAOC,uBAAuB;AAChC,CAAC;AAED,eAAeH,0BAA0B","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const useIsVisible: (defaultIsVisible?: boolean) => [isVisible: boolean, sentinelRef: React.MutableRefObject<HTMLElement | null>];
3
+ export default useIsVisible;
@@ -1,7 +1,7 @@
1
1
  import { useRef, useState, useEffect } from 'react';
2
2
  const useIsVisible = function () {
3
3
  let defaultIsVisible = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
4
- const sentinelRef = useRef();
4
+ const sentinelRef = useRef(null);
5
5
  const [isVisible, setIsVisible] = useState(defaultIsVisible);
6
6
  useEffect(() => {
7
7
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"useIsVisible.js","names":["useRef","useState","useEffect","useIsVisible","defaultIsVisible","arguments","length","undefined","sentinelRef","isVisible","setIsVisible","current","observer","IntersectionObserver","entries","forEach","_ref","isIntersecting","observe","disconnect","e","isReferenceError","ReferenceError"],"sources":["../../src/hooks/useIsVisible.jsx"],"sourcesContent":["import { useRef, useState, useEffect } from 'react';\n\nconst useIsVisible = (defaultIsVisible = true) => {\n const sentinelRef = useRef();\n const [isVisible, setIsVisible] = useState(defaultIsVisible);\n\n useEffect(() => {\n try {\n if (sentinelRef.current) {\n const observer = new IntersectionObserver((entries) => {\n entries.forEach(({ isIntersecting }) => {\n setIsVisible(isIntersecting);\n });\n }, {});\n observer.observe(sentinelRef.current);\n return () => {\n observer.disconnect();\n };\n }\n } catch (e) {\n const isReferenceError = e instanceof ReferenceError;\n if (!isReferenceError) {\n throw e;\n }\n // Do nothing if an intersection observer can't be created.\n }\n return () => {};\n }, []);\n\n return [isVisible, sentinelRef];\n};\n\nexport default useIsVisible;\n"],"mappings":"AAAA,SAASA,MAAM,EAAEC,QAAQ,EAAEC,SAAS,QAAQ,OAAO;AAEnD,MAAMC,YAAY,GAAG,SAAAA,CAAA,EAA6B;EAAA,IAA5BC,gBAAgB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,IAAI;EAC3C,MAAMG,WAAW,GAAGR,MAAM,CAAC,CAAC;EAC5B,MAAM,CAACS,SAAS,EAAEC,YAAY,CAAC,GAAGT,QAAQ,CAACG,gBAAgB,CAAC;EAE5DF,SAAS,CAAC,MAAM;IACd,IAAI;MACF,IAAIM,WAAW,CAACG,OAAO,EAAE;QACvB,MAAMC,QAAQ,GAAG,IAAIC,oBAAoB,CAAEC,OAAO,IAAK;UACrDA,OAAO,CAACC,OAAO,CAACC,IAAA,IAAwB;YAAA,IAAvB;cAAEC;YAAe,CAAC,GAAAD,IAAA;YACjCN,YAAY,CAACO,cAAc,CAAC;UAC9B,CAAC,CAAC;QACJ,CAAC,EAAE,CAAC,CAAC,CAAC;QACNL,QAAQ,CAACM,OAAO,CAACV,WAAW,CAACG,OAAO,CAAC;QACrC,OAAO,MAAM;UACXC,QAAQ,CAACO,UAAU,CAAC,CAAC;QACvB,CAAC;MACH;IACF,CAAC,CAAC,OAAOC,CAAC,EAAE;MACV,MAAMC,gBAAgB,GAAGD,CAAC,YAAYE,cAAc;MACpD,IAAI,CAACD,gBAAgB,EAAE;QACrB,MAAMD,CAAC;MACT;MACA;IACF;IACA,OAAO,MAAM,CAAC,CAAC;EACjB,CAAC,EAAE,EAAE,CAAC;EAEN,OAAO,CAACX,SAAS,EAAED,WAAW,CAAC;AACjC,CAAC;AAED,eAAeL,YAAY","ignoreList":[]}
1
+ {"version":3,"file":"useIsVisible.js","names":["useRef","useState","useEffect","useIsVisible","defaultIsVisible","arguments","length","undefined","sentinelRef","isVisible","setIsVisible","current","observer","IntersectionObserver","entries","forEach","_ref","isIntersecting","observe","disconnect","e","isReferenceError","ReferenceError"],"sources":["../../src/hooks/useIsVisible.tsx"],"sourcesContent":["import React, { useRef, useState, useEffect } from 'react';\n\nconst useIsVisible = (defaultIsVisible = true): [\n isVisible: boolean,\n sentinelRef: React.MutableRefObject<HTMLElement | null>,\n] => {\n const sentinelRef = useRef<HTMLElement | null>(null);\n const [isVisible, setIsVisible] = useState(defaultIsVisible);\n\n useEffect(() => {\n try {\n if (sentinelRef.current) {\n const observer = new IntersectionObserver((entries) => {\n entries.forEach(({ isIntersecting }) => {\n setIsVisible(isIntersecting);\n });\n }, {});\n observer.observe(sentinelRef.current);\n return () => {\n observer.disconnect();\n };\n }\n } catch (e) {\n const isReferenceError = e instanceof ReferenceError;\n if (!isReferenceError) {\n throw e;\n }\n // Do nothing if an intersection observer can't be created.\n }\n return () => {};\n }, []);\n\n return [isVisible, sentinelRef];\n};\n\nexport default useIsVisible;\n"],"mappings":"AAAA,SAAgBA,MAAM,EAAEC,QAAQ,EAAEC,SAAS,QAAQ,OAAO;AAE1D,MAAMC,YAAY,GAAG,SAAAA,CAAA,EAGhB;EAAA,IAHiBC,gBAAgB,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,IAAI;EAI3C,MAAMG,WAAW,GAAGR,MAAM,CAAqB,IAAI,CAAC;EACpD,MAAM,CAACS,SAAS,EAAEC,YAAY,CAAC,GAAGT,QAAQ,CAACG,gBAAgB,CAAC;EAE5DF,SAAS,CAAC,MAAM;IACd,IAAI;MACF,IAAIM,WAAW,CAACG,OAAO,EAAE;QACvB,MAAMC,QAAQ,GAAG,IAAIC,oBAAoB,CAAEC,OAAO,IAAK;UACrDA,OAAO,CAACC,OAAO,CAACC,IAAA,IAAwB;YAAA,IAAvB;cAAEC;YAAe,CAAC,GAAAD,IAAA;YACjCN,YAAY,CAACO,cAAc,CAAC;UAC9B,CAAC,CAAC;QACJ,CAAC,EAAE,CAAC,CAAC,CAAC;QACNL,QAAQ,CAACM,OAAO,CAACV,WAAW,CAACG,OAAO,CAAC;QACrC,OAAO,MAAM;UACXC,QAAQ,CAACO,UAAU,CAAC,CAAC;QACvB,CAAC;MACH;IACF,CAAC,CAAC,OAAOC,CAAC,EAAE;MACV,MAAMC,gBAAgB,GAAGD,CAAC,YAAYE,cAAc;MACpD,IAAI,CAACD,gBAAgB,EAAE;QACrB,MAAMD,CAAC;MACT;MACA;IACF;IACA,OAAO,MAAM,CAAC,CAAC;EACjB,CAAC,EAAE,EAAE,CAAC;EAEN,OAAO,CAACX,SAAS,EAAED,WAAW,CAAC;AACjC,CAAC;AAED,eAAeL,YAAY","ignoreList":[]}
@@ -0,0 +1,12 @@
1
+ export type Toggler = [
2
+ isOn: boolean,
3
+ setOn: () => void,
4
+ setOff: () => void,
5
+ toggle: () => void
6
+ ];
7
+ export interface ToggleHandlers {
8
+ handleToggleOn?: () => void;
9
+ handleToggleOff?: () => void;
10
+ handleToggle?: (newStatus: boolean) => void;
11
+ }
12
+ export default function useToggle(defaultIsOn?: boolean, handlers?: ToggleHandlers): Toggler;
@@ -1,33 +1,22 @@
1
1
  import { useState, useCallback } from 'react';
2
- export default function useToggle(defaultIsOn) {
2
+ export default function useToggle() {
3
+ let defaultIsOn = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
3
4
  let handlers = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
4
5
  const {
5
6
  handleToggleOn,
6
7
  handleToggleOff,
7
8
  handleToggle
8
9
  } = handlers;
9
- const [isOn, setIsOn] = useState(defaultIsOn || false);
10
+ const [isOn, setIsOn] = useState(defaultIsOn);
10
11
  const setOn = useCallback(() => {
11
12
  setIsOn(true);
12
- // istanbul ignore else
13
- if (handleToggleOn) {
14
- handleToggleOn();
15
- }
16
- // istanbul ignore else
17
- if (handleToggle) {
18
- handleToggle(true);
19
- }
13
+ handleToggleOn?.();
14
+ handleToggle?.(true);
20
15
  }, [handleToggleOn, handleToggle]);
21
16
  const setOff = useCallback(() => {
22
17
  setIsOn(false);
23
- // istanbul ignore else
24
- if (handleToggleOff) {
25
- handleToggleOff();
26
- }
27
- // istanbul ignore else
28
- if (handleToggle) {
29
- handleToggle(false);
30
- }
18
+ handleToggleOff?.();
19
+ handleToggle?.(false);
31
20
  }, [handleToggleOff, handleToggle]);
32
21
  const toggle = useCallback(() => {
33
22
  const doToggle = isOn ? setOff : setOn;
@@ -1 +1 @@
1
- {"version":3,"file":"useToggle.js","names":["useState","useCallback","useToggle","defaultIsOn","handlers","arguments","length","undefined","handleToggleOn","handleToggleOff","handleToggle","isOn","setIsOn","setOn","setOff","toggle","doToggle"],"sources":["../../src/hooks/useToggle.jsx"],"sourcesContent":["import { useState, useCallback } from 'react';\n\nexport default function useToggle(defaultIsOn, handlers = {}) {\n const { handleToggleOn, handleToggleOff, handleToggle } = handlers;\n const [isOn, setIsOn] = useState(defaultIsOn || false);\n\n const setOn = useCallback(() => {\n setIsOn(true);\n // istanbul ignore else\n if (handleToggleOn) {\n handleToggleOn();\n }\n // istanbul ignore else\n if (handleToggle) {\n handleToggle(true);\n }\n }, [handleToggleOn, handleToggle]);\n\n const setOff = useCallback(() => {\n setIsOn(false);\n // istanbul ignore else\n if (handleToggleOff) {\n handleToggleOff();\n }\n // istanbul ignore else\n if (handleToggle) {\n handleToggle(false);\n }\n }, [handleToggleOff, handleToggle]);\n\n const toggle = useCallback(() => {\n const doToggle = isOn ? setOff : setOn;\n doToggle();\n }, [isOn, setOn, setOff]);\n\n return [isOn, setOn, setOff, toggle];\n}\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,WAAW,QAAQ,OAAO;AAE7C,eAAe,SAASC,SAASA,CAACC,WAAW,EAAiB;EAAA,IAAfC,QAAQ,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAC1D,MAAM;IAAEG,cAAc;IAAEC,eAAe;IAAEC;EAAa,CAAC,GAAGN,QAAQ;EAClE,MAAM,CAACO,IAAI,EAAEC,OAAO,CAAC,GAAGZ,QAAQ,CAACG,WAAW,IAAI,KAAK,CAAC;EAEtD,MAAMU,KAAK,GAAGZ,WAAW,CAAC,MAAM;IAC9BW,OAAO,CAAC,IAAI,CAAC;IACb;IACA,IAAIJ,cAAc,EAAE;MAClBA,cAAc,CAAC,CAAC;IAClB;IACA;IACA,IAAIE,YAAY,EAAE;MAChBA,YAAY,CAAC,IAAI,CAAC;IACpB;EACF,CAAC,EAAE,CAACF,cAAc,EAAEE,YAAY,CAAC,CAAC;EAElC,MAAMI,MAAM,GAAGb,WAAW,CAAC,MAAM;IAC/BW,OAAO,CAAC,KAAK,CAAC;IACd;IACA,IAAIH,eAAe,EAAE;MACnBA,eAAe,CAAC,CAAC;IACnB;IACA;IACA,IAAIC,YAAY,EAAE;MAChBA,YAAY,CAAC,KAAK,CAAC;IACrB;EACF,CAAC,EAAE,CAACD,eAAe,EAAEC,YAAY,CAAC,CAAC;EAEnC,MAAMK,MAAM,GAAGd,WAAW,CAAC,MAAM;IAC/B,MAAMe,QAAQ,GAAGL,IAAI,GAAGG,MAAM,GAAGD,KAAK;IACtCG,QAAQ,CAAC,CAAC;EACZ,CAAC,EAAE,CAACL,IAAI,EAAEE,KAAK,EAAEC,MAAM,CAAC,CAAC;EAEzB,OAAO,CAACH,IAAI,EAAEE,KAAK,EAAEC,MAAM,EAAEC,MAAM,CAAC;AACtC","ignoreList":[]}
1
+ {"version":3,"file":"useToggle.js","names":["useState","useCallback","useToggle","defaultIsOn","arguments","length","undefined","handlers","handleToggleOn","handleToggleOff","handleToggle","isOn","setIsOn","setOn","setOff","toggle","doToggle"],"sources":["../../src/hooks/useToggle.tsx"],"sourcesContent":["import { useState, useCallback } from 'react';\n\nexport type Toggler = [\n isOn: boolean,\n setOn: () => void,\n setOff: () => void,\n toggle: () => void,\n];\n\nexport interface ToggleHandlers {\n handleToggleOn?: () => void;\n handleToggleOff?: () => void;\n handleToggle?: (newStatus: boolean) => void;\n}\n\nexport default function useToggle(defaultIsOn = false, handlers: ToggleHandlers = {}): Toggler {\n const { handleToggleOn, handleToggleOff, handleToggle } = handlers;\n const [isOn, setIsOn] = useState(defaultIsOn);\n\n const setOn = useCallback(() => {\n setIsOn(true);\n handleToggleOn?.();\n handleToggle?.(true);\n }, [handleToggleOn, handleToggle]);\n\n const setOff = useCallback(() => {\n setIsOn(false);\n handleToggleOff?.();\n handleToggle?.(false);\n }, [handleToggleOff, handleToggle]);\n\n const toggle = useCallback(() => {\n const doToggle = isOn ? setOff : setOn;\n doToggle();\n }, [isOn, setOn, setOff]);\n\n return [isOn, setOn, setOff, toggle];\n}\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,WAAW,QAAQ,OAAO;AAe7C,eAAe,SAASC,SAASA,CAAA,EAA8D;EAAA,IAA7DC,WAAW,GAAAC,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,KAAK;EAAA,IAAEG,QAAwB,GAAAH,SAAA,CAAAC,MAAA,QAAAD,SAAA,QAAAE,SAAA,GAAAF,SAAA,MAAG,CAAC,CAAC;EAClF,MAAM;IAAEI,cAAc;IAAEC,eAAe;IAAEC;EAAa,CAAC,GAAGH,QAAQ;EAClE,MAAM,CAACI,IAAI,EAAEC,OAAO,CAAC,GAAGZ,QAAQ,CAACG,WAAW,CAAC;EAE7C,MAAMU,KAAK,GAAGZ,WAAW,CAAC,MAAM;IAC9BW,OAAO,CAAC,IAAI,CAAC;IACbJ,cAAc,GAAG,CAAC;IAClBE,YAAY,GAAG,IAAI,CAAC;EACtB,CAAC,EAAE,CAACF,cAAc,EAAEE,YAAY,CAAC,CAAC;EAElC,MAAMI,MAAM,GAAGb,WAAW,CAAC,MAAM;IAC/BW,OAAO,CAAC,KAAK,CAAC;IACdH,eAAe,GAAG,CAAC;IACnBC,YAAY,GAAG,KAAK,CAAC;EACvB,CAAC,EAAE,CAACD,eAAe,EAAEC,YAAY,CAAC,CAAC;EAEnC,MAAMK,MAAM,GAAGd,WAAW,CAAC,MAAM;IAC/B,MAAMe,QAAQ,GAAGL,IAAI,GAAGG,MAAM,GAAGD,KAAK;IACtCG,QAAQ,CAAC,CAAC;EACZ,CAAC,EAAE,CAACL,IAAI,EAAEE,KAAK,EAAEC,MAAM,CAAC,CAAC;EAEzB,OAAO,CAACH,IAAI,EAAEE,KAAK,EAAEC,MAAM,EAAEC,MAAM,CAAC;AACtC","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ export interface WindowSizeData {
2
+ width: number | undefined;
3
+ height: number | undefined;
4
+ }
5
+ declare function useWindowSize(): WindowSizeData;
6
+ export default useWindowSize;
@@ -1 +1 @@
1
- {"version":3,"file":"useWindowSize.js","names":["useState","useLayoutEffect","useWindowSize","windowSize","setWindowSize","width","undefined","height","handleResize","global","innerWidth","innerHeight","addEventListener","removeEventListener"],"sources":["../../src/hooks/useWindowSize.jsx"],"sourcesContent":["import { useState, useLayoutEffect } from 'react';\n\nfunction useWindowSize() {\n // Initialize state with undefined width/height so server and client renders match\n // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/\n const [windowSize, setWindowSize] = useState({\n width: undefined,\n height: undefined,\n });\n\n useLayoutEffect(() => {\n // Handler to call on window resize\n function handleResize() {\n // Set window width/height to state\n setWindowSize({\n width: global.innerWidth,\n height: global.innerHeight,\n });\n }\n\n // Add event listener\n global.addEventListener('resize', handleResize);\n\n // Call handler right away so state gets updated with initial window size\n handleResize();\n\n // Remove event listener on cleanup\n return () => global.removeEventListener('resize', handleResize);\n }, []); // Empty array ensures that effect is only run on mount\n\n return windowSize;\n}\n\nexport default useWindowSize;\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,eAAe,QAAQ,OAAO;AAEjD,SAASC,aAAaA,CAAA,EAAG;EACvB;EACA;EACA,MAAM,CAACC,UAAU,EAAEC,aAAa,CAAC,GAAGJ,QAAQ,CAAC;IAC3CK,KAAK,EAAEC,SAAS;IAChBC,MAAM,EAAED;EACV,CAAC,CAAC;EAEFL,eAAe,CAAC,MAAM;IACpB;IACA,SAASO,YAAYA,CAAA,EAAG;MACtB;MACAJ,aAAa,CAAC;QACZC,KAAK,EAAEI,MAAM,CAACC,UAAU;QACxBH,MAAM,EAAEE,MAAM,CAACE;MACjB,CAAC,CAAC;IACJ;;IAEA;IACAF,MAAM,CAACG,gBAAgB,CAAC,QAAQ,EAAEJ,YAAY,CAAC;;IAE/C;IACAA,YAAY,CAAC,CAAC;;IAEd;IACA,OAAO,MAAMC,MAAM,CAACI,mBAAmB,CAAC,QAAQ,EAAEL,YAAY,CAAC;EACjE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;;EAER,OAAOL,UAAU;AACnB;AAEA,eAAeD,aAAa","ignoreList":[]}
1
+ {"version":3,"file":"useWindowSize.js","names":["useState","useLayoutEffect","useWindowSize","windowSize","setWindowSize","width","undefined","height","handleResize","global","innerWidth","innerHeight","addEventListener","removeEventListener"],"sources":["../../src/hooks/useWindowSize.tsx"],"sourcesContent":["import { useState, useLayoutEffect } from 'react';\n\nexport interface WindowSizeData {\n width: number | undefined;\n height: number | undefined;\n}\n\nfunction useWindowSize(): WindowSizeData {\n // Initialize state with undefined width/height so server and client renders match\n // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/\n const [windowSize, setWindowSize] = useState<WindowSizeData>({\n width: undefined,\n height: undefined,\n });\n\n useLayoutEffect(() => {\n // Handler to call on window resize\n function handleResize() {\n // Set window width/height to state\n setWindowSize({\n width: global.innerWidth,\n height: global.innerHeight,\n });\n }\n\n // Add event listener\n global.addEventListener('resize', handleResize);\n\n // Call handler right away so state gets updated with initial window size\n handleResize();\n\n // Remove event listener on cleanup\n return () => global.removeEventListener('resize', handleResize);\n }, []); // Empty array ensures that effect is only run on mount\n\n return windowSize;\n}\n\nexport default useWindowSize;\n"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,eAAe,QAAQ,OAAO;AAOjD,SAASC,aAAaA,CAAA,EAAmB;EACvC;EACA;EACA,MAAM,CAACC,UAAU,EAAEC,aAAa,CAAC,GAAGJ,QAAQ,CAAiB;IAC3DK,KAAK,EAAEC,SAAS;IAChBC,MAAM,EAAED;EACV,CAAC,CAAC;EAEFL,eAAe,CAAC,MAAM;IACpB;IACA,SAASO,YAAYA,CAAA,EAAG;MACtB;MACAJ,aAAa,CAAC;QACZC,KAAK,EAAEI,MAAM,CAACC,UAAU;QACxBH,MAAM,EAAEE,MAAM,CAACE;MACjB,CAAC,CAAC;IACJ;;IAEA;IACAF,MAAM,CAACG,gBAAgB,CAAC,QAAQ,EAAEJ,YAAY,CAAC;;IAE/C;IACAA,YAAY,CAAC,CAAC;;IAEd;IACA,OAAO,MAAMC,MAAM,CAACI,mBAAmB,CAAC,QAAQ,EAAEL,YAAY,CAAC;EACjE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;;EAER,OAAOL,UAAU;AACnB;AAEA,eAAeD,aAAa","ignoreList":[]}
package/dist/index.d.ts CHANGED
@@ -40,6 +40,11 @@ export { default as ModalLayer } from './Modal/ModalLayer';
40
40
  export { default as Overlay, OverlayTrigger } from './Overlay';
41
41
  export { default as Portal } from './Modal/Portal';
42
42
  export { default as Tooltip } from './Tooltip';
43
+ export { default as useWindowSize, type WindowSizeData } from './hooks/useWindowSize';
44
+ export { default as useToggle, type Toggler, type ToggleHandlers } from './hooks/useToggle';
45
+ export { default as useArrowKeyNavigation, type ArrowKeyNavProps } from './hooks/useArrowKeyNavigation';
46
+ export { default as useIndexOfLastVisibleChild } from './hooks/useIndexOfLastVisibleChild';
47
+ export { default as useIsVisible } from './hooks/useIsVisible';
43
48
 
44
49
  // // // // // // // // // // // // // // // // // // // // // // // // // // //
45
50
  // Things that don't have types
@@ -187,11 +192,6 @@ export const Sticky: any; // from './Sticky';
187
192
  export const SelectableBox: any; // from './SelectableBox';
188
193
  export const breakpoints: any; // from './utils/breakpoints';
189
194
  export const Variant: any; // from './utils/constants';
190
- export const useWindowSize: any; // from './hooks/useWindowSize';
191
- export const useToggle: any; // from './hooks/useToggle';
192
- export const useArrowKeyNavigation: any; // from './hooks/useArrowKeyNavigation';
193
- export const useIndexOfLastVisibleChild: any; // from './hooks/useIndexOfLastVisibleChild';
194
- export const useIsVisible: any; // from './hooks/useIsVisible';
195
195
  export const
196
196
  OverflowScrollContext: any,
197
197
  OverflowScroll: any,
package/dist/index.js CHANGED
@@ -40,6 +40,11 @@ export { default as ModalLayer } from './Modal/ModalLayer';
40
40
  export { default as Overlay, OverlayTrigger } from './Overlay';
41
41
  export { default as Portal } from './Modal/Portal';
42
42
  export { default as Tooltip } from './Tooltip';
43
+ export { default as useWindowSize } from './hooks/useWindowSize';
44
+ export { default as useToggle } from './hooks/useToggle';
45
+ export { default as useArrowKeyNavigation } from './hooks/useArrowKeyNavigation';
46
+ export { default as useIndexOfLastVisibleChild } from './hooks/useIndexOfLastVisibleChild';
47
+ export { default as useIsVisible } from './hooks/useIsVisible';
43
48
 
44
49
  // // // // // // // // // // // // // // // // // // // // // // // // // // //
45
50
  // Things that don't have types
@@ -187,11 +192,6 @@ export { default as Sticky } from './Sticky';
187
192
  export { default as SelectableBox } from './SelectableBox';
188
193
  export { default as breakpoints } from './utils/breakpoints';
189
194
  export { default as Variant } from './utils/constants';
190
- export { default as useWindowSize } from './hooks/useWindowSize';
191
- export { default as useToggle } from './hooks/useToggle';
192
- export { default as useArrowKeyNavigation } from './hooks/useArrowKeyNavigation';
193
- export { default as useIndexOfLastVisibleChild } from './hooks/useIndexOfLastVisibleChild';
194
- export { default as useIsVisible } from './hooks/useIsVisible';
195
195
  export {
196
196
  OverflowScrollContext,
197
197
  OverflowScroll,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openedx/paragon",
3
- "version": "22.11.2",
3
+ "version": "22.13.0",
4
4
  "description": "Accessible, responsive UI component library based on Bootstrap.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -0,0 +1 @@
1
+ export const cardSrcFallbackImg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXwAAACMCAYAAAB/AhJnAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAH6SURBVHgB7dRBEYBADACxwuDf5j0QUXywiYhc7zk7APzd3gNAgvABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIoQPECF8gAjhA0QIHyBC+AARwgeIED5AhPABIp4BaNpp2Q/3/wfPkGyXOQAAAABJRU5ErkJggg==';
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import classNames from 'classnames';
4
4
  import Skeleton from 'react-loading-skeleton';
5
5
  import CardContext from './CardContext';
6
- import cardSrcFallbackImg from './fallback-default.png';
6
+ import { cardSrcFallbackImg } from './CardFallbackDefaultImage';
7
7
 
8
8
  const SKELETON_HEIGHT_VALUE = 140;
9
9
  const LOGO_SKELETON_HEIGHT_VALUE = 41;
@@ -3,6 +3,7 @@ import renderer from 'react-test-renderer';
3
3
  import { render, fireEvent, screen } from '@testing-library/react';
4
4
  import CardImageCap from '../CardImageCap';
5
5
  import CardContext from '../CardContext';
6
+ import { cardSrcFallbackImg } from '../CardFallbackDefaultImage';
6
7
 
7
8
  // eslint-disable-next-line react/prop-types
8
9
  function CardImageCapWrapper({ orientation = 'vertical', isLoading, ...props }) {
@@ -119,13 +120,12 @@ describe('<CardImageCap />', () => {
119
120
  expect(logoImg.className).toEqual('pgn__card-logo-cap');
120
121
  });
121
122
 
122
- it('hiding component if it isn`t fallbackSrc and src don`t work', () => {
123
+ it('renders the default image if both src and fallbackSrc fail to load', () => {
123
124
  render(<CardImageCapWrapper src="fakeURL" fallbackSrc="fakeURL" srcAlt="Src alt text" />);
124
125
 
125
126
  const srcImg = screen.getByAltText('Src alt text');
126
127
  fireEvent.load(srcImg);
127
128
  fireEvent.error(srcImg);
128
- // test-file-stub is what our fileMock.js returns for all images
129
- expect(srcImg.src.endsWith('test-file-stub')).toEqual(true);
129
+ expect(srcImg.src).toEqual(cardSrcFallbackImg);
130
130
  });
131
131
  });
@@ -12,8 +12,8 @@ window.ResizeObserver = window.ResizeObserver
12
12
  }));
13
13
 
14
14
  function TestComponent() {
15
- const [containerElementRef, setContainerElementRef] = React.useState(null);
16
- const overflowElementRef = React.useRef(null);
15
+ const [containerElementRef, setContainerElementRef] = React.useState<HTMLDivElement | null>(null);
16
+ const overflowElementRef = React.useRef<HTMLDivElement>(null);
17
17
  const indexOfLastVisibleChild = useIndexOfLastVisibleChild(containerElementRef, overflowElementRef.current);
18
18
 
19
19
  return (
@@ -4,6 +4,7 @@ import { render, screen } from '@testing-library/react';
4
4
  import userEvent from '@testing-library/user-event';
5
5
 
6
6
  import { useToggle } from '../..';
7
+ import { ToggleHandlers } from '../useToggle';
7
8
 
8
9
  const TOGGLE_IS_ON = 'on';
9
10
  const TOGGLE_IS_OFF = 'off';
@@ -19,7 +20,7 @@ const resetHandlerMocks = () => {
19
20
  };
20
21
 
21
22
  // eslint-disable-next-line react/prop-types
22
- function FakeComponent({ defaultIsOn, handlers }) {
23
+ function FakeComponent({ defaultIsOn, handlers }: { defaultIsOn: boolean, handlers: ToggleHandlers }) {
23
24
  const [isOn, setOn, setOff, toggle] = useToggle(defaultIsOn, handlers);
24
25
 
25
26
  return (
@@ -1,16 +1,24 @@
1
1
  import { useRef, useEffect } from 'react';
2
2
 
3
- /**
4
- * A React hook to enable arrow key navigation on a component.
5
- */
3
+ interface HandleEnterArgs {
4
+ event: KeyboardEvent;
5
+ currentIndex: number;
6
+ activeElement: HTMLElement;
7
+ }
6
8
 
7
- function handleEnter({ event, currentIndex, activeElement }) {
9
+ function handleEnter({ event, currentIndex, activeElement }: HandleEnterArgs) {
8
10
  if (currentIndex === -1) { return; }
9
11
  activeElement.click();
10
12
  event.preventDefault();
11
13
  }
12
14
 
13
- function handleArrowKey({ event, currentIndex, availableElements }) {
15
+ interface HandleArrowKeyArgs {
16
+ event: KeyboardEvent;
17
+ currentIndex: number;
18
+ availableElements: NodeListOf<HTMLElement>;
19
+ }
20
+
21
+ function handleArrowKey({ event, currentIndex, availableElements }: HandleArrowKeyArgs) {
14
22
  // If the focus isn't in the container, focus on the first thing
15
23
  if (currentIndex === -1) { availableElements[0].focus(); }
16
24
 
@@ -36,6 +44,13 @@ function handleArrowKey({ event, currentIndex, availableElements }) {
36
44
  event.preventDefault();
37
45
  }
38
46
 
47
+ interface HandleEventsArgs {
48
+ event: KeyboardEvent;
49
+ ignoredKeys?: string[];
50
+ parentNode: HTMLElement | undefined;
51
+ selectors?: string;
52
+ }
53
+
39
54
  /**
40
55
  * Implement arrow key navigation for the given parentNode
41
56
  */
@@ -44,7 +59,7 @@ function handleEvents({
44
59
  ignoredKeys = [],
45
60
  parentNode,
46
61
  selectors = 'a,button,input',
47
- }) {
62
+ }: HandleEventsArgs) {
48
63
  if (!parentNode) { return; }
49
64
 
50
65
  const { key } = event;
@@ -60,7 +75,7 @@ function handleEvents({
60
75
  if (!parentNode.contains(activeElement)) { return; }
61
76
 
62
77
  // Get the list of elements we're allowed to scroll through
63
- const availableElements = parentNode.querySelectorAll(selectors);
78
+ const availableElements = parentNode.querySelectorAll<HTMLElement>(selectors);
64
79
 
65
80
  // No elements are available to loop through.
66
81
  if (!availableElements.length) { return; }
@@ -70,18 +85,27 @@ function handleEvents({
70
85
  (availableElement) => availableElement === activeElement,
71
86
  );
72
87
 
73
- if (key === 'Enter') {
74
- handleEnter({ event, currentIndex, activeElement });
88
+ if (key === 'Enter' && activeElement) {
89
+ handleEnter({ event, currentIndex, activeElement: activeElement as HTMLElement });
75
90
  }
76
91
  handleArrowKey({ event, currentIndex, availableElements });
77
92
  }
78
93
 
79
- export default function useArrowKeyNavigation(props) {
80
- const { selectors, ignoredKeys } = props || {};
81
- const parentNode = useRef();
94
+ export interface ArrowKeyNavProps {
95
+ /** e.g. 'a,button,input' */
96
+ selectors?: string;
97
+ ignoredKeys?: string[];
98
+ }
99
+
100
+ /**
101
+ * A React hook to enable arrow key navigation on a component.
102
+ */
103
+ export default function useArrowKeyNavigation(props: ArrowKeyNavProps = {}) {
104
+ const { selectors, ignoredKeys } = props;
105
+ const parentNode = useRef<HTMLElement>();
82
106
 
83
107
  useEffect(() => {
84
- const eventHandler = (event) => {
108
+ const eventHandler = (event: KeyboardEvent) => {
85
109
  handleEvents({
86
110
  event, ignoredKeys, parentNode: parentNode.current, selectors,
87
111
  });
@@ -5,25 +5,32 @@ import { useLayoutEffect, useState } from 'react';
5
5
  * that fits within its bounding rectangle. This is done by summing the widths
6
6
  * of the children until they exceed the width of the container.
7
7
  *
8
- * @param {Element} containerElementRef - container element
9
- * @param {Element} overflowElementRef - overflow element
10
- *
11
8
  * The hook returns the index of the last visible child.
9
+ *
10
+ * @param containerElementRef - container element
11
+ * @param overflowElementRef - overflow element
12
12
  */
13
- const useIndexOfLastVisibleChild = (containerElementRef, overflowElementRef) => {
13
+ const useIndexOfLastVisibleChild = (
14
+ containerElementRef: HTMLElement | null,
15
+ overflowElementRef: HTMLElement | null,
16
+ ): number => {
14
17
  const [indexOfLastVisibleChild, setIndexOfLastVisibleChild] = useState(-1);
15
18
 
16
19
  useLayoutEffect(() => {
20
+ if (!containerElementRef) {
21
+ return undefined;
22
+ }
23
+
17
24
  function updateLastVisibleChildIndex() {
18
25
  // Get array of child nodes from NodeList form
19
- const childNodesArr = Array.prototype.slice.call(containerElementRef.children);
26
+ const childNodesArr = Array.prototype.slice.call(containerElementRef!.children);
20
27
  const { nextIndexOfLastVisibleChild } = childNodesArr
21
28
  // filter out the overflow element
22
29
  .filter(childNode => childNode !== overflowElementRef)
23
30
  // sum the widths to find the last visible element's index
24
31
  .reduce((acc, childNode, index) => {
25
32
  acc.sumWidth += childNode.getBoundingClientRect().width;
26
- if (acc.sumWidth <= containerElementRef.getBoundingClientRect().width) {
33
+ if (acc.sumWidth <= containerElementRef!.getBoundingClientRect().width) {
27
34
  acc.nextIndexOfLastVisibleChild = index;
28
35
  }
29
36
  return acc;
@@ -32,23 +39,18 @@ const useIndexOfLastVisibleChild = (containerElementRef, overflowElementRef) =>
32
39
  // sometimes we'll show a dropdown with one item in it when it would fit,
33
40
  // but allowing this case dramatically simplifies the calculations we need
34
41
  // to do above.
35
- sumWidth: overflowElementRef ? overflowElementRef.getBoundingClientRect().width : 0,
42
+ sumWidth: overflowElementRef?.getBoundingClientRect().width ?? 0,
36
43
  nextIndexOfLastVisibleChild: -1,
37
44
  });
38
45
 
39
46
  setIndexOfLastVisibleChild(nextIndexOfLastVisibleChild);
40
47
  }
41
48
 
42
- if (containerElementRef) {
43
- updateLastVisibleChildIndex();
44
-
45
- const resizeObserver = new ResizeObserver(() => updateLastVisibleChildIndex());
46
- resizeObserver.observe(containerElementRef);
47
-
48
- return () => resizeObserver.disconnect();
49
- }
49
+ updateLastVisibleChildIndex();
50
50
 
51
- return undefined;
51
+ const resizeObserver = new ResizeObserver(() => updateLastVisibleChildIndex());
52
+ resizeObserver.observe(containerElementRef);
53
+ return () => resizeObserver.disconnect();
52
54
  }, [containerElementRef, overflowElementRef]);
53
55
 
54
56
  return indexOfLastVisibleChild;
@@ -1,7 +1,10 @@
1
- import { useRef, useState, useEffect } from 'react';
1
+ import React, { useRef, useState, useEffect } from 'react';
2
2
 
3
- const useIsVisible = (defaultIsVisible = true) => {
4
- const sentinelRef = useRef();
3
+ const useIsVisible = (defaultIsVisible = true): [
4
+ isVisible: boolean,
5
+ sentinelRef: React.MutableRefObject<HTMLElement | null>,
6
+ ] => {
7
+ const sentinelRef = useRef<HTMLElement | null>(null);
5
8
  const [isVisible, setIsVisible] = useState(defaultIsVisible);
6
9
 
7
10
  useEffect(() => {
@@ -0,0 +1,38 @@
1
+ import { useState, useCallback } from 'react';
2
+
3
+ export type Toggler = [
4
+ isOn: boolean,
5
+ setOn: () => void,
6
+ setOff: () => void,
7
+ toggle: () => void,
8
+ ];
9
+
10
+ export interface ToggleHandlers {
11
+ handleToggleOn?: () => void;
12
+ handleToggleOff?: () => void;
13
+ handleToggle?: (newStatus: boolean) => void;
14
+ }
15
+
16
+ export default function useToggle(defaultIsOn = false, handlers: ToggleHandlers = {}): Toggler {
17
+ const { handleToggleOn, handleToggleOff, handleToggle } = handlers;
18
+ const [isOn, setIsOn] = useState(defaultIsOn);
19
+
20
+ const setOn = useCallback(() => {
21
+ setIsOn(true);
22
+ handleToggleOn?.();
23
+ handleToggle?.(true);
24
+ }, [handleToggleOn, handleToggle]);
25
+
26
+ const setOff = useCallback(() => {
27
+ setIsOn(false);
28
+ handleToggleOff?.();
29
+ handleToggle?.(false);
30
+ }, [handleToggleOff, handleToggle]);
31
+
32
+ const toggle = useCallback(() => {
33
+ const doToggle = isOn ? setOff : setOn;
34
+ doToggle();
35
+ }, [isOn, setOn, setOff]);
36
+
37
+ return [isOn, setOn, setOff, toggle];
38
+ }
@@ -1,9 +1,14 @@
1
1
  import { useState, useLayoutEffect } from 'react';
2
2
 
3
- function useWindowSize() {
3
+ export interface WindowSizeData {
4
+ width: number | undefined;
5
+ height: number | undefined;
6
+ }
7
+
8
+ function useWindowSize(): WindowSizeData {
4
9
  // Initialize state with undefined width/height so server and client renders match
5
10
  // Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
6
- const [windowSize, setWindowSize] = useState({
11
+ const [windowSize, setWindowSize] = useState<WindowSizeData>({
7
12
  width: undefined,
8
13
  height: undefined,
9
14
  });
package/src/index.d.ts CHANGED
@@ -40,6 +40,11 @@ export { default as ModalLayer } from './Modal/ModalLayer';
40
40
  export { default as Overlay, OverlayTrigger } from './Overlay';
41
41
  export { default as Portal } from './Modal/Portal';
42
42
  export { default as Tooltip } from './Tooltip';
43
+ export { default as useWindowSize, type WindowSizeData } from './hooks/useWindowSize';
44
+ export { default as useToggle, type Toggler, type ToggleHandlers } from './hooks/useToggle';
45
+ export { default as useArrowKeyNavigation, type ArrowKeyNavProps } from './hooks/useArrowKeyNavigation';
46
+ export { default as useIndexOfLastVisibleChild } from './hooks/useIndexOfLastVisibleChild';
47
+ export { default as useIsVisible } from './hooks/useIsVisible';
43
48
 
44
49
  // // // // // // // // // // // // // // // // // // // // // // // // // // //
45
50
  // Things that don't have types
@@ -187,11 +192,6 @@ export const Sticky: any; // from './Sticky';
187
192
  export const SelectableBox: any; // from './SelectableBox';
188
193
  export const breakpoints: any; // from './utils/breakpoints';
189
194
  export const Variant: any; // from './utils/constants';
190
- export const useWindowSize: any; // from './hooks/useWindowSize';
191
- export const useToggle: any; // from './hooks/useToggle';
192
- export const useArrowKeyNavigation: any; // from './hooks/useArrowKeyNavigation';
193
- export const useIndexOfLastVisibleChild: any; // from './hooks/useIndexOfLastVisibleChild';
194
- export const useIsVisible: any; // from './hooks/useIsVisible';
195
195
  export const
196
196
  OverflowScrollContext: any,
197
197
  OverflowScroll: any,
package/src/index.js CHANGED
@@ -40,6 +40,11 @@ export { default as ModalLayer } from './Modal/ModalLayer';
40
40
  export { default as Overlay, OverlayTrigger } from './Overlay';
41
41
  export { default as Portal } from './Modal/Portal';
42
42
  export { default as Tooltip } from './Tooltip';
43
+ export { default as useWindowSize } from './hooks/useWindowSize';
44
+ export { default as useToggle } from './hooks/useToggle';
45
+ export { default as useArrowKeyNavigation } from './hooks/useArrowKeyNavigation';
46
+ export { default as useIndexOfLastVisibleChild } from './hooks/useIndexOfLastVisibleChild';
47
+ export { default as useIsVisible } from './hooks/useIsVisible';
43
48
 
44
49
  // // // // // // // // // // // // // // // // // // // // // // // // // // //
45
50
  // Things that don't have types
@@ -187,11 +192,6 @@ export { default as Sticky } from './Sticky';
187
192
  export { default as SelectableBox } from './SelectableBox';
188
193
  export { default as breakpoints } from './utils/breakpoints';
189
194
  export { default as Variant } from './utils/constants';
190
- export { default as useWindowSize } from './hooks/useWindowSize';
191
- export { default as useToggle } from './hooks/useToggle';
192
- export { default as useArrowKeyNavigation } from './hooks/useArrowKeyNavigation';
193
- export { default as useIndexOfLastVisibleChild } from './hooks/useIndexOfLastVisibleChild';
194
- export { default as useIsVisible } from './hooks/useIsVisible';
195
195
  export {
196
196
  OverflowScrollContext,
197
197
  OverflowScroll,
Binary file
Binary file
@@ -1,37 +0,0 @@
1
- import { useState, useCallback } from 'react';
2
-
3
- export default function useToggle(defaultIsOn, handlers = {}) {
4
- const { handleToggleOn, handleToggleOff, handleToggle } = handlers;
5
- const [isOn, setIsOn] = useState(defaultIsOn || false);
6
-
7
- const setOn = useCallback(() => {
8
- setIsOn(true);
9
- // istanbul ignore else
10
- if (handleToggleOn) {
11
- handleToggleOn();
12
- }
13
- // istanbul ignore else
14
- if (handleToggle) {
15
- handleToggle(true);
16
- }
17
- }, [handleToggleOn, handleToggle]);
18
-
19
- const setOff = useCallback(() => {
20
- setIsOn(false);
21
- // istanbul ignore else
22
- if (handleToggleOff) {
23
- handleToggleOff();
24
- }
25
- // istanbul ignore else
26
- if (handleToggle) {
27
- handleToggle(false);
28
- }
29
- }, [handleToggleOff, handleToggle]);
30
-
31
- const toggle = useCallback(() => {
32
- const doToggle = isOn ? setOff : setOn;
33
- doToggle();
34
- }, [isOn, setOn, setOff]);
35
-
36
- return [isOn, setOn, setOff, toggle];
37
- }