mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-12 04:09:12 +00:00
backport PR 1600
This commit is contained in:
@@ -16,6 +16,7 @@ New versions of Web Awesome are released as-needed and generally occur when a cr
|
||||
|
||||
- Changed the `sl` prefix to `wa` for Web Awesome, including tags, events, etc.
|
||||
- Changed `primary` variants to `brand` in all components
|
||||
- Improved submenu selection by implementing the [safe triangle](https://www.smashingmagazine.com/2023/08/better-context-menus-safe-triangles/) method [#1550]
|
||||
- Removed `default` from `<wa-button>` and made `neutral` the new default
|
||||
- Removed the `circle` modifier from `<wa-button>` because button's no longer have a set height
|
||||
|
||||
|
||||
16
package.json
16
package.json
@@ -25,15 +25,8 @@
|
||||
"./dist/react/*": "./dist/react/*",
|
||||
"./dist/translations/*": "./dist/translations/*"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"cdn"
|
||||
],
|
||||
"keywords": [
|
||||
"web components",
|
||||
"custom elements",
|
||||
"components"
|
||||
],
|
||||
"files": ["dist", "cdn"],
|
||||
"keywords": ["web components", "custom elements", "components"],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/shoelace-style/shoelace.git"
|
||||
@@ -136,9 +129,6 @@
|
||||
"user-agent-data-types": "^0.3.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,js}": [
|
||||
"eslint --max-warnings 0 --cache --fix",
|
||||
"prettier --write"
|
||||
]
|
||||
"*.{ts,js}": ["eslint --max-warnings 0 --cache --fix", "prettier --write"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,14 @@ export default css`
|
||||
:host {
|
||||
--submenu-offset: -2px;
|
||||
|
||||
/* Private */
|
||||
--safe-triangle-cursor-x: 0;
|
||||
--safe-triangle-cursor-y: 0;
|
||||
--safe-triangle-submenu-start-x: 0;
|
||||
--safe-triangle-submenu-start-y: 0;
|
||||
--safe-triangle-submenu-end-x: 0;
|
||||
--safe-triangle-submenu-end-y: 0;
|
||||
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -60,6 +68,22 @@ export default css`
|
||||
margin-inline-start: var(--wa-space-xs);
|
||||
}
|
||||
|
||||
/* Safe triangle */
|
||||
.menu-item--submenu-expanded::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
z-index: calc(var(--wa-z-index-dropdown) - 1);
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
clip-path: polygon(
|
||||
var(--safe-triangle-cursor-x) var(--safe-triangle-cursor-y),
|
||||
var(--safe-triangle-submenu-start-x) var(--safe-triangle-submenu-start-y),
|
||||
var(--safe-triangle-submenu-end-x) var(--safe-triangle-submenu-end-y)
|
||||
);
|
||||
}
|
||||
|
||||
:host(:focus-visible) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ export class SubmenuController implements ReactiveController {
|
||||
|
||||
private addListeners() {
|
||||
if (!this.isConnected) {
|
||||
this.host.addEventListener('mousemove', this.handleMouseMove);
|
||||
this.host.addEventListener('mouseover', this.handleMouseOver);
|
||||
this.host.addEventListener('keydown', this.handleKeyDown);
|
||||
this.host.addEventListener('click', this.handleClick);
|
||||
@@ -61,6 +62,7 @@ export class SubmenuController implements ReactiveController {
|
||||
if (!this.isPopupConnected) {
|
||||
if (this.popupRef.value) {
|
||||
this.popupRef.value.addEventListener('mouseover', this.handlePopupMouseover);
|
||||
this.popupRef.value.addEventListener('wa-reposition', this.handlePopupReposition);
|
||||
this.isPopupConnected = true;
|
||||
}
|
||||
}
|
||||
@@ -68,6 +70,7 @@ export class SubmenuController implements ReactiveController {
|
||||
|
||||
private removeListeners() {
|
||||
if (this.isConnected) {
|
||||
this.host.removeEventListener('mousemove', this.handleMouseMove);
|
||||
this.host.removeEventListener('mouseover', this.handleMouseOver);
|
||||
this.host.removeEventListener('keydown', this.handleKeyDown);
|
||||
this.host.removeEventListener('click', this.handleClick);
|
||||
@@ -77,11 +80,18 @@ export class SubmenuController implements ReactiveController {
|
||||
if (this.isPopupConnected) {
|
||||
if (this.popupRef.value) {
|
||||
this.popupRef.value.removeEventListener('mouseover', this.handlePopupMouseover);
|
||||
this.popupRef.value.removeEventListener('wa-reposition', this.handlePopupReposition);
|
||||
this.isPopupConnected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the safe triangle cursor position
|
||||
private handleMouseMove = (event: MouseEvent) => {
|
||||
this.host.style.setProperty('--safe-triangle-cursor-x', `${event.clientX}px`);
|
||||
this.host.style.setProperty('--safe-triangle-cursor-y', `${event.clientY}px`);
|
||||
};
|
||||
|
||||
private handleMouseOver = () => {
|
||||
if (this.hasSlotController.test('submenu')) {
|
||||
this.enableSubmenu();
|
||||
@@ -188,6 +198,24 @@ export class SubmenuController implements ReactiveController {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
// Set the safe triangle values for the submenu when the position changes
|
||||
private handlePopupReposition = () => {
|
||||
const submenuSlot: HTMLSlotElement | null = this.host.renderRoot.querySelector("slot[name='submenu']");
|
||||
const menu = submenuSlot?.assignedElements({ flatten: true }).filter(el => el.localName === 'wa-menu')[0];
|
||||
const isRtl = this.localize.dir() === 'rtl';
|
||||
|
||||
if (!menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { left, top, width, height } = menu.getBoundingClientRect();
|
||||
|
||||
this.host.style.setProperty('--safe-triangle-submenu-start-x', `${isRtl ? left + width : left}px`);
|
||||
this.host.style.setProperty('--safe-triangle-submenu-start-y', `${top}px`);
|
||||
this.host.style.setProperty('--safe-triangle-submenu-end-x', `${isRtl ? left + width : left}px`);
|
||||
this.host.style.setProperty('--safe-triangle-submenu-end-y', `${top + height}px`);
|
||||
};
|
||||
|
||||
private setSubmenuState(state: boolean) {
|
||||
if (this.popupRef.value) {
|
||||
if (this.popupRef.value.active !== state) {
|
||||
|
||||
Reference in New Issue
Block a user