All files / modules/75-cf/components/StackedCircleContainer StackedCircleContainer.tsx

90% Statements 27/30
62.96% Branches 17/27
75% Functions 6/8
89.66% Lines 26/29

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              2x 2x 2x   2x 2x 2x   2x 2x 2x                         2x   2x             6x       6x   6x       6x   6x 6x 6x 6x   6x                                         6x                                       2x 6x   6x 6x   6x    
/*
 * Copyright 2021 Harness Inc. All rights reserved.
 * Use of this source code is governed by the PolyForm Shield 1.0.0 license
 * that can be found in the licenses directory at the root of this repository, also available at
 * https://polyformproject.org/wp-content/uploads/2020/06/PolyForm-Shield-1.0.0.txt.
 */
 
import React from 'react'
import { slice } from 'lodash-es'
import cx from 'classnames'
import type { ContainerProps } from '@wings-software/uicore/dist/components/Container/Container'
import { Button, Container } from '@wings-software/uicore'
import { SEGMENT_PRIMARY_COLOR } from '@cf/utils/CFUtils'
import css from './StackedCircleContainer.module.scss'
 
const DEFAULT_DIAMETER = 30
const DEFAULT_CONTAINER_SIZE = 26
const DEFAULT_MAX_SHOWN_ITEMS = 3
 
export interface StackedCircleContainerProps<T> extends Omit<ContainerProps, 'color'> {
  items: T[]
  diameter?: number
  maxShownItem?: number
  keyOfItem: (item: T) => string
  renderItem: (item: T) => React.ReactNode
  renderOtherItem?: (otherItems: T[]) => React.ReactNode
  color?: (itemOrOther: T | boolean) => string
  backgroundColor?: (itemOrOther: T | boolean) => string
}
 
export const StackedCircleContainerClasses = css
 
export function StackedCircleContainer<T>({
  items,
  diameter = DEFAULT_DIAMETER,
  maxShownItem = DEFAULT_MAX_SHOWN_ITEMS,
  keyOfItem,
  renderItem,
  renderOtherItem = otherItems => <Button noStyling>+{otherItems.length}</Button>,
  color = () => 'var(--white)',
  backgroundColor = () => SEGMENT_PRIMARY_COLOR,
  ...containerProps
}: StackedCircleContainerProps<T>): JSX.Element | null {
  const len = items?.length
 
  Iif (!len) {
    return null
  }
 
  const itemContainerSize = len === 1 ? diameter : (diameter * DEFAULT_CONTAINER_SIZE) / DEFAULT_DIAMETER
 
  const otherItemCount = len - maxShownItem
  const hasOtherItems = otherItemCount > 1
  const renderedItems = slice(items, 0, hasOtherItems ? maxShownItem : len)
  const otherItems = hasOtherItems ? slice(items, maxShownItem, maxShownItem + otherItemCount) : []
 
  return (
    <Container {...containerProps}>
      <ul
        className={css.stack}
        style={{ '--size': `${diameter}px`, '--itemContainerSize': `${itemContainerSize}px` } as React.CSSProperties}
      >
        {hasOtherItems && (
          <li
            className={css.itemContainer}
            style={
              {
                '--color': color(true),
                '--background': backgroundColor(true)
              } as React.CSSProperties
            }
          >
            {renderOtherItem(otherItems)}
          </li>
        )}
 
        {renderedItems.reverse()?.map(item => {
          return (
            <li
              key={keyOfItem(item)}
              className={cx(css.itemContainer)}
              style={
                {
                  '--color': color(item),
                  '--background': backgroundColor(item)
                } as React.CSSProperties
              }
            >
              {renderItem(item)}
            </li>
          )
        })}
      </ul>
    </Container>
  )
}
 
export const makeStackedCircleShortName = (name: string): string => {
  const shortName = name
    .split(/\s/)
    .map((token, index) => (index <= 1 ? token[0] : ''))
    .reduce((obj, item) => obj + item, '')
 
  return (shortName.length === 1 ? name.substring(0, 2) : shortName).toLocaleUpperCase()
}