Compare commits

...

8 Commits

Author SHA1 Message Date
Cory LaViska
65b741cf9b Merge branch 'next' into drag-fix 2026-01-13 14:12:04 -05:00
Lindsay M
d76bef5dbb Unlist unreleased utilities from the docs (#1938) 2026-01-13 11:17:36 -05:00
Lindsay M
f8f54d543a Add justify-content utility classes (#1930)
* add `justify-content` utilities

* add docs

* fix up Align Items docs

* add Justify Content to sidebar

* add changelog

* add PR to changelog

* drop specificity of `justify-content` in layout utilities
2026-01-12 16:53:00 -05:00
Lindsay M
5b0e3ed1e8 Add missing .wa-gap-4xl utility class (#1931)
* add missing `.wa-gap-4xl`

* update the docs

* update changelog

* add PR to changelog
2026-01-12 16:35:01 -05:00
Brian Talbot
09ace44c17 A Glow Up for Dialogs That Pop Up (#1927)
* adding visual divider + padding to wa-dialog footers

* adding `wa-button`-focused `.shush` to `utils.css`
2026-01-09 14:52:23 -05:00
Lindsay M
f3de45803f Ensure consistent input heights in flex/grid containers (#1915)
* apply flex rules to `form-control` parts

* prevent input heights from growing in flex containers

* change approach: ignore `form-control` wrapper for styling
2025-12-31 11:35:37 -05:00
Steve Matney
ede1f0725d Ensuring styles apply for input labels when using 'slot="label"' (#1757)
* Ensuring styles apply for input labels when using 'slot="label"'

* Using 'has-slotted' class for codebase consistency

* Fleshing out 'has-slotted' label class to relevant form elements

* Ensuring label line height uses the correct token; removing unrelated PR changes

* Using 'has-label' class instead of 'has-slotted' for labels; applying it with all label content
2025-12-30 12:13:28 -05:00
Cory LaViska
61f89df17b fix drag bug; closes #1905 2025-12-29 11:27:20 -05:00
21 changed files with 176 additions and 29 deletions

View File

@@ -151,6 +151,7 @@
"ParamagicDev",
"peta",
"petabit",
"pointercancel",
"Preact",
"preconnect",
"prerendered",
@@ -204,6 +205,8 @@
"thead",
"Themer",
"tinycolor",
"touchcancel",
"touchend",
"transitionend",
"treeitem",
"treeshaking",

View File

@@ -196,6 +196,8 @@
</h2>
<ul>
<li><a href="/docs/utilities/align-items/">Align Items</a></li>
<!-- Pending 3.2.0 release -->
<!-- <li><a href="/docs/utilities/justify-content/">Justify Content</a></li> -->
<li><a href="/docs/utilities/gap/">Gap</a></li>
<li><a href="/docs/utilities/cluster/">Cluster</a></li>
<li><a href="/docs/utilities/flank/">Flank</a></li>

View File

@@ -130,6 +130,13 @@
}
}
/* dialogs */
wa-dialog:has([slot='footer']) [slot='footer'] {
border-block-start: var(--wa-border-width-s) solid var(--wa-color-surface-border);
flex-grow: 1; /* make footer contents span entire width of dialog */
padding-block-start: var(--wa-space-l);
}
/* anchor headings */
.anchor-heading a {
opacity: 0;
@@ -250,7 +257,6 @@
z-index: 0;
}
}
/* #endregion */
/* buttons with icon toggle on hover */
wa-button .icon-hover {
@@ -262,6 +268,13 @@
wa-button:hover .icon-hover {
display: inline-flex;
}
/* buttons that are "shushed" (visually muted) by default, but have their full presentation otherwise */
wa-button.shush {
&:not(:hover):not(active)::part(base) {
color: var(--wa-color-text-quiet);
}
}
/* #endregion */
/* #region resets */

View File

@@ -13,7 +13,11 @@ Components with the <wa-badge variant="warning">Experimental</wa-badge> badge sh
## Next
- Added `pointercancel` and `touchcancel` event handling to draggable elements to prevent drags from getting stuck
- Added `justify-content` CSS utilities [pr:1930]
- Added missing `.wa-gap-4xl` utility class [pr:1931]
- 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
## 3.1.0

View File

@@ -1,6 +1,6 @@
---
title: Align Items
description: Align items utilities set the gap property of flex and grid containers, like other Web Awesome layout utilities.
description: Align items utilities align items within flex and grid containers on the cross axis.
layout: docs
tags: layoutUtilities
---
@@ -10,6 +10,7 @@ tags: layoutUtilities
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
border-radius: var(--wa-border-radius-m);
min-block-size: 3em;
min-inline-size: 5em;
padding: var(--wa-space-2xs);
}
.preview-block {
@@ -20,16 +21,16 @@ tags: layoutUtilities
}
</style>
Web Awesome includes classes to set the `align-items` property of flex and grid containers. They can be used alongside other Web Awesome layout utilities, like [cluster](/docs/utilities/cluster) and [stack](/docs/utilities/stack), to align children in container on the container's cross axis.
Web Awesome includes classes to set the `align-items` property of flex and grid containers. Use them alongside other Web Awesome layout utilities, like [cluster](/docs/utilities/cluster) and [stack](/docs/utilities/stack), to align items in a container on the container's [cross axis](#whats-the-cross-axis).
| Class Name | `align-items` Value | Preview |
| ------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `wa-align-items-baseline` | `baseline` | <div class="wa-cluster wa-align-items-baseline preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-align-items-center` | `center` | <div class="wa-cluster wa-align-items-center preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-align-items-end` | `flex-end` | <div class="wa-cluster wa-align-items-end preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-align-items-start` | `flex-start` | <div class="wa-cluster wa-align-items-start preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-align-items-stretch` | `stretch` | <div class="wa-cluster wa-align-items-stretch preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| Class Name | `align-items` Value | Preview |
| ------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `wa-align-items-baseline` | `baseline` | <div class="wa-cluster wa-gap-2xs wa-align-items-baseline preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-align-items-center` | `center` | <div class="wa-cluster wa-gap-2xs wa-align-items-center preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-align-items-end` | `flex-end` | <div class="wa-cluster wa-gap-2xs wa-align-items-end preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-align-items-start` | `flex-start` | <div class="wa-cluster wa-gap-2xs wa-align-items-start preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-align-items-stretch` | `stretch` | <div class="wa-cluster wa-gap-2xs wa-align-items-stretch preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
## What's a Cross Axis?
## What's the Cross Axis?
The cross axis runs perpendicular to a flex container's content direction. For containers where `flex-direction` is `row` and content flows in the inline direction, the cross axis runs in the block direction. For containers where `flex-direction` is `column` and content flows in the block direction, the cross axis runs in the inline direction.
The cross axis runs perpendicular to a container's content direction. For containers where `flex-direction` is `row` and content flows in the inline direction, the cross axis runs in the block direction. For containers where `flex-direction` is `column` and content flows in the block direction, the cross axis runs in the inline direction.

View File

@@ -14,8 +14,7 @@ tags: layoutUtilities
}
</style>
Web Awesome includes classes to set the `gap` property of flex and grid containers. They can be used alongside other Web Awesome layout utilities, like [cluster](/docs/utilities/cluster) and [stack](/docs/utilities/stack), to change the space between items.
Or even by themselves — all gap properties also set `display: flex` with a specificity of 0 so that it can be trivially overridden.
Web Awesome includes classes to set the `gap` property of flex and grid containers. Use them alone to create a flex container with a gap, or use them alongside other Web Awesome layout utilities, like [cluster](/docs/utilities/cluster) and [stack](/docs/utilities/stack), to change the space between items.
Besides `wa-gap-0`, which sets `gap` to zero, each class corresponds to one of the [`--wa-space-*`](/docs/tokens/space) tokens in your theme.
@@ -31,3 +30,5 @@ Besides `wa-gap-0`, which sets `gap` to zero, each class corresponds to one of t
| `wa-gap-xl` | `--wa-space-xl` | <div class="wa-cluster wa-gap-xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-gap-2xl` | `--wa-space-2xl` | <div class="wa-cluster wa-gap-2xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-gap-3xl` | `--wa-space-3xl` | <div class="wa-cluster wa-gap-3xl"><div class="preview-block"></div><div class="preview-block"></div></div> |
<!-- Pending 3.2.0 release -->
<!-- | `wa-gap-4xl` | `--wa-space-4xl` | <div class="wa-cluster wa-gap-4xl"><div class="preview-block"></div><div class="preview-block"></div></div> | -->

View File

@@ -0,0 +1,39 @@
---
title: Justify Content
description: Justify content utilities determine how space is distributed between items in flex and grid containers.
layout: docs
tags: layoutUtilities
unpublished: true
unlisted: true
---
<style>
.preview-wrapper {
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
border-radius: var(--wa-border-radius-m);
min-block-size: 3em;
min-inline-size: 5em;
padding: var(--wa-space-2xs);
}
.preview-block {
aspect-ratio: 1 / 1;
background-color: var(--wa-color-neutral-fill-loud);
border-radius: var(--wa-border-radius-s);
min-block-size: 1em;
}
</style>
Web Awesome includes classes to set the `justify-content` property of flex and grid containers. Use them alongside other Web Awesome layout utilities, like [cluster](/docs/utilities/cluster) and [stack](/docs/utilities/stack), to distribute space between items along the container's [main axis](#whats-the-main-axis).
| Class Name | `justify-content` Value | Preview |
| ---------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `wa-justify-content-start` | `flex-start` | <div class="wa-cluster wa-gap-2xs wa-justify-content-start preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-justify-content-end` | `flex-end` | <div class="wa-cluster wa-gap-2xs wa-justify-content-end preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-justify-content-center` | `center` | <div class="wa-cluster wa-gap-2xs wa-justify-content-center preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-justify-content-space-around` | `space-around` | <div class="wa-cluster wa-gap-2xs wa-justify-content-space-around preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-justify-content-space-between` | `space-between` | <div class="wa-cluster wa-gap-2xs wa-justify-content-space-between preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
| `wa-justify-content-space-evenly` | `space-evenly` | <div class="wa-cluster wa-gap-2xs wa-justify-content-space-evenly preview-wrapper"><div class="preview-block"></div><div class="preview-block"></div></div> |
## What's the Main Axis?
The main axis runs parallel to a container's content direction. For grid containers and flex containers where `flex-direction` is `row`, the main axis runs in the inline direction. For containers where `flex-direction` is `column`, the main axis runs in the block direction.

View File

@@ -1277,7 +1277,14 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
})}
part="trigger-container form-control"
>
<div part="form-control-label" class="label" id="form-control-label">
<div
part="form-control-label"
class=${classMap({
label: true,
'has-label': hasLabel,
})}
id="form-control-label"
>
<slot name="label">${this.label}</slot>
</div>

View File

@@ -6,7 +6,6 @@ export default css`
}
.text-field {
flex: auto;
display: flex;
align-items: stretch;
justify-content: start;

View File

@@ -48,6 +48,27 @@ describe('<wa-input>', () => {
expect(input.title).to.equal('Test');
});
it('should have label with "has-label" class if label has a slotted element', async () => {
const el = await fixture<WaInput>(html` <wa-input><span slot="label">Name</span></wa-input> `);
await el.updateComplete;
const label = el.shadowRoot!.querySelector('[part~="form-control-label"]')!;
expect(label.classList.contains('has-label')).to.equal(true);
});
it('should have label with "has-label" class if label is provided as an attribute', async () => {
const el = await fixture<WaInput>(html` <wa-input label="Name"></wa-input> `);
await el.updateComplete;
const label = el.shadowRoot!.querySelector('[part~="form-control-label"]')!;
expect(label.classList.contains('has-label')).to.equal(true);
});
it('should not have "has-label" class on label if no label content is provided', async () => {
const el = await fixture<WaInput>(html` <wa-input></wa-input> `);
await el.updateComplete;
const label = el.shadowRoot!.querySelector('[part~="form-control-label"]')!;
expect(label.classList.contains('has-label')).to.equal(false);
});
it('should be disabled with the disabled attribute', async () => {
const el = await fixture<WaInput>(html` <wa-input disabled></wa-input> `);
await el.updateComplete;

View File

@@ -342,7 +342,15 @@ export default class WaInput extends WebAwesomeFormAssociatedElement {
(typeof this.value === 'number' || (this.value && this.value.length > 0));
return html`
<label part="form-control-label label" class="label" for="input" aria-hidden=${hasLabel ? 'false' : 'true'}>
<label
part="form-control-label label"
class=${classMap({
label: true,
'has-label': hasLabel,
})}
for="input"
aria-hidden=${hasLabel ? 'false' : 'true'}
>
<slot name="label">${this.label}</slot>
</label>

View File

@@ -352,7 +352,10 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
<label
part="form-control-label"
id="label"
class="label"
class=${classMap({
label: true,
'has-label': hasLabel,
})}
aria-hidden=${hasLabel ? 'false' : 'true'}
@click=${this.handleLabelClick}
>

View File

@@ -938,7 +938,10 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
<label
id="label"
part="form-control-label label"
class="label"
class=${classMap({
label: true,
'has-label': hasLabel,
})}
aria-hidden=${hasLabel ? 'false' : 'true'}
@click=${this.handleLabelClick}
>

View File

@@ -807,7 +807,7 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
id="label"
part="label"
for=${this.isRange ? 'thumb-min' : 'text-box'}
class=${classMap({ vh: !hasLabel })}
class=${classMap({ vh: !hasLabel, 'has-label': hasLabel })}
@pointerdown=${this.handleLabelPointerDown}
>
<slot name="label">${this.label}</slot>

View File

@@ -331,7 +331,15 @@ export default class WaTextarea extends WebAwesomeFormAssociatedElement {
const hasHint = this.hint ? true : !!hasHintSlot;
return html`
<label part="form-control-label label" class="label" for="input" aria-hidden=${hasLabel ? 'false' : 'true'}>
<label
part="form-control-label label"
class=${classMap({
label: true,
'has-label': hasLabel,
})}
for="input"
aria-hidden=${hasLabel ? 'false' : 'true'}
>
<slot name="label">${this.label}</slot>
</label>

View File

@@ -99,20 +99,24 @@ export class DraggableElement {
document.addEventListener('pointerup', this.handleDragStop);
document.addEventListener('pointermove', this.handleDragMove);
document.addEventListener('pointercancel', this.handleDragStop);
document.addEventListener('touchend', this.handleDragStop);
document.addEventListener('touchmove', this.handleDragMove);
document.addEventListener('touchcancel', this.handleDragStop);
this.options.start(clientX, clientY);
};
private handleDragStop = (event: PointerEvent | TouchEvent) => {
const clientX = 'touches' in event ? event.touches[0].clientX : (event as PointerEvent).clientX;
const clientY = 'touches' in event ? event.touches[0].clientY : (event as PointerEvent).clientY;
const clientX = 'changedTouches' in event ? event.changedTouches[0].clientX : (event as PointerEvent).clientX;
const clientY = 'changedTouches' in event ? event.changedTouches[0].clientY : (event as PointerEvent).clientY;
this.isDragging = false;
document.removeEventListener('pointerup', this.handleDragStop);
document.removeEventListener('pointermove', this.handleDragMove);
document.removeEventListener('pointercancel', this.handleDragStop);
document.removeEventListener('touchend', this.handleDragStop);
document.removeEventListener('touchmove', this.handleDragMove);
document.removeEventListener('touchcancel', this.handleDragStop);
this.options.stop(clientX, clientY);
};
@@ -141,8 +145,10 @@ export class DraggableElement {
public stop() {
document.removeEventListener('pointerup', this.handleDragStop);
document.removeEventListener('pointermove', this.handleDragMove);
document.removeEventListener('pointercancel', this.handleDragStop);
document.removeEventListener('touchend', this.handleDragStop);
document.removeEventListener('touchmove', this.handleDragMove);
document.removeEventListener('touchcancel', this.handleDragStop);
this.element.removeEventListener('pointerdown', this.handleDragStart);
if (supportsTouch) {
this.element.removeEventListener('touchstart', this.handleDragStart);

View File

@@ -6,8 +6,14 @@ export default css`
flex-direction: column;
}
/* Treat wrapped labels, inputs, and hints as direct children of the host element */
[part~='form-control'] {
display: contents;
}
/* Label */
:is([part~='form-control-label'], [part~='label']):has(*:not(:empty)) {
:is([part~='form-control-label'], [part~='label']):has(*:not(:empty)),
:is([part~='form-control-label'], [part~='label']).has-label {
display: inline-flex;
color: var(--wa-form-control-label-color);
font-weight: var(--wa-form-control-label-font-weight);
@@ -29,7 +35,6 @@ export default css`
line-height: var(--wa-form-control-hint-line-height);
margin-block-start: 0.5em;
font-size: var(--wa-font-size-smaller);
line-height: var(--wa-form-control-label-line-height);
&:not(.has-slotted) {
display: none;

View File

@@ -5,6 +5,7 @@
@import url('utilities/scroll-lock.css');
@import url('utilities/placeholder.css');
@import url('utilities/align-items.css');
@import url('utilities/justify-content.css');
@import url('utilities/border-radius.css');
@import url('utilities/gap.css');
@import url('utilities/text.css');

View File

@@ -45,4 +45,7 @@
.wa-gap-3xl {
gap: var(--wa-space-3xl);
}
.wa-gap-4xl {
gap: var(--wa-space-4xl);
}
}

View File

@@ -0,0 +1,20 @@
@layer wa-utilities {
.wa-justify-content-start {
justify-content: flex-start;
}
.wa-justify-content-end {
justify-content: flex-end;
}
.wa-justify-content-center {
justify-content: center;
}
.wa-justify-content-space-around {
justify-content: space-around;
}
.wa-justify-content-space-between {
justify-content: space-between;
}
.wa-justify-content-space-evenly {
justify-content: space-evenly;
}
}

View File

@@ -27,11 +27,11 @@
[class*='wa-cluster'] {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
:where([class*='wa-cluster']) {
align-items: center;
justify-content: flex-start;
}
/* #endregion */
@@ -75,7 +75,6 @@
[class*='wa-frame'] {
display: flex;
aspect-ratio: 1 / 1;
justify-content: center;
overflow: hidden;
}
@@ -98,6 +97,7 @@
:where([class*='wa-frame']) {
align-items: center;
justify-content: center;
}
/* #endregion */
@@ -118,7 +118,6 @@
[class*='wa-split'] {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
[class*='wa-split'],
@@ -141,6 +140,7 @@
:where([class*='wa-split']) {
align-items: center;
justify-content: space-between;
}
/* #endregion */
@@ -149,11 +149,11 @@
[class*='wa-stack'] {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
:where([class*='wa-stack']) {
align-items: stretch;
justify-content: flex-start;
}
/* #endregion */
}