Compare commits

..

3 Commits

Author SHA1 Message Date
Kelsey Jackson
1d498040aa updated layouts again 2025-08-05 10:33:37 -05:00
Kelsey Jackson
c6239b17b9 added conditional 2025-08-05 10:06:16 -05:00
Kelsey Jackson
9bcdf3a0c5 updated templates 2025-08-05 09:55:01 -05:00
52 changed files with 1224 additions and 1008 deletions

View File

@@ -135,7 +135,6 @@
"noopener",
"noreferrer",
"noscript",
"Notdog",
"novalidate",
"nowrap",
"Numberish",

7
package-lock.json generated
View File

@@ -13977,7 +13977,7 @@
},
"packages/webawesome": {
"name": "@awesome.me/webawesome",
"version": "3.0.0-beta.4",
"version": "3.0.0-beta.3",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^4.1.0",
@@ -14000,7 +14000,7 @@
},
"packages/webawesome-pro": {
"name": "@shoelace-style/webawesome-pro",
"version": "3.0.0-beta.4",
"version": "3.0.0-beta.3",
"dependencies": {
"@ctrl/tinycolor": "^4.1.0",
"@floating-ui/dom": "^1.6.13",
@@ -14013,9 +14013,6 @@
"qr-creator": "^1.0.0",
"style-observer": "^0.0.7"
},
"devDependencies": {
"@wc-toolkit/jsx-types": "^1.3.0"
},
"engines": {
"node": ">=14.17.0"
}

View File

@@ -182,10 +182,6 @@ export default {
jsxTypesPlugin({
fileName: 'custom-elements-jsx.d.ts',
outdir,
defaultExport: true,
componentTypePath: (_name, _tag, modulePath) => {
return `./${modulePath}`;
},
}),
//

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="38c11e3f20" data-cdn-url="{% cdnUrl %}" class="wa-cloak">
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}" class="wa-cloak">
<head>
{% include 'head.njk' %}
<meta name="theme-color" content="#f36944">
@@ -44,7 +44,7 @@
</head>
<body class="layout-{{ layout | stripExtension }}{{ ' page-wide' if wide }}">
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
<wa-page view="desktop" disable-navigation-toggle mobile-breakpoint="1180">
<wa-page view="desktop" disable-navigation-toggle="" mobile-breakpoint="1180">
<header slot="header" class="wa-split">
{# Logo #}
<div id="docs-branding">
@@ -127,7 +127,7 @@
{% block header %}
<h1 class="title">{{ title }}</h1>
{% endblock %}
{% block beforeContent %}{% endblock %}
{% block content %}

View File

@@ -31,19 +31,16 @@
<!-- Components -->
<wa-details appearance="outlined">
<h2 slot="summary">
<a class="wa-cluster wa-gap-xs" href="/docs/components/" title="Overview">
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
<a href="/docs/components/" title="Overview">
Components
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
</a>
</h2>
<ul>
<li>
<span class="wa-split">
<a class="wa-cluster wa-gap-xs" href="/docs/components/page/">
Page <wa-icon name="flask" aria-hidden="true"></wa-icon>
</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</span>
<a href="/docs/components/page/">Page</a>
<wa-icon name="flask" aria-hidden="true"></wa-icon>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</li>
<li><a href="/docs/components/animated-image/">Animated Image</a></li>
<li><a href="/docs/components/animation/">Animation</a></li>
@@ -60,16 +57,12 @@
<li><a href="/docs/components/callout/">Callout</a></li>
<li><a href="/docs/components/card/">Card</a></li>
<li>
<a class="wa-cluster wa-gap-xs" href="/docs/components/carousel/">
Carousel
<wa-icon name="flask" aria-hidden="true"></wa-icon>
</a>
<a href="/docs/components/carousel/">Carousel</a>
<wa-icon name="flask" aria-hidden="true"></wa-icon>
<ul>
<li>
<a class="wa-cluster wa-gap-xs" href="/docs/components/carousel-item/">
Carousel Item
<wa-icon name="flask" aria-hidden="true"></wa-icon>
</a>
<a href="/docs/components/carousel-item/">Carousel Item</a>
<wa-icon name="flask" aria-hidden="true"></wa-icon>
</li>
</ul>
</li>
@@ -77,10 +70,8 @@
<li><a href="/docs/components/color-picker/">Color Picker</a></li>
<li><a href="/docs/components/comparison/">Comparison</a></li>
<li>
<a class="wa-cluster wa-gap-xs" href="/docs/components/copy-button/">
Copy Button
<wa-icon name="flask" aria-hidden="true"></wa-icon>
</a>
<a href="/docs/components/copy-button/">Copy Button</a>
<wa-icon name="flask" aria-hidden="true"></wa-icon>
</li>
<li><a href="/docs/components/details/">Details</a></li>
<li><a href="/docs/components/dialog/">Dialog</a></li>
@@ -145,9 +136,9 @@
<!-- Style utilities -->
<wa-details appearance="outlined">
<h2 slot="summary">
<a class="wa-cluster wa-gap-xs" href="/docs/utilities/" title="Overview">
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
<a href="/docs/utilities/" title="Overview">
Style Utilities
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
</a>
</h2>
<ul>
@@ -163,9 +154,9 @@
<!-- Layout -->
<wa-details appearance="outlined">
<h2 slot="summary">
<a class="wa-cluster wa-gap-xs" href="/docs/layout/" title="Overview">
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
<a href="/docs/layout/" title="Overview">
Layout
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
</a>
</h2>
<ul>
@@ -178,12 +169,9 @@
<li><a href="/docs/utilities/split/">Split</a></li>
<li><a href="/docs/utilities/stack/">Stack</a></li>
<li>
<span class="wa-split">
<a class="wa-cluster wa-gap-xs" href="/docs/components/page/">
Page <wa-icon name="flask" aria-hidden="true"></wa-icon>
</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</span>
<a href="/docs/components/page/">Page</a>
<wa-icon name="flask" aria-hidden="true"></wa-icon>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</li>
</ul>
</wa-details>
@@ -191,17 +179,15 @@
<!-- Patterns -->
<wa-details appearance="outlined">
<h2 slot="summary">
<a class="wa-cluster wa-gap-xs" href="/docs/patterns/" title="Overview">
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
<a href="/docs/patterns/" title="Overview">
Patterns
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
</a>
</h2>
<ul>
<li>
<span class="wa-split">
<a href="/docs/patterns/app/">App</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</span>
<a href="/docs/patterns/app/">App</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
<ul>
<li>
<a href="/docs/patterns/app/action-panel/">Action Panel</a>
@@ -244,10 +230,8 @@
</ul>
</li>
<li>
<span class="wa-split">
<a href="/docs/patterns/blog-news/">Blog &amp; News</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</span>
<a href="/docs/patterns/blog-news/">Blog &amp; News</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
<ul>
<li>
<a href="/docs/patterns/blog-news/banners/">Banners</a>
@@ -291,7 +275,7 @@
<li>
<a href="/docs/patterns/blog-news/login/">Sign Up &amp; Login</a>
</li>
<li>
<li>
<a href="/docs/patterns/blog-news/numbers/">Numbers</a>
</li>
<li>
@@ -300,16 +284,14 @@
<li>
<a href="/docs/patterns/blog-news/teams/">Teams</a>
</li>
<li>
<li>
<a href="/docs/patterns/blog-news/testimonials/">Testimonials</a>
</li>
</ul>
</li>
<li>
<span class="wa-split">
<a href="/docs/patterns/ecommerce/">Ecommerce</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</span>
<a href="/docs/patterns/ecommerce/">Ecommerce</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
<ul>
<li>
<a href="/docs/patterns/ecommerce/category-filter/">Category Filter</a>
@@ -347,10 +329,8 @@
</ul>
</li>
<li>
<span class="wa-split">
<a href="/docs/patterns/layouts/">Layouts</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</span>
<a href="/docs/patterns/layouts/">Layouts</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
<ul>
<li>
<a href="/docs/patterns/layouts/ecommerce/">Ecommerce</a>
@@ -372,19 +352,17 @@
<li><a href="/docs/color-palettes">Color Palettes</a></li>
<li><a href="/docs/themes">Themes</a></li>
<li>
<span class="wa-split">
<a href="/themer" data-turbo="false">Theme Builder</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</span>
<a href="/themer" data-turbo="false">Theme Builder</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
</li>
</ul>
<!-- Design tokens -->
<wa-details appearance="outlined">
<h2 slot="summary">
<a class="wa-cluster wa-gap-xs" href="/docs/tokens/" title="Overview">
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
<a href="/docs/tokens/" title="Overview">
Design Tokens
<wa-icon name="grid-2" aria-hidden="true"></wa-icon>
</a>
</h2>
<ul>

View File

@@ -16,6 +16,7 @@
<wa-badge variant="brand" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge variant="brand" appearance="filled">Filled</wa-badge>
<wa-badge variant="brand" appearance="outlined">Outlined</wa-badge>
<wa-badge variant="brand" appearance="plain">Plain</wa-badge>
</div>
</td>
<td>
@@ -24,6 +25,7 @@
<wa-badge class="wa-brand" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge class="wa-brand" appearance="filled">Filled</wa-badge>
<wa-badge class="wa-brand" appearance="outlined">Outlined</wa-badge>
<wa-badge class="wa-brand" appearance="plain">Plain</wa-badge>
</div>
</td>
</tr>
@@ -35,6 +37,7 @@
<wa-badge variant="neutral" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge variant="neutral" appearance="filled">Filled</wa-badge>
<wa-badge variant="neutral" appearance="outlined">Outlined</wa-badge>
<wa-badge variant="neutral" appearance="plain">Plain</wa-badge>
</div>
</td>
<td>
@@ -43,6 +46,7 @@
<wa-badge class="wa-neutral" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge class="wa-neutral" appearance="filled">Filled</wa-badge>
<wa-badge class="wa-neutral" appearance="outlined">Outlined</wa-badge>
<wa-badge class="wa-neutral" appearance="plain">Plain</wa-badge>
</div>
</td>
</tr>
@@ -54,6 +58,7 @@
<wa-badge variant="success" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge variant="success" appearance="filled">Filled</wa-badge>
<wa-badge variant="success" appearance="outlined">Outlined</wa-badge>
<wa-badge variant="success" appearance="plain">Plain</wa-badge>
</div>
</td>
<td>
@@ -62,6 +67,7 @@
<wa-badge class="wa-success" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge class="wa-success" appearance="filled">Filled</wa-badge>
<wa-badge class="wa-success" appearance="outlined">Outlined</wa-badge>
<wa-badge class="wa-success" appearance="plain">Plain</wa-badge>
</div>
</td>
</tr>
@@ -73,6 +79,7 @@
<wa-badge variant="warning" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge variant="warning" appearance="filled">Filled</wa-badge>
<wa-badge variant="warning" appearance="outlined">Outlined</wa-badge>
<wa-badge variant="warning" appearance="plain">Plain</wa-badge>
</div>
</td>
<td>
@@ -81,6 +88,7 @@
<wa-badge class="wa-warning" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge class="wa-warning" appearance="filled">Filled</wa-badge>
<wa-badge class="wa-warning" appearance="outlined">Outlined</wa-badge>
<wa-badge class="wa-warning" appearance="plain">Plain</wa-badge>
</div>
</td>
</tr>
@@ -92,6 +100,7 @@
<wa-badge variant="danger" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge variant="danger" appearance="filled">Filled</wa-badge>
<wa-badge variant="danger" appearance="outlined">Outlined</wa-badge>
<wa-badge variant="danger" appearance="plain">Plain</wa-badge>
</div>
</td>
<td>
@@ -100,6 +109,7 @@
<wa-badge class="wa-danger" appearance="filled outlined">Filled + Outlined</wa-badge>
<wa-badge class="wa-danger" appearance="filled">Filled</wa-badge>
<wa-badge class="wa-danger" appearance="outlined">Outlined</wa-badge>
<wa-badge class="wa-danger" appearance="plain">Plain</wa-badge>
</div>
</td>
</tr>

View File

@@ -40,6 +40,66 @@
</div>
<wa-divider></wa-divider>
<h3>Button Group</h3>
<div class="table-scroll">
<table>
<thead>
<th></th>
<th><code>size=""</code></th>
<th><code>.wa-size-[s|m|l]</code></th>
</thead>
<tbody>
<tr>
<th><code>small</code>/<code>s</code></th>
<td>
<wa-button-group orientation="horizontal" size="small">
<wa-button value="1">Button L</wa-button>
<wa-button value="2">Button R</wa-button>
</wa-button-group>
</td>
<td>
<wa-button-group orientation="horizontal" class="wa-size-s">
<wa-button value="1">Button L</wa-button>
<wa-button value="2">Button R</wa-button>
</wa-button-group>
</td>
</tr>
<tr>
<th><code>medium</code>/<code>m</code></th>
<td>
<wa-button-group orientation="horizontal" size="medium">
<wa-button value="1">Button L</wa-button>
<wa-button value="2">Button R</wa-button>
</wa-button-group>
</td>
<td>
<wa-button-group orientation="horizontal" class="wa-size-m">
<wa-button value="1">Button L</wa-button>
<wa-button value="2">Button R</wa-button>
</wa-button-group>
</td>
</tr>
<tr>
<th><code>large</code>/<code>l</code></th>
<td>
<wa-button-group orientation="horizontal" size="large">
<wa-button value="1">Button L</wa-button>
<wa-button value="2">Button R</wa-button>
</wa-button-group>
</td>
<td>
<wa-button-group orientation="horizontal" class="wa-size-l">
<wa-button value="1">Button L</wa-button>
<wa-button value="2">Button R</wa-button>
</wa-button-group>
</td>
</tr>
</tbody>
</table>
</div>
<wa-divider></wa-divider>
<h3>Callout</h3>
<div class="table-scroll">

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="38c11e3f20" data-cdn-url="{% cdnUrl %}">
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
<head>
{% include 'head.njk' %}
{% block head %}{% endblock %}

View File

@@ -56,7 +56,7 @@ document.addEventListener('click', event => {
const code = codeExample.querySelector('code');
const cdnUrl = document.documentElement.dataset.cdnUrl;
const html =
`<script data-fa-kit-code="38c11e3f20" type="module" src="${cdnUrl}webawesome.loader.js"></script>\n` +
`<script data-fa-kit-code="b10bfbde90" type="module" src="${cdnUrl}webawesome.loader.js"></script>\n` +
`<link rel="stylesheet" href="${cdnUrl}styles/webawesome.css">\n\n` +
`${code.textContent}`;
const css = 'html > body {\n padding: 2rem !important;\n}';

View File

@@ -181,6 +181,11 @@ wa-page > header {
li wa-icon {
color: var(--wa-color-text-quiet);
vertical-align: middle;
&[name='flask'] {
margin-inline: 0.125em;
}
}
}
@@ -200,16 +205,25 @@ 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 {
text-decoration: underline;
color: var(--wa-color-brand-on-normal);
wa-icon {
color: var(--wa-color-brand-on-quiet);
}
}
}
}
@@ -394,14 +408,12 @@ wa-button#search-trigger {
box-shadow: none;
}
&::part(label) {
text-align: start;
width: 100%;
}
}
#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 */

View File

@@ -15,6 +15,41 @@ category: Actions
## Examples
### Button Sizes
Unless otherwise specified,
the size of [buttons](/docs/components/button) will be determined by the Button Group's `size` attribute.
```html {.example}
<wa-button-group size="small" label="Alignment">
<wa-button>Left</wa-button>
<wa-button>Center</wa-button>
<wa-button>Right</wa-button>
</wa-button-group>
<br /><br />
<wa-button-group size="medium" label="Alignment">
<wa-button>Left</wa-button>
<wa-button>Center</wa-button>
<wa-button>Right</wa-button>
</wa-button-group>
<br /><br />
<wa-button-group size="large" label="Alignment">
<wa-button>Left</wa-button>
<wa-button>Center</wa-button>
<wa-button>Right</wa-button>
</wa-button-group>
```
:::info
While you can still set the size of [buttons](/docs/components/button) individually,
and it will override the inherited size,
it is rarely a good idea to mix sizes within the same button group.
:::
### Vertical Button Groups
Set the `orientation` attribute to `vertical` to make a vertical button group.

View File

@@ -50,15 +50,15 @@ Use the `expand-icon` and `collapse-icon` slots to change the expand and collaps
### Icon Position
The default position for the expand and collapse icons is at the end of the summary. Set the `icon-placement` attribute to `start` to place the icon at the start of the summary.
The default position for the expand and collapse icons is at the end of the summary. Set the `icon-position` attribute to `start` to place the icon at the start of the summary.
```html {.example}
<div class="wa-stack">
<wa-details summary="Start" icon-placement="start">
<wa-details summary="Start" icon-position="start">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</wa-details>
<wa-details summary="End" icon-placement="end">
<wa-details summary="End" icon-position="end">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</wa-details>
@@ -85,14 +85,14 @@ Links and other interactive elements will still retain their behavior:
### Right-to-Left Languages
The details component, including its `icon-placement`, automatically adapts to right-to-left languages:
The details component, including its `icon-position`, automatically adapts to right-to-left languages:
```html {.example}
<div class="wa-stack">
<wa-details summary="تبديلني" lang="ar" dir="rtl">
استخدام طريقة لوريم إيبسوم لأنها تعطي توزيعاَ طبيعياَ -إلى حد ما- للأحرف عوضاً عن
</wa-details>
<wa-details summary="تبديلني" lang="ar" dir="rtl" icon-placement="start">
<wa-details summary="تبديلني" lang="ar" dir="rtl" icon-position="start">
استخدام طريقة لوريم إيبسوم لأنها تعطي توزيعاَ طبيعياَ -إلى حد ما- للأحرف عوضاً عن
</wa-details>
</div>

View File

@@ -7,10 +7,6 @@ category: Imagery
Web Awesome comes bundled with over 2,000 free icons courtesy of [Font Awesome](https://fontawesome.com/). These icons are part of the `default` icon library. Font Awesome Pro users can unlock additional icon families. Or, if you prefer, you can register your own [custom icon library](#icon-library).
```html {.example}
<wa-icon name="face-awesome" variant="light" label="Awesome" style="font-size: 2em;"></wa-icon>
```
:::info
Not sure which icon to use? [Find the perfect icon over at Font Awesome!](https://fontawesome.com/search?o=r&m=free&f=brands%2Cclassic)
:::
@@ -21,66 +17,45 @@ Not sure which icon to use? [Find the perfect icon over at Font Awesome!](https:
The default icon library is Font Awesome Free, which comes with two icon families: `classic` and `brands`. Use the `family` attribute to set the icon family.
Many Font Awesome Pro icon families have variants such as `thin`, `light`, `regular`, and `solid`. Font Awesome Pro users can [provide their kit code](/docs/#using-font-awesome-kit-codes) to unlock additional premium icon families, including `sharp`, `duotone`, `sharp-duotone`, and additional Pro+ icon packs.
For supportive icon families, use the `variant` attribute to set the variant.
Many Font Awesome Pro icon families have variants such as `thin`, `light`, `regular`, and `solid`. Font Awesome Pro users can [provide their kit code](/docs/#using-font-awesome-kit-codes) to unlock additional families, including `sharp`, `duotone`, and `sharp-duotone`. For these icon families, use the `variant` attribute to set the variant.
```html {.example}
<div class="wa-stack wa-gap-xl">
<div class="wa-flank" style="--flank-size: 12ch;">
<span>Classic</span>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon name="eyedropper"></wa-icon>
<wa-icon variant="regular" name="grip-vertical"></wa-icon>
<wa-icon variant="light" name="play"></wa-icon>
<wa-icon variant="thin" name="star"></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 12ch;">
<span>Duotone</span>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="duotone" name="eyedropper"></wa-icon>
<wa-icon family="duotone" variant="regular" name="grip-vertical"></wa-icon>
<wa-icon family="duotone" variant="light" name="play"></wa-icon>
<wa-icon family="duotone" variant="thin" name="star"></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 12ch;">
<span>Sharp</span>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="sharp" name="eyedropper"></wa-icon>
<wa-icon family="sharp" variant="regular" name="grip-vertical"></wa-icon>
<wa-icon family="sharp" variant="light" name="play"></wa-icon>
<wa-icon family="sharp" variant="thin" name="star"></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 12ch;">
<span>Sharp Duotone</span>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="sharp-duotone" name="eyedropper"></wa-icon>
<wa-icon family="sharp-duotone" variant="regular" name="grip-vertical"></wa-icon>
<wa-icon family="sharp-duotone" variant="light" name="play"></wa-icon>
<wa-icon family="sharp-duotone" variant="thin" name="star"></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 12ch;">
<span>Brands</span>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="brands" name="font-awesome"></wa-icon>
<wa-icon family="brands" name="web-awesome"></wa-icon>
<wa-icon family="brands" name="github"></wa-icon>
<wa-icon family="brands" name="discord"></wa-icon>
</div>
</div>
</div>
<wa-icon name="eyedropper"></wa-icon>
<wa-icon name="grip-vertical"></wa-icon>
<wa-icon name="play"></wa-icon>
<wa-icon name="star"></wa-icon>
<wa-icon name="user"></wa-icon>
```
### Labels
### Colors
For non-decorative icons, use the `label` attribute to announce it to assistive devices.
Icons inherit their color from the current text color. Thus, you can set the `color` property on the `<wa-icon>` element or an ancestor to change the color.
```html {.example}
<wa-icon name="star" label="Favorite" style="font-size: 1.5em;"></wa-icon>
<div style="color: #4a90e2;">
<wa-icon name="exclamation-triangle"></wa-icon>
<wa-icon name="archive"></wa-icon>
<wa-icon name="battery-three-quarters"></wa-icon>
<wa-icon name="bell"></wa-icon>
</div>
<div style="color: #9013fe;">
<wa-icon name="clock"></wa-icon>
<wa-icon name="cloud"></wa-icon>
<wa-icon name="download"></wa-icon>
<wa-icon name="file"></wa-icon>
</div>
<div style="color: #417505;">
<wa-icon name="flag"></wa-icon>
<wa-icon name="heart"></wa-icon>
<wa-icon name="image"></wa-icon>
<wa-icon name="bolt-lightning"></wa-icon>
</div>
<div style="color: #f5a623;">
<wa-icon name="microphone"></wa-icon>
<wa-icon name="search"></wa-icon>
<wa-icon name="star"></wa-icon>
<wa-icon name="trash"></wa-icon>
</div>
```
### Sizing
@@ -88,7 +63,7 @@ For non-decorative icons, use the `label` attribute to announce it to assistive
Icons are sized relative to the current font size. To change their size, set the `font-size` property on the icon itself or on a parent element as shown below.
```html {.example}
<div class="wa-cluster" style="font-size: 44px;">
<div style="font-size: 32px;">
<wa-icon name="bell"></wa-icon>
<wa-icon name="heart"></wa-icon>
<wa-icon name="image"></wa-icon>
@@ -98,317 +73,27 @@ Icons are sized relative to the current font size. To change their size, set the
</div>
```
### Auto Width
### Fixed Width Icons
By default, icons have a 1em height and a fixed 1em width. Use the `auto-width` attribute to allow the icon to use its natural variable width.
By default, icons have a 1em height and a variable width. Use the `fixed-width` attribute to render the host element in a 1em by 1em box.
```html {.example}
Without auto-width<br />
<div style="font-size: 1.5em; color: #193154;">
<wa-icon family="solid" name="exclamation" style="background: lightsalmon;"></wa-icon>
<wa-icon family="solid" name="circle-check" style="background: lightsalmon;"></wa-icon>
<wa-icon family="solid" name="input-numeric" style="background: lightsalmon;"></wa-icon>
<wa-icon family="solid" name="ruler-vertical" style="background: lightsalmon;"></wa-icon>
<wa-icon family="solid" name="ruler-horizontal" style="background: lightsalmon;"></wa-icon>
<wa-icon family="solid" name="airplay" style="background: lightsalmon;"></wa-icon>
</div>
<br />
With auto-width<br />
<div style="font-size: 1.5em; color: #193154;">
<wa-icon auto-width family="solid" name="exclamation" style="background: lightsalmon;"></wa-icon>
<wa-icon auto-width family="solid" name="circle-check" style="background: lightsalmon;"></wa-icon>
<wa-icon auto-width family="solid" name="input-numeric" style="background: lightsalmon;"></wa-icon>
<wa-icon auto-width family="solid" name="ruler-vertical" style="background: lightsalmon;"></wa-icon>
<wa-icon auto-width family="solid" name="ruler-horizontal" style="background: lightsalmon;"></wa-icon>
<wa-icon auto-width family="solid" name="airplay" style="background: lightsalmon;"></wa-icon>
</div>
<wa-icon fixed-width name="cloud"></wa-icon>
<wa-icon fixed-width name="user"></wa-icon>
<wa-icon fixed-width name="truck"></wa-icon>
<wa-icon fixed-width name="file"></wa-icon>
<wa-icon fixed-width name="skating"></wa-icon>
<wa-icon fixed-width name="snowplow"></wa-icon>
```
### Colors
### Labels
Icons inherit their color from the current text color. Thus, you can set the `color` property on the `<wa-icon>` element or an ancestor to change the color.
For non-decorative icons, use the `label` attribute to announce it to assistive devices.
```html {.example}
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon name="strawberry" style="color: salmon;"></wa-icon>
<wa-icon name="crab" style="color: coral;"></wa-icon>
<wa-icon name="sun" style="color: gold;"></wa-icon>
<wa-icon name="leaf" style="color: mediumseagreen;"></wa-icon>
<wa-icon name="cloud-showers-heavy" style="color: steelblue;"></wa-icon>
<wa-icon name="cat-space" style="color: mediumpurple;"></wa-icon>
</div>
<wa-icon name="star" label="Add to favorites"></wa-icon>
```
### Duotone
Font Awesome's [Duotone icons](https://docs.fontawesome.com/web/style/duotone) change with the `color` property as well, but you can customize the primary and secondary colors independently using the `--primary-color` and `--secondary-color` custom properties. To change the opacity of either, use `--primary-opacity` and `--secondary-opacity`.
Note that these custom properties will not inherit and _must be applied directly to the icon_.
```html {.example}
<div class="wa-stack">
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon
family="duotone"
name="crow"
style="--primary-color: dodgerblue; --secondary-color: gold; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
name="campfire"
style="--primary-color: sienna; --secondary-color: red; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
name="birthday-cake"
style="--primary-color: pink; --secondary-color: palevioletred; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
name="ear"
style="--primary-color: sandybrown; --secondary-color: bisque; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
name="corn"
style="--primary-color: mediumseagreen; --secondary-color: gold; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
name="cookie-bite"
style="--primary-color: saddlebrown; --secondary-color: burlywood; --secondary-opacity: 1.0;"
></wa-icon>
</div>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon
family="duotone"
variant="regular"
name="crow"
style="--primary-color: dodgerblue; --secondary-color: gold; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="regular"
name="campfire"
style="--primary-color: sienna; --secondary-color: red; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="regular"
name="birthday-cake"
style="--primary-color: pink; --secondary-color: palevioletred; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="regular"
name="ear"
style="--primary-color: sandybrown; --secondary-color: bisque; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="regular"
name="corn"
style="--primary-color: mediumseagreen; --secondary-color: gold; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="regular"
name="cookie-bite"
style="--primary-color: saddlebrown; --secondary-color: burlywood; --secondary-opacity: 1.0;"
></wa-icon>
</div>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon
family="duotone"
variant="light"
name="crow"
style="--primary-color: dodgerblue; --secondary-color: gold; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="light"
name="campfire"
style="--primary-color: sienna; --secondary-color: red; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="light"
name="birthday-cake"
style="--primary-color: pink; --secondary-color: palevioletred; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="light"
name="ear"
style="--primary-color: sandybrown; --secondary-color: bisque; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="light"
name="corn"
style="--primary-color: mediumseagreen; --secondary-color: gold; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="light"
name="cookie-bite"
style="--primary-color: saddlebrown; --secondary-color: burlywood; --secondary-opacity: 1.0;"
></wa-icon>
</div>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon
family="duotone"
variant="thin"
name="crow"
style="--primary-color: dodgerblue; --secondary-color: gold; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="thin"
name="campfire"
style="--primary-color: sienna; --secondary-color: red; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="thin"
name="birthday-cake"
style="--primary-color: pink; --secondary-color: palevioletred; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="thin"
name="ear"
style="--primary-color: sandybrown; --secondary-color: bisque; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="thin"
name="corn"
style="--primary-color: mediumseagreen; --secondary-color: gold; --secondary-opacity: 1.0;"
></wa-icon>
<wa-icon
family="duotone"
variant="thin"
name="cookie-bite"
style="--primary-color: saddlebrown; --secondary-color: burlywood; --secondary-opacity: 1.0;"
></wa-icon>
</div>
</div>
```
:::info
Duotone icons can be unlocked by [providing a valid Font Awesome kit code](/docs/#using-font-awesome-kit-codes).
:::
### Swap Duotone Opacity
For duotone icons, you can swap the primary and secondary opacity values using the `swap-opacity` attribute. This is useful when you want to emphasize the secondary layer of the icon.
```html {.example}
Normal duotone<br />
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="duotone" name="home"></wa-icon>
<wa-icon family="duotone" name="user"></wa-icon>
<wa-icon family="duotone" name="envelope"></wa-icon>
<wa-icon family="duotone" name="calendar"></wa-icon>
</div>
<br />
Swapped duotone<br />
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="duotone" name="home" swap-opacity></wa-icon>
<wa-icon family="duotone" name="user" swap-opacity></wa-icon>
<wa-icon family="duotone" name="envelope" swap-opacity></wa-icon>
<wa-icon family="duotone" name="calendar" swap-opacity></wa-icon>
</div>
```
### Font Awesome Pro+
If you're a [Font Awesome Pro+ customer](https://fontawesome.com/), you have access to even more premium icons! Just set the appropriate `family`, `variant`, and `name` on the icon.
```html {.example}
<div class="wa-stack wa-gap-xl">
<div class="wa-flank" style="--flank-size: 10ch;">
<a href="https://fontawesome.com/icons/packs/notdog" target="_blank">Notdog</a>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="notdog" variant="solid" name="house"></wa-icon>
<wa-icon
family="notdog"
variant="duo-solid"
name="house"
style="--secondary-color: skyblue; --secondary-opacity: 0.8;"
></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 10ch;">
<a href="https://fontawesome.com/icons/packs/chisel" target="_blank">Chisel</a>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="chisel" variant="regular" name="house"></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 10ch;">
<a href="https://fontawesome.com/icons/packs/etch" target="_blank">Etch</a>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="etch" variant="solid" name="house"></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 10ch;">
<a href="https://fontawesome.com/icons/packs/jelly" target="_blank">Jelly</a>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="jelly" variant="regular" name="house"></wa-icon>
<wa-icon
family="jelly"
variant="duo-regular"
name="house"
style="--secondary-color: skyblue; --secondary-opacity: 0.8;"
></wa-icon>
<wa-icon family="jelly" variant="fill-regular" name="house"></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 10ch;">
<a href="https://fontawesome.com/icons/packs/slab" target="_blank">Slab</a>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon family="slab" variant="regular" name="house"></wa-icon>
<wa-icon family="slab" variant="press-regular" name="house"></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 10ch;">
<a href="https://fontawesome.com/icons/packs/thumbprint" target="_blank">Thumbprint</a>
<div class="wa-cluster" style="font-size: 1.5em;">
<wa-icon
family="thumbprint"
variant="light"
name="house"
style="--secondary-color: skyblue; --secondary-opacity: 0.8;"
></wa-icon>
</div>
</div>
<div class="wa-flank" style="--flank-size: 10ch;">
<a href="https://fontawesome.com/icons/packs/whiteboard" target="_blank">Whiteboard</a>
<div class="wa-cluster" style="font-size: 32px;">
<wa-icon family="whiteboard" variant="semibold" name="house"></wa-icon>
</div>
</div>
</div>
```
:::info
Pro+ icons can be unlocked by [providing a valid Font Awesome kit code](/docs/#using-font-awesome-kit-codes).
:::
### Custom Icons
Custom icons can be loaded individually with the `src` attribute. Only SVGs on a local or CORS-enabled endpoint are supported. If you're using more than one custom icon, it might make sense to register a [custom icon library](#icon-libraries).
@@ -602,9 +287,7 @@ Icons in this library are licensed under the [MIT License](https://github.com/lu
import { registerIconLibrary } from '/dist/webawesome.js';
registerIconLibrary('iconoir', {
resolver: (name, family) => {
return `https://cdn.jsdelivr.net/npm/iconoir@7.11.0/icons/regular/${name}.svg`;
},
resolver: name => `https://cdn.jsdelivr.net/gh/lucaburgio/iconoir@latest/icons/${name}.svg`,
mutator: svg =>
svg.querySelectorAll('path').forEach(path => {
path.setAttribute('fill', 'none');
@@ -614,7 +297,7 @@ Icons in this library are licensed under the [MIT License](https://github.com/lu
</script>
<div style="font-size: 24px;">
<wa-icon library="iconoir" name="check-circle"></wa-icon>
<wa-icon library="iconoir" name="check-circled-outline"></wa-icon>
<wa-icon library="iconoir" name="drawer"></wa-icon>
<wa-icon library="iconoir" name="keyframes"></wa-icon>
<wa-icon library="iconoir" name="headset-help"></wa-icon>

View File

@@ -366,7 +366,7 @@ Here's a comprehensive example showing different lazy loading scenarios:
const option = document.createElement('wa-option');
option.setAttribute('value', 'foo');
option.selected = true;
option.selected = true
option.innerText = 'Foo';
// For the multiple select with existing selected options, make the new option selected
@@ -403,4 +403,4 @@ Here's a comprehensive example showing different lazy loading scenarios:
:::info
The key principle is that the select component prioritizes user interactions and explicit selections over programmatic changes, ensuring a predictable user experience even with dynamically loaded content.
:::
:::

View File

@@ -32,7 +32,7 @@ Now you can [start using Web Awesome!](/docs/usage)
## Using Font Awesome Kit Codes
Font Awesome users can provide their kit code to unlock premium icon packs. You can provide yours by adding the `data-fa-kit-code` attribute to any element on the page, or by calling the `setKitCode()` method.
Font Awesome users can set their kit code to unlock Font Awesome Pro icons. You can provide it by adding the `data-fa-kit-code` attribute to any element on the page, or by calling the `setKitCode()` method.
```html
<!-- Option 1: the data-fa-kit-code attribute -->
@@ -45,10 +45,6 @@ Font Awesome users can provide their kit code to unlock premium icon packs. You
</script>
```
:::info
Not a Font Awesome user yet? [Learn more about premium icon packs](https://fontawesome.com/) and sign up for an account to unlock them!
:::
---
{# This looks weird, but without it, markdownItAttrs flags the raw calls incorrectly. #}

View File

@@ -22,7 +22,43 @@ Through the magic of a mutation observer, changing the `lang` attribute will aut
## Available Translations
Web Awesome ships with [a number of translations](https://github.com/shoelace-style/webawesome/tree/next/packages/webawesome/src/translations). The default is English (US), which also serves as the fallback locale. As such, you do not need to import the English translation.
Web Awesome ships with a number of translations. The default is English (US), which also serves as the fallback locale. As such, you do not need to import the English translation.
Available translations include:
<div style="columns: 3; gap: 1rem; margin-block-end: 1.5rem;">
- ar
- cs
- da
- de-ch
- de
- en-gb
- en
- es
- fa
- fi
- fr
- he
- hr
- hu
- id
- it
- ja
- nb
- nl
- nn
- pl
- pt
- ru
- sl
- sv
- tr
- uk
- zh-cn
- zh-tw
</div>
You can import translations using the following syntax, where `<code>` is replaced with any language code shown above.

View File

@@ -10,28 +10,6 @@ Components with the <wa-badge variant="warning">Experimental</wa-badge> badge sh
## Next
### Bug Fixes and Improvements {data-no-outline}
- 🚨 BREAKING: Updated `<wa-icon>` to use Font Awesome 7 [pr:1222]
- Added the `auto-width` attribute to automatically size icons, since FA7 is fixed-width by default now
- Improved support for duotone icons in `<wa-icon>`, including custom colors, custom opacity, and opacity swapping
- Removed the `fixed-width` attribute as it's now the default behavior
- 🚨 BREAKING: Renamed the `icon-position` attribute to `icon-placement` in `<wa-details>` [discuss:1340]
- 🚨 BREAKING: Removed the `size` attribute from `<wa-button-group>` as it only set the initial size and gets out of sync when buttons are updated (apply a `size` to each button instead)
- Added the Hindi translation [pr:1307]
- Added `--show-duration` and `--hide-duration` to `<wa-select>` [issue:1281]
- Fixed incorrectly named exported tooltip parts in `<wa-slider>` [pr:1277]
- Fixed a bug in `<wa-dropdown>` that caused menus to overflow the viewport instead of resizing [issue:1267]
- Fixed a bug in `<wa-dropdown>` that prevented keyboard selection of items when nested in shadow roots [issue:1270]
- Fixed a bug in `<wa-dropdown>` that prevented items passed in from slots from being detected [issue:1271]
- Fixed a bug in JSX typings that prevented the types file from being exported [pr:1295]
- Fixed a bug in JSX typings that generated the incorrect component imports [issue:1303]
- Fixed a bug in `<wa-slider>` that prevented the thumb from receiving focus when clicking/tapping [issue:1312]
- Fixed a bug in `<wa-scroller>` that caused the shadow to appear below relatively-positioned elements [issue:1326]
- Fixed `<wa-button>` to have `static` positioning by default and `relative` positioning only when used with `<wa-badge>` [pr:1346]
## 3.0.0-beta.4
### New Features {data-no-outline}
- Added the `icon-position` attribute to `<wa-details>` [discuss:1099]
@@ -39,14 +17,12 @@ Components with the <wa-badge variant="warning">Experimental</wa-badge> badge sh
- Added `--wa-tooltip-border-color`, `--wa-tooltip-border-style`, and `--wa-tooltip-border-width` tokens [issue:1224]
- Added the `without-arrow` attribute to `<wa-popover>` and `<wa-tooltip>` to hide arrows without artifacts
- Added JSX types for use with React and others [pr:1256]
- Added `<input type="file">` to native styles [pr:1279]
### Bug Fixes and Improvements {data-no-outline}
- Fixed a bug in `<wa-details>` that caused the content to overflow the container when animating [issue:1149]
- Fixed a bug in `<wa-dialog>` and `<wa-drawer>` that prevented the header from showing when the label was missing [issue:1209]
- Fixed a missing dependency required for React wrappers
- Fixed missing `:hover` and `:active` styles on native buttons without an appearance modifier class
## 3.0.0-beta.3

View File

@@ -252,16 +252,22 @@ This creates confusion because the part will be documented, but it won't work wh
### Emitting Events
Components must only emit events that start with `wa-` as a namespace. For compatibility with frameworks that utilize DOM templates, events must have lowercase, kebab-style names. For example, use `wa-event` instead of `waEvent`.
Components must only emit events that start with `wa-` as a namespace. For compatibility with frameworks that utilize DOM templates, events must have lowercase, kebab-style names. For example, use `wa-change` instead of `waChange`.
This convention avoids the problem of browsers lowercasing attributes, causing some frameworks to be unable to listen to them. This problem isn't specific to one framework, but [Vue's documentation](https://vuejs.org/v2/guide/components-custom-events.html#Event-Names) provides a good explanation of the problem.
### Change Events
When change events are emitted by Web Awesome components, they should be named `wa-change` and they should only be emitted as a result of user input. Programmatic changes, such as setting `el.value = '…'` _should not_ result in a change event being emitted. This is consistent with how native form controls work.
### Data Attribute Invokers
Some components can be controlled using [data attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/data-*) that trigger specific behaviors. These controls must use the following convention:
```html
<button data-component="action id">Button text</button>
<button data-component="action id">
Button text
</button>
```
The `data-component` portion corresponds to the component's name without the `wa-` prefix. For example, `data-dialog` must control a `<wa-dialog>` component.
@@ -271,9 +277,13 @@ The `action` parameter is required and must be a concise, descriptive term indic
The `id` parameter must point to the ID of the target component. The ID may be omitted if and only if the target component wraps the element with the `data-` attribute.
```html
<wa-dialog id="my-dialog"> Dialog content </wa-dialog>
<wa-dialog id="my-dialog">
Dialog content
</wa-dialog>
<button data-dialog="open my-dialog">Open dialog</button>
<button data-dialog="open my-dialog">
Open dialog
</button>
```
### CSS Custom Properties
@@ -406,4 +416,4 @@ or for hydrated rendering only:
```bash
SSR_ONLY="true" npm run test
```
```

View File

@@ -404,7 +404,6 @@ Create a variety of form controls with `<input type="">`, `<select>`, and `<text
<label>Time <input type="time" /></label>
<label>Number <input type="number" placeholder="12345" /></label>
<label>Color <input type="color" value="#f36944" /></label>
<label>File <input type="file" multiple /></label>
<label>Range <input type="range" /></label>
<label>Select
<select>
@@ -431,27 +430,6 @@ Create a variety of form controls with `<input type="">`, `<select>`, and `<text
</script>
```
Add the `wa-size-s`, `wa-size-m`, or `wa-size-l` class to any form control or its parent `<label>` to specify its size.
```html {.example}
<div class="wa-stack">
<input type="text" placeholder="Small input" class="wa-size-s" />
<div class="wa-cluster">
<label class="wa-size-s"><input type="checkbox" checked /> Small checkbox</label>
<label class="wa-size-s"><input type="radio" name="radio-small" value="1" checked /> Small radio</label>
</div>
<input type="text" placeholder="Medium input" class="wa-size-m" />
<div class="wa-cluster">
<label class="wa-size-m"><input type="checkbox" checked /> Medium checkbox</label>
<label class="wa-size-m"><input type="radio" name="radio-medium" value="1" checked /> Medium radio</label>
</div>
<input type="text" placeholder="Large input" class="wa-size-l" />
<div class="wa-cluster">
<label class="wa-size-l"><input type="checkbox" checked /> Large checkbox</label>
<label class="wa-size-l"><input type="radio" name="radio-large" value="1" checked /> Large radio</label>
</div>
</div>
```
Add the `wa-filled` class to an input to give it a filled background.
```html {.example}
@@ -475,12 +453,6 @@ Add the `wa-pill` class to an input or select to give it rounded edges.
</div>
```
Add any [button](#buttons) modifier class to `<input type="file">` to change the file selector button's color variant, appearance, size, and shape.
```html {.example}
<input type="file" class="wa-filled wa-outlined wa-warning wa-size-s wa-pill" />
```
### Fieldsets
Group form controls together with `<fieldset>` and `<legend>`.

View File

@@ -3,7 +3,7 @@ unlisted: true
layout: false
---
<!doctype html>
<html lang="en" class="wa-cloak" data-fa-kit-code="38c11e3f20">
<html lang="en" class="wa-cloak" data-fa-kit-code="b10bfbde90">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
@@ -304,15 +304,15 @@ layout: false
<wa-divider></wa-divider>
<dl class="wa-stack">
<div class="wa-flank wa-align-items-center">
<dt><wa-icon name="user" label="Name"></wa-icon></dt>
<dt><wa-icon name="user" label="Name" fixed-width></wa-icon></dt>
<dd>Tom Bombadil</dd>
</div>
<div class="wa-flank wa-align-items-center">
<dt><wa-icon name="calendar-days" label="Date"></wa-icon></dt>
<dt><wa-icon name="calendar-days" label="Date" fixed-width></wa-icon></dt>
<dd><wa-format-date date="2025-03-15"></wa-format-date></dd>
</div>
<div class="wa-flank wa-align-items-center">
<dt><wa-icon name="coin-vertical"></wa-icon></dt>
<dt><wa-icon name="coin-vertical" fixed-width></wa-icon></dt>
<dd>Paid with copper pennies</dd>
</div>
</dl>
@@ -344,19 +344,19 @@ layout: false
<h4 class="wa-heading-s">What You Get</h4>
<div class="wa-stack">
<div class="wa-flank">
<wa-icon name="user"></wa-icon>
<wa-icon name="user" fixed-width></wa-icon>
<span class="wa-caption-m">9 users</span>
</div>
<div class="wa-flank">
<wa-icon name="ring"></wa-icon>
<wa-icon name="ring" fixed-width></wa-icon>
<span class="wa-caption-m">1 ring</span>
</div>
<div class="wa-flank">
<wa-icon name="chess-rook"></wa-icon>
<wa-icon name="chess-rook" fixed-width></wa-icon>
<span class="wa-caption-m">API access to Isengard</span>
</div>
<div class="wa-flank">
<wa-icon name="feather"></wa-icon>
<wa-icon name="feather" fixed-width></wa-icon>
<span class="wa-caption-m">Priority eagle support</span>
</div>
</div>

View File

@@ -273,7 +273,7 @@ layout: page
<wa-callout variant="brand">
<div class="wa-stack">
<div class="wa-cluster icon-heading">
<wa-icon name="sparkles" variant="regular"></wa-icon>
<wa-icon name="sparkles" variant="regular" fixed-width></wa-icon>
<h3>Bigger and beta than ever</h3>
</div>
<p>This beta is battle-tested and built to last, but if you see something, say something. Please <a href="https://github.com/shoelace-style/webawesome/issues">report bugs</a> or <a href="https://github.com/shoelace-style/webawesome/discussions">ask for help</a>!</p>
@@ -285,10 +285,10 @@ layout: page
<div class="wa-stack">
<div class="wa-split">
<div class="wa-cluster icon-heading">
<wa-icon name="pen-ruler" class="brand-orange"></wa-icon>
<wa-icon name="pen-ruler" fixed-width class="brand-orange"></wa-icon>
<h3>Get started</h3>
</div>
<wa-icon name="arrow-right"></wa-icon>
<wa-icon name="arrow-right" fixed-width></wa-icon>
</div>
<p>Check out our installation guide to start building with Web Awesome.</p>
</div>
@@ -302,28 +302,28 @@ layout: page
<div class="grid">
<div class="wa-stack">
<div class="wa-cluster icon-heading">
<wa-icon name="code" class="brand-orange"></wa-icon>
<wa-icon name="code" fixed-width class="brand-orange"></wa-icon>
<h3>Entirely native</h3>
</div>
<p>Built on web standards to last for years to come. No excess tooling. No third-party bloat.</p>
</div>
<div class="wa-stack">
<div class="wa-cluster icon-heading">
<wa-icon name="palette" class="brand-orange"></wa-icon>
<wa-icon name="palette" fixed-width class="brand-orange"></wa-icon>
<h3>Fully customizable</h3>
</div>
<p>Show off your own style with components that consistently adapt to your theme.</p>
</div>
<div class="wa-stack">
<div class="wa-cluster icon-heading">
<wa-icon name="wheelchair-move" class="brand-orange"></wa-icon>
<wa-icon name="wheelchair-move" fixed-width class="brand-orange"></wa-icon>
<h3>Accessibility forward</h3>
</div>
<p>Build a website that everyone can use. Designed to be inclusive and usable by everyone.</p>
</div>
<div class="wa-stack">
<div class="wa-cluster icon-heading">
<wa-icon name="handshake-simple" class="brand-orange"></wa-icon>
<wa-icon name="handshake-simple" fixed-width class="brand-orange"></wa-icon>
<h3>Proudly open source</h3>
</div>
<p>Use Web Awesome Free however you like. Always free, always open source.</p>
@@ -342,10 +342,10 @@ layout: page
<div class="wa-stack">
<div class="wa-split">
<div class="wa-cluster icon-heading">
<wa-icon family="brands" name="github"></wa-icon>
<wa-icon family="brands" name="github" fixed-width></wa-icon>
<h3>GitHub</h3>
</div>
<wa-icon name="arrow-up-right"></wa-icon>
<wa-icon name="arrow-up-right" fixed-width></wa-icon>
</div>
<p>Get involved by opening issues, contributing to discussions, or creating PRs.</p>
</div>
@@ -354,10 +354,10 @@ layout: page
<div class="wa-stack">
<div class="wa-split">
<div class="wa-cluster icon-heading">
<wa-icon family="brands" name="discord"></wa-icon>
<wa-icon family="brands" name="discord" fixed-width></wa-icon>
<h3>Discord</h3>
</div>
<wa-icon name="arrow-up-right"></wa-icon>
<wa-icon name="arrow-up-right" fixed-width></wa-icon>
</div>
<p>Share your work, ask questions, and explore ideas with other Web Awesome builders.</p>
</div>
@@ -365,19 +365,19 @@ layout: page
<wa-button href="mailto:hello@webawesome.com" appearance="filled" class="tile">
<div class="wa-split">
<div class="wa-cluster icon-heading">
<wa-icon name="envelope-open"></wa-icon>
<wa-icon name="envelope-open" fixed-width></wa-icon>
<h3 class="wa-cluster wa-gap-xs">
<span>hello@webawesome.com</span>
<wa-icon name="hand-wave" variant="regular"></wa-icon>
</h3>
</div>
<wa-icon name="arrow-up-right"></wa-icon>
<wa-icon name="arrow-up-right" fixed-width></wa-icon>
</div>
</wa-button>
</div>
</div>
<wa-divider></wa-divider>
<wa-divider></wa-divider>
<div class="wa-stack wa-gap-xl">
<h2 class="wa-cluster brand-font">
@@ -388,34 +388,34 @@ layout: page
<wa-button href="https://bsky.app/profile/webawesome.com" rel="noopener noreferrer" target="_blank" appearance="filled" class="tile">
<div class="wa-split">
<div class="wa-cluster icon-heading">
<wa-icon family="brands" name="bluesky"></wa-icon>
<wa-icon family="brands" name="bluesky" fixed-width></wa-icon>
<h3>Bluesky</h3>
</div>
<wa-icon name="arrow-up-right"></wa-icon>
<wa-icon name="arrow-up-right" fixed-width></wa-icon>
</div>
</wa-button>
<wa-button href="https://x.com/webawesomer" rel="noopener noreferrer" target="_blank" appearance="filled" class="tile">
<div class="wa-split">
<div class="wa-cluster icon-heading">
<wa-icon family="brands" name="x-twitter"></wa-icon>
<wa-icon family="brands" name="x-twitter" fixed-width></wa-icon>
<h3>Twitter (X)</h3>
</div>
<wa-icon name="arrow-up-right"></wa-icon>
<wa-icon name="arrow-up-right" fixed-width></wa-icon>
</div>
</wa-button>
<wa-button href="https://www.threads.com/@web.awesome" rel="noopener noreferrer" target="_blank" appearance="filled" class="tile">
<div class="wa-split">
<div class="wa-cluster icon-heading">
<wa-icon family="brands" name="threads"></wa-icon>
<wa-icon family="brands" name="threads" fixed-width></wa-icon>
<h3>Threads</h3>
</div>
<wa-icon name="arrow-up-right"></wa-icon>
<wa-icon name="arrow-up-right" fixed-width></wa-icon>
</div>
</wa-button>
</div>
</div>
<wa-divider></wa-divider>
<wa-divider></wa-divider>
<footer>
<div class="wa-crown">

View File

@@ -4,7 +4,7 @@
"access": "public"
},
"description": "A forward-thinking library of web components.",
"version": "3.0.0-beta.4",
"version": "3.0.0-beta.3",
"homepage": "https://webawesome.com/",
"author": "Web Awesome",
"license": "MIT",
@@ -19,7 +19,6 @@
"import": "./dist/webawesome.js"
},
"./dist/custom-elements.json": "./dist/custom-elements.json",
"./dist/custom-elements-jsx.d.ts": "./dist/custom-elements-jsx.d.ts",
"./dist/webawesome.js": "./dist/webawesome.js",
"./dist/webawesome.loader.js": "./dist/webawesome.loader.js",
"./dist/styles": "./dist/styles",

View File

@@ -464,25 +464,7 @@ export async function build(options = {}) {
function handleWatchEvent(evt) {
return async filename => {
const changedFile = relative(getRootDir(), filename);
let message = '';
if (evt === 'change') {
message = chalk.blue(`File modified ${chalk.gray(`(${changedFile})`)}`);
} else if (evt === 'unlink') {
message = chalk.red(`File deleted ${chalk.gray(`(${changedFile})`)}`);
} else if (evt === 'add') {
message = chalk.green(`File added ${chalk.gray(`(${changedFile})`)}`);
}
if (message) {
if (spinner) {
spinner.info(message);
} else {
console.log(message);
}
}
spinner.info(`File modified ${chalk.gray(`(${relative(getRootDir(), filename)})`)}`);
if (typeof options.beforeWatchEvent === 'function') {
await options.beforeWatchEvent(evt, filename);
}

View File

@@ -3,6 +3,7 @@ import { html } from 'lit';
import { customElement, property, query, state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import sizeStyles from '../../styles/utilities/size.css';
import variantStyles from '../../styles/utilities/variants.css';
import type WaButton from '../button/button.js';
import styles from './button-group.css';
@@ -19,7 +20,7 @@ import styles from './button-group.css';
*/
@customElement('wa-button-group')
export default class WaButtonGroup extends WebAwesomeElement {
static css = [variantStyles, styles];
static css = [sizeStyles, variantStyles, styles];
@query('slot') defaultSlot: HTMLSlotElement;
@@ -35,6 +36,9 @@ export default class WaButtonGroup extends WebAwesomeElement {
/** The button group's orientation. */
@property({ reflect: true }) orientation: 'horizontal' | 'vertical' = 'horizontal';
/** The component's size. */
@property({ reflect: true }) size: 'small' | 'medium' | 'large'; // unset by default to not override child elements
/** The button group's theme variant. Defaults to `neutral` if not within another element with a variant. */
@property({ reflect: true }) variant: 'neutral' | 'brand' | 'success' | 'warning' | 'danger' = 'neutral';
@@ -81,6 +85,7 @@ export default class WaButtonGroup extends WebAwesomeElement {
if (button) {
if ((button as WaButton).appearance === 'outlined') this.hasOutlined = true;
if (this.size) button.setAttribute('size', this.size);
button.classList.add('wa-button-group__button');
button.classList.toggle('wa-button-group__horizontal', this.orientation === 'horizontal');
button.classList.toggle('wa-button-group__vertical', this.orientation === 'vertical');

View File

@@ -1,9 +1,6 @@
@layer wa-component {
:host {
display: inline-block;
}
:host(:has(wa-badge)) {
position: relative;
}
}
@@ -187,10 +184,6 @@
}
.label {
display: inline-block;
}
.is-icon-button .label {
display: flex;
}

View File

@@ -25,8 +25,13 @@ export default class WaCallout extends WebAwesomeElement {
@property({ reflect: true }) variant: 'brand' | 'neutral' | 'success' | 'warning' | 'danger' = 'brand';
/** The callout's visual appearance. */
@property({ reflect: true }) appearance: 'accent' | 'filled' | 'outlined' | 'plain' | 'outlined filled' =
'outlined filled';
@property({ reflect: true }) appearance:
| 'accent'
| 'filled'
| 'outlined'
| 'plain'
| 'outlined filled'
| 'outlined accent' = 'outlined filled';
/** The callout's size. */
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';

View File

@@ -46,10 +46,6 @@
cursor: pointer;
}
[part~='label'] {
display: inline;
}
/* Checked */
[part~='control']:has(:checked, :indeterminate) {
color: var(--checked-icon-color);

View File

@@ -490,7 +490,7 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
const target = event.target as HTMLInputElement;
const oldValue = this.value;
// Prevent the `<wa-input>` element's `change` event from bubbling up
// Prevent the `<wa-input>` element's `wa-change` event from bubbling up
event.stopPropagation();
if (this.input.value) {

View File

@@ -191,13 +191,13 @@ export default class WaCopyButton extends WebAwesomeElement {
<!-- Render a visually hidden label to appease the accessibility checking gods -->
<span class="wa-visually-hidden">${this.currentLabel}</span>
<slot part="copy-icon" name="copy-icon">
<wa-icon library="system" name="copy" variant="regular"></wa-icon>
<wa-icon library="system" name="copy" variant="regular" fixed-width></wa-icon>
</slot>
<slot part="success-icon" name="success-icon" variant="solid" hidden>
<wa-icon library="system" name="check"></wa-icon>
<wa-icon library="system" name="check" fixed-width></wa-icon>
</slot>
<slot part="error-icon" name="error-icon" variant="solid" hidden>
<wa-icon library="system" name="xmark"></wa-icon>
<wa-icon library="system" name="xmark" fixed-width></wa-icon>
</slot>
<wa-tooltip
class=${classMap({

View File

@@ -102,8 +102,8 @@ details {
}
}
/* 'Start' icon placement */
:host([icon-placement='start']) summary {
/* 'Start' icon position */
:host([icon-position='start']) summary {
flex-direction: row-reverse;
justify-content: start;
}

View File

@@ -77,8 +77,8 @@ export default class WaDetails extends WebAwesomeElement {
/** The element's visual appearance. */
@property({ reflect: true }) appearance: 'filled' | 'outlined' | 'plain' = 'outlined';
/** The location of the expand/collapse icon. */
@property({ attribute: 'icon-placement', reflect: true }) iconPlacement: 'start' | 'end' = 'end';
/** The position of the expand/collapse icon. */
@property({ attribute: 'icon-position', reflect: true }) iconPosition: 'start' | 'end' = 'end';
disconnectedCallback() {
super.disconnectedCallback();
@@ -268,10 +268,20 @@ export default class WaDetails extends WebAwesomeElement {
<span part="icon">
<slot name="expand-icon">
<wa-icon library="system" variant="solid" name=${isRtl ? 'chevron-left' : 'chevron-right'}></wa-icon>
<wa-icon
library="system"
variant="solid"
name=${isRtl ? 'chevron-left' : 'chevron-right'}
fixed-width
></wa-icon>
</slot>
<slot name="collapse-icon">
<wa-icon library="system" variant="solid" name=${isRtl ? 'chevron-left' : 'chevron-right'}></wa-icon>
<wa-icon
library="system"
variant="solid"
name=${isRtl ? 'chevron-left' : 'chevron-right'}
fixed-width
></wa-icon>
</slot>
</span>
</summary>

View File

@@ -17,9 +17,6 @@
color: var(--wa-color-text-normal);
text-align: start;
user-select: none;
overflow: auto;
max-width: var(--auto-size-available-width) !important;
max-height: var(--auto-size-available-height) !important;
&.show {
animation: show var(--show-duration) ease;

View File

@@ -8,7 +8,6 @@ import { WaAfterShowEvent } from '../../events/after-show.js';
import { WaHideEvent } from '../../events/hide.js';
import { WaSelectEvent } from '../../events/select.js';
import { WaShowEvent } from '../../events/show.js';
import { activeElements } from '../../internal/active-elements.js';
import { animateWithClass } from '../../internal/animate.js';
import { uniqueId } from '../../internal/math.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
@@ -124,30 +123,19 @@ export default class WaDropdown extends WebAwesomeElement {
}
}
/** Gets all dropdown items slotted in the menu. */
/** Gets all <wa-dropdown-item> elements slotted in the menu that aren't disabled. */
private getItems(includeDisabled = false): WaDropdownItem[] {
const items = this.defaultSlot
.assignedElements({ flatten: true })
.filter(el => el.localName === 'wa-dropdown-item') as WaDropdownItem[];
const items = [...this.children].filter(
el => el.localName === 'wa-dropdown-item' && !el.hasAttribute('slot'),
) as WaDropdownItem[];
return includeDisabled ? items : items.filter(item => !item.disabled);
}
/** Gets all dropdown items in a specific submenu. */
private getSubmenuItems(parentItem: WaDropdownItem, includeDisabled = false): WaDropdownItem[] {
// Find the submenu slot within the parent item
const submenuSlot =
parentItem.shadowRoot?.querySelector<HTMLSlotElement>('slot[name="submenu"]') ||
parentItem.querySelector<HTMLSlotElement>('slot[name="submenu"]');
if (!submenuSlot) {
return [];
}
// Get the items from the submenu slot
const items = submenuSlot
.assignedElements({ flatten: true })
.filter(el => el.localName === 'wa-dropdown-item') as WaDropdownItem[];
const items = [...parentItem.children].filter(
el => el.localName === 'wa-dropdown-item' && el.getAttribute('slot') === 'submenu',
) as WaDropdownItem[];
return includeDisabled ? items : items.filter(item => !item.disabled);
}
@@ -289,7 +277,7 @@ export default class WaDropdown extends WebAwesomeElement {
return;
}
const activeElement = [...activeElements()].find(el => el.localName === 'wa-dropdown-item');
const activeElement = document.activeElement as HTMLElement;
const isFocusedOnItem = activeElement?.localName === 'wa-dropdown-item';
const currentSubmenuItem = this.getCurrentSubmenuItem();
const isInSubmenu = !!currentSubmenuItem;
@@ -718,9 +706,7 @@ export default class WaDropdown extends WebAwesomeElement {
flip
flip-fallback-strategy="best-fit"
shift
shift-padding="10"
auto-size="vertical"
auto-size-padding="10"
shift-padding="8"
>
<slot
name="trigger"

View File

@@ -4,38 +4,30 @@
--secondary-color: currentColor;
--secondary-opacity: 0.4;
box-sizing: content-box;
display: inline-flex;
align-items: center;
justify-content: center;
vertical-align: -0.125em;
}
/* Standard */
:host(:not([auto-width])) {
width: 1.25em;
height: 1em;
}
/* Auto-width */
:host([auto-width]) {
box-sizing: content-box !important;
width: auto;
height: 1em;
}
svg {
height: 1em;
display: inline-block;
width: auto;
height: inherit;
fill: currentColor;
overflow: visible;
/* Duotone colors with path-specific opacity fallback */
path[data-duotone-primary] {
.fa-primary {
color: var(--primary-color);
opacity: var(--path-opacity, var(--primary-opacity));
opacity: var(--primary-opacity);
}
path[data-duotone-secondary] {
.fa-secondary {
color: var(--secondary-color);
opacity: var(--path-opacity, var(--secondary-opacity));
opacity: var(--secondary-opacity);
}
}
:host([fixed-width]) {
width: 1em;
justify-content: center;
}

View File

@@ -133,6 +133,17 @@ describe('<wa-icon>', () => {
});
describe('negative cases', () => {
// using new library so we can test for malformed icons when registered
it("svg not rendered with an icon that doesn't exist in the library", async () => {
const el = await fixture<WaIcon>(html` <wa-icon library="test-library" name="does-not-exist"></wa-icon> `);
// Still renders svgs for empty icons.
expect(el.shadowRoot?.querySelector('svg')).to.be.instanceof(SVGElement);
expect(el.getBoundingClientRect().height).to.equal(16);
expect(el.getBoundingClientRect().width).to.equal(16);
});
it('emits wa-error when the file cant be retrieved', async () => {
const el = await fixture<WaIcon>(html` <wa-icon library="test-library"></wa-icon> `);
const listener = oneEvent(el, 'wa-error') as Promise<WaErrorEvent>;

View File

@@ -63,11 +63,8 @@ export default class WaIcon extends WebAwesomeElement {
*/
@property() variant: string;
/** Sets the width of the icon to match the cropped SVG viewBox. This operates like the Font `fa-width-auto` class. */
@property({ attribute: 'auto-width', type: Boolean, reflect: true }) autoWidth: false;
/** Swaps the opacity of duotone icons. */
@property({ attribute: 'swap-opacity', type: Boolean, reflect: true }) swapOpacity = false;
/** Draws the icon in a fixed-width both. */
@property({ attribute: 'fixed-width', type: Boolean, reflect: true }) fixedWidth: false;
/**
* An external URL of an SVG file. Be sure you trust the content you are including, as it will be executed as code and
@@ -106,7 +103,7 @@ export default class WaIcon extends WebAwesomeElement {
if (this.name && library) {
return {
url: library.resolver(this.name, family, this.variant, this.autoWidth),
url: library.resolver(this.name, family, this.variant),
fromLibrary: true,
};
}
@@ -118,7 +115,7 @@ export default class WaIcon extends WebAwesomeElement {
}
/** Given a URL, this function returns the resulting SVG element or an appropriate error symbol. */
private resolveIcon = async (url: string, library?: IconLibrary): Promise<SVGResult> => {
private async resolveIcon(url: string, library?: IconLibrary): Promise<SVGResult> {
let fileData: Response;
if (library?.spriteSheet) {
@@ -136,10 +133,10 @@ export default class WaIcon extends WebAwesomeElement {
// to be passed to the library's mutator function.
await this.updateComplete;
const svg = this.shadowRoot!.querySelector<SVGElement>("[part='svg']")!;
const svg = this.shadowRoot!.querySelector("[part='svg']")!;
if (typeof library.mutator === 'function') {
library.mutator(svg, this);
library.mutator(svg as SVGElement);
}
return this.svg;
@@ -170,7 +167,7 @@ export default class WaIcon extends WebAwesomeElement {
} catch {
return CACHEABLE_ERROR;
}
};
}
@watch('label')
handleLabelChange() {
@@ -187,7 +184,7 @@ export default class WaIcon extends WebAwesomeElement {
}
}
@watch(['family', 'name', 'library', 'variant', 'src', 'autoWidth', 'swapOpacity'])
@watch(['family', 'name', 'library', 'variant', 'src'])
async setIcon() {
const { url, fromLibrary } = this.getIconSource();
const library = fromLibrary ? getIconLibrary(this.library) : undefined;
@@ -227,7 +224,7 @@ export default class WaIcon extends WebAwesomeElement {
break;
default:
this.svg = svg.cloneNode(true) as SVGElement;
library?.mutator?.(this.svg, this);
library?.mutator?.(this.svg);
this.dispatchEvent(new WaLoadEvent());
}
}
@@ -240,7 +237,7 @@ export default class WaIcon extends WebAwesomeElement {
const svg = this.shadowRoot?.querySelector('svg');
if (svg) {
library?.mutator?.(svg, this);
library?.mutator?.(svg);
}
}

View File

@@ -1,55 +1,11 @@
import { getKitCode } from '../../utilities/base-path.js';
import type { IconLibrary } from './library.js';
const FA_VERSION = '7.0.0';
function getIconUrl(name: string, family: string, variant: string) {
const kitCode = getKitCode();
const isPro = kitCode.length > 0;
let folder = 'solid';
// Notdog (Pro+)
if (family === 'notdog') {
if (variant === 'solid') folder = 'solid';
if (variant === 'duo-solid') folder = 'duo-solid';
return `https://ka-p.fontawesome.com/releases/v${FA_VERSION}/svgs/notdog-${folder}/${name}.svg?token=${encodeURIComponent(kitCode)}`;
}
// Chisel (Pro+)
if (family === 'chisel') {
return `https://ka-p.fontawesome.com/releases/v${FA_VERSION}/svgs/chisel-regular/${name}.svg?token=${encodeURIComponent(kitCode)}`;
}
// Etch (Pro+)
if (family === 'etch') {
return `https://ka-p.fontawesome.com/releases/v${FA_VERSION}/svgs/etch-solid/${name}.svg?token=${encodeURIComponent(kitCode)}`;
}
// Jelly (Pro+)
if (family === 'jelly') {
if (variant === 'regular') folder = 'regular';
if (variant === 'duo-regular') folder = 'duo-regular';
if (variant === 'fill-regular') folder = 'fill-regular';
return `https://ka-p.fontawesome.com/releases/v${FA_VERSION}/svgs/jelly-${folder}/${name}.svg?token=${encodeURIComponent(kitCode)}`;
}
// Slab (Pro+)
if (family === 'slab') {
if (variant === 'solid' || variant === 'regular') folder = 'regular';
if (variant === 'press-regular') folder = 'press-regular';
return `https://ka-p.fontawesome.com/releases/v${FA_VERSION}/svgs/slab-${folder}/${name}.svg?token=${encodeURIComponent(kitCode)}`;
}
// Thumbprint (Pro+)
if (family === 'thumbprint') {
return `https://ka-p.fontawesome.com/releases/v${FA_VERSION}/svgs/thumbprint-light/${name}.svg?token=${encodeURIComponent(kitCode)}`;
}
// Whiteboard (Pro+)
if (family === 'whiteboard') {
return `https://ka-p.fontawesome.com/releases/v${FA_VERSION}/svgs/whiteboard-semibold/${name}.svg?token=${encodeURIComponent(kitCode)}`;
}
// Classic
if (family === 'classic') {
if (variant === 'thin') folder = 'thin';
@@ -89,8 +45,8 @@ function getIconUrl(name: string, family: string, variant: string) {
// Use the default CDN
return isPro
? `https://ka-p.fontawesome.com/releases/v${FA_VERSION}/svgs/${folder}/${name}.svg?token=${encodeURIComponent(kitCode)}`
: `https://ka-f.fontawesome.com/releases/v${FA_VERSION}/svgs/${folder}/${name}.svg`;
? `https://ka-p.fontawesome.com/releases/v6.7.2/svgs/${folder}/${name}.svg?token=${encodeURIComponent(kitCode)}`
: `https://ka-f.fontawesome.com/releases/v6.7.2/svgs/${folder}/${name}.svg`;
}
const library: IconLibrary = {
@@ -98,46 +54,6 @@ const library: IconLibrary = {
resolver: (name: string, family = 'classic', variant = 'solid') => {
return getIconUrl(name, family, variant);
},
mutator: (svg, hostEl) => {
// Duotone families
if (hostEl?.family && !svg.hasAttribute('data-duotone-initialized')) {
const { family, variant } = hostEl;
if (
// Duotone
family === 'duotone' ||
// Sharp duotone
family === 'sharp-duotone' ||
// Notdog duo-solid
(family === 'notdog' && variant === 'duo-solid') ||
// Jelly duo-regular
(family === 'jelly' && variant === 'duo-regular') ||
// Thumbprint
family === 'thumbprint'
) {
// Identify the primary and secondary paths. The secondary path is the one that has an opacity attribute.
const paths = [...svg.querySelectorAll<SVGPathElement>('path')];
const primaryPath = paths.find(p => !p.hasAttribute('opacity'));
const secondaryPath = paths.find(p => p.hasAttribute('opacity'));
if (!primaryPath || !secondaryPath) return;
primaryPath.setAttribute('data-duotone-primary', '');
secondaryPath.setAttribute('data-duotone-secondary', '');
// Swap the primary and secondary opacity using CSS custom properties
if (hostEl.swapOpacity && primaryPath && secondaryPath) {
const originalOpacity = secondaryPath.getAttribute('opacity') || '0.4';
// Set path-specific opacity custom properties
primaryPath.style.setProperty('--path-opacity', originalOpacity);
secondaryPath.style.setProperty('--path-opacity', '1');
}
svg.setAttribute('data-duotone-initialized', '');
}
}
},
};
export default library;

View File

@@ -9,31 +9,31 @@ export const icons: { [key: string]: { [key: string]: string } } = {
// Solid variant
//
solid: {
check: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M530.8 134.1C545.1 144.5 548.3 164.5 537.9 178.8L281.9 530.8C276.4 538.4 267.9 543.1 258.5 543.9C249.1 544.7 240 541.2 233.4 534.6L105.4 406.6C92.9 394.1 92.9 373.8 105.4 361.3C117.9 348.8 138.2 348.8 150.7 361.3L252.2 462.8L486.2 141.1C496.6 126.8 516.6 123.6 530.9 134z"/></svg>`,
'chevron-down': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M297.4 470.6C309.9 483.1 330.2 483.1 342.7 470.6L534.7 278.6C547.2 266.1 547.2 245.8 534.7 233.3C522.2 220.8 501.9 220.8 489.4 233.3L320 402.7L150.6 233.4C138.1 220.9 117.8 220.9 105.3 233.4C92.8 245.9 92.8 266.2 105.3 278.7L297.3 470.7z"/></svg>`,
'chevron-left': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M169.4 297.4C156.9 309.9 156.9 330.2 169.4 342.7L361.4 534.7C373.9 547.2 394.2 547.2 406.7 534.7C419.2 522.2 419.2 501.9 406.7 489.4L237.3 320L406.6 150.6C419.1 138.1 419.1 117.8 406.6 105.3C394.1 92.8 373.8 92.8 361.3 105.3L169.3 297.3z"/></svg>`,
'chevron-right': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M471.1 297.4C483.6 309.9 483.6 330.2 471.1 342.7L279.1 534.7C266.6 547.2 246.3 547.2 233.8 534.7C221.3 522.2 221.3 501.9 233.8 489.4L403.2 320L233.9 150.6C221.4 138.1 221.4 117.8 233.9 105.3C246.4 92.8 266.7 92.8 279.2 105.3L471.2 297.3z"/></svg>`,
circle: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576C178.6 576 64 461.4 64 320z"/></svg>`,
eyedropper: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M405.6 93.2L304 194.8L294.6 185.4C282.1 172.9 261.8 172.9 249.3 185.4C236.8 197.9 236.8 218.2 249.3 230.7L409.3 390.7C421.8 403.2 442.1 403.2 454.6 390.7C467.1 378.2 467.1 357.9 454.6 345.4L445.2 336L546.8 234.4C585.8 195.4 585.8 132.2 546.8 93.3C507.8 54.4 444.6 54.3 405.7 93.3zM119.4 387.3C104.4 402.3 96 422.7 96 443.9L96 486.3L69.4 526.2C60.9 538.9 62.6 555.8 73.4 566.6C84.2 577.4 101.1 579.1 113.8 570.6L153.7 544L196.1 544C217.3 544 237.7 535.6 252.7 520.6L362.1 411.2L316.8 365.9L207.4 475.3C204.4 478.3 200.3 480 196.1 480L160 480L160 443.9C160 439.7 161.7 435.6 164.7 432.6L274.1 323.2L228.8 277.9L119.4 387.3z"/></svg>`,
'grip-vertical': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M288 104C288 81.9 270.1 64 248 64L200 64C177.9 64 160 81.9 160 104L160 152C160 174.1 177.9 192 200 192L248 192C270.1 192 288 174.1 288 152L288 104zM288 296C288 273.9 270.1 256 248 256L200 256C177.9 256 160 273.9 160 296L160 344C160 366.1 177.9 384 200 384L248 384C270.1 384 288 366.1 288 344L288 296zM160 488L160 536C160 558.1 177.9 576 200 576L248 576C270.1 576 288 558.1 288 536L288 488C288 465.9 270.1 448 248 448L200 448C177.9 448 160 465.9 160 488zM480 104C480 81.9 462.1 64 440 64L392 64C369.9 64 352 81.9 352 104L352 152C352 174.1 369.9 192 392 192L440 192C462.1 192 480 174.1 480 152L480 104zM352 296L352 344C352 366.1 369.9 384 392 384L440 384C462.1 384 480 366.1 480 344L480 296C480 273.9 462.1 256 440 256L392 256C369.9 256 352 273.9 352 296zM480 488C480 465.9 462.1 448 440 448L392 448C369.9 448 352 465.9 352 488L352 536C352 558.1 369.9 576 392 576L440 576C462.1 576 480 558.1 480 536L480 488z"/></svg>`,
indeterminate: `<svg part="indeterminate-icon" class="icon" viewBox="0 0 16 16"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round"><g stroke="currentColor" stroke-width="2"><g transform="translate(2.285714 6.857143)"><path d="M10.2857143,1.14285714 L1.14285714,1.14285714"/></g></g></g></svg>`,
minus: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M96 320C96 302.3 110.3 288 128 288L512 288C529.7 288 544 302.3 544 320C544 337.7 529.7 352 512 352L128 352C110.3 352 96 337.7 96 320z"/></svg>`,
pause: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M176 96C149.5 96 128 117.5 128 144L128 496C128 522.5 149.5 544 176 544L240 544C266.5 544 288 522.5 288 496L288 144C288 117.5 266.5 96 240 96L176 96zM400 96C373.5 96 352 117.5 352 144L352 496C352 522.5 373.5 544 400 544L464 544C490.5 544 512 522.5 512 496L512 144C512 117.5 490.5 96 464 96L400 96z"/></svg>`,
play: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M187.2 100.9C174.8 94.1 159.8 94.4 147.6 101.6C135.4 108.8 128 121.9 128 136L128 504C128 518.1 135.5 531.2 147.6 538.4C159.7 545.6 174.8 545.9 187.2 539.1L523.2 355.1C536 348.1 544 334.6 544 320C544 305.4 536 291.9 523.2 284.9L187.2 100.9z"/></svg>`,
star: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M341.5 45.1C337.4 37.1 329.1 32 320.1 32C311.1 32 302.8 37.1 298.7 45.1L225.1 189.3L65.2 214.7C56.3 216.1 48.9 222.4 46.1 231C43.3 239.6 45.6 249 51.9 255.4L166.3 369.9L141.1 529.8C139.7 538.7 143.4 547.7 150.7 553C158 558.3 167.6 559.1 175.7 555L320.1 481.6L464.4 555C472.4 559.1 482.1 558.3 489.4 553C496.7 547.7 500.4 538.8 499 529.8L473.7 369.9L588.1 255.4C594.5 249 596.7 239.6 593.9 231C591.1 222.4 583.8 216.1 574.8 214.7L415 189.3L341.5 45.1z"/></svg>`,
user: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M320 312C386.3 312 440 258.3 440 192C440 125.7 386.3 72 320 72C253.7 72 200 125.7 200 192C200 258.3 253.7 312 320 312zM290.3 368C191.8 368 112 447.8 112 546.3C112 562.7 125.3 576 141.7 576L498.3 576C514.7 576 528 562.7 528 546.3C528 447.8 448.2 368 349.7 368L290.3 368z"/></svg>`,
xmark: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M183.1 137.4C170.6 124.9 150.3 124.9 137.8 137.4C125.3 149.9 125.3 170.2 137.8 182.7L275.2 320L137.9 457.4C125.4 469.9 125.4 490.2 137.9 502.7C150.4 515.2 170.7 515.2 183.2 502.7L320.5 365.3L457.9 502.6C470.4 515.1 490.7 515.1 503.2 502.6C515.7 490.1 515.7 469.8 503.2 457.3L365.8 320L503.1 182.6C515.6 170.1 515.6 149.8 503.1 137.3C490.6 124.8 470.3 124.8 457.8 137.3L320.5 274.7L183.1 137.4z"/></svg>`,
check: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>`,
'chevron-down': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M233.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L256 338.7 86.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z"/></svg>`,
'chevron-left': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M9.4 233.4c-12.5 12.5-12.5 32.8 0 45.3l192 192c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256 246.6 86.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0l-192 192z"/></svg>`,
'chevron-right': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M310.6 233.4c12.5 12.5 12.5 32.8 0 45.3l-192 192c-12.5 12.5-32.8 12.5-45.3 0s12.5-32.8 0-45.3L242.7 256 73.4 86.6c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0l192 192z"/></svg>`,
circle: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512z"/></svg>`,
eyedropper: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><path d="M341.6 29.2L240.1 130.8l-9.4-9.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l160 160c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-9.4-9.4L482.8 170.4c39-39 39-102.2 0-141.1s-102.2-39-141.1 0zM55.4 323.3c-15 15-23.4 35.4-23.4 56.6v42.4L5.4 462.2c-8.5 12.7-6.8 29.6 4 40.4s27.7 12.5 40.4 4L89.7 480h42.4c21.2 0 41.6-8.4 56.6-23.4L309.4 335.9l-45.3-45.3L143.4 411.3c-3 3-7.1 4.7-11.3 4.7H96V379.9c0-4.2 1.7-8.3 4.7-11.3L221.4 247.9l-45.3-45.3L55.4 323.3z"/></svg>`,
'grip-vertical': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M40 352l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zm192 0l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zM40 320c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0zM232 192l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40zM40 160c-22.1 0-40-17.9-40-40L0 72C0 49.9 17.9 32 40 32l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0zM232 32l48 0c22.1 0 40 17.9 40 40l0 48c0 22.1-17.9 40-40 40l-48 0c-22.1 0-40-17.9-40-40l0-48c0-22.1 17.9-40 40-40z"/></svg>`,
indeterminate: `<svg part="indeterminate-icon" class="icon" viewBox="0 0 16 16"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round"><g stroke="currentColor" stroke-width="2"><g transform="translate(2.285714, 6.857143)"><path d="M10.2857143,1.14285714 L1.14285714,1.14285714"></path></g></g></g></svg>`,
minus: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M432 256c0 17.7-14.3 32-32 32L48 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/></svg>`,
pause: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="10" viewBox="0 0 320 512"><path d="M48 64C21.5 64 0 85.5 0 112V400c0 26.5 21.5 48 48 48H80c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H48zm192 0c-26.5 0-48 21.5-48 48V400c0 26.5 21.5 48 48 48h32c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48H240z"/></svg>`,
play: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><path d="M73 39c-14.8-9.1-33.4-9.4-48.5-.9S0 62.6 0 80V432c0 17.4 9.4 33.4 24.5 41.9s33.7 8.1 48.5-.9L361 297c14.3-8.7 23-24.2 23-41s-8.7-32.2-23-41L73 39z"/></svg>`,
star: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><path d="M316.9 18C311.6 7 300.4 0 288.1 0s-23.4 7-28.8 18L195 150.3 51.4 171.5c-12 1.8-22 10.2-25.7 21.7s-.7 24.2 7.9 32.7L137.8 329 113.2 474.7c-2 12 3 24.2 12.9 31.3s23 8 33.8 2.3l128.3-68.5 128.3 68.5c10.8 5.7 23.9 4.9 33.8-2.3s14.9-19.3 12.9-31.3L438.5 329 542.7 225.9c8.6-8.5 11.7-21.2 7.9-32.7s-13.7-19.9-25.7-21.7L381.2 150.3 316.9 18z"/></svg>`,
user: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M224 256A128 128 0 1 0 224 0a128 128 0 1 0 0 256zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"/></svg>`,
xmark: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="12" viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>`,
},
//
// Regular variant
//
regular: {
'circle-question': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M528 320C528 205.1 434.9 112 320 112C205.1 112 112 205.1 112 320C112 434.9 205.1 528 320 528C434.9 528 528 434.9 528 320zM64 320C64 178.6 178.6 64 320 64C461.4 64 576 178.6 576 320C576 461.4 461.4 576 320 576C178.6 576 64 461.4 64 320zM320 240C302.3 240 288 254.3 288 272C288 285.3 277.3 296 264 296C250.7 296 240 285.3 240 272C240 227.8 275.8 192 320 192C364.2 192 400 227.8 400 272C400 319.2 364 339.2 344 346.5L344 350.3C344 363.6 333.3 374.3 320 374.3C306.7 374.3 296 363.6 296 350.3L296 342.2C296 321.7 310.8 307 326.1 302C332.5 299.9 339.3 296.5 344.3 291.7C348.6 287.5 352 281.7 352 272.1C352 254.4 337.7 240.1 320 240.1zM288 432C288 414.3 302.3 400 320 400C337.7 400 352 414.3 352 432C352 449.7 337.7 464 320 464C302.3 464 288 449.7 288 432z"/></svg>`,
'circle-xmark': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M320 112C434.9 112 528 205.1 528 320C528 434.9 434.9 528 320 528C205.1 528 112 434.9 112 320C112 205.1 205.1 112 320 112zM320 576C461.4 576 576 461.4 576 320C576 178.6 461.4 64 320 64C178.6 64 64 178.6 64 320C64 461.4 178.6 576 320 576zM231 231C221.6 240.4 221.6 255.6 231 264.9L286 319.9L231 374.9C221.6 384.3 221.6 399.5 231 408.8C240.4 418.1 255.6 418.2 264.9 408.8L319.9 353.8L374.9 408.8C384.3 418.2 399.5 418.2 408.8 408.8C418.1 399.4 418.2 384.2 408.8 374.9L353.8 319.9L408.8 264.9C418.2 255.5 418.2 240.3 408.8 231C399.4 221.7 384.2 221.6 374.9 231L319.9 286L264.9 231C255.5 221.6 240.3 221.6 231 231z"/></svg>`,
copy: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M480 400L288 400C279.2 400 272 392.8 272 384L272 128C272 119.2 279.2 112 288 112L421.5 112C425.7 112 429.8 113.7 432.8 116.7L491.3 175.2C494.3 178.2 496 182.3 496 186.5L496 384C496 392.8 488.8 400 480 400zM288 448L480 448C515.3 448 544 419.3 544 384L544 186.5C544 169.5 537.3 153.2 525.3 141.2L466.7 82.7C454.7 70.7 438.5 64 421.5 64L288 64C252.7 64 224 92.7 224 128L224 384C224 419.3 252.7 448 288 448zM160 192C124.7 192 96 220.7 96 256L96 512C96 547.3 124.7 576 160 576L352 576C387.3 576 416 547.3 416 512L416 496L368 496L368 512C368 520.8 360.8 528 352 528L160 528C151.2 528 144 520.8 144 512L144 256C144 247.2 151.2 240 160 240L176 240L176 192L160 192z"/></svg>`,
eye: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M320 144C254.8 144 201.2 173.6 160.1 211.7C121.6 247.5 95 290 81.4 320C95 350 121.6 392.5 160.1 428.3C201.2 466.4 254.8 496 320 496C385.2 496 438.8 466.4 479.9 428.3C518.4 392.5 545 350 558.6 320C545 290 518.4 247.5 479.9 211.7C438.8 173.6 385.2 144 320 144zM127.4 176.6C174.5 132.8 239.2 96 320 96C400.8 96 465.5 132.8 512.6 176.6C559.4 220.1 590.7 272 605.6 307.7C608.9 315.6 608.9 324.4 605.6 332.3C590.7 368 559.4 420 512.6 463.4C465.5 507.1 400.8 544 320 544C239.2 544 174.5 507.2 127.4 463.4C80.6 419.9 49.3 368 34.4 332.3C31.1 324.4 31.1 315.6 34.4 307.7C49.3 272 80.6 220 127.4 176.6zM320 400C364.2 400 400 364.2 400 320C400 290.4 383.9 264.5 360 250.7C358.6 310.4 310.4 358.6 250.7 360C264.5 383.9 290.4 400 320 400zM240.4 311.6C242.9 311.9 245.4 312 248 312C283.3 312 312 283.3 312 248C312 245.4 311.8 242.9 311.6 240.4C274.2 244.3 244.4 274.1 240.5 311.5zM286 196.6C296.8 193.6 308.2 192.1 319.9 192.1C328.7 192.1 337.4 193 345.7 194.7C346 194.8 346.2 194.8 346.5 194.9C404.4 207.1 447.9 258.6 447.9 320.1C447.9 390.8 390.6 448.1 319.9 448.1C258.3 448.1 206.9 404.6 194.7 346.7C192.9 338.1 191.9 329.2 191.9 320.1C191.9 309.1 193.3 298.3 195.9 288.1C196.1 287.4 196.2 286.8 196.4 286.2C208.3 242.8 242.5 208.6 285.9 196.7z"/></svg>`,
'eye-slash': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M73 39.1C63.6 29.7 48.4 29.7 39.1 39.1C29.8 48.5 29.7 63.7 39 73.1L567 601.1C576.4 610.5 591.6 610.5 600.9 601.1C610.2 591.7 610.3 576.5 600.9 567.2L504.5 470.8C507.2 468.4 509.9 466 512.5 463.6C559.3 420.1 590.6 368.2 605.5 332.5C608.8 324.6 608.8 315.8 605.5 307.9C590.6 272.2 559.3 220.2 512.5 176.8C465.4 133.1 400.7 96.2 319.9 96.2C263.1 96.2 214.3 114.4 173.9 140.4L73 39.1zM208.9 175.1C241 156.2 278.1 144 320 144C385.2 144 438.8 173.6 479.9 211.7C518.4 247.4 545 290 558.5 320C544.9 350 518.3 392.5 479.9 428.3C476.8 431.1 473.7 433.9 470.5 436.7L425.8 392C439.8 371.5 448 346.7 448 320C448 249.3 390.7 192 320 192C293.3 192 268.5 200.2 248 214.2L208.9 175.1zM390.9 357.1L282.9 249.1C294 243.3 306.6 240 320 240C364.2 240 400 275.8 400 320C400 333.4 396.7 346 390.9 357.1zM135.4 237.2L101.4 203.2C68.8 240 46.4 279 34.5 307.7C31.2 315.6 31.2 324.4 34.5 332.3C49.4 368 80.7 420 127.5 463.4C174.6 507.1 239.3 544 320.1 544C357.4 544 391.3 536.1 421.6 523.4L384.2 486C364.2 492.4 342.8 496 320 496C254.8 496 201.2 466.4 160.1 428.3C121.6 392.6 95 350 81.5 320C91.9 296.9 110.1 266.4 135.5 237.2z"/></svg>`,
star: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M320.1 32C329.1 32 337.4 37.1 341.5 45.1L415 189.3L574.9 214.7C583.8 216.1 591.2 222.4 594 231C596.8 239.6 594.5 249 588.2 255.4L473.7 369.9L499 529.8C500.4 538.7 496.7 547.7 489.4 553C482.1 558.3 472.4 559.1 464.4 555L320.1 481.6L175.8 555C167.8 559.1 158.1 558.3 150.8 553C143.5 547.7 139.8 538.8 141.2 529.8L166.4 369.9L52 255.4C45.6 249 43.4 239.6 46.2 231C49 222.4 56.3 216.1 65.3 214.7L225.2 189.3L298.8 45.1C302.9 37.1 311.2 32 320.2 32zM320.1 108.8L262.3 222C258.8 228.8 252.3 233.6 244.7 234.8L119.2 254.8L209 344.7C214.4 350.1 216.9 357.8 215.7 365.4L195.9 490.9L309.2 433.3C316 429.8 324.1 429.8 331 433.3L444.3 490.9L424.5 365.4C423.3 357.8 425.8 350.1 431.2 344.7L521 254.8L395.5 234.8C387.9 233.6 381.4 228.8 377.9 222L320.1 108.8z"/></svg>`,
'circle-question': `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--!Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M464 256A208 208 0 1 0 48 256a208 208 0 1 0 416 0zM0 256a256 256 0 1 1 512 0A256 256 0 1 1 0 256zm169.8-90.7c7.9-22.3 29.1-37.3 52.8-37.3l58.3 0c34.9 0 63.1 28.3 63.1 63.1c0 22.6-12.1 43.5-31.7 54.8L280 264.4c-.2 13-10.9 23.6-24 23.6c-13.3 0-24-10.7-24-24l0-13.5c0-8.6 4.6-16.5 12.1-20.8l44.3-25.4c4.7-2.7 7.6-7.7 7.6-13.1c0-8.4-6.8-15.1-15.1-15.1l-58.3 0c-3.4 0-6.4 2.1-7.5 5.3l-.4 1.2c-4.4 12.5-18.2 19-30.6 14.6s-19-18.2-14.6-30.6l.4-1.2zM224 352a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z"/></svg>`,
'circle-xmark': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path d="M256 48a208 208 0 1 1 0 416 208 208 0 1 1 0-416zm0 464A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c-9.4 9.4-9.4 24.6 0 33.9l47 47-47 47c-9.4 9.4-9.4 24.6 0 33.9s24.6 9.4 33.9 0l47-47 47 47c9.4 9.4 24.6 9.4 33.9 0s9.4-24.6 0-33.9l-47-47 47-47c9.4-9.4 9.4-24.6 0-33.9s-24.6-9.4-33.9 0l-47 47-47-47c-9.4-9.4-24.6-9.4-33.9 0z"/></svg>`,
copy: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><path d="M384 336H192c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16l140.1 0L400 115.9V320c0 8.8-7.2 16-16 16zM192 384H384c35.3 0 64-28.7 64-64V115.9c0-12.7-5.1-24.9-14.1-33.9L366.1 14.1c-9-9-21.2-14.1-33.9-14.1H192c-35.3 0-64 28.7-64 64V320c0 35.3 28.7 64 64 64zM64 128c-35.3 0-64 28.7-64 64V448c0 35.3 28.7 64 64 64H256c35.3 0 64-28.7 64-64V416H272v32c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V192c0-8.8 7.2-16 16-16H96V128H64z"/></svg>`,
eye: `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><path d="M288 80c-65.2 0-118.8 29.6-159.9 67.7C89.6 183.5 63 226 49.4 256c13.6 30 40.2 72.5 78.6 108.3C169.2 402.4 222.8 432 288 432s118.8-29.6 159.9-67.7C486.4 328.5 513 286 526.6 256c-13.6-30-40.2-72.5-78.6-108.3C406.8 109.6 353.2 80 288 80zM95.4 112.6C142.5 68.8 207.2 32 288 32s145.5 36.8 192.6 80.6c46.8 43.5 78.1 95.4 93 131.1c3.3 7.9 3.3 16.7 0 24.6c-14.9 35.7-46.2 87.7-93 131.1C433.5 443.2 368.8 480 288 480s-145.5-36.8-192.6-80.6C48.6 356 17.3 304 2.5 268.3c-3.3-7.9-3.3-16.7 0-24.6C17.3 208 48.6 156 95.4 112.6zM288 336c44.2 0 80-35.8 80-80s-35.8-80-80-80c-.7 0-1.3 0-2 0c1.3 5.1 2 10.5 2 16c0 35.3-28.7 64-64 64c-5.5 0-10.9-.7-16-2c0 .7 0 1.3 0 2c0 44.2 35.8 80 80 80zm0-208a128 128 0 1 1 0 256 128 128 0 1 1 0-256z"/></svg>`,
'eye-slash': `<svg xmlns="http://www.w3.org/2000/svg" height="16" width="20" viewBox="0 0 640 512"><path d="M38.8 5.1C28.4-3.1 13.3-1.2 5.1 9.2S-1.2 34.7 9.2 42.9l592 464c10.4 8.2 25.5 6.3 33.7-4.1s6.3-25.5-4.1-33.7L525.6 386.7c39.6-40.6 66.4-86.1 79.9-118.4c3.3-7.9 3.3-16.7 0-24.6c-14.9-35.7-46.2-87.7-93-131.1C465.5 68.8 400.8 32 320 32c-68.2 0-125 26.3-169.3 60.8L38.8 5.1zm151 118.3C226 97.7 269.5 80 320 80c65.2 0 118.8 29.6 159.9 67.7C518.4 183.5 545 226 558.6 256c-12.6 28-36.6 66.8-70.9 100.9l-53.8-42.2c9.1-17.6 14.2-37.5 14.2-58.7c0-70.7-57.3-128-128-128c-32.2 0-61.7 11.9-84.2 31.5l-46.1-36.1zM394.9 284.2l-81.5-63.9c4.2-8.5 6.6-18.2 6.6-28.3c0-5.5-.7-10.9-2-16c.7 0 1.3 0 2 0c44.2 0 80 35.8 80 80c0 9.9-1.8 19.4-5.1 28.2zm51.3 163.3l-41.9-33C378.8 425.4 350.7 432 320 432c-65.2 0-118.8-29.6-159.9-67.7C121.6 328.5 95 286 81.4 256c8.3-18.4 21.5-41.5 39.4-64.8L83.1 161.5C60.3 191.2 44 220.8 34.5 243.7c-3.3 7.9-3.3 16.7 0 24.6c14.9 35.7 46.2 87.7 93 131.1C174.5 443.2 239.2 480 320 480c47.8 0 89.9-12.9 126.2-32.5zm-88-69.3L302 334c-23.5-5.4-43.1-21.2-53.7-42.3l-56.1-44.2c-.2 2.8-.3 5.6-.3 8.5c0 70.7 57.3 128 128 128c13.3 0 26.1-2 38.2-5.8z"/></svg>`,
star: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M287.9 0c9.2 0 17.6 5.2 21.6 13.5l68.6 141.3 153.2 22.6c9 1.3 16.5 7.6 19.3 16.3s.5 18.1-5.9 24.5L433.6 328.4l26.2 155.6c1.5 9-2.2 18.1-9.7 23.5s-17.3 6-25.3 1.7l-137-73.2L151 509.1c-8.1 4.3-17.9 3.7-25.3-1.7s-11.2-14.5-9.7-23.5l26.2-155.6L31.1 218.2c-6.5-6.4-8.7-15.9-5.9-24.5s10.3-14.9 19.3-16.3l153.2-22.6L266.3 13.5C270.4 5.2 278.7 0 287.9 0zm0 79L235.4 187.2c-3.5 7.1-10.2 12.1-18.1 13.3L99 217.9 184.9 303c5.5 5.5 8.1 13.3 6.8 21L171.4 443.7l105.2-56.2c7.1-3.8 15.6-3.8 22.6 0l105.2 56.2L384.2 324.1c-1.3-7.7 1.2-15.5 6.8-21l85.9-85.1L358.6 200.5c-7.8-1.2-14.6-6.1-18.1-13.3L287.9 79z"/></svg>',
},
};

View File

@@ -2,9 +2,8 @@ import type WaIcon from '../icon/icon.js';
import defaultLibrary from './library.default.js';
import systemLibrary from './library.system.js';
export type IconLibraryHostElement = WaIcon;
export type IconLibraryResolver = (name: string, family: string, variant: string, autoWidth: boolean) => string;
export type IconLibraryMutator = (svg: SVGElement, hostElement?: IconLibraryHostElement) => void;
export type IconLibraryResolver = (name: string, family: string, variant: string) => string;
export type IconLibraryMutator = (svg: SVGElement) => void;
export interface IconLibrary {
name: string;
resolver: IconLibraryResolver;

View File

@@ -0,0 +1,250 @@
: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);
}

View File

@@ -0,0 +1,11 @@
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;
}
}
`;

View File

@@ -0,0 +1,15 @@
import { expect } from '@open-wc/testing';
import { html } from 'lit';
import { fixtures } from '../../internal/test/fixture.js';
describe('<wa-page>', () => {
for (const fixture of fixtures) {
describe(`with "${fixture.type}" rendering`, () => {
it('should render a component', async () => {
const el = await fixture(html` <wa-page></wa-page> `);
expect(el).to.exist;
});
});
}
});

View File

@@ -0,0 +1,455 @@
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<typeof ResizeObserver>) {}
// eslint-disable-next-line
observe(..._args: Parameters<ResizeObserver['observe']>) {}
// eslint-disable-next-line
unobserve(..._args: Parameters<ResizeObserver['unobserve']>) {}
// eslint-disable-next-line
disconnect(..._args: Parameters<ResizeObserver['disconnect']>) {}
};
}
//
// 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: '<length>',
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 `<wa-drawer>`.
* @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 `<wa-drawer>`.
* @slot navigation-toggle - Use this slot to slot in your own button + icon for toggling the navigation drawer. By default it is a `<wa-button>` + a 3 bars `<wa-icon>`
* @slot navigation-toggle-icon - Use this to slot in your own icon for toggling the navigation drawer. By default it is 3 bars `<wa-icon>`.
* @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 `<nav>` 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 `<wa-drawer>`.
* @csspart navigation-footer - The footer for a navigation area. On mobile this will be the footer for `<wa-drawer>`.
* @csspart navigation-toggle - The default `<wa-button>` that will toggle the `<wa-drawer>` for mobile viewports.
* @csspart navigation-toggle-icon - The default `<wa-icon>` 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<this>): 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`
<a href="#main-content" part="skip-to-content" class="wa-visually-hidden">
<slot name="skip-to-content">Skip to content</slot>
</a>
<!-- unsafeHTML needed for SSR until this is solved: https://github.com/lit/lit/issues/4696 -->
${unsafeHTML(`
<style id="mobile-styles">
${mobileStyles(toLength(this.mobileBreakpoint))}
</style>
`)}
<div class="base" part="base">
<div class="banner" part="banner">
<slot name="banner"></slot>
</div>
<div class="header" part="header">
<slot name="navigation-toggle">
<wa-button part="navigation-toggle" size="small" appearance="plain" variant="neutral">
<slot name="navigation-toggle-icon">
<wa-icon name="bars" part="navigation-toggle-icon" label="Toggle navigation drawer"></wa-icon>
</slot>
</wa-button>
</slot>
<slot name="header"></slot>
</div>
<div class="subheader" part="subheader">
<slot name="subheader"></slot>
</div>
<div class="body" part="body">
<div class="menu" part="menu">
<slot name="menu">
<nav name="navigation" class="navigation" part="navigation navigation-desktop">
<!-- Add fallback divs so that CSS grid works properly. -->
<slot name="desktop-navigation-header">
<slot name=${this.view === 'desktop' ? 'navigation-header' : '___'}><div></div></slot>
</slot>
<slot name="desktop-navigation">
<slot name=${this.view === 'desktop' ? 'navigation' : '____'}><div></div></slot>
</slot>
<slot name="desktop-navigation-footer">
<slot name=${this.view === 'desktop' ? 'navigation-footer' : '___'}><div></div></slot>
</slot>
</nav>
</slot>
</div>
<div class="main" part="main">
<div class="main-header" part="main-header">
<slot name="main-header"></slot>
</div>
<div class="main-content" part="main-content">
<slot name="skip-to-content-target"></slot>
<slot></slot>
</div>
<div class="main-footer" part="main-footer">
<slot name="main-footer"></slot>
</div>
</div>
<div class="aside" part="aside">
<slot name="aside"></slot>
</div>
</div>
<div class="footer" part="footer">
<slot name="footer"></slot>
</div>
</div>
<wa-drawer
part="drawer"
placement=${this.navigationPlacement}
light-dismiss
?open=${live(this.navOpen)}
@wa-after-show=${() => (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"
>
<slot slot="label" part="navigation-header" name="mobile-navigation-header">
<slot name=${this.view === 'mobile' ? 'navigation-header' : '___'}></slot>
</slot>
<slot name="mobile-navigation">
<slot name=${this.view === 'mobile' ? 'navigation' : '____'}></slot>
</slot>
<slot name="mobile-navigation-footer">
<slot
part="navigation-footer"
slot="footer"
name=${this.view === 'mobile' ? 'navigation-footer' : '___'}
></slot>
</slot>
</wa-drawer>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
'wa-page': WaPage;
}
}
//
// Append a supporting light DOM styles for <wa-page>
//
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: \`<a href="#id-for-h2">\` 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];

View File

@@ -20,7 +20,6 @@
}
#content {
z-index: 1; /* below shadows */
border-radius: inherit;
scroll-behavior: smooth;
scrollbar-width: thin;
@@ -103,7 +102,6 @@
#start-shadow,
#end-shadow {
position: absolute;
z-index: 2;
right: 0;
left: 0;
height: var(--shadow-size);

View File

@@ -1,7 +1,5 @@
:host {
--tag-max-size: 10ch;
--show-duration: 100ms;
--hide-duration: 100ms;
}
/* Add ellipses to multi select options */
@@ -32,10 +30,6 @@
position: relative;
vertical-align: middle;
/* Pass through from select to the popup */
--show-duration: inherit;
--hide-duration: inherit;
&::part(popup) {
z-index: 900;
}

View File

@@ -74,8 +74,6 @@ import styles from './select.css';
* @csspart clear-button - The clear button.
* @csspart expand-icon - The container that wraps the expand icon.
*
* @cssproperty [--show-duration=100ms] - The duration of the show animation.
* @cssproperty [--hide-duration=100ms] - The duration of the hide animation.
* @cssproperty [--tag-max-size=10ch] - When using `multiple`, the max size of tags before their content is truncated.
*
* @cssstate blank - The select is empty.

View File

@@ -33,8 +33,6 @@
}
#slider {
touch-action: none;
&:focus {
outline: none;
}

View File

@@ -841,8 +841,8 @@ export default class WaSlider extends WebAwesomeFormAssociatedElement {
id=${`tooltip${thumbId !== 'thumb' ? '-' + thumbId : ''}`}
part="tooltip"
exportparts="
base:tooltip__base,
body:tooltip__body,
tooltip:tooltip__tooltip,
content:tooltip__content,
arrow:tooltip__arrow
"
trigger="manual"

View File

@@ -35,7 +35,8 @@ export default class WaTag extends WebAwesomeElement {
@property({ reflect: true }) variant: 'brand' | 'neutral' | 'success' | 'warning' | 'danger' = 'neutral';
/** The tag's visual appearance. */
@property({ reflect: true }) appearance: 'accent' | 'filled' | 'outlined' | 'outlined filled' = 'outlined filled';
@property({ reflect: true }) appearance: 'accent' | 'outlined accent' | 'filled' | 'outlined' | 'outlined filled' =
'outlined filled';
/** The tag's size. */
@property({ reflect: true }) size: 'small' | 'medium' | 'large' = 'medium';

View File

@@ -55,8 +55,6 @@ const supportsTouch = typeof window !== 'undefined' && 'ontouchstart' in window;
* Drag functionality will be enabled as soon as the constructor is called. A `start()` and `stop()` method can be used
* to start and stop it, if needed.
*
* Use `touch-action: none` on touch devices if scrolling occurs while dragging. Avoid preventing the touchstart event!
*
* @usage
*
* const draggable = new DraggableElement(element, {
@@ -87,6 +85,9 @@ export class DraggableElement {
const clientX = supportsTouch && 'touches' in event ? event.touches[0].clientX : (event as PointerEvent).clientX;
const clientY = supportsTouch && 'touches' in event ? event.touches[0].clientY : (event as PointerEvent).clientY;
// Prevent scrolling while dragging
event.preventDefault();
if (
this.isDragging ||
// Prevent right-clicks from triggering drags

View File

@@ -560,219 +560,124 @@
button,
input[type='button'],
input[type='reset'],
input[type='submit'],
input[type='file'] {
/* We allow modifier classes on <input type="file">,
* but these selectors ensure the styles only apply to
* the file selector button in the user agent's shadow root */
&:not(input[type='file']),
&::file-selector-button {
display: inline-flex;
align-items: center;
justify-content: center;
input[type='submit'] {
display: inline-flex;
align-items: center;
justify-content: center;
height: var(--wa-form-control-height);
padding: 0 var(--wa-form-control-padding-inline);
height: var(--wa-form-control-height);
padding: 0 var(--wa-form-control-padding-inline);
font-family: inherit;
font-size: var(--wa-form-control-value-font-size);
font-weight: var(--wa-font-weight-action);
line-height: calc(var(--wa-form-control-height) - var(--border-width) * 2);
text-decoration: none;
vertical-align: middle;
white-space: nowrap;
color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
font-family: inherit;
font-size: var(--wa-form-control-value-font-size);
font-weight: var(--wa-font-weight-action);
line-height: calc(var(--wa-form-control-height) - var(--border-width) * 2);
text-decoration: none;
vertical-align: middle;
white-space: nowrap;
border-style: var(--wa-border-style);
border-width: max(1px, var(--wa-form-control-border-width));
border-radius: var(--wa-form-control-border-radius);
background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
border-color: transparent;
border-style: var(--wa-border-style);
border-width: max(1px, var(--wa-form-control-border-width));
border-radius: var(--wa-form-control-border-radius);
transition-property: background, border, box-shadow, color;
transition-duration: var(--wa-transition-fast);
transition-timing-function: var(--wa-transition-easing);
transition-property: background, border, box-shadow, color;
transition-duration: var(--wa-transition-fast);
transition-timing-function: var(--wa-transition-easing);
cursor: pointer;
user-select: none;
-webkit-user-select: none;
}
cursor: pointer;
user-select: none;
-webkit-user-select: none;
/* Default styles for standard buttons */
:where(&:not(input[type='file'])) {
color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
&.wa-plain {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: transparent;
border-color: transparent;
&:not(:disabled) {
&:hover {
background-color: color-mix(
in oklab,
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
var(--wa-color-mix-hover)
);
}
&:active {
background-color: color-mix(
in oklab,
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
var(--wa-color-mix-active)
);
}
}
}
/* Default styles for file selector buttons */
:where(&:is(input[type='file'])) {
&::file-selector-button {
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
background-color: var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal));
border-color: transparent;
}
&:not(:disabled) {
&::file-selector-button:hover {
background-color: color-mix(
in oklab,
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
var(--wa-color-mix-hover)
);
}
&::file-selector-button:active {
background-color: color-mix(
in oklab,
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
var(--wa-color-mix-active)
);
}
}
}
/* Modifier classes */
&.wa-plain {
&:not(input[type='file']),
&::file-selector-button {
&:not(:disabled):hover {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: transparent;
border-color: transparent;
background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet));
}
&:not(:disabled) {
&:not(input[type='file']):hover,
&::file-selector-button:hover {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet));
}
&:not(input[type='file']):active,
&::file-selector-button:active {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: color-mix(
in oklab,
var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)),
var(--wa-color-mix-active)
);
}
&:not(:disabled):active {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: color-mix(
in oklab,
var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)),
var(--wa-color-mix-active)
);
}
}
&.wa-outlined {
&:not(input[type='file']),
&::file-selector-button {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: transparent;
border-color: var(--wa-color-border-loud, var(--wa-color-neutral-border-loud));
&:not(:disabled):hover {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: transparent;
border-color: var(--wa-color-border-loud, var(--wa-color-neutral-border-loud));
background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet));
}
&:not(:disabled) {
&:not(input[type='file']):hover,
&::file-selector-button:hover {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet));
}
&:not(input[type='file']):active,
&::file-selector-button:active {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: color-mix(
in oklab,
var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)),
var(--wa-color-mix-active)
);
}
&:not(:disabled):active {
color: var(--wa-color-on-quiet, var(--wa-color-neutral-on-quiet));
background-color: color-mix(
in oklab,
var(--wa-color-fill-quiet, var(--wa-color-neutral-fill-quiet)),
var(--wa-color-mix-active)
);
}
}
&.wa-filled {
&:not(input[type='file']),
&::file-selector-button {
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
background-color: var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal));
border-color: transparent;
&:not(:disabled):hover {
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
background-color: var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal));
border-color: transparent;
background-color: color-mix(
in oklab,
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
var(--wa-color-mix-hover)
);
}
&:not(:disabled) {
&:not(input[type='file']):hover,
&::file-selector-button:hover {
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
background-color: color-mix(
in oklab,
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
var(--wa-color-mix-hover)
);
}
&:not(input[type='file']):active,
&::file-selector-button:active {
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
background-color: color-mix(
in oklab,
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
var(--wa-color-mix-active)
);
}
&:not(:disabled):active {
color: var(--wa-color-on-normal, var(--wa-color-neutral-on-normal));
background-color: color-mix(
in oklab,
var(--wa-color-fill-normal, var(--wa-color-neutral-fill-normal)),
var(--wa-color-mix-active)
);
}
&.wa-outlined {
&:not(input[type='file']),
&::file-selector-button {
border-color: var(--wa-color-border-normal, var(--wa-color-neutral-border-normal));
}
border-color: var(--wa-color-border-normal, var(--wa-color-neutral-border-normal));
}
}
&.wa-accent {
&:not(input[type='file']),
&::file-selector-button {
color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
border-color: transparent;
color: var(--wa-color-on-loud, var(--wa-color-neutral-on-loud));
background-color: var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud));
border-color: transparent;
&:not(:disabled):hover {
background-color: color-mix(
in oklab,
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
var(--wa-color-mix-hover)
);
}
&:not(:disabled) {
&:not(input[type='file']):hover,
&::file-selector-button:hover {
background-color: color-mix(
in oklab,
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
var(--wa-color-mix-hover)
);
}
&:not(input[type='file']):active,
&::file-selector-button:active {
background-color: color-mix(
in oklab,
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
var(--wa-color-mix-active)
);
}
}
}
&.wa-pill {
&:not(input[type='file']),
&::file-selector-button {
border-radius: var(--wa-border-radius-pill);
&:not(:disabled):active {
background-color: color-mix(
in oklab,
var(--wa-color-fill-loud, var(--wa-color-neutral-fill-loud)),
var(--wa-color-mix-active)
);
}
}
@@ -800,6 +705,10 @@
}
}
&.wa-pill {
border-radius: var(--wa-border-radius-pill);
}
/* Adds space between icons and adjacent elements
* Prefer sibling selectors over :first-child/:last-child to avoid extra space when an icon is used alone */
& > wa-icon:has(+ *) {
@@ -812,25 +721,6 @@
}
/* #endregion */
/* #region File Inputs ~~~~~~~~~~~~~~~~~~~~~ */
input[type='file'] {
display: block;
max-inline-size: 100%;
color: var(--wa-form-control-value-color);
font-family: inherit;
font-size: var(--wa-form-control-value-font-size);
font-weight: var(--wa-form-control-value-font-weight);
line-height: var(--wa-form-control-value-line-height);
vertical-align: middle;
border-radius: var(--wa-border-radius-m);
cursor: pointer;
}
/* #endregion */
/* #region Checkboxes + Radios ~~~~~~~~~~~~~ */
input[type='checkbox'],
label:has(input[type='checkbox']),

View File

@@ -1,43 +0,0 @@
import type { Translation } from '../utilities/localize.js';
import { registerTranslation } from '../utilities/localize.js';
const translation: Translation = {
$code: 'hi',
$name: 'हिन्दी',
$dir: 'ltr',
carousel: 'कैरोसेल',
clearEntry: 'प्रविष्टि साफ़ करें',
close: 'बंद करें',
copied: 'कॉपी किया गया',
copy: 'कॉपी करें',
currentValue: 'वर्तमान मान',
error: 'त्रुटि',
goToSlide: (slide, count) => `${count} में से स्लाइड ${slide} पर जाएं`,
hidePassword: 'पासवर्ड छुपाएं',
loading: 'लोड हो रहा है',
nextSlide: 'अगली स्लाइड',
numOptionsSelected: num => {
if (num === 0) return 'कोई विकल्प चयनित नहीं';
if (num === 1) return '1 विकल्प चयनित';
return `${num} विकल्प चयनित`;
},
pauseAnimation: 'एनिमेशन रोकें',
playAnimation: 'एनिमेशन चलाएं',
previousSlide: 'पिछली स्लाइड',
progress: 'प्रगति',
remove: 'हटाएं',
resize: 'आकार बदलें',
scrollableRegion: 'स्क्रॉल करने योग्य क्षेत्र',
scrollToEnd: 'अंत तक स्क्रॉल करें',
scrollToStart: 'आरंभ तक स्क्रॉल करें',
selectAColorFromTheScreen: 'स्क्रीन से एक रंग चुनें',
showPassword: 'पासवर्ड दिखाएं',
slideNum: slide => `स्लाइड ${slide}`,
toggleColorFormat: 'रंग प्रारूप बदलें',
zoomIn: 'ज़ूम इन',
zoomOut: 'ज़ूम आउट',
};
registerTranslation(translation);
export default translation;