npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-expansion

v0.3.1

Published

Fully customizable and reusable expand/collapse component

Downloads

10

Readme

react-expansion

Fully customizable and reusable expand/collapse component

NPM JavaScript Style Guide

What is this

react-expansion sees the expand/collapse system as the composition of multiple bricks. the picture bellow resumes it all.

react-expansion

Picture generated with excalidraw.

Install

npm install --save react-expansion

or

yarn add react-expansion

Demo

This ongoing codeSandbox will contain reusable examples

Props and Usage hints

To use react-expansion, you need to define a few components on your own because we prefer to stay agnostic to the UI.

These components will receive the following props:

|Prop | value| |--------------------|------------------| |expanded | a boolean that indicates whether the component is expanded/collapsed | |toggleExpansion | if controlled, will toggle the expansion state | |position | will be spread to IndicatorComponent, LabelComponent and ActionsComponent, and indicates respectively the position of the nested component |

The ExpandCollapse component props are:

|Prop | PropType | Default value | Usage | |------------------------|---------------------------|------------------|------------------| |expanded | bool | undefined | If present, the expand collapse becomes controlled by this prop | |initialValue | bool | false | If not controlled, this is the initial expansion state when the component is mounted | |labelPosition | oneOf(['start', 'end']) | start | Indicates the position of the label component and/or label children | |actionsPosition | oneOf(['start', 'end']) | end | Indicates the position of the action component and/or the actions children | |indicatorPosition | oneOf(['start', 'end']) | end | Indicates the position of the indicator component | |Component | String or func | React.Fragment | Is the component in which the Expansion header and content will be wrapped into | |ComponentProps | object | {} | The props of the top level wrapper component | |ExpansionComponent | String or func | undefined | The component to be mounted to wrap the Expansion Header (that contains the indicator, label, actions, divider) | |ExpansionProps | object | {} | The props to be passed to the ExpansionComponent plus the automatic props described the in the previous table | |IndicatorComponent | String or func | undefined | The component that is supposed to indicate the expansion state and toggles it | |IndicatorProps | object | {} | The props to be passed to the IndicatorComponent plus the automatic props described the in the previous table | |LabelComponent | String or func | undefined | The component in which the label prop is wrapped | |LabelProps | object | {} | The props to be passed to the LabelComponent plus the automatic props described the in the previous table | |ActionsComponent | String or func | undefined | The component in which the actions prop is wrapped | |ActionsProps | object | {} | The props to be passed to the ActionComponent plus the automatic props described the in the previous table | |DividerComponent | String or func | undefined | The component that will be mounted as a divider (may be an hr or any custom object (even a form)) | |DividerProps | object | {} | The props to be passed to the DividerComponent plus the automatic props described the in the previous table | |contentContainerProps | object | {} | The props to be passed to the div containing the content, these props are only passed if the component is expaned | |actions | any | undefined | The actions children to be mounted in the actions area | |children | any | undefined | What will be hidden/visible depending on the expansion state | |label | any | undefined | The label to display in its position | |keepMounted | bool | undefined | If true, the content will stay into the dom, but the div containing it will have a display: none style | |onExpandChange | func | undefined | will be called with the next expansion state whenever the expand collapse changed | |contentDisplay | string | undefined | The display style property's value that will be given the content container when visible |

You can also imperatively handle the expansion state if not controlled. The useImperativeHandle hook exposes the following functions:

  • expand
  • collapse
  • toggleExpansion

and can be used like this:

const myRef = React.useRef()
function expand() {
  myRef.current.expand()
}
function collapse() {
  myRef.current.collapse()
}
function toggle() {
  myRef.current.toggleExpansion()
}
// later
<SomeButton onClick={toggle}>Toggle</SomeButton>
<SomeButton onClick={expand}>Expand</SomeButton>
<SomeButton onClick={collapse}>Collapse</SomeButton>
<ExpandCollapse ref={myRef} {...}>Some tags and children</ExpandCollapse>

Limitations and roadmap

  • The ExpandCollapse component wraps the children in a div so its display style is managed and thus we can offer the keepMounted ability
  • There is no support for animations, but we hope it will be released in the v2 (instead, you can pass the needed css using className or style via the contentContainerProps)

Usage examples

There is a lot of examples that can be made with this ExpandCollapse.

Let's create a navigation file system that will display a files tree (folders & files).

I will be using Material-ui to illustrate my examples for faster dev.

First: the IndicatorComponent

const useIndicatorStyles = makeStyles({
  iconButton: {
    border: `1px solid`,
    padding: '0px',
  },
  icon: {
    width: '12px',
    height: '12px'
  }
});
function FileSystemIndicator({ expanded, toggleExpansion, variant = 'file'}) {
  const classes = useIndicatorStyles()
  if (variant === 'file') {
    return null; // no indicator when it's a file
  }
  return (
    <IconButton color="primary"  className={classes.iconButton} onClick={toggleExpansion} size="small">
      <SvgIcon className={classes.icon}>
        {expanded ? <ArrowDown /> : <ArrowRight />}
      </SvgIcon>
    </IconButton>
  )
}

Then: the LabelComponent

import File from '@material-ui/icons/InsertDriveFile'
import FolderOpen from '@material-ui/icons/FolderOpen'
import FolderClosed from '@material-ui/icons/Folder'

const useStyles = makeStyles({
  root: {
    cursor: 'pointer',
    display: 'flex',
    alignItems: 'center',
    marginLeft: 4
  },
  icon: {
    width: '12px',
    height: '12px',
    marginRight: 4
  }
})
function FileSystemLabel({filename, fileUrl, variant = 'file', expanded, toggleExpansion}) {
  const classes = useStyles()
  function onClick() {
    if (fileUrl) {
      alert(`We can load a file content here from it's url ${fileUrl}`)
    } else {
      toggleExpansion()
    }
  }
  return (
    <Typography onClick={onClick} color="primary" component="div" className={classes.root}>
      <SvgIcon className={classes.icon}>
        {variant === 'folder' && expanded && <FolderOpen/>}
        {variant === 'folder' && !expanded && <FolderClosed/>}
        {variant === 'file' && <File/>}
      </SvgIcon>
      <Typography color="primary" component="span">
        {filename}
      </Typography>
    </Typography>
  )
}

Then: the DividerComponent which will be nothing:

function Nothing() {
  return null;
}

And then, the FileUnit that returns our ExpandCollapse:

function FileUnit({children, filename, variant, fileUrl, ...rest}) {
  return (
    <ExpandCollapse
      keepMounted
      Component="div"
      indicatorPosition='start'
      ExpansionComponent='div'
      ExpansionProps={{style: {display: 'flex', alignItems: 'center'}}}
      LabelComponent={FileSystemLabel}
      LabelProps={{filename, variant, fileUrl}}
      label={filename}
      IndicatorComponent={FileSystemIndicator}
      IndicatorProps={{variant}}
      contentContainerProps={{
        style: {
          marginLeft: 24
        }
      }}
      {...rest}
    >
      {children}
    </ExpandCollapse>
  )
}

The resulting ExpandCollapse with a minimal example will give this output

file system example

We can also create a large variant of expand collapse and combine them. Here is a picture, I am still looking to create multiple other examples in a demo package.

file system example

License

MIT © incepter