mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-19 15:34:15 +00:00
Compare commits
8 Commits
lm/layout-
...
progress-r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e23d423d29 | ||
|
|
c8ddc2c1c0 | ||
|
|
64a9374aa9 | ||
|
|
67785f64cb | ||
|
|
39ab883802 | ||
|
|
08ef969db3 | ||
|
|
72c4fb7af7 | ||
|
|
827d70b2f5 |
@@ -178,11 +178,11 @@ If you want the dialog to close when the user clicks on the overlay, add the `li
|
||||
|
||||
### Preventing the Dialog from Closing
|
||||
|
||||
By default, dialogs will close when the user clicks the close button, clicks the overlay, or presses the [[Escape]] key. In most cases, the default behavior is the best behavior in terms of UX. However, there are situations where this may be undesirable, such as when data loss will occur.
|
||||
By default, dialogs will close when the user clicks the close button or presses the [[Escape]] key. In most cases, the default behavior is the best behavior in terms of UX. However, there are situations where this may be undesirable, such as when data loss will occur.
|
||||
|
||||
To keep the dialog open in such cases, you can cancel the `wa-hide` event. When canceled, the dialog will remain open and pulse briefly to draw the user's attention to it.
|
||||
|
||||
You can use `event.detail.source` to determine which element triggered the request to close. This example prevents the dialog from closing when the overlay is clicked, but allows the close button or [[Escape]] to dismiss it.
|
||||
You can use `event.detail.source` to determine which element triggered the request to close. This example prevents the dialog from closing unless a specific button is clicked.
|
||||
|
||||
```html {.example}
|
||||
<wa-dialog label="Dialog" class="dialog-deny-close">
|
||||
|
||||
@@ -13,11 +13,18 @@ Components with the <wa-badge variant="warning">Experimental</wa-badge> badge sh
|
||||
|
||||
## Next
|
||||
|
||||
- Added `justify-content` CSS utilities [pr:1930]
|
||||
- Added missing `.wa-gap-4xl` utility class [pr:1931]
|
||||
- Added `pointercancel` and `touchcancel` event handling to draggable elements to prevent drags from getting stuck
|
||||
- Added `wa-justify-content-*` utility classes [pr:1930]
|
||||
- Added missing `wa-gap-4xl` utility class [pr:1931]
|
||||
- Added `track` and `indicator` CSS parts to `<wa-progress-ring>` [pr:1863]
|
||||
- Fixed a bug in `<wa-combobox>` that prevented the listbox from opening when options were preselected [issue:1883]
|
||||
- Fixed a bug in `<wa-popup>` and `<wa-dropdown-item>` that caused an error when removing a popup while it was opening [issue:1910]
|
||||
- Fixed a bug in `<wa-popup>` and `<wa-dropdown>` that caused errors when shadow DOM queries returned null [issue:1911]
|
||||
- Fixed a bug in `<wa-combobox>` that prevented the listbox from opening when options were preselected [issue:1883]
|
||||
- Fixed a bug in draggable elements that caused a TypeError on `touchend` events when `event.touches` was empty
|
||||
- Fixed a bug in `<wa-tree-item>` that caused the cursor to show a pointer when no expand icon was present [pr:1936]
|
||||
- Modified `wa-align-items-*` utility classes to apply `display: flex` by default [pr:1943]
|
||||
|
||||
## 3.1.0
|
||||
|
||||
@@ -20,6 +20,8 @@ tags: layoutUtilities
|
||||
}
|
||||
</style>
|
||||
|
||||
{{ description }}
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-cluster">
|
||||
<div></div>
|
||||
|
||||
@@ -20,7 +20,7 @@ tags: layoutUtilities
|
||||
}
|
||||
</style>
|
||||
|
||||
When space is limited, the items wrap.
|
||||
{{ description }} When space is limited, the items wrap.
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-flank">
|
||||
|
||||
@@ -19,6 +19,8 @@ tags: layoutUtilities
|
||||
}
|
||||
</style>
|
||||
|
||||
{{ description }}
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-frame" style="max-inline-size: 20rem;">
|
||||
<div></div>
|
||||
|
||||
@@ -20,6 +20,8 @@ tags: layoutUtilities
|
||||
}
|
||||
</style>
|
||||
|
||||
{{ description }}
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-grid">
|
||||
<div></div>
|
||||
|
||||
@@ -20,6 +20,8 @@ tags: layoutUtilities
|
||||
}
|
||||
</style>
|
||||
|
||||
{{ description }}
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-split">
|
||||
<div></div>
|
||||
|
||||
@@ -20,6 +20,8 @@ tags: layoutUtilities
|
||||
}
|
||||
</style>
|
||||
|
||||
{{ description }}
|
||||
|
||||
```html {.example}
|
||||
<div class="wa-stack">
|
||||
<div></div>
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function (plop) {
|
||||
},
|
||||
{
|
||||
type: 'add',
|
||||
path: '../../src/components/{{ tagWithoutPrefix tag }}/{{ tagWithoutPrefix tag }}.css',
|
||||
path: '../../src/components/{{ tagWithoutPrefix tag }}/{{ tagWithoutPrefix tag }}.styles.ts',
|
||||
templateFile: 'templates/component/styles.hbs',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ import { html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { watch } from '../../internal/watch.js';
|
||||
import WebAwesomeElement from '../../internal/webawesome-element.js';
|
||||
import styles from './{{ tagWithoutPrefix tag }}.css';
|
||||
import styles from './{{ tagWithoutPrefix tag }}.styles.js';
|
||||
|
||||
/**
|
||||
* @summary Short summary of the component's intended use.
|
||||
@@ -21,7 +21,7 @@ import styles from './{{ tagWithoutPrefix tag }}.css';
|
||||
*/
|
||||
@customElement("{{ tag }}")
|
||||
export default class {{ properCase tag }} extends WebAwesomeElement {
|
||||
static css = styles;
|
||||
static css = [styles];
|
||||
|
||||
/** An example attribute. */
|
||||
@property() attr = 'example';
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
:host {
|
||||
display: block;
|
||||
import { css } from "lit";
|
||||
|
||||
export default css`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
`
|
||||
|
||||
@@ -155,20 +155,21 @@ export default class WaDropdownItem extends WebAwesomeElement {
|
||||
|
||||
/** Opens the submenu. */
|
||||
async openSubmenu() {
|
||||
if (!this.hasSubmenu || !this.submenuElement) return;
|
||||
const submenu = this.submenuElement;
|
||||
if (!this.hasSubmenu || !submenu || !this.isConnected) return;
|
||||
|
||||
// Notify parent dropdown to handle positioning
|
||||
this.notifyParentOfOpening();
|
||||
|
||||
// Use Popover API to show the submenu
|
||||
this.submenuElement.showPopover();
|
||||
this.submenuElement.hidden = false;
|
||||
this.submenuElement.setAttribute('data-visible', '');
|
||||
submenu.showPopover?.();
|
||||
submenu.hidden = false;
|
||||
submenu.setAttribute('data-visible', '');
|
||||
this.submenuOpen = true;
|
||||
this.setAttribute('aria-expanded', 'true');
|
||||
|
||||
// Animate the submenu
|
||||
await animateWithClass(this.submenuElement, 'show');
|
||||
await animateWithClass(submenu, 'show');
|
||||
|
||||
// Set focus to the first submenu item
|
||||
setTimeout(() => {
|
||||
@@ -210,16 +211,19 @@ export default class WaDropdownItem extends WebAwesomeElement {
|
||||
|
||||
/** Closes the submenu. */
|
||||
async closeSubmenu() {
|
||||
if (!this.hasSubmenu || !this.submenuElement) return;
|
||||
const submenu = this.submenuElement;
|
||||
if (!this.hasSubmenu || !submenu) return;
|
||||
|
||||
this.submenuOpen = false;
|
||||
this.setAttribute('aria-expanded', 'false');
|
||||
|
||||
if (!this.submenuElement.hidden) {
|
||||
await animateWithClass(this.submenuElement, 'hide');
|
||||
this.submenuElement.hidden = true;
|
||||
this.submenuElement.removeAttribute('data-visible');
|
||||
this.submenuElement.hidePopover();
|
||||
if (!submenu.hidden) {
|
||||
await animateWithClass(submenu, 'hide');
|
||||
if (submenu?.isConnected) {
|
||||
submenu.hidden = true;
|
||||
submenu.removeAttribute('data-visible');
|
||||
submenu.hidePopover?.();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,9 +138,9 @@ export default class WaDropdown extends WebAwesomeElement {
|
||||
|
||||
/** Gets all dropdown items slotted in the menu. */
|
||||
private getItems(includeDisabled = false): WaDropdownItem[] {
|
||||
const items = this.defaultSlot
|
||||
.assignedElements({ flatten: true })
|
||||
.filter(el => el.localName === 'wa-dropdown-item') as WaDropdownItem[];
|
||||
const items = (this.defaultSlot?.assignedElements({ flatten: true }) ?? []).filter(
|
||||
el => el.localName === 'wa-dropdown-item',
|
||||
) as WaDropdownItem[];
|
||||
|
||||
return includeDisabled ? items : items.filter(item => !item.disabled);
|
||||
}
|
||||
@@ -165,9 +165,9 @@ export default class WaDropdown extends WebAwesomeElement {
|
||||
|
||||
/** Syncs item sizes with the dropdown's size property. */
|
||||
private syncItemSizes() {
|
||||
const items = this.defaultSlot
|
||||
.assignedElements({ flatten: true })
|
||||
.filter(el => el.localName === 'wa-dropdown-item') as WaDropdownItem[];
|
||||
const items = (this.defaultSlot?.assignedElements({ flatten: true }) ?? []).filter(
|
||||
el => el.localName === 'wa-dropdown-item',
|
||||
) as WaDropdownItem[];
|
||||
items.forEach(item => (item.size = this.size));
|
||||
}
|
||||
|
||||
@@ -230,7 +230,7 @@ export default class WaDropdown extends WebAwesomeElement {
|
||||
/** Shows the dropdown menu. This should only be called from within updated(). */
|
||||
private async showMenu() {
|
||||
const anchor = this.getTrigger();
|
||||
if (!anchor) return;
|
||||
if (!anchor || !this.popup || !this.menu) return;
|
||||
|
||||
const showEvent = new WaShowEvent();
|
||||
this.dispatchEvent(showEvent);
|
||||
@@ -270,6 +270,8 @@ export default class WaDropdown extends WebAwesomeElement {
|
||||
|
||||
/** Hides the dropdown menu. This should only be called from within updated(). */
|
||||
private async hideMenu() {
|
||||
if (!this.popup || !this.menu) return;
|
||||
|
||||
const hideEvent = new WaHideEvent({ source: this });
|
||||
this.dispatchEvent(hideEvent);
|
||||
if (hideEvent.defaultPrevented) {
|
||||
@@ -720,12 +722,12 @@ export default class WaDropdown extends WebAwesomeElement {
|
||||
nativeButton.setAttribute('aria-haspopup', 'menu');
|
||||
nativeButton.setAttribute('aria-expanded', this.open ? 'true' : 'false');
|
||||
|
||||
this.menu.setAttribute('aria-expanded', 'false');
|
||||
this.menu?.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
|
||||
render() {
|
||||
// On initial render, we want to use this.open, for everything else, we sync off of this.popup.active to get animations working.
|
||||
let active = this.hasUpdated ? this.popup.active : this.open;
|
||||
let active = this.hasUpdated ? this.popup?.active : this.open;
|
||||
|
||||
return html`
|
||||
<wa-popup
|
||||
|
||||
@@ -286,11 +286,11 @@ export default class WaPopup extends WebAwesomeElement {
|
||||
|
||||
private start() {
|
||||
// We can't start the positioner without an anchor
|
||||
if (!this.anchorEl || !this.active) {
|
||||
if (!this.anchorEl || !this.active || !this.isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.popup.showPopover?.();
|
||||
this.popup?.showPopover?.();
|
||||
|
||||
this.cleanup = autoUpdate(this.anchorEl, this.popup, () => {
|
||||
this.reposition();
|
||||
@@ -299,7 +299,7 @@ export default class WaPopup extends WebAwesomeElement {
|
||||
|
||||
private async stop(): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
this.popup.hidePopover?.();
|
||||
this.popup?.hidePopover?.();
|
||||
|
||||
if (this.cleanup) {
|
||||
this.cleanup();
|
||||
@@ -317,7 +317,7 @@ export default class WaPopup extends WebAwesomeElement {
|
||||
/** Forces the popup to recalculate and reposition itself. */
|
||||
reposition() {
|
||||
// Nothing to do if the popup is inactive or the anchor doesn't exist
|
||||
if (!this.active || !this.anchorEl) {
|
||||
if (!this.active || !this.anchorEl || !this.popup) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -498,7 +498,7 @@ export default class WaPopup extends WebAwesomeElement {
|
||||
}
|
||||
|
||||
private updateHoverBridge = () => {
|
||||
if (this.hoverBridge && this.anchorEl) {
|
||||
if (this.hoverBridge && this.anchorEl && this.popup) {
|
||||
const anchorRect = this.anchorEl.getBoundingClientRect();
|
||||
const popupRect = this.popup.getBoundingClientRect();
|
||||
const isVertical = this.placement.includes('top') || this.placement.includes('bottom');
|
||||
|
||||
@@ -15,6 +15,8 @@ import styles from './progress-ring.styles.js';
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart label - The progress ring label.
|
||||
* @csspart track - The progress ring's track.
|
||||
* @csspart indicator - The progress ring's indicator.
|
||||
*
|
||||
* @cssproperty --size - The diameter of the progress ring (cannot be a percentage).
|
||||
* @cssproperty --track-width - The width of the track.
|
||||
@@ -70,8 +72,8 @@ export default class WaProgressRing extends WebAwesomeElement {
|
||||
style="--percentage: ${this.value / 100}"
|
||||
>
|
||||
<svg class="image">
|
||||
<circle class="track"></circle>
|
||||
<circle class="indicator" style="stroke-dashoffset: ${this.indicatorOffset}"></circle>
|
||||
<circle part="track" class="track"></circle>
|
||||
<circle part="indicator" class="indicator" style="stroke-dashoffset: ${this.indicatorOffset}"></circle>
|
||||
</svg>
|
||||
|
||||
<slot id="label" part="label" class="label"></slot>
|
||||
|
||||
@@ -85,6 +85,10 @@ export default css`
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tree-item:not(.tree-item-has-expand-button):not(.tree-item-loading) .expand-button {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.tree-item-loading .expand-icon-slot wa-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ export default class WaTreeItem extends WebAwesomeElement {
|
||||
}
|
||||
|
||||
render() {
|
||||
const isRtl = this.hasUpdated ? this.localize.dir() === 'rtl' : this.dir === 'rtl';
|
||||
const isRtl = this.localize.dir() === 'rtl';
|
||||
const showExpandButton = !this.loading && (!this.isLeaf || this.lazy);
|
||||
|
||||
return html`
|
||||
|
||||
Reference in New Issue
Block a user