mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 12:09:26 +00:00
Add popper.js to dropdowns
This commit is contained in:
5
package-lock.json
generated
5
package-lock.json
generated
@@ -452,6 +452,11 @@
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"dev": true
|
||||
},
|
||||
"popper.js": {
|
||||
"version": "1.16.0",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.0.tgz",
|
||||
"integrity": "sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw=="
|
||||
},
|
||||
"pretty-bytes": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.3.0.tgz",
|
||||
|
||||
@@ -30,5 +30,7 @@
|
||||
"workbox-build": "4.3.1"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {}
|
||||
"dependencies": {
|
||||
"popper.js": "^1.16.0"
|
||||
}
|
||||
}
|
||||
|
||||
11
src/components.d.ts
vendored
11
src/components.d.ts
vendored
@@ -55,6 +55,10 @@ export namespace Components {
|
||||
interface SDropdown {
|
||||
'close': () => Promise<void>;
|
||||
'open': () => Promise<void>;
|
||||
/**
|
||||
* The preferred placement of the dropdown menu. Note that the actual placement may vary as needed to keep the menu inside of the viewport.
|
||||
*/
|
||||
'placement': 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
|
||||
}
|
||||
interface SDropdownDivider {}
|
||||
interface SDropdownItem {
|
||||
@@ -354,7 +358,12 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
'type'?: string;
|
||||
}
|
||||
interface SDropdown {}
|
||||
interface SDropdown {
|
||||
/**
|
||||
* The preferred placement of the dropdown menu. Note that the actual placement may vary as needed to keep the menu inside of the viewport.
|
||||
*/
|
||||
'placement'?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end';
|
||||
}
|
||||
interface SDropdownDivider {}
|
||||
interface SDropdownItem {
|
||||
/**
|
||||
|
||||
@@ -18,11 +18,13 @@ $dropdown-color: $menu-color !default;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
// TODO: use $dropdown-* variables here
|
||||
.s-dropdown__trigger {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.s-dropdown__menu {
|
||||
position: absolute;
|
||||
top: calc(100% + 2px);
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
font-family: $dropdown-font-family;
|
||||
font-weight: $dropdown-font-weight;
|
||||
font-size: $dropdown-font-size;
|
||||
@@ -31,16 +33,12 @@ $dropdown-color: $menu-color !default;
|
||||
border: solid 1px $dropdown-border-color;
|
||||
border-radius: 4px;
|
||||
box-shadow: $dropdown-box-shadow;
|
||||
padding-top: 10px; // TODO: these should match $dropdown-item-padding-y
|
||||
padding-bottom: 10px;
|
||||
padding-top: $menu-padding-y;
|
||||
padding-bottom: $menu-padding-y;
|
||||
opacity: 0;
|
||||
transform-origin: top left;
|
||||
transform: scale(0.9);
|
||||
transition: 100ms opacity, 100ms transform;
|
||||
z-index: 10;
|
||||
transition: 100ms opacity;
|
||||
}
|
||||
|
||||
.s-dropdown--open .s-dropdown__menu {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, Method, State, h } from '@stencil/core';
|
||||
import { Component, Method, Prop, State, Watch, h } from '@stencil/core';
|
||||
import PopperJs from 'popper.js';
|
||||
|
||||
@Component({
|
||||
tag: 's-dropdown',
|
||||
@@ -8,6 +9,8 @@ import { Component, Method, State, h } from '@stencil/core';
|
||||
export class Dropdown {
|
||||
items: [HTMLSDropdownItemElement];
|
||||
menu: HTMLElement;
|
||||
popper: PopperJs;
|
||||
trigger: HTMLElement;
|
||||
|
||||
constructor() {
|
||||
this.handleDocumentClick = this.handleDocumentClick.bind(this);
|
||||
@@ -20,10 +23,41 @@ export class Dropdown {
|
||||
|
||||
@State() isOpen = false;
|
||||
|
||||
/**
|
||||
* The preferred placement of the dropdown menu. Note that the actual placement may vary as needed to keep the menu
|
||||
* inside of the viewport.
|
||||
*/
|
||||
@Prop() placement: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end' = 'bottom-start';
|
||||
|
||||
@Watch('placement')
|
||||
handlePlacementChange() {
|
||||
if (this.popper) {
|
||||
this.popper.options.placement = this.placement;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
this.popper = new PopperJs(this.trigger, this.menu, {
|
||||
placement: this.placement,
|
||||
modifiers: {
|
||||
offset: {
|
||||
offset: '0, 2px'
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
componentDidUnload() {
|
||||
if (this.popper) {
|
||||
this.popper.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Method()
|
||||
async open() {
|
||||
this.items = this.getAllItems();
|
||||
this.menu.hidden = false;
|
||||
this.popper.scheduleUpdate();
|
||||
requestAnimationFrame(() => (this.isOpen = true));
|
||||
|
||||
document.addEventListener('click', this.handleDocumentClick);
|
||||
@@ -70,8 +104,7 @@ export class Dropdown {
|
||||
}
|
||||
|
||||
handleDocumentKeyDown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
if (event.key === 'Escape' || event.key === 'Tab') {
|
||||
this.close();
|
||||
}
|
||||
|
||||
@@ -98,7 +131,7 @@ export class Dropdown {
|
||||
}
|
||||
|
||||
handleMenuMouseDown(event: MouseEvent) {
|
||||
// Keep focus on the dropdown trigger when selecting a menu item
|
||||
// Keep focus on the dropdown trigger when selecting menu items
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
@@ -135,7 +168,7 @@ export class Dropdown {
|
||||
's-dropdown--open': this.isOpen
|
||||
}}
|
||||
>
|
||||
<span class="s-dropdown__trigger" onClick={() => this.toggleMenu()}>
|
||||
<span class="s-dropdown__trigger" ref={el => (this.trigger = el)} onClick={() => this.toggleMenu()}>
|
||||
<slot name="trigger" />
|
||||
</span>
|
||||
|
||||
|
||||
@@ -201,6 +201,9 @@
|
||||
<s-dropdown-item>Dropdown Item 2</s-dropdown-item>
|
||||
<s-dropdown-item>Dropdown Item 3</s-dropdown-item>
|
||||
<s-dropdown-divider></s-dropdown-divider>
|
||||
<s-dropdown-item checked>Checked</s-dropdown-item>
|
||||
<s-dropdown-item disabled>Disabled</s-dropdown-item>
|
||||
<s-dropdown-divider></s-dropdown-divider>
|
||||
<s-dropdown-item>
|
||||
Prefix
|
||||
<span slot="prefix"><i class="fa fa-save"></i></span>
|
||||
@@ -213,9 +216,6 @@
|
||||
Suffix Icon
|
||||
<span slot="suffix"><i class="fa fa-external-link"></i></span>
|
||||
</s-dropdown-item>
|
||||
<s-dropdown-divider></s-dropdown-divider>
|
||||
<s-dropdown-item checked>Checked</s-dropdown-item>
|
||||
<s-dropdown-item disabled>Disabled</s-dropdown-item>
|
||||
</s-dropdown>
|
||||
|
||||
<hr />
|
||||
|
||||
Reference in New Issue
Block a user