kopia lustrzana https://github.com/shoelace-style/shoelace
remove popover util
rodzic
d720121044
commit
ee9ce8a87b
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
Ładowanie…
Reference in New Issue