remove popover util

pull/463/head
Cory LaViska 2021-05-26 12:43:03 -04:00
rodzic d720121044
commit ee9ce8a87b
2 zmienionych plików z 0 dodań i 171 usunięć

Wyświetl plik

@ -241,7 +241,3 @@ Form controls should support validation through the following conventions:
- All form controls must have a `reportValidity()` method that report their validity during form submission
- All form controls should mirror their native validation attributes such as `required`, `pattern`, `minlength`, `maxlength`, etc. when possible
- All form controls must be serialized by `<sl-form>`
### Positioning Popovers
Shoelace uses an internal popover utility for dropdowns, tooltips, etc. This is a light abstraction of Popper.js designed to make positioning and transitioning things easy and consistent throughout the library. When possible, use this utility instead of relying on Popper directly. See `src/utilities/popover.ts` for details.

Wyświetl plik

@ -1,167 +0,0 @@
//
// A positioning utility for popovers that handles show/hide/transitionEnd events with simple callbacks.
//
// Powered by Popper.js.
//
// NOTE:
//
// - The popover MUST have at least one property that transitions, otherwise transitionEnd won't fire and the popover
// won't be hidden. If transitions are delegated to a child element, set the `transitionElement` property accordingly.
//
// - When the popover is shown, it's assigned `PopoverOptions.visibleClass`. You can use this class to provide different
// transitions for show/hide.
//
// - Popper uses `translate3d` to position elements, so adding a transition to the `transform` property may have an
// undesired effect when the element is shown and when its placement changes.
//
import { Instance as PopperInstance, createPopper } from '@popperjs/core/dist/esm';
export default class Popover {
anchor: HTMLElement;
isVisible: boolean;
popover: HTMLElement;
popper: PopperInstance;
options: PopoverOptions;
constructor(anchor: HTMLElement, popover: HTMLElement, options?: PopoverOptions) {
this.handleTransitionEnd = this.handleTransitionEnd.bind(this);
this.anchor = anchor;
this.popover = popover;
this.options = Object.assign(
{
skidding: 0,
distance: 0,
placement: 'bottom-start',
strategy: 'absolute',
transitionElement: this.popover,
visibleClass: 'popover-visible',
onAfterShow: () => {},
onAfterHide: () => {},
onTransitionEnd: () => {}
},
options
);
this.isVisible = false;
this.popover.hidden = true;
this.popover.classList.remove(this.options.visibleClass!);
this.popover.addEventListener('transitionend', this.handleTransitionEnd);
}
handleTransitionEnd(event: TransitionEvent) {
const target = event.target as HTMLElement;
// Make sure the transition event originates from from the correct element, and not one that has bubbled up
if (target === this.options.transitionElement) {
// This is called before the element is hidden so users can do things like reset scroll. It will fire once for
// every transition property. Use `event.propertyName` to determine which property has finished transitioning.
this.options.onTransitionEnd!.call(this, event);
// Make sure we only do this once, since transitionend will fire for every transition
if (!this.isVisible && !this.popover.hidden) {
this.popover.hidden = true;
this.popover.classList.remove(this.options.visibleClass!);
this.options.onAfterHide!.call(this);
}
}
}
destroy() {
this.popover.removeEventListener('transitionend', this.handleTransitionEnd);
if (this.popper) {
this.popper.destroy();
}
}
show() {
this.isVisible = true;
this.popover.hidden = false;
this.popover.clientWidth; // force reflow
requestAnimationFrame(() => this.popover.classList.add(this.options.visibleClass!));
if (this.popper) {
this.popper.destroy();
}
this.popper = createPopper(this.anchor, this.popover, {
placement: this.options.placement,
strategy: this.options.strategy,
modifiers: [
{
name: 'flip',
options: {
boundary: 'viewport'
}
},
{
name: 'offset',
options: {
offset: [this.options.skidding, this.options.distance]
}
}
]
});
this.popover.addEventListener('transitionend', () => this.options.onAfterShow!.call(this), { once: true });
// Reposition the menu after it appears in case a modifier kicked in
requestAnimationFrame(() => this.popper.update());
}
hide() {
// Apply the hidden styles and wait for the transition before hiding completely
this.isVisible = false;
this.popover.classList.remove(this.options.visibleClass!);
}
reposition() {
this.popper.update();
}
setOptions(options: PopoverOptions) {
this.options = Object.assign(this.options, options);
this.isVisible
? this.popover.classList.add(this.options.visibleClass!)
: this.popover.classList.remove(this.options.visibleClass!);
// Update popper options
if (this.popper) {
this.popper.setOptions({
placement: this.options.placement,
strategy: this.options.strategy
});
requestAnimationFrame(() => this.popper.update());
}
}
}
interface PopoverOptions {
distance?: number;
placement?:
| 'auto'
| 'auto-start'
| 'auto-end'
| 'top'
| 'top-start'
| 'top-end'
| 'bottom'
| 'bottom-start'
| 'bottom-end'
| 'right'
| 'right-start'
| 'right-end'
| 'left'
| 'left-start'
| 'left-end';
skidding?: number;
strategy?: 'absolute' | 'fixed';
transitionElement?: HTMLElement;
visibleClass?: string;
onAfterShow?: () => any;
onAfterHide?: () => any;
onTransitionEnd?: (event: TransitionEvent) => any;
}