{"dist":{"shasum":"f411a9a67daf9c85ceab0a3cb53f158de61c75da","tarball":"https://registry.npmjs.org/use-descendants/-/use-descendants-1.0.0-beta.0.tgz","fileCount":7,"integrity":"sha512-NFsuHJf+udQ0px3E71JTgylczmWYlpLj9CcwKmxvY64rrbNqKk7JxKETTS3RXKFJVe6E2a/e9zzH3WsDVJ/QZw==","signatures":[{"sig":"MEUCIQDuK9LI6C0TIiHSxKLazkPD7hXd9mgsifJn4A9nG/PUhQIgVkoyikTa46sObWaQuBtiu5LsNM4Lm6LTz1lbEO9Ee6k=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":9368,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJg52QICRA9TVsSAnZWagAAMPAP/RbAYA4wPjhtwpR4cpB3\ngAx17JK/e+AJkOmLUbb7Ly0Ut9gjitga8K4gPhMKAHdZEXVX1V05YAzw+z2f\nRzUUIv/O2kqJ8ucy6xSZbfmCM8fivN36zerOnqPMJKDSDEqv9cKPTezxznGg\ndR7pOAzroVW7Z5vj4arfiUw9Gg6Tkbun4tIyeFFW1pIWsROEO9FvOg56dZ0k\nE8dOBO3LQKgDK4aBVcQF309stVqcGwbCw7RaOMig5NJ5VY36r1XAOQbfMcaQ\nm2Fh3rB71TXKWJ+KlnpGOGG5rzxqIuUqB8USiBqi2jayyMVIRn8tz63fIWmH\n8GV0+s2u2V5oqZNzw2xTxmafB8if03dXFMWc17zg825vvuRWGm7m72BziZdl\nylpsRUEXSadrAITxc1WdhuIxX6tMLAreH9dG0H+ox49KQ7EvNwbZ1VUAPVDi\n0E1Skrx5/Bs7V+k6LABg1yI7w64PQsQqOPVAX98eI7BodI9u+7JVr46Ocmrb\nQfy4u5/3u+/2sHY6TIcukiafBwD9JCuqKpxDxq9E+XTJHEtNUK0yf/z7DIOD\nPOlQB3OaKHQoZ/Lb+LIg8g8Fi9Zb5/Yk7GkOQJIuWhBcM6naQsUm94OdHgsz\nXJu4ySDdSTcgVxRZ17Don4X49JpXQs9lHfDwie2M6qTBU7v7qN0yKQqGDm44\nIlNO\r\n=9peH\r\n-----END PGP SIGNATURE-----\r\n"},"main":"./dist/index.js","name":"use-descendants","module":"./dist/index.modern.js","readme":"# useDescendants ![npm bundle size](https://img.shields.io/bundlephobia/minzip/use-descendants)\n\n> Warning: useDescendants is experimental and primarily intended for personal use. It heavily relies on refs and the DOM and likely will not be concurrent mode compatible.\n\nuseDescendants is a react hook for keeping track of descendant components and their relative indeces. It's based off the [@reach/descendants](https://www.npmjs.com/package/@reach/descendants) package, but is much faster and half the size, with no dependencies.\n\nIf you want to understand more about what this package does or why we need it, read the [Problem Complex](https://www.npmjs.com/package/@reach/descendants) from the @reach/descendants package.\n\nIn short, this package allows each item in a list to know it's 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.\n\nThis enables component composition:\n\n```js\n<List>\n  <Item /> // I'm index 0\n  <Item /> // I'm index 1<div>\n    <div>\n      <Item /> // I'm arbitrarily nested, but still know that I'm index 2\n    </div>\n  </div>\n</List>\n```\n\n<br />\n\n## Installation\n\n```\n$ yarn add use-descendants\n```\n\n<br />\n\n## Example ([live](https://codesandbox.io/s/use-descendants-demo-wi96j?file=/src/App.js))\n\nIn this example, we'll create a menu with items that can be selected on hover.\n\n```js\nimport {\n  createDescendants,\n  useDescendants,\n  useDescendant\n} from 'use-descendants'\n\nconst DescendantContext = createDescendants()\nconst MenuContext = createContext()\n\nconst Menu = ({ children }) => {\n  const { ref, ...contextProps } = useDescendants()\n  const [selected, setSelected] = useState(0)\n\n  return (\n    <DescendantContext.Provider value={contextProps}>\n      <MenuContext.Provider value={{ selected, setSelected }}>\n        <div role=\"menu\" ref={ref}>\n          {children}\n        </div>\n      </MenuContext.Provider>\n    </DescendantContext.Provider>\n  )\n}\n\nconst MenuItem = ({ children }) => {\n  const { selected, setSelected } = useContext(MenuContext)\n  const { index, ref } = useDescendant(DescendantContext)\n\n  const isSelected = index === selected\n\n  return (\n    <div\n      role=\"menuitem\"\n      ref={ref}\n      data-selected={isSelected}\n      onMouseMove={() => setSelected(index)}\n    >\n      {children}\n    </div>\n  )\n}\n```\n\nPretty simple, right? The beauty of this API is that Menu's children can be wrapped arbitrarily, as opposed to normal rendering techniques.\n\n```jsx\n// Before\n<Menu>\n  {items.map(item => (\n    <MenuItem>{item}</MenuItem>\n  ))}\n</Menu>\n```\n\n```jsx\n// After, use any component tree\n<Menu>\n  <MenuItem>Hello</MenuItem>\n  <BlogMenuItems />\n  <RedItem>Im Red</RedItem>\n\n  <>\n    <>\n      <>\n        <MenuItem>Deep</MenuItem>\n      </>\n    </>\n  </>\n</Menu>\n```\n\n<br />\n\n## Usage\n\nThere are two hooks: `useDescendants` (used in the parent) and `useDescendant` (used in each child). You will also need to use `createDescendants` to wrap each child with context.\n\n### useDescendants\n\nMaintains state related to the list of descendants.\n\n```js\nconst { ref, ...contextProps } = useDescendants()\n\n<ul ref={ref}>\n  // ...\n</ul>\n```\n\nThe returned `ref` should be applied to the DOM element of your parent. The rest of the values returned from `useDescendants` should be passed via context.\n\nThe context props:\n\n- `list`: a ref with an array of currently rendered descendants\n- `map`: a ref with an object of every mounted (even if not rendered) descendant, keyed by component id\n- `force`: a way to forcefully re-render the parent\n\nLearn more about `list` and `map` in the [Advanced](#advanced) section.\n\n### createDescendants\n\nCreates a new descendant context.\n\n```js\nconst DescendantContext = createDescendants()\n\n<DescendantContext.Provider value={contextProps}>\n // ...\n</DescendantContext.Provider>\n```\n\nThe created context must be passed to `useDescendant` below.\n\n### useDescendant\n\nuseDescendant accepts two arguments: `context`, the context you created with `createDescendants`, and `props`, arbitrary props that you want available in the parent.\n\nAny props you pass will be available in the parent in `contextProps.map[id]`, where `id` is the component id returned below.\n\nuseDescendant returns three values:\n\n- `ref` should be applied to the DOM element of this child.\n- `index` is the relative index of this child in the list\n- `id` is the unique id of this component\n\n```js\nconst { ref, index, id } = useDescendant(context, props?)\n\n<li ref={ref}>\n // ...\n</li>\n```\n\n<br />\n\n## Why?\n\nTo enable composable APIs instead of falling back to rendering data arrays. I prefer abstractions like `<select><option /></select>` instead of `<select options={[]} />`.\n\n## Advanced\n\nuseDescendants heavily relies on refs to avoid unnecessary re-renders, which makes it about 3x faster than @reach/descendants because nothing is kept in state. We manually re-render the parent only when necessary.\n\nIt also heavily relies on the DOM. Under the hood, we use `document.querySelectorAll` to get all of the descendant DOM elements, and then keep an up-to-date list of their relative indeces.\n\nThis is because React provides no easy way of querying the component tree, and recursively checking `children` in the parent would be slow. But the DOM does provide an easy way to query the tree, and the DOM always represents the accurate state of our descendants.\n\nAnother downside of @reach/descendants was that any props passed to an item must be memoized. Passing an un-memoized function caused an infinite re-render. In useDescendants, you can pass any props, memoized or not, because we keep them in a ref.\n\n### How it works\n\nWhen a descendant is mounted, it is assigned a unique id and an index of -1. We wait for the item to mount the ref, then add the `[data-descendant]` attribute to the DOM element with the components unique id (i.e. `data-descendant=\"2h7g2b\"`)\n\nThe parent list then queries the DOM for all elements with `[data-descendant]` and compares it to our list of descendants. If they are different, we update our list and re-render the parent. This re-renders all of the descendants, who can now compare their id to the list received from the parent via context. Now each descendant knows it's relative index to other descendants.\n\nIn the parent, we can use `list` and `map` to retrieve information about each descendant. For example, if we wanted the props of the fourth descendant, we can get the descendant id from the list and use it to lookup in the map:\n\n```js\nconst id = list.current[3]._internalId\nconst props = map.current[id] // All of the props passed to `useDescendant` by the fourth descendant\n```\n\nThis makes it easy to pass data from the children back up to the parent.\n\n## Credits\n\n- [@reach/descendants](https://www.npmjs.com/package/@reach/descendants) and [Chance](https://twitter.com/chancethedev), who introduced me to this concept\n","source":"./index.js","license":"MIT","scripts":{"build":"microbundle --compress --no-sourcemap","prepublish":"yarn build"},"_npmUser":{"name":"paco","email":"pvco.coursey@gmail.com"},"description":"> Warning: useDescendants is experimental and primarily intended for personal use. It heavily relies on refs and the DOM and likely will not be concurrent mode compatible.","directories":{},"maintainers":[{"name":"paco","email":"pvco.coursey@gmail.com"}],"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"microbundle":"^0.12.3"},"peerDependencies":{"react":"*","react-dom":"*"},"_npmOperationalInternal":{"tmp":"tmp/use-descendants_1.0.0-beta.0_1625777160019_0.8548022305293694","host":"s3://npm-registry-packages"},"_id":"use-descendants@1.0.0-beta.0","version":"1.0.0-beta.0"}