@transferwise/components 0.0.0-experimental-9a61b0a → 0.0.0-experimental-73858ea

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -11,8 +11,9 @@ var formatting = require('@transferwise/formatting');
11
11
  var throttle = require('lodash.throttle');
12
12
  var reactTransitionGroup = require('react-transition-group');
13
13
  var reactDom = require('react-dom');
14
- var neptuneValidation = require('@transferwise/neptune-validation');
14
+ var focus = require('@react-aria/focus');
15
15
  var mergeRefs = require('react-merge-refs');
16
+ var neptuneValidation = require('@transferwise/neptune-validation');
16
17
  var reactPopper = require('react-popper');
17
18
  var react$1 = require('@headlessui/react');
18
19
  var reactId = require('@radix-ui/react-id');
@@ -1490,268 +1491,23 @@ function getInitials(name) {
1490
1491
  return allInitials[0] + allInitials.slice(-1);
1491
1492
  }
1492
1493
 
1493
- const THROTTLE_MS = 100;
1494
- const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
1495
- const useClientWidth = ({
1496
- ref,
1497
- throttleMs = THROTTLE_MS
1498
- }) => {
1499
- const [clientWidth, setClientWidth] = React.useState(null);
1500
- useIsomorphicLayoutEffect(() => {
1501
- // eslint-disable-next-line unicorn/consistent-function-scoping
1502
- const updateClientWidth = () => {
1503
- if (ref) {
1504
- // when `ref` is a window
1505
- if ('innerWidth' in ref) {
1506
- setClientWidth(ref.innerWidth);
1507
- }
1508
- // when `ref` is an element
1509
- else if (ref.current) {
1510
- setClientWidth(ref.current.clientWidth);
1511
- }
1512
- }
1513
- };
1514
- // This assignment saves a reference to the function so it will be the same passed to both addEventListener removeEventListener.
1515
- // If throttle gets passed directly to both add and removeEventListenet the results will be that the event
1516
- // won't get removed even if the component is unmounted.
1517
- const attachedFunction = throttle__default.default(updateClientWidth, throttleMs);
1518
- window.addEventListener('resize', attachedFunction, true);
1519
- // using requestAnimationFrame to perform the calculation before the next repaint
1520
- // getting width earlier causes issues in animations when used with react-transition-group
1521
- window.requestAnimationFrame(updateClientWidth);
1522
- return () => window.removeEventListener('resize', attachedFunction, true);
1523
- }, []);
1524
- return [clientWidth];
1525
- };
1526
- useClientWidth.THROTTLE_MS = THROTTLE_MS;
1527
-
1528
- const useConditionalListener = ({
1529
- attachListener,
1530
- callback,
1531
- eventType,
1532
- parent
1533
- }) => {
1534
- React.useEffect(() => {
1535
- if (attachListener && !neptuneValidation.isUndefined(parent)) {
1536
- parent.addEventListener(eventType, callback, true);
1537
- }
1538
- return () => {
1539
- if (!neptuneValidation.isUndefined(parent)) {
1540
- parent.removeEventListener(eventType, callback, true);
1541
- }
1542
- };
1543
- }, [attachListener, callback, eventType, parent]);
1544
- };
1545
-
1546
- const DirectionContext = /*#__PURE__*/React.createContext(exports.Direction.LTR);
1547
- const DirectionProvider = ({
1548
- direction,
1549
- children
1550
- }) => {
1551
- return /*#__PURE__*/jsxRuntime.jsx(DirectionContext.Provider, {
1552
- value: direction,
1553
- children: children
1554
- });
1555
- };
1556
-
1557
- const useDirection = () => {
1558
- const direction = React.useContext(DirectionContext);
1559
- return {
1560
- direction,
1561
- isRTL: direction === 'rtl'
1562
- };
1563
- };
1564
-
1565
- const ObserverParams = {
1566
- threshold: 0.1
1567
- };
1568
-
1569
- /**
1570
- * useHasIntersected.
1571
- * Use this custom hook to detect when an element has became visible inside the viewport. This hook checks only if the intersection happend.
1572
- * Once the intersection has happened the hook will not return false even if the element gets out of the viewport.
1573
- *
1574
- * @param elRef.elRef
1575
- * @param {object} [elRef] - node object that contains a react reference to the element that needs to be observed.
1576
- * @param {strimng} [loading = 'eager'] - string that contains the type of loading.
1577
- * @param elRef.loading
1578
- * @usage `const [hasIntersected] = useHasIntersected({imageRef,loading});`
1579
- */
1580
- const useHasIntersected = ({
1581
- elRef,
1582
- loading
1583
- }) => {
1584
- const [hasIntersected, setHasIntersected] = React.useState(false);
1585
- const {
1586
- current
1587
- } = elRef || {};
1588
- const isValidReference = () => {
1589
- return elRef && current;
1590
- };
1591
- const handleOnIntersect = (entries, observer) => {
1592
- entries.forEach(entry => {
1593
- if (entry.isIntersecting) {
1594
- setHasIntersected(true);
1595
- observer.unobserve(current);
1596
- }
1597
- });
1598
- };
1599
- React.useEffect(() => {
1600
- let observer;
1601
- let didCancel = false;
1602
-
1603
- // Check if window is define for SSR and Old browsers fallback
1604
- if (typeof window === 'undefined' || !window.IntersectionObserver || !isValidReference()) {
1605
- setHasIntersected(true);
1606
- } else if (!didCancel) {
1607
- observer = new IntersectionObserver(handleOnIntersect, ObserverParams);
1608
- observer.observe(current);
1609
- }
1610
- return () => {
1611
- didCancel = true;
1612
- if (observer) {
1613
- observer.unobserve(current);
1614
- }
1615
- };
1616
- }, [elRef]);
1617
- if (loading === 'eager') {
1618
- return [false];
1619
- }
1620
- return [hasIntersected];
1621
- };
1622
-
1623
- const useLayout = () => {
1624
- const windowReference = typeof window === 'undefined' ? undefined : window;
1625
- const [breakpoint, setBreakpoint] = React.useState();
1626
- const [clientWidth] = useClientWidth({
1627
- ref: windowReference
1628
- });
1629
- React.useEffect(() => {
1630
- if (!clientWidth) {
1631
- return;
1632
- }
1633
- if (clientWidth <= exports.Breakpoint.EXTRA_SMALL) {
1634
- setBreakpoint(exports.Breakpoint.EXTRA_SMALL);
1635
- return;
1636
- }
1637
- if (exports.Breakpoint.EXTRA_SMALL < clientWidth && clientWidth <= exports.Breakpoint.SMALL) {
1638
- setBreakpoint(exports.Breakpoint.SMALL);
1639
- return;
1640
- }
1641
- if (exports.Breakpoint.SMALL < clientWidth && clientWidth <= exports.Breakpoint.MEDIUM) {
1642
- setBreakpoint(exports.Breakpoint.MEDIUM);
1643
- return;
1644
- }
1645
- if (exports.Breakpoint.MEDIUM < clientWidth && clientWidth <= exports.Breakpoint.LARGE) {
1646
- setBreakpoint(exports.Breakpoint.LARGE);
1647
- return;
1648
- }
1649
- if (exports.Breakpoint.LARGE < clientWidth) {
1650
- setBreakpoint(exports.Breakpoint.EXTRA_LARGE);
1651
- }
1652
- }, [clientWidth]);
1653
- return {
1654
- isMobile: !!breakpoint && [exports.Breakpoint.EXTRA_SMALL, exports.Breakpoint.SMALL].includes(breakpoint),
1655
- isExtraSmall: breakpoint === exports.Breakpoint.EXTRA_SMALL,
1656
- isSmall: breakpoint === exports.Breakpoint.SMALL,
1657
- isMedium: breakpoint === exports.Breakpoint.MEDIUM,
1658
- isLarge: breakpoint === exports.Breakpoint.LARGE,
1659
- isExtraLarge: breakpoint === exports.Breakpoint.EXTRA_LARGE
1660
- };
1661
- };
1662
-
1663
- /**
1664
- * This function returns the first and the last focusable elements within a node.
1665
- *
1666
- * @param {Node} focusBoundaryContainer - the area that contains focused elements.
1667
- * @returns {object} focusableEls - which contains the first focusable element and the last focusable element. First and last can be the same element if area contains one or none focusable element.
1668
- */
1669
-
1670
- const getFocusableElements = focusBoundaryContainer => {
1671
- const focusableEls = {
1672
- first: focusBoundaryContainer,
1673
- last: focusBoundaryContainer
1674
- };
1675
- if (focusBoundaryContainer?.querySelectorAll) {
1676
- const allEls = [...focusBoundaryContainer.querySelectorAll('a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])')].filter(element => !element.hasAttribute('disabled'));
1677
- if (allEls.length > 0) {
1678
- [focusableEls.first] = allEls;
1679
- focusableEls.last = allEls[allEls.length - 1];
1680
- }
1681
- }
1682
- return focusableEls;
1683
- };
1684
-
1685
- /**
1686
- * This function resets the focus to either last of first focusable elements within a node.
1687
- *
1688
- * @param {object} focusableEls - contains the first last of first focusable elements within a node.
1689
- * @param {object} event - the triggered event
1690
- */
1691
-
1692
- const resetFocus = ({
1693
- focusableEls: {
1694
- first,
1695
- last
1696
- },
1697
- event
1698
- }) => {
1699
- const {
1700
- activeElement
1701
- } = document;
1702
- if (event.shiftKey && activeElement === first) {
1703
- if (last) {
1704
- last.focus();
1705
- }
1706
- event.preventDefault();
1707
- }
1708
- if (!event.shiftKey && activeElement === last) {
1709
- if (first) {
1710
- first.focus();
1711
- }
1712
- event.preventDefault();
1713
- }
1714
- };
1715
-
1716
- const {
1717
- TAB
1718
- } = Key;
1719
1494
  const FocusBoundary = ({
1720
1495
  children
1721
1496
  }) => {
1722
- const boundaryReference = React.useRef(null);
1723
- const parent = neptuneValidation.isUndefined(document) ? undefined : document;
1724
- const [focusableEls, setFocusableEls] = React.useState({});
1497
+ const wrapperReference = React.useRef(null);
1725
1498
  React.useEffect(() => {
1726
- if (boundaryReference?.current) {
1727
- boundaryReference.current.focus({
1728
- preventScroll: true
1729
- });
1730
- setFocusableEls(getFocusableElements(boundaryReference.current));
1731
- }
1499
+ wrapperReference.current?.focus({
1500
+ preventScroll: true
1501
+ });
1732
1502
  }, []);
1733
- // If event type is Tab the resetFocus will force the focus to either the first focusable or last in boundaryRef .
1734
- useConditionalListener({
1735
- eventType: 'keydown',
1736
- callback: event => {
1737
- if (neptuneValidation.isKey({
1738
- keyType: TAB,
1739
- event
1740
- })) {
1741
- resetFocus({
1742
- event,
1743
- focusableEls
1744
- });
1745
- }
1746
- },
1747
- attachListener: true,
1748
- parent
1749
- });
1750
1503
  return /*#__PURE__*/jsxRuntime.jsx("div", {
1751
- ref: boundaryReference,
1504
+ ref: wrapperReference,
1752
1505
  tabIndex: -1,
1753
- className: "np-focus-boundary outline-none",
1754
- children: children
1506
+ children: /*#__PURE__*/jsxRuntime.jsx(focus.FocusScope, {
1507
+ contain: true,
1508
+ restoreFocus: true,
1509
+ children: children
1510
+ })
1755
1511
  });
1756
1512
  };
1757
1513
  var FocusBoundary$1 = FocusBoundary;
@@ -2007,6 +1763,176 @@ SlidingPanel.defaultProps = {
2007
1763
  };
2008
1764
  var SlidingPanel$1 = SlidingPanel;
2009
1765
 
1766
+ const THROTTLE_MS = 100;
1767
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
1768
+ const useClientWidth = ({
1769
+ ref,
1770
+ throttleMs = THROTTLE_MS
1771
+ }) => {
1772
+ const [clientWidth, setClientWidth] = React.useState(null);
1773
+ useIsomorphicLayoutEffect(() => {
1774
+ // eslint-disable-next-line unicorn/consistent-function-scoping
1775
+ const updateClientWidth = () => {
1776
+ if (ref) {
1777
+ // when `ref` is a window
1778
+ if ('innerWidth' in ref) {
1779
+ setClientWidth(ref.innerWidth);
1780
+ }
1781
+ // when `ref` is an element
1782
+ else if (ref.current) {
1783
+ setClientWidth(ref.current.clientWidth);
1784
+ }
1785
+ }
1786
+ };
1787
+ // This assignment saves a reference to the function so it will be the same passed to both addEventListener removeEventListener.
1788
+ // If throttle gets passed directly to both add and removeEventListenet the results will be that the event
1789
+ // won't get removed even if the component is unmounted.
1790
+ const attachedFunction = throttle__default.default(updateClientWidth, throttleMs);
1791
+ window.addEventListener('resize', attachedFunction, true);
1792
+ // using requestAnimationFrame to perform the calculation before the next repaint
1793
+ // getting width earlier causes issues in animations when used with react-transition-group
1794
+ window.requestAnimationFrame(updateClientWidth);
1795
+ return () => window.removeEventListener('resize', attachedFunction, true);
1796
+ }, []);
1797
+ return [clientWidth];
1798
+ };
1799
+ useClientWidth.THROTTLE_MS = THROTTLE_MS;
1800
+
1801
+ const useConditionalListener = ({
1802
+ attachListener,
1803
+ callback,
1804
+ eventType,
1805
+ parent
1806
+ }) => {
1807
+ React.useEffect(() => {
1808
+ if (attachListener && !neptuneValidation.isUndefined(parent)) {
1809
+ parent.addEventListener(eventType, callback, true);
1810
+ }
1811
+ return () => {
1812
+ if (!neptuneValidation.isUndefined(parent)) {
1813
+ parent.removeEventListener(eventType, callback, true);
1814
+ }
1815
+ };
1816
+ }, [attachListener, callback, eventType, parent]);
1817
+ };
1818
+
1819
+ const DirectionContext = /*#__PURE__*/React.createContext(exports.Direction.LTR);
1820
+ const DirectionProvider = ({
1821
+ direction,
1822
+ children
1823
+ }) => {
1824
+ return /*#__PURE__*/jsxRuntime.jsx(DirectionContext.Provider, {
1825
+ value: direction,
1826
+ children: children
1827
+ });
1828
+ };
1829
+
1830
+ const useDirection = () => {
1831
+ const direction = React.useContext(DirectionContext);
1832
+ return {
1833
+ direction,
1834
+ isRTL: direction === 'rtl'
1835
+ };
1836
+ };
1837
+
1838
+ const ObserverParams = {
1839
+ threshold: 0.1
1840
+ };
1841
+
1842
+ /**
1843
+ * useHasIntersected.
1844
+ * Use this custom hook to detect when an element has became visible inside the viewport. This hook checks only if the intersection happend.
1845
+ * Once the intersection has happened the hook will not return false even if the element gets out of the viewport.
1846
+ *
1847
+ * @param elRef.elRef
1848
+ * @param {object} [elRef] - node object that contains a react reference to the element that needs to be observed.
1849
+ * @param {strimng} [loading = 'eager'] - string that contains the type of loading.
1850
+ * @param elRef.loading
1851
+ * @usage `const [hasIntersected] = useHasIntersected({imageRef,loading});`
1852
+ */
1853
+ const useHasIntersected = ({
1854
+ elRef,
1855
+ loading
1856
+ }) => {
1857
+ const [hasIntersected, setHasIntersected] = React.useState(false);
1858
+ const {
1859
+ current
1860
+ } = elRef || {};
1861
+ const isValidReference = () => {
1862
+ return elRef && current;
1863
+ };
1864
+ const handleOnIntersect = (entries, observer) => {
1865
+ entries.forEach(entry => {
1866
+ if (entry.isIntersecting) {
1867
+ setHasIntersected(true);
1868
+ observer.unobserve(current);
1869
+ }
1870
+ });
1871
+ };
1872
+ React.useEffect(() => {
1873
+ let observer;
1874
+ let didCancel = false;
1875
+
1876
+ // Check if window is define for SSR and Old browsers fallback
1877
+ if (typeof window === 'undefined' || !window.IntersectionObserver || !isValidReference()) {
1878
+ setHasIntersected(true);
1879
+ } else if (!didCancel) {
1880
+ observer = new IntersectionObserver(handleOnIntersect, ObserverParams);
1881
+ observer.observe(current);
1882
+ }
1883
+ return () => {
1884
+ didCancel = true;
1885
+ if (observer) {
1886
+ observer.unobserve(current);
1887
+ }
1888
+ };
1889
+ }, [elRef]);
1890
+ if (loading === 'eager') {
1891
+ return [false];
1892
+ }
1893
+ return [hasIntersected];
1894
+ };
1895
+
1896
+ const useLayout = () => {
1897
+ const windowReference = typeof window === 'undefined' ? undefined : window;
1898
+ const [breakpoint, setBreakpoint] = React.useState();
1899
+ const [clientWidth] = useClientWidth({
1900
+ ref: windowReference
1901
+ });
1902
+ React.useEffect(() => {
1903
+ if (!clientWidth) {
1904
+ return;
1905
+ }
1906
+ if (clientWidth <= exports.Breakpoint.EXTRA_SMALL) {
1907
+ setBreakpoint(exports.Breakpoint.EXTRA_SMALL);
1908
+ return;
1909
+ }
1910
+ if (exports.Breakpoint.EXTRA_SMALL < clientWidth && clientWidth <= exports.Breakpoint.SMALL) {
1911
+ setBreakpoint(exports.Breakpoint.SMALL);
1912
+ return;
1913
+ }
1914
+ if (exports.Breakpoint.SMALL < clientWidth && clientWidth <= exports.Breakpoint.MEDIUM) {
1915
+ setBreakpoint(exports.Breakpoint.MEDIUM);
1916
+ return;
1917
+ }
1918
+ if (exports.Breakpoint.MEDIUM < clientWidth && clientWidth <= exports.Breakpoint.LARGE) {
1919
+ setBreakpoint(exports.Breakpoint.LARGE);
1920
+ return;
1921
+ }
1922
+ if (exports.Breakpoint.LARGE < clientWidth) {
1923
+ setBreakpoint(exports.Breakpoint.EXTRA_LARGE);
1924
+ }
1925
+ }, [clientWidth]);
1926
+ return {
1927
+ isMobile: !!breakpoint && [exports.Breakpoint.EXTRA_SMALL, exports.Breakpoint.SMALL].includes(breakpoint),
1928
+ isExtraSmall: breakpoint === exports.Breakpoint.EXTRA_SMALL,
1929
+ isSmall: breakpoint === exports.Breakpoint.SMALL,
1930
+ isMedium: breakpoint === exports.Breakpoint.MEDIUM,
1931
+ isLarge: breakpoint === exports.Breakpoint.LARGE,
1932
+ isExtraLarge: breakpoint === exports.Breakpoint.EXTRA_LARGE
1933
+ };
1934
+ };
1935
+
2010
1936
  const INITIAL_Y_POSITION = 0;
2011
1937
  const CONTENT_SCROLL_THRESHOLD = 1;
2012
1938
  const MOVE_OFFSET_THRESHOLD = 50;