Compare commits

..

3 Commits

Author SHA1 Message Date
Brian Talbot
7e42f92ee2 syncing up 'Community & Support' label in sidebar.njk
* to match the updated title in resources/support.md
2025-11-14 17:33:14 -05:00
Brian Talbot
56a28f6b9b WIP - adding FAQs to support.md 2025-11-14 17:30:06 -05:00
Brian Talbot
52b0e0994e fixing typo in support.md 2025-11-14 16:50:20 -05:00
19 changed files with 75 additions and 204 deletions

View File

@@ -124,22 +124,6 @@ export default async function (eleventyConfig) {
eleventyConfig.addFilter('stripExtension', string => path.parse(string + '').name);
eleventyConfig.addFilter('stripPrefix', content => content.replace(/^wa-/, ''));
eleventyConfig.addFilter('uniqueId', (_value, length = 8) => nanoid(length));
eleventyConfig.addGlobalData('eleventyComputed', {
// Page title with smart + default site name formatting
pageTitle: data => composePageTitle(data.title),
// Open Graph title with smart + default site name formatting
ogTitle: data => composePageTitle(data.ogTitle || data.title),
ogDescription: data => data.ogDescription || data.description,
ogImage: data => data.ogImage || siteMetadata.image,
ogUrl: data => {
if (data.ogUrl) return data.ogUrl;
const url = data.page?.url || '';
return url ? `${siteMetadata.url}${url}` : siteMetadata.url;
},
ogType: data => data.ogType || 'website',
});
// Trims whitespace and pipes from the start and end of a string. Useful for CEM types, which can be pipe-delimited.
// With Prettier 3, this means a leading pipe will exist be present when the line wraps.
eleventyConfig.addFilter('trimPipes', content => {
@@ -313,19 +297,18 @@ export default async function (eleventyConfig) {
// This needs to happen in "eleventy.after" otherwise incremental builds never update.
eleventyConfig.on('eleventy.after', function () {
const baseDir = process.env.BASE_DIR || 'docs';
let assetsDir = path.join(baseDir, 'assets');
let assetsDir = path.join(process.env.BASE_DIR || 'docs', 'assets');
const siteAssetsDir = path.join(eleventyConfig.directories.output, 'assets');
fs.cpSync(assetsDir, siteAssetsDir, { recursive: true });
// Passthrough copy for manifest.json (PWA manifest file)
fs.cpSync(path.join(baseDir, 'manifest.json'), path.join(eleventyConfig.directories.output, 'manifest.json'));
});
for (let glob of passThrough) {
eleventyConfig.addPassthroughCopy(glob);
}
// Passthrough copy for manifest.json (PWA manifest file)
eleventyConfig.addPassthroughCopy('manifest.json');
// // SSR plugin
// if (!isDev) {
// //

View File

@@ -16,7 +16,7 @@
{# Resources #}
<h2>Resources</h2>
<ul>
<li><a href="/docs/resources/support">Help & Support</a></li>
<li><a href="/docs/resources/support">Community & Support</a></li>
<li><a href="https://github.com/shoelace-style/webawesome/">Source Code</a></li>
<li>
<span class="wa-split">

View File

@@ -0,0 +1,15 @@
<section class="faqs wa-stack wa-gap-xs">
<wa-details icon-placement="start" name="general" summary="What is Web Awesome?" appearance="plain">
Web Awesome is primarily geared towards web builders with some front-end development experience. At its core, it's a design system toolkit — a collection of reusable bits and pieces to help snap together user interfaces with a consistent and customizable look and feel.
</wa-details>
<wa-details icon-placement="start" name="general" summary="What is Web Awesome?" appearance="plain">
Web Awesome is primarily geared towards web builders with some front-end development experience. At its core, it's a design system toolkit — a collection of reusable bits and pieces to help snap together user interfaces with a consistent and customizable look and feel.
</wa-details>
<wa-details icon-placement="start" name="general" summary="What is Web Awesome?" appearance="plain">
Web Awesome is primarily geared towards web builders with some front-end development experience. At its core, it's a design system toolkit — a collection of reusable bits and pieces to help snap together user interfaces with a consistent and customizable look and feel.
</wa-details>
</section>

View File

@@ -38,7 +38,7 @@ wa-page > [slot='banner'] {
}
&.banner-wa-launch {
/* custom brand colors carried over from theme-site for the banner */
/* custom brand colors carrried over from theme-site for the banner */
--wa-color-brand-95: #fef0ec;
--wa-color-brand-90: #fce0d8;
--wa-color-brand-80: #f8bcac;

View File

@@ -5,6 +5,7 @@
border-radius: var(--wa-border-radius-l);
padding: 0;
margin: 0 auto;
overflow: hidden;
&::part(dialog) {
margin-block-start: 10vh;

View File

@@ -14,19 +14,13 @@ Components with the <wa-badge variant="warning">Experimental</wa-badge> badge sh
## Next
- Fixed a bug in `<wa-slider>` that caused some touch devices to end up with the incorrect value [issue:1703]
- Fixed a bug in `<wa-card>` that prevented some slots from being detected correctly [discuss:1450]
- Fixed a z-index bug in `<wa-scroller>` styles [issue:1724]
- Fixed a bug in `<wa-icon>` that caused some icon libraries to render with the incorrect SVG fill [issue:1733]
- Fixed a bug in `<wa-tree-item>` that caused the spinner to not show when lazy loading [issue:1678]
- Fixed a bug in `<wa-dropdown>` that caused the browser to hang when cancelling the `wa-hide` event [issue:1483]
- Improved performance of `<wa-icon>` so initial rendering occurs faster, especially with multiple icons on the page [issue:1729]
## 3.0.0
- 🚨 BREAKING: Changed `appearance="filled outlined"` to `appearance="filled-outlined"` in the following elements [issue:1127]
- `<wa-badge>`
- `<wa-button>`
- `<wa-callout>`
- `<wa-card>`
- `<wa-details>`
- `<wa-input>`
- `<wa-select>`

View File

@@ -4,7 +4,18 @@ description: Web Awesome has a growing community of designers and developers tha
layout: page
---
<p>We know people have their own way of reaching out, so our team makes sure you can find us wherever you need — whether its filing an issue on GitHub, chatting with the community on Discord, or getting private help via email. If youre just getting started, dont miss our <a href="/docs/">Instillation Guide</a>.</p>
<style>
.faqs wa-details::part(header) {
padding-inline: var(--wa-space-0);
}
.faqs wa-details::part(content) {
padding-block-start: var(--wa-space-0);
padding-inline: var(--wa-space-0);
}
</style>
<p>We know people have their own way of reaching out, so our team makes sure you can find us wherever you need — whether its filing an issue on GitHub, chatting with the community on Discord, or getting private help via email. If youre just getting started, dont miss our <a href="/docs/">Installation Guide</a>.</p>
<wa-divider></wa-divider>
@@ -88,4 +99,9 @@ layout: page
</a>
</div>
<wa-divider></wa-divider>
## Frequently Asked Questions
{% include "support/faqs.njk" %}
</div>

View File

@@ -22,7 +22,7 @@ As soon as all elements are registered _or_ after two seconds have elapsed, the
:::details Are you using Turbo in your app?
If you're using [Turbo](https://turbo.hotwired.dev/) to serve a multi-page application (MPA) as a single page application (SPA), you might notice FOUCE when navigating from page to page. This is because Turbo renders the new page's content before the autoloader has a chance to register new components.
If you're using [Turbo](https://turbo.hotwired.dev/) to serve a multi-page application (MPA) as a single page application (SPA), you might notice FOUCE when navigating from page to page. This is because Turbo renders the new page's content before the autoloader has a change to register new components.
The following function acts as a middleware to ensure components are registered _before_ the page shows, eliminating FOUCE for page-to-page navigation with Turbo.

View File

@@ -16,28 +16,27 @@
}
/* Appearance modifiers */
:host([appearance='plain']) {
:host([appearance~='plain']) {
background-color: transparent;
border-color: transparent;
box-shadow: none;
}
:host([appearance='outlined']) {
:host([appearance~='outlined']) {
background-color: var(--wa-color-surface-default);
border-color: var(--wa-color-surface-border);
}
:host([appearance='filled']) {
:host([appearance~='filled']) {
background-color: var(--wa-color-neutral-fill-quiet);
border-color: transparent;
}
:host([appearance='filled-outlined']) {
background-color: var(--wa-color-neutral-fill-quiet);
border-color: var(--wa-color-surface-border);
:host([appearance~='filled'][appearance~='outlined']) {
border-color: var(--wa-color-neutral-border-quiet);
}
:host([appearance='accent']) {
:host([appearance~='accent']) {
color: var(--wa-color-neutral-on-loud);
background-color: var(--wa-color-neutral-fill-loud);
border-color: transparent;

View File

@@ -30,19 +30,11 @@ import styles from './card.css';
export default class WaCard extends WebAwesomeElement {
static css = [sizeStyles, styles];
private readonly hasSlotController = new HasSlotController(
this,
'footer',
'header',
'media',
'header-actions',
'footer-actions',
'actions',
);
private readonly hasSlotController = new HasSlotController(this, 'footer', 'header', 'media');
/** The card's visual appearance. */
@property({ reflect: true })
appearance: 'accent' | 'filled' | 'outlined' | 'filled-outlined' | 'plain' = 'outlined';
appearance: 'accent' | 'filled' | 'outlined' | 'plain' = 'outlined';
/** Renders the card with a header. Only needed for SSR, otherwise is automatically added. */
@property({ attribute: 'with-header', type: Boolean, reflect: true }) withHeader = false;

View File

@@ -1,6 +1,4 @@
import { aTimeout, expect, fixture, html, waitUntil } from '@open-wc/testing';
import sinon from 'sinon';
import type WaDropdown from './dropdown.js';
import { expect, fixture, html } from '@open-wc/testing';
describe('<wa-dropdown>', () => {
it('should render a component', async () => {
@@ -8,112 +6,4 @@ describe('<wa-dropdown>', () => {
expect(el).to.exist;
});
it('should respect the open attribute when included', async () => {
const el = await fixture<WaDropdown>(html`
<wa-dropdown open>
<wa-button slot="trigger">Dropdown</wa-button>
<wa-dropdown-item>One</wa-dropdown-item>
</wa-dropdown>
`);
await el.updateComplete;
await aTimeout(200);
expect(el.open).to.be.true;
});
it('should fire a single show/after-show and hide/after-hide in normal open/close flow', async () => {
const el = await fixture<WaDropdown>(html`
<wa-dropdown>
<wa-button slot="trigger">Dropdown</wa-button>
<wa-dropdown-item>One</wa-dropdown-item>
<wa-dropdown-item>Two</wa-dropdown-item>
</wa-dropdown>
`);
// setup spies to track how often we see different show/hide events
const showSpy = sinon.spy();
const afterShowSpy = sinon.spy();
const hideSpy = sinon.spy();
const afterHideSpy = sinon.spy();
el.addEventListener('wa-show', showSpy);
el.addEventListener('wa-after-show', afterShowSpy);
el.addEventListener('wa-hide', hideSpy);
el.addEventListener('wa-after-hide', afterHideSpy);
// open the dropdown by triggering a click on the trigger
const trigger = el.querySelector<HTMLElement>('[slot="trigger"]')!;
trigger.click();
await waitUntil(() => showSpy.calledOnce);
await waitUntil(() => afterShowSpy.calledOnce);
expect(showSpy.callCount).to.equal(1);
expect(afterShowSpy.callCount).to.equal(1);
expect(el.open).to.be.true;
// close the dropdown by clicking the trigger again
trigger.click();
await waitUntil(() => hideSpy.calledOnce);
await waitUntil(() => afterHideSpy.calledOnce);
expect(hideSpy.callCount).to.equal(1);
expect(afterHideSpy.callCount).to.equal(1);
expect(el.open).to.be.false;
});
it('should fire a single show/after-show and hide/after-hide when wa-hide event is cancelled', async () => {
const el = await fixture<WaDropdown>(html`
<wa-dropdown>
<wa-button slot="trigger">Dropdown</wa-button>
<wa-dropdown-item>One</wa-dropdown-item>
<wa-dropdown-item>Two</wa-dropdown-item>
</wa-dropdown>
`);
// setup spies to track how often we see different show/hide events
const showSpy = sinon.spy();
const afterShowSpy = sinon.spy();
const hideSpy = sinon.spy();
const afterHideSpy = sinon.spy();
el.addEventListener('wa-show', showSpy);
el.addEventListener('wa-after-show', afterShowSpy);
// Intercept wa-hide and prevent it
el.addEventListener('wa-hide', event => {
event.preventDefault();
hideSpy(event);
});
el.addEventListener('wa-after-hide', afterHideSpy);
// open the dropdown by triggering a click on the trigger
const trigger = el.querySelector<HTMLElement>('[slot="trigger"]')!;
trigger.click();
await waitUntil(() => showSpy.calledOnce);
await waitUntil(() => afterShowSpy.calledOnce);
expect(showSpy.callCount).to.equal(1);
expect(afterShowSpy.callCount).to.equal(1);
expect(el.open).to.be.true;
// click on the trigger (which should do nothing to the open state)
trigger.click();
await waitUntil(() => hideSpy.calledOnce);
expect(hideSpy.callCount).to.equal(1);
// after-hide should not have been called if hide is cancelled
expect(afterHideSpy.callCount).to.equal(0);
expect(el.open).to.be.true;
});
});

View File

@@ -109,18 +109,6 @@ export default class WaDropdown extends WebAwesomeElement {
async updated(changedProperties: PropertyValues) {
if (changedProperties.has('open')) {
const previousOpen = changedProperties.get('open');
// check if the previous value is the same
// (if they are, do not trigger menu showing / hiding)
if (previousOpen === this.open) {
return;
}
// check if we are changing from undefined to false
// (if we are, we can skip menu hiding)
if (previousOpen === undefined && this.open === false) {
return;
}
this.customStates.set('open', this.open);
if (this.open) {
@@ -239,12 +227,6 @@ export default class WaDropdown extends WebAwesomeElement {
return;
}
// if this dropdown is already open, do nothing
// (this can happen when wa-hide was cancelled)
if (this.popup.active) {
return;
}
openDropdowns.forEach(dropdown => (dropdown.open = false));
this.popup.active = true; // Use wa-popup's active property instead of showPopover

View File

@@ -25,6 +25,7 @@
svg {
height: 1em;
fill: currentColor;
overflow: visible;
/* Duotone colors with path-specific opacity fallback */

View File

@@ -187,7 +187,7 @@ export default class WaIcon extends WebAwesomeElement {
}
}
@watch(['family', 'name', 'library', 'variant', 'src', 'autoWidth', 'swapOpacity'], { waitUntilFirstUpdate: true })
@watch(['family', 'name', 'library', 'variant', 'src', 'autoWidth', 'swapOpacity'])
async setIcon() {
const { url, fromLibrary } = this.getIconSource();
const library = fromLibrary ? getIconLibrary(this.library) : undefined;
@@ -249,7 +249,7 @@ export default class WaIcon extends WebAwesomeElement {
return this.svg;
}
return html`<svg part="svg" width="16" height="16"></svg>`;
return html`<svg part="svg" fill="currentColor" width="16" height="16"></svg>`;
}
}

View File

@@ -53,19 +53,6 @@
overflow-y: auto;
}
#start-shadow,
#end-shadow {
z-index: 2;
}
#start-shadow {
opacity: var(--start-shadow-opacity);
}
#end-shadow {
opacity: var(--end-shadow-opacity);
}
/* Horizontal shadows */
:host([orientation='horizontal']) {
#start-shadow,
@@ -77,6 +64,14 @@
pointer-events: none;
}
#start-shadow {
opacity: var(--start-shadow-opacity);
}
#end-shadow {
opacity: var(--end-shadow-opacity);
}
#start-shadow {
&:dir(ltr) {
left: 0;
@@ -107,12 +102,21 @@
#start-shadow,
#end-shadow {
position: absolute;
z-index: 2;
right: 0;
left: 0;
height: var(--shadow-size);
pointer-events: none;
}
#start-shadow {
opacity: var(--start-shadow-opacity);
}
#end-shadow {
opacity: var(--end-shadow-opacity);
}
#start-shadow {
top: 0;
background: linear-gradient(to bottom, var(--shadow-color), transparent 100%);

View File

@@ -74,6 +74,7 @@
padding: 0 var(--wa-form-control-padding-inline);
position: relative;
vertical-align: middle;
width: 100%;
transition:
background-color var(--wa-transition-normal),
border var(--wa-transition-normal),

View File

@@ -119,7 +119,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
@state() optionValues: Set<string | null> | undefined;
/** The name of the select, submitted as a name/value pair with form data. */
@property({ reflect: true }) name = '';
@property() name = '';
private _defaultValue: null | string | string[] = null;

View File

@@ -73,16 +73,12 @@ slot:not([name])::slotted(wa-icon) {
rotate: -90deg;
}
.tree-item-expanded:not(.tree-item-loading) slot[name='expand-icon'],
.tree-item-expanded slot[name='expand-icon'],
.tree-item:not(.tree-item-expanded) slot[name='collapse-icon'] {
display: none;
}
.tree-item:not(.tree-item-has-expand-button):not(.tree-item-loading) .expand-icon-slot {
display: none;
}
.tree-item-loading .expand-icon-slot wa-icon {
.tree-item:not(.tree-item-has-expand-button) .expand-icon-slot {
display: none;
}

View File

@@ -254,7 +254,6 @@ export default class WaTreeItem extends WebAwesomeElement {
'tree-item-expanded': this.expanded,
'tree-item-selected': this.selected,
'tree-item-leaf': this.isLeaf,
'tree-item-loading': this.loading,
'tree-item-has-expand-button': showExpandButton,
})}"
>
@@ -273,10 +272,8 @@ export default class WaTreeItem extends WebAwesomeElement {
${when(
this.loading,
() => html` <wa-spinner part="spinner" exportparts="base:spinner__base"></wa-spinner> `,
() => html`
<wa-icon name=${isRtl ? 'chevron-left' : 'chevron-right'} library="system" variant="solid"></wa-icon>
`,
)}
<wa-icon name=${isRtl ? 'chevron-left' : 'chevron-right'} library="system" variant="solid"></wa-icon>
</slot>
<slot class="expand-icon-slot" name="collapse-icon">
<wa-icon name=${isRtl ? 'chevron-left' : 'chevron-right'} library="system" variant="solid"></wa-icon>