3.1.0 • Published 10 months ago

@chakra-ui/descendant v3.1.0

Weekly downloads
61,597
License
MIT
Repository
github
Last release
10 months ago

Descendant

Keep track of descendant components and their relative indices.

A descendant index solution for better accessibility support in compound components.

Note 🚨: This package is primarily intended for internal use by the Chakra UI library. You should not use it directly in your production projects.

Installation

yarn add @chakra-ui/descendant

# or

npm i @chakra-ui/descendant

Motivation

Descendants observer is a utility hook for keeping track of descendant elements and their relative indices.

In short, this package allows each item in a list to know its relative index and the parent of the list can keep track of each child, without needing to render in a loop and pass each component an index.

This enables component composition:

<List>
  <Item /> // I'm index 0
  <Item /> // I'm index 1<div>
    <div>
      <Item /> // I'm arbitrarily nested, but still know that I'm index 2
    </div>
  </div>
</List>

Usage

import { createDescendantContext } from "@chakra-ui/descendant"
import * as React from "react"

const [
  DescendantsProvider,
  useDescendantsContext,
  useDescendants,
  useDescendant,
] = createDescendantContext()

const MenuContext = React.createContext({})

function Menu({ children }) {
  // 1. Call the `useDescendants` hook
  const descendants = useDescendants()

  const [selected, setSelected] = React.useState(1)
  const context = React.useMemo(() => ({ selected, setSelected }), [selected])

  return (
    // 2. Add the descendants context
    <DescendantsProvider value={descendants}>
      <MenuContext.Provider value={context}>
        <div role="menu" style={{ maxWidth: 320 }}>
          <button
            onClick={() => {
              const prev = descendants.prev(selected)
              prev.node.focus()
              setSelected(prev.index)
            }}
          >
            Prev
          </button>
          <button
            onClick={() => {
              const next = descendants.next(selected)
              next.node.focus()
              setSelected(next.index)
            }}
          >
            Next
          </button>
          {children}
        </div>
      </MenuContext.Provider>
    </DescendantsProvider>
  )
}

const MenuItem = ({ children }) => {
  const { selected, setSelected } = React.useContext(MenuContext)

  // 3. Read from descendant context
  const { index, register } = useDescendant()

  const isSelected = index === selected

  return (
    <div
      role="menuitem"
      ref={register}
      aria-selected={isSelected}
      onMouseMove={() => setSelected(index)}
      style={{ color: isSelected ? "red" : "black" }}
    >
      {children} - {index}
    </div>
  )
}

const Example = () => {
  const [show, setShow] = React.useState(false)
  const [show2, setShow2] = React.useState(false)

  const toggle = () => {
    setShow(!show)
    if (!show === true) {
      setTimeout(() => {
        setShow2(true)
      }, 1000)
    }
  }

  return (
    <div>
      <button onClick={toggle}>Toggle</button>
      <Menu>
        <MenuItem>One</MenuItem>
        {show && <MenuItem>Two</MenuItem>}
        <MenuItem>Three</MenuItem>
        <MenuItem>Four</MenuItem>
        <div>
          {show2 && <MenuItem>Testing 🌟</MenuItem>}
          <MenuItem>Five</MenuItem>
        </div>
      </Menu>
    </div>
  )
}
3.1.0

10 months ago

3.0.14

1 year ago

3.0.13

1 year ago

3.0.12

1 year ago

3.0.11

1 year ago

3.0.10

2 years ago

3.0.8

2 years ago

2.1.4

2 years ago

3.0.9

2 years ago

3.0.4

2 years ago

3.0.3

2 years ago

3.0.2

2 years ago

3.0.7

2 years ago

3.0.6

2 years ago

3.0.5

2 years ago

3.0.0-next.2

2 years ago

3.0.1

2 years ago

3.0.0

2 years ago

3.0.0-next.1

2 years ago

3.0.0-next.0

2 years ago

2.1.2

2 years ago

2.1.3

2 years ago

2.1.1

2 years ago

2.1.0

2 years ago

2.0.2-next.1

3 years ago

2.0.2-next.0

3 years ago

2.0.1

3 years ago

2.0.0

3 years ago

1.1.3

3 years ago

1.1.2

3 years ago

1.1.1

3 years ago

1.1.0

3 years ago

1.0.9

3 years ago

1.0.8

3 years ago

1.0.7

3 years ago

1.0.6

3 years ago

1.0.5

3 years ago

1.0.4

3 years ago

1.0.3

3 years ago

1.0.2

3 years ago

1.0.1

3 years ago

1.0.0

3 years ago

1.0.0-rc.8

4 years ago

1.0.0-rc.7

4 years ago

1.0.0-rc.6

4 years ago

1.0.0-rc.5

4 years ago

1.0.0-rc.4

4 years ago

1.0.0-rc.3

4 years ago

1.0.0-rc.2

4 years ago

1.0.0-rc.1

4 years ago

1.0.0-rc.0

4 years ago

1.0.0-next.7

4 years ago

1.0.0-next.6

4 years ago

1.0.0-next.5

4 years ago

1.0.0-next.4

4 years ago

1.0.0-next.3

4 years ago

1.0.0-next.2

4 years ago

1.0.0-next.1

4 years ago

1.0.0-next.0

4 years ago