All files / packages/design-system/ui/components/breadcrumbs index.react.jsx

32% Statements 8/25
46.15% Branches 6/13
0% Functions 0/5
33.33% Lines 8/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114                          9x 9x 9x 9x                                                                   9x                                                                   4x                       4x                           2x      
// Copyright (c) 2015-present, salesforce.com, inc. All rights reserved
// Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license
 
import React, { useRef } from 'react';
import classNames from 'classnames';
 
const Crumb = ({
  children,
  className,
  hasMenu,
  kxScopeBreadcrumbsItem,
  kxTypeUnderline
}) => {
  const pointerRef = { current: { offsetX: '50%', offsetY: '50%' } };
  const breadCrumbRef = useRef();
  const requestRef = { current: null };
  const previousTimeRef = { current: null };
 
  const setCoordProps = element => {
    const { offsetX } = pointerRef.current;
    element.style.setProperty(
      '--slds-kx-breadcrumbs-pointer-position-x',
      `${offsetX}px`
    );
  };
 
  const handleMove = ({ offsetX, offsetY }) => {
    pointerRef.current = { offsetX, offsetY };
  };
 
  const handleEnter = () => {
    requestRef.current = window.requestAnimationFrame(timestamp => {
      animate(timestamp, breadCrumbRef.current);
    });
    breadCrumbRef.current.addEventListener('mousemove', handleMove);
  };
 
  const handleLeave = () => {
    window.cancelAnimationFrame(requestRef.current);
    breadCrumbRef.current.removeEventListener('mousemove', handleMove);
  };
 
  const animate = (timestamp, element) => {
    if (previousTimeRef.current !== undefined) setCoordProps(element);
    previousTimeRef.current = timestamp;
    requestRef.current = window.requestAnimationFrame(timestamp => {
      animate(timestamp, element);
    });
  };
 
  return (
    <li
      className={classNames('slds-breadcrumb__item', className)}
      {...kxTypeUnderline && {
        'kx-type': 'underline'
      }}
      {...kxScopeBreadcrumbsItem && { 'kx-scope': 'breadcrumbs-item' }}
    >
      {hasMenu ? (
        children
      ) : (
        <a
          ref={breadCrumbRef}
          href="#"
          onClick={e => e.preventDefault()}
          {...kxScopeBreadcrumbsItem &&
            kxTypeUnderline && {
              onMouseEnter: handleEnter,
              onMouseLeave: handleLeave
            }}
        >
          {children}
        </a>
      )}
    </li>
  );
};
 
const BreadCrumbs = ({
  children,
  kxScopeBreadcrumbsItem,
  kxTypeUnderline,
  listClassNames
}) => {
  const kineticsChildren = crumbs =>
    React.Children.map(crumbs, child => {
      // checking isValidElement is the safe way and avoids a typescript error too
      if (React.isValidElement(child)) {
        return React.cloneElement(child, {
          kxScopeBreadcrumbsItem,
          kxTypeUnderline
        });
      }
      return child;
    });
 
  return (
    <nav role="navigation" aria-label="Breadcrumbs">
      <ol
        className={classNames(
          'slds-breadcrumb slds-list_horizontal slds-wrap',
          listClassNames
        )}
      >
        {kxScopeBreadcrumbsItem ? kineticsChildren(children) : children}
      </ol>
    </nav>
  );
};
 
BreadCrumbs.Crumb = Crumb;
 
export default BreadCrumbs;