OnClickOutside

This is great to track when some UI component needs to react to events outsdie its component heirachy. Consider a Drawer that can be closed when the user clicks "outside" the Drawer. Another good case is using a Menu whose dropdown should close when the user clicks "away".

Traditionally we would inspect the click event to determine if the traget element is within the DOM heirachy. This problem breaks down in the following example. When we place a SingleSelect or any Menu in the Drawer we can no longer rely on the DOM heirachy to tell us what is "inside" the Drawer. Determining "insideness" when using the Menu is dificult beacuse it "portals" its dropdown to a DOM element outside React's component heirachy (a sibling element to the body). If we only use the DOM heirachy then the dropdown will not be considered a child of the Drawer.

{() => {
    class StateManager extends React.Component {
      constructor(props, context) {
        super(props, context)
        this.state = {
          isOpen: false,
          selectedItem: null,
          items: [
            { id: 1, value: 'First Option' },
            { id: 2, value: 'Second Option' },
          ],
        }
        this.handleClickOutside = this.handleClickOutside.bind(this)
        this.openDrawer = this.openDrawer.bind(this)
        this.handleSelect = this.handleSelect.bind(this)
      }
      handleClickOutside() {
        this.setState({ isOpen: false })
      }
      openDrawer() {
        this.setState({
          isOpen: true,
        })
      }
      handleSelect(selectedItemId) {
        const selectedItem = this.state.items.find(
          item => item.id === selectedItemId,
        )
        this.setState({ selectedItem })
      }
      render() {
        const renderAssetTypeOptions = ({ getItemProps }) => {
          const group = this.state.items.map((item, index) => {
            const itemProps = getItemProps({ item, index })
            return (
              <ListItem
                onClick={itemProps.onClick}
                onMouseDown={itemProps.onMouseDown}
                id={itemProps.id}
                selected={itemProps.isSelected || itemProps.isActive}
                key={index}
              >
                <ListItemText primary={item.value} />
              
            )
          })
          return <List bordered>{group}</List>
        }
        const drawer = (
          <Drawer
            open={this.state.isOpen}
            placement="right"
            handleClickOutside={this.handleClickOutside}
          >
            <SpacedGroup direction="vertical">
              <p>
                This is the drawer with a portaled select. Will the selection of
                the option in the portaled dropdown be considered "outside"?
              </p>
              <SingleSelect
                fullWidth
                renderOptions={renderAssetTypeOptions}
                onSelect={this.handleSelect}
                selectedItem={this.state.selectedItem}
              />
            </SpacedGroup>
          </Drawer>
        )
        return (
          <div>
            <Button onClick={this.openDrawer}>Open Drawer</Button>
            {drawer}
          </div>
        )
      }
    }
    return <StateManager />
  }}
</Playground>

API