From 3e3e5276a61e316da6d97110b67c4b7cb5738125 Mon Sep 17 00:00:00 2001
From: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
Date: Wed, 20 Aug 2025 17:07:29 -0400
Subject: [PATCH 1/9] Apply `position: relative` only to buttons that contain
badges (#1346)
* make relative positioning conditional
* add changelog
---
packages/webawesome/docs/docs/resources/changelog.md | 1 +
packages/webawesome/src/components/button/button.css | 3 +++
2 files changed, 4 insertions(+)
diff --git a/packages/webawesome/docs/docs/resources/changelog.md b/packages/webawesome/docs/docs/resources/changelog.md
index dcf0fdd4f..5bc2f7912 100644
--- a/packages/webawesome/docs/docs/resources/changelog.md
+++ b/packages/webawesome/docs/docs/resources/changelog.md
@@ -28,6 +28,7 @@ Components with the Experimental badge sh
- Fixed a bug in JSX typings that generated the incorrect component imports [issue:1303]
- Fixed a bug in `` that prevented the thumb from receiving focus when clicking/tapping [issue:1312]
- Fixed a bug in `` that caused the shadow to appear below relatively-positioned elements [issue:1326]
+- Fixed `` to have `static` positioning by default and `relative` positioning only when used with `` [pr:1346]
## 3.0.0-beta.4
diff --git a/packages/webawesome/src/components/button/button.css b/packages/webawesome/src/components/button/button.css
index 68aa78c1a..4bb79f2b2 100644
--- a/packages/webawesome/src/components/button/button.css
+++ b/packages/webawesome/src/components/button/button.css
@@ -1,6 +1,9 @@
@layer wa-component {
:host {
display: inline-block;
+ }
+
+ :host(:has(wa-badge)) {
position: relative;
}
}
From 9d82749abb9c655a614266efe267f04b39a4935a Mon Sep 17 00:00:00 2001
From: Brian Talbot
Date: Wed, 20 Aug 2025 17:24:36 -0400
Subject: [PATCH 2/9] =?UTF-8?q?=F0=9F=92=85=20Docs:=20Sidebar=20Visual=20+?=
=?UTF-8?q?=20UI=20Polish=20(#1341)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* using layout utilities for sidebar heading link styling
* syncing up sidebar heading + general link styles
* updating sidebar heading text + icon alignment
* updating layout of experimental + pro badge decoratives
* increasing visual padding of `#search-trigger`'s ``
* fixing `` indentations
---
.../webawesome/docs/_includes/sidebar.njk | 90 ++++++++++++-------
.../webawesome/docs/assets/styles/docs.css | 17 +---
2 files changed, 58 insertions(+), 49 deletions(-)
diff --git a/packages/webawesome/docs/_includes/sidebar.njk b/packages/webawesome/docs/_includes/sidebar.njk
index 6af15e91a..18ed29c1f 100644
--- a/packages/webawesome/docs/_includes/sidebar.njk
+++ b/packages/webawesome/docs/_includes/sidebar.njk
@@ -31,16 +31,19 @@
- Page
-
- PRO
+
+
+ Page
+
+ PRO
+
Animated Image
Animation
@@ -57,12 +60,16 @@
Callout
Card
- Carousel
-
+
+ Carousel
+
+
@@ -70,8 +77,10 @@
Color Picker
Comparison
- Copy Button
-
+
+ Copy Button
+
+
Details
Dialog
@@ -136,9 +145,9 @@
@@ -154,9 +163,9 @@
@@ -179,15 +191,17 @@
- App
- PRO
+
+ App
+ PRO
+
- Blog & News
- PRO
+
+ Blog & News
+ PRO
+
- Ecommerce
- PRO
+
+ Ecommerce
+ PRO
+
- Layouts
- PRO
+
+ Layouts
+ PRO
+
diff --git a/packages/webawesome/docs/assets/styles/docs.css b/packages/webawesome/docs/assets/styles/docs.css
index 93ebd9527..dfd417d68 100644
--- a/packages/webawesome/docs/assets/styles/docs.css
+++ b/packages/webawesome/docs/assets/styles/docs.css
@@ -181,11 +181,6 @@ wa-page > header {
li wa-icon {
color: var(--wa-color-text-quiet);
- vertical-align: middle;
-
- &[name='flask'] {
- margin-inline: 0.125em;
- }
}
}
@@ -205,25 +200,16 @@ wa-badge.pro {
color: var(--wa-color-text-quiet);
a {
- display: flex;
- align-items: center;
- gap: 0.4em;
color: var(--wa-color-text-normal);
text-decoration: none;
wa-icon {
- margin-block-end: -0.15em;
font-size: var(--wa-font-size-s);
font-weight: var(--wa-font-weight-action);
- color: var(--wa-color-gray-70);
}
&:hover {
- color: var(--wa-color-brand-on-normal);
-
- wa-icon {
- color: var(--wa-color-brand-on-quiet);
- }
+ text-decoration: underline;
}
}
}
@@ -415,6 +401,7 @@ wa-button#search-trigger {
#search-trigger kbd {
font-size: var(--wa-font-size-2xs);
line-height: var(--wa-form-control-value-line-height);
+ padding-inline: 0.33em;
}
/* Search list pages */
From 8b763d039218e50383f0e85f82ce62f3ddc5b704 Mon Sep 17 00:00:00 2001
From: Konnor Rogers
Date: Wed, 20 Aug 2025 17:45:28 -0400
Subject: [PATCH 3/9] remove page (#1352)
---
package-lock.json | 2 +-
.../webawesome/src/components/page/page.css | 250 ----------
.../src/components/page/page.mobile.styles.ts | 11 -
.../src/components/page/page.test.ts | 15 -
.../webawesome/src/components/page/page.ts | 455 ------------------
5 files changed, 1 insertion(+), 732 deletions(-)
delete mode 100644 packages/webawesome/src/components/page/page.css
delete mode 100644 packages/webawesome/src/components/page/page.mobile.styles.ts
delete mode 100644 packages/webawesome/src/components/page/page.test.ts
delete mode 100644 packages/webawesome/src/components/page/page.ts
diff --git a/package-lock.json b/package-lock.json
index 174475f77..7aa7c731d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14000,7 +14000,7 @@
},
"packages/webawesome-pro": {
"name": "@shoelace-style/webawesome-pro",
- "version": "3.0.0-beta.3",
+ "version": "3.0.0-beta.4",
"dependencies": {
"@ctrl/tinycolor": "^4.1.0",
"@floating-ui/dom": "^1.6.13",
diff --git a/packages/webawesome/src/components/page/page.css b/packages/webawesome/src/components/page/page.css
deleted file mode 100644
index 812debb1a..000000000
--- a/packages/webawesome/src/components/page/page.css
+++ /dev/null
@@ -1,250 +0,0 @@
-:host {
- display: block;
- background-color: var(--wa-color-surface-default);
- box-sizing: border-box;
- height: 100%;
- --menu-width: auto;
- --main-width: 1fr;
- --aside-width: auto;
- --banner-height: 0px;
- --header-height: 0px;
- --subheader-height: 0px;
- --scroll-margin-top: calc(var(--header-height, 0px) + var(--subheader-height, 0px) + 0.5em);
-}
-
-slot[name]:not([name='skip-to-content'], [name='navigation-toggle'])::slotted(*) {
- display: flex;
- background-color: var(--wa-color-surface-default);
-}
-
-::slotted([slot='banner']) {
- align-items: center;
- justify-content: center;
- gap: var(--wa-space-m);
- padding: var(--wa-space-xs) var(--wa-space-m);
-}
-
-::slotted([slot='header']) {
- align-items: center;
- justify-content: space-between;
- flex-wrap: wrap;
- gap: var(--wa-space-m);
- padding: var(--wa-space-m);
- flex: auto;
-}
-
-::slotted([slot='subheader']) {
- align-items: center;
- justify-content: space-between;
- flex-wrap: wrap;
- gap: var(--wa-space-m);
- padding: var(--wa-space-xs) var(--wa-space-m);
-}
-
-::slotted([slot*='navigation']),
-::slotted([slot='menu']),
-::slotted([slot='aside']) {
- flex-direction: column;
- gap: var(--wa-space-m);
- padding: var(--wa-space-m);
-}
-
-::slotted([slot='main-header']) {
- align-items: center;
- justify-content: space-between;
- flex-wrap: wrap;
- gap: var(--wa-space-m);
- padding: var(--wa-space-m) var(--wa-space-3xl);
-}
-
-slot:not([name]) {
- /* See #331 */
- &::slotted(main),
- &::slotted(section) {
- padding: var(--wa-space-3xl);
- }
-}
-
-::slotted([slot='main-footer']),
-::slotted([slot='footer']) {
- align-items: start;
- justify-content: space-between;
- flex-wrap: wrap;
- gap: var(--wa-space-m);
- padding: var(--wa-space-3xl);
-}
-
-:host([disable-sticky~='banner']) :is([part~='header'], [part~='subheader']) {
- --banner-height: 0px !important;
-}
-:host([disable-sticky~='header']) [part~='subheader'] {
- --header-height: 0px !important;
-}
-
-/* Nothing else depends on subheader-height. */
-:host([disable-sticky~='subheader']) {
-}
-:host([disable-sticky~='aside']) [part~='aside'],
-:host([disable-sticky~='menu']) [part~='menu'] {
- height: unset;
- max-height: unset;
-}
-
-:host([disable-sticky~='banner']) [part~='banner'],
-:host([disable-sticky~='header']) [part~='header'],
-:host([disable-sticky~='subheader']) [part~='subheader'],
-:host([disable-sticky~='aside']) [part~='aside'],
-:host([disable-sticky~='menu']) [part~='menu'] {
- position: static;
- overflow: unset;
- z-index: unset;
-}
-
-:host([disable-sticky~='aside']) [part~='aside'],
-:host([disable-sticky~='menu']) [part~='menu'] {
- height: auto;
- max-height: auto;
-}
-
-[part~='base'] {
- min-height: 100%;
- display: grid;
- grid-template-rows: repeat(3, minmax(0, auto)) minmax(0, 1fr) minmax(0, auto);
- grid-template-columns: 100%;
- width: 100%;
- grid-template-areas:
- 'banner'
- 'header'
- 'subheader'
- 'body'
- 'footer';
-}
-
-/* Grid areas */
-[part~='banner'] {
- grid-area: banner;
-}
-[part~='header'] {
- grid-area: header;
-}
-[part~='subheader'] {
- grid-area: subheader;
-}
-[part~='menu'] {
- grid-area: menu;
-}
-[part~='body'] {
- grid-area: body;
-}
-[part~='main'] {
- grid-area: main;
-}
-[part~='aside'] {
- grid-area: aside;
-}
-[part~='footer'] {
- grid-area: footer;
-}
-
-/* Z-indexes */
-[part~='banner'],
-[part~='header'],
-[part~='subheader'] {
- position: sticky;
- z-index: 5;
-}
-[part~='banner'] {
- top: 0px;
-}
-[part~='header'] {
- top: var(--banner-height);
-
- /** Make the header flex so that you don't unexpectedly have the default toggle button appearing above a slotted div because block elements are fun. */
- display: flex;
- flex-wrap: wrap;
- align-items: center;
- justify-content: space-between;
-}
-[part~='subheader'] {
- top: calc(var(--header-height) + var(--banner-height));
-}
-[part~='body'] {
- display: grid;
- height: 100%;
- align-items: flex-start;
- grid-template-columns: minmax(0, var(--menu-width)) minmax(0, var(--main-width)) minmax(0, var(--aside-width));
- grid-template-rows: minmax(0, 1fr);
- grid-template-areas: 'menu main aside';
-}
-[part~='main'] {
- display: grid;
- min-height: 100%;
- grid-template-columns: minmax(0, 1fr);
- grid-template-rows: minmax(0, auto) minmax(0, 1fr) minmax(0, auto);
- grid-template-areas:
- 'main-header'
- 'main-content'
- 'main-footer';
-}
-[part~='main-header'] {
- grid-area: main-header;
-}
-[part~='main-content'] {
- grid-area: main-content;
-}
-[part~='main-footer'] {
- grid-area: main-footer;
-}
-
-.skip-to-content {
- position: absolute;
- top: var(--wa-space-m);
- left: var(--wa-space-m);
- z-index: 6;
- border-radius: var(--wa-corners-1x);
- background-color: var(--wa-color-surface-default);
- color: var(--wa-color-text-link);
- text-decoration: none;
- padding: var(--wa-space-s) var(--wa-space-m);
- box-shadow: var(--wa-shadow-l);
- outline: var(--wa-focus-ring);
- outline-offset: var(--wa-focus-ring-offset);
-}
-
-[part~='menu'],
-[part~='aside'] {
- position: sticky;
- top: calc(var(--banner-height) + var(--header-height) + var(--subheader-height));
- z-index: 4;
- height: calc(100dvh - var(--header-height) - var(--banner-height) - var(--subheader-height));
- max-height: calc(100dvh - var(--header-height) - var(--banner-height) - var(--subheader-height));
- overflow: auto;
-}
-
-[part~='navigation'] {
- height: 100%;
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- grid-template-rows: minmax(0, auto) minmax(0, 1fr) minmax(0, auto);
-}
-
-[part~='drawer']::part(dialog) {
- background-color: var(--wa-color-surface-default);
-}
-
-/* Set these on the slot because we don't always control the navigation-toggle since that may be slotted. */
-slot[name~='navigation-toggle'],
-:host([disable-navigation-toggle]) slot[name~='navigation-toggle'] {
- display: none;
-}
-
-/* Sometimes the media query in the viewport is stubborn in iframes. This is an extra check to make it behave properly. */
-:host(:not([disable-navigation-toggle])[view='mobile']) slot[name~='navigation-toggle'] {
- display: contents;
-}
-
-[part~='navigation-toggle'] {
- /* Use only a margin-inline-start because the slotted header is expected to have default padding
- so it looks really awkward if this sets a margin-inline-end and the slotted header has a padding-inline-start. */
- margin-inline-start: var(--wa-space-m);
-}
diff --git a/packages/webawesome/src/components/page/page.mobile.styles.ts b/packages/webawesome/src/components/page/page.mobile.styles.ts
deleted file mode 100644
index 6338be789..000000000
--- a/packages/webawesome/src/components/page/page.mobile.styles.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export default (breakpoint: string = '768px') => `
- @media screen and (width < ${breakpoint}) {
- [part~='navigation'] {
- display: none;
- }
-
- :host(:not([disable-navigation-toggle])) slot[name~='navigation-toggle'] {
- display: contents;
- }
- }
-`;
diff --git a/packages/webawesome/src/components/page/page.test.ts b/packages/webawesome/src/components/page/page.test.ts
deleted file mode 100644
index b5e049e4d..000000000
--- a/packages/webawesome/src/components/page/page.test.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import { expect } from '@open-wc/testing';
-import { html } from 'lit';
-import { fixtures } from '../../internal/test/fixture.js';
-
-describe('', () => {
- for (const fixture of fixtures) {
- describe(`with "${fixture.type}" rendering`, () => {
- it('should render a component', async () => {
- const el = await fixture(html` `);
-
- expect(el).to.exist;
- });
- });
- }
-});
diff --git a/packages/webawesome/src/components/page/page.ts b/packages/webawesome/src/components/page/page.ts
deleted file mode 100644
index 55089e237..000000000
--- a/packages/webawesome/src/components/page/page.ts
+++ /dev/null
@@ -1,455 +0,0 @@
-import type { PropertyValues } from 'lit';
-import { html, isServer } from 'lit';
-import { customElement, property, query } from 'lit/decorators.js';
-import { live } from 'lit/directives/live.js';
-import { unsafeHTML } from 'lit/directives/unsafe-html.js';
-import WebAwesomeElement from '../../internal/webawesome-element.js';
-import visuallyHidden from '../../styles/utilities/visually-hidden.css';
-import '../button/button.js';
-import '../drawer/drawer.js';
-import type WaDrawer from '../drawer/drawer.js';
-import '../icon/icon.js';
-import styles from './page.css';
-import mobileStyles from './page.mobile.styles.js';
-
-if (typeof ResizeObserver === 'undefined') {
- globalThis.ResizeObserver = class {
- // eslint-disable-next-line
- constructor(..._args: ConstructorParameters) {}
- // eslint-disable-next-line
- observe(..._args: Parameters) {}
- // eslint-disable-next-line
- unobserve(..._args: Parameters) {}
- // eslint-disable-next-line
- disconnect(..._args: Parameters) {}
- };
-}
-
-//
-// TODO - the toPx and toLength functions aren't used anywhere else, and they're not named or documented well enough to
-// abstract into a utility as-is.
-//
-
-/** Converts a non-pixel value to a pixel value. */
-function toPx(value: string | number, element: HTMLElement | SVGElement = document.documentElement): number {
- if (!Number.isNaN(Number(value))) {
- return Number(value);
- }
-
- // If CSS.registerProperty isn't supported, try to parse as-is
- if (!window.CSS || !CSS.registerProperty) {
- if (typeof value === 'string' && value.endsWith('px')) {
- return parseFloat(value);
- }
- return Number(value) || 0;
- }
-
- const resolver = '--wa-length-resolver';
-
- // Register the property if not already done
- if (!CSS.registerProperty.toString().includes(resolver)) {
- try {
- CSS.registerProperty({
- name: resolver,
- syntax: '',
- inherits: false,
- initialValue: '0px',
- });
- } catch (e) {
- // Property might already be registered
- }
- }
-
- const previousValue = element.style.getPropertyValue(resolver);
- element.style.setProperty(resolver, value as string);
- const computedValue = getComputedStyle(element)?.getPropertyValue(resolver);
- element.style.setProperty(resolver, previousValue);
-
- if (computedValue?.endsWith('px')) {
- return parseFloat(computedValue);
- }
-
- return Number(computedValue) || 0;
-}
-
-/** Converts a number or string to a CSS px value. Not used anywhere else, so consolidated here for the time being. */
-function toLength(px: number | string): string {
- return Number.isNaN(Number(px)) ? (px as string) : `${px}px`;
-}
-
-/**
- * @summary Pages offer an easy way to scaffold entire page layouts using minimal markup.
- * @documentation https://webawesome.com/docs/components/page
- * @status experimental
- * @since 3.0
- *
- * @slot - The page's main content.
- * @slot banner - The banner that gets display above the header. The banner will not be shown if no content is provided.
- * @slot header - The header to display at the top of the page. If a banner is present, the header will appear below the banner. The header will not be shown if there is no content.
- * @slot subheader - A subheader to display below the `header`. This is a good place to put things like breadcrumbs.
- * @slot menu - The left side of the page. If you slot an element in here, you will override the default `navigation` slot and will be handling navigation on your own. This also will not disable the fallback behavior of the navigation button. This section "sticks" to the top as the page scrolls.
- * @slot navigation-header - The header for a navigation area. On mobile this will be the header for ``.
- * @slot navigation - The main content to display in the navigation area. This is displayed on the left side of the page, if `menu` is not used. This section "sticks" to the top as the page scrolls.
- * @slot navigation-footer - The footer for a navigation area. On mobile this will be the footer for ``.
- * @slot navigation-toggle - Use this slot to slot in your own button + icon for toggling the navigation drawer. By default it is a `` + a 3 bars ``
- * @slot navigation-toggle-icon - Use this to slot in your own icon for toggling the navigation drawer. By default it is 3 bars ``.
- * @slot main-header - Header to display inline above the main content.
- * @slot main-footer - Footer to display inline below the main content.
- * @slot aside - Content to be shown on the right side of the page. Typically contains a table of contents, ads, etc. This section "sticks" to the top as the page scrolls.
- * @slot skip-to-content - The "skip to content" slot. You can override this If you would like to override the `Skip to content` button and add additional "Skip to X", they can be inserted here.
- * @slot footer - The content to display in the footer. This is always displayed underneath the viewport so will always make the page "scrollable".
- *
- * @csspart base - The component's base wrapper.
- * @csspart banner - The banner to show above header.
- * @csspart header - The header, usually for top level navigation / branding.
- * @csspart subheader - Shown below the header, usually intended for things like breadcrumbs and other page level navigation.
- * @csspart body - The wrapper around menu, main, and aside.
- * @csspart menu - The left hand side of the page. Generally intended for navigation.
- * @csspart navigation - The `` that wraps the navigation slots on desktop viewports.
- * @csspart navigation-header - The header for a navigation area. On mobile this will be the header for ``.
- * @csspart navigation-footer - The footer for a navigation area. On mobile this will be the footer for ``.
- * @csspart navigation-toggle - The default `` that will toggle the `` for mobile viewports.
- * @csspart navigation-toggle-icon - The default `` displayed inside of the navigation-toggle button.
- * @csspart main-header - The header above main content.
- * @csspart main-content - The main content.
- * @csspart main-footer - The footer below main content.
- * @csspart aside - The right hand side of the page. Used for things like table of contents, ads, etc.
- * @csspart skip-links - Wrapper around skip-link
- * @csspart skip-link - The "skip to main content" link
- * @csspart footer - The footer of the page. This is always below the initial viewport size.
- * @csspart dialog-wrapper - A wrapper around elements such as dialogs or other modal-like elements.
- *
- * @cssproperty [--menu-width=auto] - The width of the page's "menu" section.
- * @cssproperty [--main-width=1fr] - The width of the page's "main" section.
- * @cssproperty [--aside-width=auto] - The wide of the page's "aside" section.
- * @cssproperty [--banner-height=0px] - The height of the banner. This gets calculated when the page initializes. If the height is known, you can set it here to prevent shifting when the page loads.
- * @cssproperty [--header-height=0px] - The height of the header. This gets calculated when the page initializes. If the height is known, you can set it here to prevent shifting when the page loads.
- * @cssproperty [--subheader-height=0px] - The height of the subheader. This gets calculated when the page initializes. If the height is known, you can set it here to prevent shifting when the page loads.
- */
-@customElement('wa-page')
-export default class WaPage extends WebAwesomeElement {
- static css = [visuallyHidden, styles];
-
- private headerResizeObserver = this.slotResizeObserver('header');
- private subheaderResizeObserver = this.slotResizeObserver('subheader');
- private bannerResizeObserver = this.slotResizeObserver('banner');
- private footerResizeObserver = this.slotResizeObserver('footer');
-
- private slotResizeObserver(slot: string) {
- return new ResizeObserver(entries => {
- for (const entry of entries) {
- if (entry.contentBoxSize) {
- const contentBoxSize = entry.borderBoxSize[0];
- this.style.setProperty(`--${slot}-height`, `${contentBoxSize.blockSize}px`);
- }
- }
- });
- }
-
- private handleNavigationToggle = (e: Event) => {
- // Don't toggle the nav when we're in desktop mode
- if (this.view === 'desktop') {
- // Just in case, try to hide the navigation.
- this.hideNavigation();
- return;
- }
-
- const path = e.composedPath();
-
- const navigationToggleSlot = this.navigationToggleSlot;
-
- if (
- path.find((el: Element) => {
- return (
- el.hasAttribute?.('data-toggle-nav') ||
- el.assignedSlot === navigationToggleSlot ||
- el === navigationToggleSlot
- );
- })
- ) {
- e.preventDefault();
- this.toggleNavigation();
- }
- };
-
- @query("[part~='header']") header: HTMLElement;
- @query("[part~='subheader']") subheader: HTMLElement;
- @query("[part~='footer']") footer: HTMLElement;
- @query("[part~='banner']") banner: HTMLElement;
- @query("[part~='drawer']") navigationDrawer: WaDrawer;
- @query("slot[name~='navigation-toggle']") navigationToggleSlot: HTMLSlotElement;
-
- /**
- * The view is a reflection of the "mobileBreakpoint", when the page is larger than the `mobile-breakpoint` (768px by
- * default), it is considered to be a "desktop" view. The view is merely a way to distinguish when to show/hide the
- * navigation. You can use additional media queries to make other adjustments to content as necessary.
- * The default is "desktop" because the "mobile navigation drawer" isn't accessible via SSR due to drawer requiring JS.
- */
- @property({ attribute: 'view', reflect: true }) view: 'mobile' | 'desktop' = 'desktop';
-
- /**
- * Whether or not the navigation drawer is open. Note, the navigation drawer is only "open" on mobile views.
- */
- @property({ attribute: 'nav-open', reflect: true, type: Boolean }) navOpen = false;
-
- /**
- * At what page width to hide the "navigation" slot and collapse into a hamburger button.
- * Accepts both numbers (interpreted as px) and CSS lengths (e.g. `50em`), which are resolved based on the root element.
- */
- @property({ attribute: 'mobile-breakpoint', type: String })
- mobileBreakpoint = '768px';
-
- /**
- * Where to place the navigation when in the mobile viewport.
- */
- @property({ attribute: 'navigation-placement', reflect: true }) navigationPlacement: 'start' | 'end' = 'start';
-
- /**
- * Determines whether or not to hide the default hamburger button.
- * This will automatically flip to "true" if you add an element with `data-toggle-nav` anywhere in the element light DOM.
- * Generally this will be set for you and you don't need to do anything, unless you're using SSR, in which case you should set this manually for initial page loads.
- */
- @property({ attribute: 'disable-navigation-toggle', reflect: true, type: Boolean }) disableNavigationToggle: boolean =
- false;
-
- pageResizeObserver = new ResizeObserver(entries => {
- for (const entry of entries) {
- if (entry.contentBoxSize) {
- const contentBoxSize = entry.borderBoxSize[0];
- const pageWidth = contentBoxSize.inlineSize;
-
- const oldView = this.view;
-
- if (pageWidth >= toPx(this.mobileBreakpoint)) {
- this.view = 'desktop';
- } else {
- this.view = 'mobile';
- }
-
- this.requestUpdate('view', oldView);
- }
- }
- });
-
- protected update(changedProperties: PropertyValues): void {
- if (changedProperties.has('view')) {
- this.hideNavigation();
- }
- super.update(changedProperties);
- }
-
- constructor() {
- super();
-
- if (!isServer) {
- this.addEventListener('click', this.handleNavigationToggle);
- }
- }
-
- connectedCallback() {
- super.connectedCallback();
-
- this.pageResizeObserver.observe(this);
-
- const navQuery = ":not([slot='toggle-navigation']) [data-toggle-nav]";
-
- // check once on initial connect
- // eslint-disable-next-line
- this.disableNavigationToggle = Boolean(this.querySelector(navQuery));
-
- setTimeout(() => {
- this.headerResizeObserver.observe(this.header);
- this.subheaderResizeObserver.observe(this.subheader);
- this.bannerResizeObserver.observe(this.banner);
- this.footerResizeObserver.observe(this.footer);
-
- // Check again when the element updates
- // eslint-disable-next-line
- this.disableNavigationToggle = Boolean(this.querySelector(navQuery));
- });
- }
-
- firstUpdated() {
- // If the user provides a #main-content id, it should be present in the default slot and the "skip to
- // content" link will point to it. If not, we'll prepend an empty element for them so things just work.
- if (!document.getElementById('main-content')) {
- const div = document.createElement('div');
- div.id = 'main-content';
- div.slot = 'skip-to-content-target';
- this.prepend(div);
- }
- }
-
- disconnectedCallback() {
- super.disconnectedCallback();
- this.pageResizeObserver.unobserve(this);
- this.headerResizeObserver.unobserve(this.header);
- this.subheaderResizeObserver.unobserve(this.subheader);
- this.footerResizeObserver.unobserve(this.footer);
- this.bannerResizeObserver.unobserve(this.banner);
- }
-
- /**
- * Shows the mobile navigation drawer
- */
- showNavigation() {
- this.navOpen = true;
- }
-
- /**
- * Hides the mobile navigation drawer
- */
- hideNavigation() {
- this.navOpen = false;
- }
-
- /**
- * Toggles the mobile navigation drawer
- */
- toggleNavigation() {
- this.navOpen = !this.navOpen;
- }
-
- render() {
- return html`
-
- Skip to content
-
-
-
- ${unsafeHTML(`
-
- `)}
-
-
- (this.navOpen = this.navigationDrawer.open)}
- @wa-after-hide=${() => (this.navOpen = this.navigationDrawer.open)}
- exportparts="
- dialog:drawer__dialog,
- overlay:drawer__overlay,
- panel:drawer__panel,
- header:drawer__header,
- header-actions:drawer__header-actions,
- title:drawer__title,
- close-button:drawer__close-button,
- close-button__base:drawer__close-button__base,
- body:drawer__body,
- footer:drawer__footer
- "
- class="navigation-drawer"
- >
-
-
-
-
-
-
-
-
-
-
-
- `;
- }
-}
-
-declare global {
- interface HTMLElementTagNameMap {
- 'wa-page': WaPage;
- }
-}
-
-//
-// Append a supporting light DOM styles for
-//
-const stylesheet = new CSSStyleSheet();
-
-stylesheet.replaceSync(`
-:is(html, body):has(wa-page) {
- min-height: 100%;
- height: 100%;
- padding: 0;
- margin: 0;
- }
-
- /**
- Because headers are sticky, this is needed to make sure page fragment anchors scroll down past the headers / subheaders and are visible.
- IE: \`\` anchors.
- */
- wa-page :is(*, *:after, *:before) {
- scroll-margin-top: var(--scroll-margin-top);
- }
-
- wa-page[view='desktop'] [data-toggle-nav] {
- display: none;
- }
-
- wa-page[view='mobile'] .wa-desktop-only, wa-page[view='desktop'] .wa-mobile-only {
- display: none !important;
- }
-`);
-document.adoptedStyleSheets = [...document.adoptedStyleSheets, stylesheet];
From 493e1c06b9c85ec7b379b301b5ef2057cf081182 Mon Sep 17 00:00:00 2001
From: Cory LaViska
Date: Thu, 21 Aug 2025 11:35:05 -0400
Subject: [PATCH 4/9] Fixes spacing between clear and password toggle icons in
`` (#1351)
* fixes spacing between icons; closes #1325
* use form control padding token
---------
Co-authored-by: lindsaym-fa
---
packages/webawesome/docs/docs/resources/changelog.md | 1 +
packages/webawesome/src/components/input/input.css | 1 +
2 files changed, 2 insertions(+)
diff --git a/packages/webawesome/docs/docs/resources/changelog.md b/packages/webawesome/docs/docs/resources/changelog.md
index 5bc2f7912..f6ca98735 100644
--- a/packages/webawesome/docs/docs/resources/changelog.md
+++ b/packages/webawesome/docs/docs/resources/changelog.md
@@ -29,6 +29,7 @@ Components with the Experimental badge sh
- Fixed a bug in `` that prevented the thumb from receiving focus when clicking/tapping [issue:1312]
- Fixed a bug in `` that caused the shadow to appear below relatively-positioned elements [issue:1326]
- Fixed `` to have `static` positioning by default and `relative` positioning only when used with `` [pr:1346]
+- Fixed spacing in `` when both clear and password toggle icons are present [issue:1325]
## 3.0.0-beta.4
diff --git a/packages/webawesome/src/components/input/input.css b/packages/webawesome/src/components/input/input.css
index e0a12fe7d..6aae262f7 100644
--- a/packages/webawesome/src/components/input/input.css
+++ b/packages/webawesome/src/components/input/input.css
@@ -174,6 +174,7 @@ textarea {
padding: 0;
transition: var(--wa-transition-normal) color;
cursor: pointer;
+ margin-inline-start: var(--wa-form-control-padding-inline);
@media (hover: hover) {
&:hover {
From 5e0b5f3fe6db8d78c5761f777013a7d005df6bf0 Mon Sep 17 00:00:00 2001
From: Cory LaViska
Date: Thu, 21 Aug 2025 11:46:09 -0400
Subject: [PATCH 5/9] update system icon view boxes (#1357)
---
.../src/components/icon/library.system.ts | 38 +++++++++----------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/packages/webawesome/src/components/icon/library.system.ts b/packages/webawesome/src/components/icon/library.system.ts
index 8012a6e5c..ffbdb9d91 100644
--- a/packages/webawesome/src/components/icon/library.system.ts
+++ b/packages/webawesome/src/components/icon/library.system.ts
@@ -9,31 +9,31 @@ export const icons: { [key: string]: { [key: string]: string } } = {
// Solid variant
//
solid: {
- check: ` `,
- 'chevron-down': ` `,
- 'chevron-left': ` `,
- 'chevron-right': ` `,
- circle: ` `,
- eyedropper: ` `,
- 'grip-vertical': ` `,
+ check: ` `,
+ 'chevron-down': ` `,
+ 'chevron-left': ` `,
+ 'chevron-right': ` `,
+ circle: ` `,
+ eyedropper: ` `,
+ 'grip-vertical': ` `,
indeterminate: ` `,
- minus: ` `,
- pause: ` `,
- play: ` `,
- star: ` `,
- user: ` `,
- xmark: ` `,
+ minus: ` `,
+ pause: ` `,
+ play: ` `,
+ star: ` `,
+ user: ` `,
+ xmark: ` `,
},
//
// Regular variant
//
regular: {
- 'circle-question': ` `,
- 'circle-xmark': ` `,
- copy: ` `,
- eye: ` `,
- 'eye-slash': ` `,
- star: ` `,
+ 'circle-question': ` `,
+ 'circle-xmark': ` `,
+ copy: ` `,
+ eye: ` `,
+ 'eye-slash': ` `,
+ star: ` `,
},
};
From e016e4bd488f3f1d86944340ed5cb7059c55bf85 Mon Sep 17 00:00:00 2001
From: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
Date: Thu, 21 Aug 2025 13:29:09 -0400
Subject: [PATCH 6/9] Fix home page icons (#1358)
---
packages/webawesome/docs/index.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/webawesome/docs/index.md b/packages/webawesome/docs/index.md
index 0efecb8b4..49188f8fd 100644
--- a/packages/webawesome/docs/index.md
+++ b/packages/webawesome/docs/index.md
@@ -141,10 +141,11 @@ layout: page
display: flex;
align-items: center;
justify-content: center;
+ block-size: 2em;
+ inline-size: 2em;
background-color: var(--wa-color-neutral-fill-loud);
color: var(--wa-color-neutral-on-loud);
border-radius: 0.25rem;
- aspect-ratio: 1;
padding: 0.5em;
&.brand-orange {
From adaea2fa5f44bda5667670e6cd68b56875481282 Mon Sep 17 00:00:00 2001
From: Konnor Rogers
Date: Thu, 21 Aug 2025 14:12:39 -0400
Subject: [PATCH 7/9] fix wa-page fallback loading in free repo (#1359)
---
packages/webawesome/docs/_includes/head.njk | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/packages/webawesome/docs/_includes/head.njk b/packages/webawesome/docs/_includes/head.njk
index e5cd41b5c..36efab00d 100644
--- a/packages/webawesome/docs/_includes/head.njk
+++ b/packages/webawesome/docs/_includes/head.njk
@@ -26,5 +26,17 @@
{% endfor %}
+
+
{# Used by Web Awesome App to inject other assets into the head. #}
{% server "head" %}
From 4f1de3918bab02b39145c480726e06a2d151e760 Mon Sep 17 00:00:00 2001
From: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:00:09 -0400
Subject: [PATCH 8/9] Fix button positioning for real (#1361)
---
packages/webawesome/src/components/button/button.css | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/packages/webawesome/src/components/button/button.css b/packages/webawesome/src/components/button/button.css
index 4bb79f2b2..a3b0e1783 100644
--- a/packages/webawesome/src/components/button/button.css
+++ b/packages/webawesome/src/components/button/button.css
@@ -1,8 +1,17 @@
@layer wa-component {
:host {
display: inline-block;
+
+ /* Workaround because Chrome doesn't like :host(:has()) below
+ * https://issues.chromium.org/issues/40062355
+ * Firefox doesn't like this nested rule, so both are needed */
+ &:has(wa-badge) {
+ position: relative;
+ }
}
+ /* Apply relative positioning only when needed to position wa-badge
+ * This avoids creating a new stacking context for every button */
:host(:has(wa-badge)) {
position: relative;
}
From 7ccfed9e930f84236fcdeaf8754337cf614b88fb Mon Sep 17 00:00:00 2001
From: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
Date: Fri, 22 Aug 2025 10:47:12 -0400
Subject: [PATCH 9/9] Use FA7 icons in native styles (#1362)
* replace icons with FA7 paths
* replace details icon
---
packages/webawesome/src/styles/native.css | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/packages/webawesome/src/styles/native.css b/packages/webawesome/src/styles/native.css
index ef4742eb5..c57b6f03f 100644
--- a/packages/webawesome/src/styles/native.css
+++ b/packages/webawesome/src/styles/native.css
@@ -454,7 +454,7 @@
&::after {
content: '';
background-color: var(--wa-color-text-quiet);
- mask: url('data:image/svg+xml;utf8, ')
+ mask: url('data:image/svg+xml;utf8, ')
center no-repeat;
width: 1rem;
height: 1rem;
@@ -916,8 +916,8 @@
&:indeterminate::after {
position: absolute;
- width: 100%;
- height: 100%;
+ width: round(calc(100% - var(--wa-form-control-border-width) * 2), 1px);
+ height: round(calc(100% - var(--wa-form-control-border-width) * 2), 1px);
content: '';
@@ -927,7 +927,7 @@
}
&:checked::after {
- mask: url('data:image/svg+xml;utf8, ')
+ mask: url('data:image/svg+xml;utf8, ')
center no-repeat;
}
@@ -940,7 +940,7 @@
/* Radio */
input[type='radio'] {
--checked-icon-color: var(--wa-form-control-activated-color);
- --checked-icon-scale: 0.75;
+ --checked-icon-scale: 0.7;
color: transparent;
@@ -1059,6 +1059,8 @@
select {
--icon-caret: url('data:image/svg+xml;utf8, ');
+ --icon-caret: url('data:image/svg+xml;utf8, ');
+
appearance: none;
position: relative;