7.5.0 • Published 1 year ago

use-rects v7.5.0

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

use-rects

Package that allows to resolve DOM elements sizes and positions

Contents

usePopupPosition

Allows you to quickly build dropdowns

  • flip - used to allow popup to change position if there is no space for original align
  • pessimistic allows to show popup separated from anchor egdes, cause there is no proper fit
  • align - topleft | bottomleft | bottomright | topright
  • trackVisible - hides dropdown if anchor is hidden/obstructed on the page. Doesn't count anything with 'absolute', 'fixed', etc. as obstruction

Example of the component

Just copy-paste and use this a base (with some tailwind)

import React, { useState } from 'react';
import { usePopupPosition } from 'use-rects';

export const Dropdown = () => {
  const [open, setOpen] = useState(false);

  // const handleClose = () => setOpen(false);
  const handleToggle = () => setOpen(o => !o);

  const { popupRef, anchorRef, popupPosition } = usePopupPosition({
    delay: 15,
    flip: true,
    align: 'bottomleft',
  });

  return (
    <div ref={anchorRef} className="relative">
      <div onClick={handleToggle}>Trigger</div>

      {open && (
        <div
          ref={popupRef}
          style={{
            ...popupPosition.style,
            width: popupPosition.meta?.anchorWidth,
          }}
          className="fixed z-popper py-2"
        >
          <div className="shadow-sm rounded">Dropdown</div>
        </div>
      )}
    </div>
  );
};

Troublesooting

You still have to build your own dropdown. So remember this:

  • add Z-index of you own if needed
  • trackVisible won't work if you have 'fixed' your navbars and other parts of the layout
  • dropdown must have 'height'. don't make it's content with 0 height and make some magic inside
  • use results of the hook for position only. don't style this popup. Add your div inside and style it. Insluding margin, borders, etc.

returns:

type PopupStyle = {
  top?: number;
  bottom?: number;

  left?: number;
  right?: number;

  opacity?: 1 | 0;
  position?: 'fixed';
  display?: 'none' | undefined;
};

type UsePopupResult = {
  style: PopupStyle;
  meta?: { pessimistic?: boolean; flip?: boolean; anchorWidth?: number };
};

type ReturnType = {
  popupRef: (node: HTMLDivElement) => void;
  anchorRef: (node: HTMLDivElement) => void;

  anchorPosition: Position;
  popupPosition: UsePopupResult;
};

example:

const Dropdown = () => {
  const [open, setOpen] = useState(false);
  const { popupRef, anchorRef, popupPosition } = usePopupPosition({
    delay: 50,
  });

  return (
    <div style={{ position: 'relative' }}>
      <input
        readOnly
        ref={anchorRef}
        onClick={() => setOpen(true)}
        value="test me"
      />
      {!!open && (
        <div
          ref={popupRef}
          onClick={() => setOpen(false)}
          style={{ position: 'fixed', ...popupPosition.style }}
        >
          DROPDOWN
        </div>
      )}
    </div>
  );
};

Use resulting style inside of container. If you need extra margins - don't apply them in combination with flip. Put another container inside and style it

useContainerSize

returns:

type ReturnType = {
  containerRef: React.MutableRefObject<any>;
  height: number;
  width: number;
};

example:

const { height, width, containerRef: ref } = useContainerSize({ delay: 20 });

return <div ref={ref} />;

useElementPosition

returns:

type ReturnType = [(node: HTMLDivElement) => void, Position];

example:

const [ref, position] = useElementPosition({
  delay: 20,
});

return <div ref={ref} />;
7.4.0

1 year ago

7.3.0

1 year ago

7.1.2

1 year ago

7.2.0

1 year ago

7.1.1

1 year ago

7.1.0

1 year ago

7.5.0

1 year ago

7.0.0

1 year ago

6.0.0

1 year ago

5.1.0

1 year ago

5.0.0

1 year ago

4.3.0

1 year ago

4.2.0

1 year ago

4.1.0

1 year ago

4.0.1

1 year ago

4.0.0

1 year ago

3.0.0

1 year ago

2.1.0

1 year ago

2.0.3

1 year ago

2.0.2

1 year ago

2.0.1

1 year ago

2.0.0

1 year ago

1.2.1

1 year ago