Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Simonwep/nanopop
🍦 Minimalistic, small, positioning engine. Build for high-performance, minimal footprint and maximum control over positioning behavior.
https://github.com/Simonwep/nanopop
popper positioning-engine widget
Last synced: 3 months ago
JSON representation
🍦 Minimalistic, small, positioning engine. Build for high-performance, minimal footprint and maximum control over positioning behavior.
- Host: GitHub
- URL: https://github.com/Simonwep/nanopop
- Owner: simonwep
- License: mit
- Created: 2020-05-08T15:10:28.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2024-01-26T12:07:30.000Z (10 months ago)
- Last Synced: 2024-08-01T19:51:47.667Z (3 months ago)
- Topics: popper, positioning-engine, widget
- Language: TypeScript
- Homepage: https://simonwep.github.io/nanopop
- Size: 467 KB
- Stars: 643
- Watchers: 5
- Forks: 12
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Ultra Tiny, Opinionated Positioning Engine
Nanopop is an ultra-tiny positioning engine. Hold up, isn't there [PopperJS](https://github.com/popperjs/popper-core)?
Yeah - and PopperJS is great! But there are tons of features that, in most cases, you just might not need. This library is less than a third of PopperJS.#### When should I use Nanopop and not PopperJS?
1. Situations where you want **full control** over positioning, including handling events such as scrolling, and manual resizing.
2. **Performance-critical** cases with lots of elements [...] nanopop will only makes changes if you say so.
3. Poppers with **minimal footprint** such as drop-downs and tooltips which don't require that much configurability.
4. You might have some special needs about how your popper behaves. Index exposes a function for the sole purpose of positioning something, use it in your own library!This library was originally part of [pickr](https://github.com/Simonwep/pickr) - now ported to TS with tests and a few updates / bug-fixes.
> Heads up! This is the readme for v2 - if you're looking for the first version head over [here](https://github.com/Simonwep/nanopop/tree/539de9558a113ca6548a0d7d316ae8c65d7817d5) (v1 is not maintained anymore).
## Getting Started
Install via npm:
```shell
$ npm install nanopop
```Install via yarn:
```shell
$ yarn add nanopop
```Include directly via jsdelivr:
```html```
Using [JavaScript Modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules):
````js
import {
reposition, // Core, stateless function to reposition an element
createPopper, // Stateful function which keeps track of your configuration
defaults, // A subset of nanopops options used as default values
version // Current version
} from 'https://cdn.jsdelivr.net/npm/nanopop/lib/nanopop.min.mjs'
````> 🌟 Index is fully tree-shakable! E.g. if you only use `reposition` you'll probably end up with less than 500B code!
## Usage
```js
reposition(
/* reference: */ document.querySelector('.btn'),
/* popper: */ document.querySelector('.dropdown'),
/* We're using the default options */
);
```> ⚠ The popper-element must have set `position` to `fixed`.
> ℹ Because the default-`container` is `document.documentElement` you might have to increase the `height` of the `html` element to make room for your popper (e.g. `html {height: 100vh;}`)
#### All options
```ts
import {reposition, createPopper} from 'nanopop';// Using a object and reposition directly
const nanopop = reposition(reference, popper, {// The DOMRect of the container, it used the html-element as default.
// You could also create your own boundary using a custon DOMRect (https://developer.mozilla.org/en-US/docs/Web/API/DOMRect)!
container: document.documentElement.getBoundingClientRect(),// Optional arrow element that is positioned between the popper and the reference element.
arrow: undefined,// Margin between the popper element and the reference
margin: 8,// Minimum space between the popper and the container
padding: 0,// Preferred position, any combination of [top|right|bottom|left]-[start|middle|end] is valid.
// 'middle' is used as default-variant if you leave it out.
position: 'bottom-middle',// In case the variant-part (start, middle or end) cannot be applied you can specify what (and if)
// should be tried next.
variantFlipOrder: {
start: 'sme', // In case of -start try 'start' first, if that fails 'middle' and 'end' if both doesn't work.
middle: 'mse',
end: 'ems'
},// The same as variantFlipOrder, but if all variants fail you might want to try other positions.
positionFlipOrder: {
top: 'tbrl', // Try 'top' first, 'bottom' second, 'right' third and 'left' as latest position.
right: 'rltb',
bottom: 'btrl',
left: 'lrbt'
}
});/**
* Using the createPopper function to create a stateful wrapper
*
* Correct ways of calling it are:
* createPopper(reference: HTMLElement, popper: HTMLElement, options?: NanoPopOptions)
* createPopper(options?: NanoPopOptions)
* ⚠ If you omit options entierly you'll have to set both the reference and the popper later when calling .update!
*/
const popper = createPopper({...});
popper.update(); // You can pass an object to update which will get merged with the existing config.
```Calling `popper.update(...)` or `reposition(...)` both returns a position-pair (For example `te` for **T**op-**E**nd) or `null` based on if it was possible to find a position for the popper without clipping it._
> Tip: The returned position-pair is perfect for tool-tips to give them a little arrow!
## Caveats
1. The popper-element must have `position` set to `fixed`.
2. If nanopop cannot find a position without clipping your popper it'll revert its `top` and `left` values - you can use css / js to handle this case.