Compare commits

...

72 Commits

Author SHA1 Message Date
Cory LaViska
1b1cdfb21a improve icon button detection; fixes #1475 2025-10-14 14:37:02 -04:00
Brian Talbot
3c0924fac2 Docs: Optimizing Logo SVGs (#1561)
* optmizing svg in logo.njk
* optimizing svg in logo-simple.njk
2025-10-14 11:48:50 -04:00
Lindsay M
d490d04ebc Optimize theme builder font data (#1545) 2025-10-14 10:07:48 -04:00
Cory LaViska
52b5f557e0 prettier (#1572) 2025-10-13 12:07:44 -04:00
Cory LaViska
dd1c689e33 fix type (#1571) 2025-10-13 10:58:53 -04:00
Cory LaViska
f398899991 update changelog (#1570) 2025-10-13 10:47:43 -04:00
LX
8fc0ee89ff Fix missing form-control-label part on texarea (#1533) 2025-10-13 10:45:39 -04:00
trent
ed17964f10 remove unsupported tag ‘plain’ appearance visual test (#1519) 2025-10-13 10:43:55 -04:00
Jean-Baptiste Muscat
64ce424c42 Document code completion setup for Web Awesome (#1550)
* Document code completion setup for Web Awesome

Added instructions for enabling code completion in VS Code and JetBrains IDEs for Web Awesome components.

This mirror what already exist for Shoelace: https://shoelace.style/getting-started/usage#code-completion
+ a new line to explain how to setup VS Code completion from the CDN

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

* Update packages/webawesome/docs/docs/usage.md

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-10-13 10:43:16 -04:00
Jason Polete
51253650e1 Fix wa-details accordion behavior in react (#1538)
* fix wa-details accordion in react (#1534)

* Update packages/webawesome/src/components/details/details.test.ts

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>

* Remove unused import

* Fix unintended indent

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-10-13 10:40:35 -04:00
Leon Vogt
0b45173192 Enhance icon button label check (#1543) 2025-10-13 10:39:29 -04:00
Konnor Rogers
0eb8eaea00 add versions.txt (#1546) 2025-10-03 23:42:31 -04:00
Brian Talbot
334e3361b4 Docs: Add Planned Features to Navigation (#1539)
* adding plannedBadge() macro + planned-badge.njk

* adding planned features to sidebar.njk

* adding .icon-shrink utility to utils.css

* using icon-shrink on sidebar's experimental iconography

* revising proBadge macro

* defining params in a more clear manner
* adding shrink param to visually reduce badge size

* setting proBadge to shrink in sidebar.njk

* addressing PR feedback

* reverting proBadge shrink param

* revisiting pro + sidebar wa-badge styling

* removing text-transform from pro badge
* scaling down sidebar-based wa-badges using 1 step below
--wa-font-size-scale
2025-10-03 17:34:52 -04:00
Brian Talbot
5e482739a9 updating Home view to support purchasing Pro (#1528) 2025-10-03 12:56:05 -04:00
Lindsay M
c0b18f6580 Round --content-width-* and use in the docs (#1526)
* use `--content-width-*` properties for docs

* round `--content-width-*` values to prevent rendering bugs
2025-10-02 16:13:05 -04:00
Brian Talbot
c18df17429 Docs: Add Links to Licenses + Supporting Utilities (#1537)
* adding .appearance-plain for lists to utils.css

* adding gitLastModifiedISO filter to .eleventy.js

* adding link to Pro License in sidebar.njk

* adding link to Free License in sidebar.njk

* adding link to Terms of Service in sidebar.njk

* adding "last updated" date to changelog.md
2025-10-02 15:46:32 -04:00
Brian Talbot
2ec957ff76 Docs: Update + Show Social Media Links (#1531)
* adding mastodon social link to docs/index.md
* adding social links to sidebar's colophon
* updating community.md with latest social network details
2025-10-01 12:04:32 -04:00
Lindsay M
1fd68dfb3c Fix focus ring in <wa-scroller>, <wa-dialog>, and <wa-drawer> (#1525)
* visible focus outlines for scrollable containers

* add changelog
2025-09-30 18:09:58 -04:00
randomguy-2650
0b5689de62 remove last smart quote (forgotten in previous PR) (#1523) 2025-09-30 12:26:38 -04:00
Konnor Rogers
8ffd9991db Fix 11ty / server handoff for Brian (#1518)
* update for brian's stuff
* change to top level
2025-09-30 11:29:52 -04:00
Cory LaViska
566f98359c fix name (#1522) 2025-09-30 10:03:40 -04:00
randomguy-2650
6387dffe75 Make the README better (#1494)
* Make the README better

• Replace straight quotes with smart quotes
• Revise Node.js minimum requirement wording (to prevent line breaks)
• Replace old links to LitElement (Polymer) to Lit
• Replace mentions of “NPM” with “npm”, as per https://github.com/npm/cli?tab=readme-ov-file#is-it-npm-or-npm-or-npm
• Fix some grammar and abbreviations
• Made “dependencies” and “devDependencies” mentions unquoted to be consistent
• Correct “MIT license” with “MIT License”, as per https://opensource.org/license/mit

* Make some specific changes to make wording more clear

* add missing dot

* remove smart quotes
2025-09-29 12:32:58 -04:00
randomguy-2650
bb747d50dd Add missing CSS part into JSDoc (Dialog, Drawer) (#1515)
* add missing CSS part into JSDoc

* add missing CSS part into JSDoc
2025-09-29 12:12:08 -04:00
Brian Talbot
2704ef7197 Docs: Polish Pro Badge (#1504)
* updating Pro Badge's appearance
* abstracting Pro Badge into include
* adding nanoid-based uniqueId filter to eleventyConfig
* ensuring Pro Badge instances have unique ids
* using added uniqueId filter + nanoid
* converting Pro Badge to be macro-based
* customizing Pro Badge's associated wa-tooltip size
2025-09-29 11:59:49 -04:00
Brian Talbot
336a3acdd0 Docs: Add Shared Monorepo Utils + DRY Out Styling (#1497)
* adding utils.css
* importing utils.css in docs.css
* removing shared styles now in utils.css
* using hover-icon util in toggle navigation
* updating hover-icon a11y in header
* revising wa-icon embiggening utility
2025-09-26 14:35:19 -04:00
Cory LaViska
e68640b8ca update changelog (#1500) 2025-09-25 16:30:24 -04:00
Adilet
487b629995 Add Kazakh translation (#1496)
* Add Kazakh translation

* Fix kk.ts translation entry
2025-09-25 14:56:45 -04:00
Brian Talbot
255647d2a9 fixing theme.js logic (#1492)
* to adhere to original work in talbs/update-theme-logic
* to also account for work in talbs/update-header
2025-09-25 10:55:40 -04:00
Brian Talbot
53f1b3615d Docs: Update Theme Logic (#1491)
* updating theme.js to handle static site theme
* removing redundant theme logic from base.njk
2025-09-24 17:10:19 -04:00
Brian Talbot
d00d8bac4e Docs: Update Header (#1490)
* updating color-scheme-selectors and theme-selectors
* abstracting repo links into github-icon-buttons
* adjusting responsive logo treatment
* moving version + beta info to sidebar
* removing unused + outdated header styling
* adding brand logo to sidebar
* updating `.brand-logo` styling
* abstracting search-trigger-button
2025-09-24 16:39:01 -04:00
Konnor Rogers
87864924e1 fix auto width typing (#1482) 2025-09-24 13:48:04 -04:00
randomguy-2650
ce3496a621 Improve contributing page (#1443)
* add `@customElement()` decorator

• Hope this doesn’t ping some random user

* replace “->” with “→”
2025-09-24 13:47:45 -04:00
Brian Talbot
cf80b57a79 Update Layouts to Prep for Site Assets (#1470)
* syncing up `<body>` classes on blank.njk
* using `wa_page_attributes` block instead of `pageType`
* using `head` block instead of `pageType`
* removing `pageType` from `<body>` classes
* removing `pageType` from eleventyConfig
* updating color-scheme-selector's icons
* allowing `wa-page` attributes to override those set in base.njk
* allowing pageClass to be used on base.njk's `<body>`
2025-09-22 19:06:54 -04:00
Lindsay M
694a9eccb9 Make sure essential CSS is always imported (#1476)
* import relevant utilities into native styles

* import color variant classes into free palettes

* import the default palette into kitchen sink, not the default theme

* fix palette path

* import each theme's intended palette
2025-09-22 14:12:49 -04:00
Alicia Garcia-Raboso
502df6ee9c Remove duplicated declaration (#1473) 2025-09-19 09:43:57 -04:00
Lindsay M
44142fb56d Fix badge positioning for link buttons (#1463)
* Fix badge positioning for link buttons

* add changelog
2025-09-18 11:53:52 -04:00
Lindsay M
7e00d2b02e Fix incorrect class in color palette instructions (#1462) 2025-09-18 11:16:36 -04:00
Lindsay M
fcf37f83a1 Fix details focus ring (#1464)
* remove duplicate styles, fix focus outline

* update native details focus ring and rounding
2025-09-18 11:15:54 -04:00
Kelsey Jackson
0beceff73f update to the button if it has an icon in it's default slot (#1461) 2025-09-18 08:42:38 -05:00
Brian Talbot
afe60eae69 Docs: Icon Component - Update Default Width (#1466)
* updating default width value in icon component docs
* noting default icon width change in 3.0.0-beta.5's changelog
2025-09-18 09:33:09 -04:00
Bryce A. Glass
b4f45f4ff1 Update align-items.md (#1467)
Fixed some internal links from `/docs/layout/` to `docs/utilities/`
2025-09-18 08:50:37 -04:00
Brian Talbot
fd4cded708 Add Input-Based Visually Hidden Utilities (#1454)
* adding input-based visually hidden utilities
* documenting input-based visually hidden utilities
2025-09-16 09:17:07 -04:00
konnorrogers
4b2b72e822 update package-lock version 2025-09-15 19:13:18 -04:00
konnorrogers
56657ebcfc Bump package.json version 2025-09-15 19:11:14 -04:00
Konnor Rogers
844015df7b pin tinycolor (#1455) 2025-09-15 19:08:05 -04:00
Brian Talbot
d5da2e2db5 simplifying pageHeader/pageFooter overrides in base.njk (#1453) 2025-09-15 16:42:09 -04:00
randomguy-2650
efbc404524 add variant="danger" to Delete dropdown item (#1445) 2025-09-15 09:34:09 -04:00
randomguy-2650
b6afa148ae fix typo (#1442) 2025-09-15 09:29:53 -04:00
randomguy-2650
7c3795897c Fix typo in Textarea docs (#1444)
* fix typo

* Update packages/webawesome/docs/docs/components/textarea.md

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-09-13 09:59:48 -04:00
Cory LaViska
986e52f977 make event cancelable (#1434) 2025-09-11 11:55:35 -04:00
konnorrogers
6dce88429a Bump changelog
Bump package.json version

update lockfile
2025-09-10 12:45:43 -04:00
Kelsey Jackson
04497cfd13 Add horizontal orientation to <wa-card> (#874)
* started horizontal card logic

* a little more work

* remove SSR attributes

These are no longer used since we're not serving up an SSR version of the website anymore.

* more work

* looking for old code

* added actions slot to horizontal card

* troubleshooting linter issue

* fixed liniting error

* responded to feedback

* added jsDoc and updated example

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-09-10 10:27:15 -05:00
randomguy-2650
75116a5b0c Replace invisible BOM marker in Dialog/Drawer with a zero‐width space (#1410)
* replace BOM marker with a zero‐width space

* replace BOM marker with a zero‐width space
2025-09-10 11:06:15 -04:00
Cory LaViska
5e192023b4 reword (#1427) 2025-09-10 11:05:53 -04:00
Brian Talbot
26b29189db fixing GitHub discussion links to point to webawesome project (#1425) 2025-09-10 10:53:38 -04:00
trent
ac20e495d9 allow bundlers access to package.json (#1415) 2025-09-10 10:53:17 -04:00
Cory LaViska
4ac31e06f3 remove whitespace; closes #1417 (#1418) 2025-09-10 10:38:06 -04:00
Konnor Rogers
4993b1034f add notes about skips (#1419)
* add notes about skips

* prettier

* re-add support for 'unpublished: true'

* prettier
2025-09-10 10:32:48 -04:00
Cory LaViska
b3b93091f7 Add intersection observer component (#1406)
* add intersection observer component

* remove prefix

* update description
2025-09-08 17:22:45 -04:00
Brian Talbot
8cf20d9938 Docs: Fix Color Swatch Hover States (#1407)
* removing unused `--background-color-hover` from `docs.css`
* fixing `.swatch` hover-based `background-color`
* linting + formatting `docs/tokens/color.md`
2025-09-05 16:30:15 -04:00
randomguy-2650
63296b7ed5 update FA version from 7.0.0 to 7.0.1 (#1399) 2025-09-03 15:01:35 -04:00
Brian Talbot
0e56ed0cbb Prep for Pro + Product Marketing (#1390)
* adding conditional header + footer includes to `base.njk`

- support for custom headers via `header` front matter variable
- support for custom footers via `footer` front matter variable
- backward compatibility with default header

* revising `base.njk`'s body classes

* adding fileSlug-based class to body
* adding pageType-based class (default `docs`) to body

* adding conditional CSS asset logic to `base.njk`

* to load marketing-based CSS based on pageType
* to load docs-based CSS by default

* disabling wa-page's sticky header for marketing pageType
2025-09-03 12:37:28 -04:00
Cory LaViska
e70cb5c66d add changelog entry (#1398) 2025-09-03 08:13:55 -04:00
Michael Romer
913abd0db1 Reflect icon properties to its attributes (#1395) 2025-09-03 08:12:11 -04:00
Cory LaViska
d2798a96da flip color picker to keep it in the viewport (#1391) 2025-09-02 18:02:48 -04:00
Konnor Rogers
42729153db update vercel sh clone (#1392) 2025-09-02 17:52:25 -04:00
Cory LaViska
c2df5ca1ea fix typo (#1381) 2025-08-29 11:34:48 -04:00
Cory LaViska
c49813c7c1 Update themer to use bunny fonts instead of google fonts (#1378)
* use fonts.bunny.net for web fonts

* use bunny
2025-08-27 19:24:44 +00:00
Cory LaViska
f63dfbfff0 fix var name (#1372) 2025-08-25 16:17:58 -04:00
Cory LaViska
9a7947debd fix radio group styles; closes #1178 (#1360) 2025-08-25 14:30:59 -04:00
Cory LaViska
d2e1653519 fix value assignment; closes #1323 (#1368) 2025-08-25 12:35:34 -04:00
Cory LaViska
5b7004e72d Fix edge case where interactive elements inside <wa-details> would cause it to open/close (#1350)
* fixes #1252

* fixes #1250

* update changelog
2025-08-25 11:08:36 -04:00
90 changed files with 1742 additions and 517 deletions

View File

@@ -21,7 +21,7 @@ Twitter: [@webawesomer](https://twitter.com/webawesomer)
## Developers ✨
Developers can use this documentation to learn how to build Web Awesome from source. You will need Node >= 14.17 to build and run the project locally.
Developers can use this documentation to learn how to build Web Awesome from source. You will need Node.js 14.17 or later to build and run the project locally.
**You don't need to do any of this to use Web Awesome!** This page is for people who want to contribute to the project, tinker with the source, or create a custom build of Web Awesome.
@@ -29,31 +29,29 @@ If that's not what you're trying to do, the [documentation website](https://weba
### What are you using to build Web Awesome?
Components are built with [LitElement](https://lit-element.polymer-project.org/), a custom elements base class that provides an intuitive API and reactive data binding. The build is a custom script with bundling powered by [esbuild](https://esbuild.github.io/).
Components are built with [Lit](https://lit.dev/), a custom elements base class that provides an intuitive API and reactive data binding. The build is a custom script with bundling powered by [esbuild](https://esbuild.github.io/).
### Understanding the Web Awesome monorepo
Web Awesome uses [NPM workspaces](https://docs.npmjs.com/cli/v11/using-npm/workspaces) for its monorepo structure and is fairly minimal in what it provides.
Web Awesome uses [npm workspaces](https://docs.npmjs.com/cli/v11/using-npm/workspaces) for its monorepo structure and is fairly minimal in what it provides.
By using a NPM workspaces and a monorepo structure, we can get consistent builds, shared configurations, and reduced duplication across repositories which reduces regressions and forces consistency across `webawesome`, `webawesome-pro`, and `webawesome-app`.
By using npm workspaces and a monorepo structure, we can get consistent builds, shared configurations, and reduced duplication across repositories which reduces regressions and forces consistency across `webawesome`, `webawesome-pro`, and `webawesome-app`.
Generally, if you plan to only work with the free version of `webawesome` it is easiest to go to `packages/webawesome` and run all commands from there.
### Where do NPM dependencies go?
### Where do npm dependencies go?
Any dependencies intended to be used across all packages (IE: `prettier`, `eslint`) that are _NOT_ used at runtime should be in the root `devDependencies` of `package.json`.
Any dependencies intended to be used across all packages (i.e., `prettier`, `eslint`) that are **not** used at runtime should be in the root `devDependencies` of `package.json`.
```bash
npm install -D -w prettier
```
Any dependencies that will be used at runtime by a package should be part of the specific package's `"dependencies"` such as `lit`. This is required because if that dependency is not in the `packages/*/package.json`, it will not be installed when used via NPM.
Any dependencies that will be used at runtime by a package should be part of the specific package's `dependencies` such as `lit`. This is required because if that dependency is not in the `packages/*/package.json`, it will not be installed when used via npm.
Individual packages are also free to install devDependencies as needed as long as they are specific to that package only.
Individual packages are also free to install `devDependencies` as needed as long as they are specific to that package only.
To do install a package specific to a package, change your working directory to that package's root
IE: `cd packages/webawesome && npm install <package-name>`
To install a package specific to a Web Awesome package, change your working directory to that package's root (i.e., `cd packages/webawesome && npm install <package-name>`).
### Forking the Repo
@@ -67,14 +65,14 @@ npm install
### Developing
Once you've cloned the repo, run the following command from the respective directory within `packages/*`
Once you've cloned the repo, run the following command from the respective directory within `packages/*`.
```bash
cd packages/webawesome
npm start
```
This will spin up the dev server. After the initial build, a browser will open automatically. There is currently no hot module reloading (HMR), as browser's don't provide a way to reregister custom elements, but most changes to the source will reload the browser automatically.
This will spin up the dev server. After the initial build, a browser will open automatically. There is currently no hot module reloading (HMR), as browsers don't provide a way to reregister custom elements, but most changes to the source will reload the browser automatically.
### Building
@@ -102,7 +100,7 @@ This will generate a source file, a stylesheet, and a docs page for you. When yo
Right now the only additional packages are in private repositories.
To add additional packages from other repositories, run: `git clone <url> packages/<package-name>` to clone your repo into `packages/`.
To add additional packages from other repositories, run `git clone <url> packages/<package-name>` to clone your repo into `packages/`.
Make sure to run `npm install` at the root of the monorepo after adding your package!
@@ -112,4 +110,4 @@ Web Awesome is an open source project and contributions are encouraged! If you'r
## License
Web Awesome is available under the terms of the MIT license.
Web Awesome is available under the terms of the [MIT License](LICENSE.md).

6
VERSIONS.txt Normal file
View File

@@ -0,0 +1,6 @@
3.0.0-beta.1
3.0.0-beta.2
3.0.0-beta.3
3.0.0-beta.4
3.0.0-beta.5
3.0.0-beta.6

View File

@@ -92,6 +92,7 @@
"heroicons",
"hexa",
"Hotwire",
"hrefs",
"Iconoir",
"Iframes",
"iife",

36
package-lock.json generated
View File

@@ -6478,6 +6478,16 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"dev": true
},
"node_modules/eleventy-plugin-git-commit-date": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/eleventy-plugin-git-commit-date/-/eleventy-plugin-git-commit-date-0.1.3.tgz",
"integrity": "sha512-dmdkGpMuRj8apWptC1QGqAsLHCguddFlfPjbjflGCqXdJ8cdhEjrzzvI/rL0XUvzCC4ETgGl9i/wDU6ujZ94gA==",
"dev": true,
"license": "MIT",
"dependencies": {
"cross-spawn": "^7.0.3"
}
},
"node_modules/emoji-regex": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
@@ -13008,12 +13018,6 @@
"node": ">=0.8.0"
}
},
"node_modules/style-observer": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/style-observer/-/style-observer-0.0.7.tgz",
"integrity": "sha512-t75H3CRy+vd5q3yqyrf/De4tkz33hPQTiCcfh0NTesI5G7kJnZ227LEYTwqjKTtaFOCJvqZcYFHpJlF8bsk3bQ==",
"license": "MIT"
},
"node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -13977,10 +13981,10 @@
},
"packages/webawesome": {
"name": "@awesome.me/webawesome",
"version": "3.0.0-beta.4",
"version": "3.0.0-beta.6",
"license": "MIT",
"dependencies": {
"@ctrl/tinycolor": "^4.1.0",
"@ctrl/tinycolor": "4.1.0",
"@floating-ui/dom": "^1.6.13",
"@lit/react": "^1.0.8",
"@shoelace-style/animations": "^1.2.0",
@@ -13988,11 +13992,11 @@
"composed-offset-position": "^0.0.6",
"lit": "^3.2.1",
"nanoid": "^5.1.5",
"qr-creator": "^1.0.0",
"style-observer": "^0.0.7"
"qr-creator": "^1.0.0"
},
"devDependencies": {
"@wc-toolkit/jsx-types": "^1.3.0"
"@wc-toolkit/jsx-types": "^1.3.0",
"eleventy-plugin-git-commit-date": "^0.1.3"
},
"engines": {
"node": ">=14.17.0"
@@ -14000,9 +14004,9 @@
},
"packages/webawesome-pro": {
"name": "@shoelace-style/webawesome-pro",
"version": "3.0.0-beta.4",
"version": "3.0.0-beta.6",
"dependencies": {
"@ctrl/tinycolor": "^4.1.0",
"@ctrl/tinycolor": "4.1.0",
"@floating-ui/dom": "^1.6.13",
"@lit/react": "^1.0.8",
"@shoelace-style/animations": "^1.2.0",
@@ -14010,11 +14014,11 @@
"composed-offset-position": "^0.0.6",
"lit": "^3.2.1",
"nanoid": "^5.1.5",
"qr-creator": "^1.0.0",
"style-observer": "^0.0.7"
"qr-creator": "^1.0.0"
},
"devDependencies": {
"@wc-toolkit/jsx-types": "^1.3.0"
"@wc-toolkit/jsx-types": "^1.3.0",
"eleventy-plugin-git-commit-date": "^0.1.3"
},
"engines": {
"node": ">=14.17.0"

View File

@@ -1,4 +1,6 @@
import { nanoid } from 'nanoid';
import { parse as HTMLParse } from 'node-html-parser';
import { execFileSync } from 'node:child_process';
import * as fs from 'node:fs';
import * as path from 'node:path';
import { anchorHeadingsTransformer } from './_transformers/anchor-headings.js';
@@ -19,6 +21,7 @@ import { replaceTextPlugin } from './_plugins/replace-text.js';
import { searchPlugin } from './_plugins/search.js';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
const isDev = process.argv.includes('--develop');
const ignoreGit = process.env.ELEVENTY_IGNORE_GIT === 'true';
const passThroughExtensions = ['js', 'css', 'png', 'svg', 'jpg', 'mp4'];
async function getPackageData() {
@@ -57,6 +60,15 @@ export default async function (eleventyConfig) {
if (updateComponentData) {
allComponents = getComponents();
}
// Invalidate last-modified cache for changed content files during watch
if (Array.isArray(changedFiles)) {
for (const file of changedFiles) {
if (/\.(md|njk|html)$/i.test(file)) {
lastModCache.delete(file);
}
}
}
});
/**
@@ -87,12 +99,97 @@ export default async function (eleventyConfig) {
eleventyConfig.addFilter('markdown', content => markdown.render(content || ''));
eleventyConfig.addFilter('stripExtension', string => path.parse(string + '').name);
eleventyConfig.addFilter('stripPrefix', content => content.replace(/^wa-/, ''));
eleventyConfig.addFilter('uniqueId', (_value, length = 8) => nanoid(length));
// Returns last modified date as ISO 8601 (UTC, Z-suffixed)
// Fallback order: front matter override -> Git last commit date -> filesystem mtime -> now
// Caching: in-memory per inputPath during one build/dev session
// Override: pass a Date or string: {{ page.inputPath | gitLastModifiedISO(lastUpdated) }}
const lastModCache = new Map();
let repoRoot = null; // lazily resolved; null => not resolved, undefined => failed
function getLastModifiedISO(inputPath, overrideDate) {
if (overrideDate instanceof Date) {
return overrideDate.toISOString();
}
if (typeof overrideDate === 'string' && overrideDate) {
const parsed = new Date(overrideDate);
if (!isNaN(parsed.getTime())) return parsed.toISOString();
}
if (!inputPath) return new Date().toISOString();
if (lastModCache.has(inputPath)) return lastModCache.get(inputPath);
// Try Git (ISO via %cI). Use a repo-root-relative path for portability.
if (!ignoreGit) {
try {
if (repoRoot === null) {
try {
repoRoot = execFileSync('git', ['rev-parse', '--show-toplevel'], {
stdio: ['ignore', 'pipe', 'ignore'],
cwd: __dirname,
})
.toString()
.trim();
} catch (_) {
repoRoot = undefined;
}
}
const gitPath = repoRoot ? path.relative(repoRoot, inputPath) : inputPath;
const args = ['log', '-1', '--format=%cI', '--follow', '--', gitPath];
const result = execFileSync('git', args, {
stdio: ['ignore', 'pipe', 'ignore'],
cwd: repoRoot || path.dirname(inputPath),
})
.toString()
.trim();
if (result) {
const iso = new Date(result).toISOString();
lastModCache.set(inputPath, iso);
return iso;
}
} catch (_) {
// continue to fs fallback
}
}
// Fallback to filesystem mtime
try {
const stats = fs.statSync(inputPath);
const iso = new Date(stats.mtime).toISOString();
lastModCache.set(inputPath, iso);
return iso;
} catch (_) {
const now = new Date().toISOString();
lastModCache.set(inputPath, now);
return now;
}
}
eleventyConfig.addFilter('gitLastModifiedISO', function (inputPath, overrideDate) {
return getLastModifiedISO(inputPath, overrideDate);
});
// Attach lastUpdatedISO to page data so templates can use {{ lastUpdatedISO }} directly
eleventyConfig.addGlobalData('eleventyComputed', {
lastUpdatedISO: data => getLastModifiedISO(data.page?.inputPath, data.lastUpdated),
});
// Trims whitespace and pipes from the start and end of a string. Useful for CEM types, which can be pipe-delimited.
// With Prettier 3, this means a leading pipe will exist be present when the line wraps.
eleventyConfig.addFilter('trimPipes', content => {
return typeof content === 'string' ? content.replace(/^(\s|\|)/g, '').replace(/(\s|\|)$/g, '') : content;
});
/**
* @example
{% set foo = {foo: "bar"} %}
{% set bar = {bar: "baz"} %}
{% set merged = foo | merge(bar) %}
{{ merged | dump }}
*/
eleventyConfig.addFilter('merge', function (obj1, obj2) {
return Object.assign({}, obj1, obj2);
});
// Custom filter to sort with a priority item first, e.g.
// {{ collection | sortWithFirst('fileSlug', 'default') }} => the item with the fileSlug of 'default' will be first
eleventyConfig.addFilter('sortWithFirst', function (collection, property, firstValue) {
@@ -159,6 +256,15 @@ export default async function (eleventyConfig) {
// Use our own markdown instance
eleventyConfig.setLibrary('md', markdown);
// for files with `unpublished: true`, it will make sure they do not make it into the final build at all, but will be usable in development.
eleventyConfig.addPreprocessor('unpublished', '*', (data, content) => {
if (data.unpublished && process.env.ELEVENTY_RUN_MODE === 'build') {
return false;
}
return content;
});
// Add anchors to headings
eleventyConfig.addTransform('doc-transforms', function (content) {
let doc = HTMLParse(content, { blockTextElements: { code: true } });

View File

@@ -74,12 +74,12 @@ export const themes = [
body: {
name: 'Quicksand',
css: 'Quicksand, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Crimson+Pro:ital,wght@0,200..900;1,200..900&family=Quicksand:wght@300..700&display=swap',
href: 'https://fonts.bunny.net/css2?family=Quicksand:wght@300..700&display=swap',
},
heading: {
name: 'Quicksand',
css: 'Quicksand, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Crimson+Pro:ital,wght@0,200..900;1,200..900&family=Quicksand:wght@300..700&display=swap',
href: 'https://fonts.bunny.net/css2?family=Quicksand:wght@300..700&display=swap',
},
code: {
name: 'OS Default',
@@ -89,7 +89,7 @@ export const themes = [
longform: {
name: 'Crimson Pro',
css: '"Crimson Pro", serif',
href: 'https://fonts.googleapis.com/css2?family=Crimson+Pro:ital,wght@0,200..900;1,200..900&family=Quicksand:wght@300..700&display=swap',
href: 'https://fonts.bunny.net/css2?family=Crimson+Pro:ital,wght@0,200..900;1,200..900&display=swap',
},
},
icons: {
@@ -194,22 +194,22 @@ export const themes = [
body: {
name: 'Inter',
css: 'Inter, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Aleo:ital,wght@0,100..900;1,100..900&family=Geist+Mono:wght@100..900&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Inter:ital,wght@0,100..900;1,100..900&display=swap',
},
heading: {
name: 'Inter',
css: 'Inter, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Aleo:ital,wght@0,100..900;1,100..900&family=Geist+Mono:wght@100..900&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Inter:ital,wght@0,100..900;1,100..900&display=swap',
},
code: {
name: 'Geist Mono',
css: '"Geist Mono", monospace',
href: 'https://fonts.googleapis.com/css2?family=Aleo:ital,wght@0,100..900;1,100..900&family=Geist+Mono:wght@100..900&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Geist+Mono:wght@100..900&display=swap',
},
longform: {
name: 'Aleo',
css: 'Aleo, serif',
href: 'https://fonts.googleapis.com/css2?family=Aleo:ital,wght@0,100..900;1,100..900&family=Geist+Mono:wght@100..900&family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Aleo:ital,wght@0,100..900;1,100..900&display=swap',
},
},
icons: {
@@ -254,22 +254,22 @@ export const themes = [
body: {
name: 'Space Grotesk',
css: '"Space Grotesk", sans-serif',
href: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=Podkova:wght@400..800&family=Space+Grotesk:wght@300..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap',
href: 'https://fonts.bunny.net/css2?family=Space+Grotesk:wght@300..700&display=swap',
},
heading: {
name: 'IBM Plex Sans Condensed',
css: '"IBM Plex Sans Condensed", sans-serif',
href: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=Podkova:wght@400..800&family=Space+Grotesk:wght@300..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap',
href: 'https://fonts.bunny.net/css2?family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap',
},
code: {
name: 'Space Mono',
css: '"Space Mono", monospace',
href: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=Podkova:wght@400..800&family=Space+Grotesk:wght@300..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap',
href: 'https://fonts.bunny.net/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap',
},
longform: {
name: 'Podkova',
css: 'Podkova, serif',
href: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Condensed:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=Podkova:wght@400..800&family=Space+Grotesk:wght@300..700&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap',
href: 'https://fonts.bunny.net/css2?family=Podkova:wght@400..800&display=swap',
},
},
icons: {
@@ -314,22 +314,22 @@ export const themes = [
body: {
name: 'Figtree',
css: 'Figtree, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Chivo+Mono:ital,wght@0,100..900;1,100..900&family=Figtree:ital,wght@0,300..900;1,300..900&family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap',
},
heading: {
name: 'Figtree',
css: 'Figtree, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Chivo+Mono:ital,wght@0,100..900;1,100..900&family=Figtree:ital,wght@0,300..900;1,300..900&family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap',
},
code: {
name: 'Chivo Mono',
css: '"Chivo Mono", monospace',
href: 'https://fonts.googleapis.com/css2?family=Chivo+Mono:ital,wght@0,100..900;1,100..900&family=Figtree:ital,wght@0,300..900;1,300..900&family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Chivo+Mono:ital,wght@0,100..900;1,100..900&display=swap',
},
longform: {
name: 'Fraunces',
css: 'Fraunces, serif',
href: 'https://fonts.googleapis.com/css2?family=Chivo+Mono:ital,wght@0,100..900;1,100..900&family=Figtree:ital,wght@0,300..900;1,300..900&family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Fraunces:ital,wght@0,100..900;1,100..900&display=swap',
},
},
icons: {
@@ -374,22 +374,22 @@ export const themes = [
body: {
name: 'Wix Madefor Text',
css: '"Wix Madefor Text", sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto+Serif:ital,opsz,wght@0,8..144,100..900;1,8..144,100..900&family=Roboto:ital,wght@0,100..900;1,100..900&family=Wix+Madefor+Text:ital,wght@0,400..800;1,400..800&display=swap',
href: 'https://fonts.bunny.net/css2?family=Wix+Madefor+Text:ital,wght@0,400..800;1,400..800&display=swap',
},
heading: {
name: 'Wix Madefor Text',
css: '"Wix Madefor Text", sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto+Serif:ital,opsz,wght@0,8..144,100..900;1,8..144,100..900&family=Roboto:ital,wght@0,100..900;1,100..900&family=Wix+Madefor+Text:ital,wght@0,400..800;1,400..800&display=swap',
href: 'https://fonts.bunny.net/css2?family=Wix+Madefor+Text:ital,wght@0,400..800;1,400..800&display=swap',
},
code: {
name: 'Roboto Mono',
css: '"Roboto Mono", monospace',
href: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto+Serif:ital,opsz,wght@0,8..144,100..900;1,8..144,100..900&family=Roboto:ital,wght@0,100..900;1,100..900&family=Wix+Madefor+Text:ital,wght@0,400..800;1,400..800&display=swap',
href: 'https://fonts.bunny.net/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap',
},
longform: {
name: 'Roboto Serif',
css: '"Roboto Serif", serif',
href: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&family=Roboto+Serif:ital,opsz,wght@0,8..144,100..900;1,8..144,100..900&family=Roboto:ital,wght@0,100..900;1,100..900&family=Wix+Madefor+Text:ital,wght@0,400..800;1,400..800&display=swap',
href: 'https://fonts.bunny.net/css2?family=Roboto+Serif:ital,wght@0,100..900;1,100..900&display=swap',
},
},
icons: {
@@ -434,12 +434,12 @@ export const themes = [
body: {
name: 'Mulish',
css: 'Mulish, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400..700;1,400..700&family=Mulish:ital,wght@0,200..1000;1,200..1000&display=swap',
href: 'https://fonts.bunny.net/css2?family=Mulish:ital,wght@0,200..1000;1,200..1000&display=swap',
},
heading: {
name: 'Lora',
css: 'Lora, serif',
href: 'https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400..700;1,400..700&family=Mulish:ital,wght@0,200..1000;1,200..1000&display=swap',
href: 'https://fonts.bunny.net/css2?family=Lora:ital,wght@0,400..700;1,400..700&display=swap',
},
code: {
name: 'OS Default',
@@ -449,7 +449,7 @@ export const themes = [
longform: {
name: 'Lora',
css: 'Lora, serif',
href: 'https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400..700;1,400..700&family=Mulish:ital,wght@0,200..1000;1,200..1000&display=swap',
href: 'https://fonts.bunny.net/css2?family=Lora:ital,wght@0,400..700;1,400..700&display=swap',
},
},
icons: {
@@ -494,22 +494,22 @@ export const themes = [
body: {
name: 'Nunito',
css: 'Nunito, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Azeret+Mono:ital,wght@0,100..900;1,100..900&family=BioRhyme:wght@200..800&family=Fredoka:wght@300..700&family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap',
href: 'https://fonts.bunny.net/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap',
},
heading: {
name: 'Fredoka',
css: 'Fredoka, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Azeret+Mono:ital,wght@0,100..900;1,100..900&family=BioRhyme:wght@200..800&family=Fredoka:wght@300..700&family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap',
href: 'https://fonts.bunny.net/css2?family=Fredoka:wght@300..700&display=swap',
},
code: {
name: 'Azeret Mono',
css: '"Azeret Mono", monospace',
href: 'https://fonts.googleapis.com/css2?family=Azeret+Mono:ital,wght@0,100..900;1,100..900&family=BioRhyme:wght@200..800&family=Fredoka:wght@300..700&family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap',
href: 'https://fonts.bunny.net/css2?family=Azeret+Mono:ital,wght@0,100..900;1,100..900&display=swap',
},
longform: {
name: 'BioRhyme',
css: 'BioRhyme, serif',
href: 'https://fonts.googleapis.com/css2?family=Azeret+Mono:ital,wght@0,100..900;1,100..900&family=BioRhyme:wght@200..800&family=Fredoka:wght@300..700&family=Nunito:ital,wght@0,200..1000;1,200..1000&display=swap',
href: 'https://fonts.bunny.net/css2?family=BioRhyme:wght@200..800&display=swap',
},
},
icons: {
@@ -554,12 +554,12 @@ export const themes = [
body: {
name: 'DM Sans',
css: '"DM Sans", sans-serif',
href: 'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Playfair:ital,opsz,wght@0,5..1200,300..900;1,5..1200,300..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=DM+Sans:ital,wght@0,100..1000;1,100..1000&display=swap',
},
heading: {
name: 'Playfair Display',
css: '"Playfair Display", serif',
href: 'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Playfair:ital,opsz,wght@0,5..1200,300..900;1,5..1200,300..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap',
},
code: {
name: 'OS Default',
@@ -569,7 +569,7 @@ export const themes = [
longform: {
name: 'Playfair',
css: 'Playfair, serif',
href: 'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&family=Playfair+Display:ital,wght@0,400..900;1,400..900&family=Playfair:ital,opsz,wght@0,5..1200,300..900;1,5..1200,300..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Playfair:ital,wght@0,300..900;1,300..900&display=swap',
},
},
icons: {
@@ -614,12 +614,12 @@ export const themes = [
body: {
name: 'Inter',
css: 'Inter, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Inter:ital,wght@0,100..900;1,100..900&display=swap',
},
heading: {
name: 'Inter',
css: 'Inter, sans-serif',
href: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap',
href: 'https://fonts.bunny.net/css2?family=Inter:ital,wght@0,100..900;1,100..900&display=swap',
},
code: {
name: 'OS Default',

View File

@@ -15,10 +15,9 @@
{% if hasSidebar %}<script type="module" src="/assets/scripts/sidebar.js"></script>{% endif %}
<script defer data-domain="webawesome.com" src="https://plausible.io/js/script.js"></script>
{# Docs styles #}
<link rel="stylesheet" href="/assets/styles/docs.css" />
{% block head %}{% endblock %}
{% block head %}
<link rel="stylesheet" href="/assets/styles/docs.css" />
{% endblock %}
<script type="module">
// Set the initial color scheme before the page renders to prevent flashing
@@ -26,75 +25,60 @@
const isDark = value === 'dark' || (value === 'auto' && matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.classList.toggle('wa-dark', isDark);
</script>
<script type="module">
// Set the initial theme before the page renders to prevent flashing
const savedTheme = localStorage.getItem('theme') || 'default';
// Update the theme stylesheet link first
const themeStylesheet = document.getElementById('theme-stylesheet');
if (themeStylesheet) {
themeStylesheet.href = `/dist/styles/themes/${savedTheme}.css`;
}
if (savedTheme !== 'default') {
document.documentElement.classList.add(`wa-theme-${savedTheme}`);
}
</script>
</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">
<header slot="header" class="wa-split">
{# Logo #}
<div id="docs-branding">
{# Nav toggle #}
<wa-button appearance="plain" size="small" data-toggle-nav>
<wa-icon name="bars" label="Toggle navigation"></wa-icon>
</wa-button>
<body class="layout-{{ layout | stripExtension }} page-{{ pageClass or page.fileSlug or 'home' }}{{ ' page-wide' if wide }}">
{% set defaultWaPageAttributes = defaultWaPageAttributes or { view: 'desktop', 'disable-navigation-toggle': true, 'mobile-breakpoint': 1180 } %}
{% set waPageAttributes = waPageAttributes or {} %}
{% set mergedWaPageAttributes = defaultWaPageAttributes | merge(waPageAttributes) %}
<wa-page
{% for key, value in mergedWaPageAttributes %}
{% if value != null and value != false %}
{{ key }}="{{ value }}"
{% endif %}
{% endfor %}
>
{% block pageHeader %}
<header slot="header" class="wa-split">
{# Nav toggle #}
<wa-button appearance="plain" size="small" data-toggle-nav>
<wa-icon name="bars" label="Toggle navigation" class="icon-default icon-embiggen"></wa-icon>
<wa-icon name="burger" aria-hidden="true" class="icon-hover icon-embiggen"></wa-icon>
</wa-button>
<a href="/" aria-label="Web Awesome">
<span class="wa-desktop-only">{% include "logo.njk" %}</span>
<span class="wa-mobile-only">{% include "logo-simple.njk" %}</span>
</a>
<small id="version-number" class="wa-desktop-only">{{ package.version }}</small>
<wa-badge variant="brand" appearance="filled" class="wa-desktop-only">Beta</wa-badge>
</div>
{# Logo - Desktop #}
<a class="brand-logo wa-desktop-only" href="/" aria-label="Web Awesome">
{% include "logo.njk" %}
</a>
<div id="docs-toolbar" class="wa-cluster">
{# Desktop selectors #}
<div class="wa-desktop-only wa-cluster wa-gap-xs">
{% include "theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
</div>
{#- Logo - mobile branding -#}
<a href="/" class="brand-logo wa-mobile-only" aria-label="Web Awesome">
{# Logo - Mobile #}
{% include "logo-simple.njk" %}
</a>
<wa-divider orientation="vertical" class="wa-desktop-only"></wa-divider>
<div id="github-buttons" class="wa-cluster wa-gap-xs">
<wa-button id="github-repo-button" href="https://github.com/shoelace-style/webawesome" rel="noopener noreferrer" target="_blank" appearance="filled" size="small">
<wa-icon family="brands" name="github" label="GitHub"></wa-icon>
</wa-button>
<wa-tooltip for="github-repo-button" distance="2">GitHub</wa-tooltip>
<wa-button id="github-star-button" href="https://github.com/shoelace-style/webawesome/stargazers" rel="noopener noreferrer" target="_blank" appearance="filled" size="small">
<wa-icon name="star" variant="regular" label="Star this repository"></wa-icon>
</wa-button>
<wa-tooltip for="github-star-button" distance="2">Star this repository</wa-tooltip>
</div>
<wa-divider orientation="vertical"></wa-divider>
{# Login #}
{% server "loginOrAvatar" %}
</div>
</header>
<div id="docs-toolbar" class="wa-cluster gap-s">
<div class="wa-desktop-only wa-cluster wa-gap-2xs">
{% include "theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
{% include "github-icon-buttons.njk" %}
</div>
{#- Login -#}
{% include "login-or-avatar.njk" ignore missing %}
</div>
</header>
{% endblock %}
{# Sidebar #}
{% if hasSidebar %}
{# Mobile selectors #}
<div class="wa-mobile-only" slot="navigation-header">
<div class="wa-cluster wa-gap-xs" style="flex-wrap: nowrap;">
{% include "theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
<div class="wa-cluster wa-gap-s">
<a class="brand-logo" href="/" aria-label="Web Awesome">{% include "logo-simple.njk" %}</a>
<div class="wa-cluster wa-gap-2xs" style="flex-wrap: nowrap;">
{% include "theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
{% include "github-icon-buttons.njk" %}
</div>
</div>
</div>
<div slot="navigation" id="sidebar" class="docs-aside" data-remember-scroll>
@@ -138,6 +122,9 @@
</main>
{% include 'search.njk' %}
{# Footer #}
{% block pageFooter %}{% endblock %}
</wa-page>
</body>

View File

@@ -1,25 +1,35 @@
<wa-select class="color-scheme-selector" appearance="filled" size="small" value="auto" title="Press \ to toggle">
<wa-icon class="only-light" slot="start" name="sun" variant="regular"></wa-icon>
<wa-icon class="only-dark" slot="start" name="moon" variant="regular"></wa-icon>
<wa-option value="light">
<wa-icon slot="start" name="sun" variant="regular"></wa-icon>
<wa-dropdown class="color-scheme-selector" title="Press \ to toggle">
<wa-button slot="trigger" id="color-scheme-selector-trigger" appearance="plain">
<wa-icon name="sun-bright" variant="regular" class="icon-embiggen only-light"></wa-icon>
<wa-icon name="moon-stars" variant="regular" class="icon-embiggen only-dark"></wa-icon>
</wa-button>
<wa-dropdown-item value="light">
<wa-icon slot="icon" name="sun-bright" variant="regular" class="icon-embiggen"></wa-icon>
Light
</wa-option>
<wa-option value="dark">
<wa-icon slot="start" name="moon" variant="regular"></wa-icon>
</wa-dropdown-item>
<wa-dropdown-item value="dark">
<wa-icon slot="icon" name="moon-stars" variant="regular" class="icon-embiggen"></wa-icon>
Dark
</wa-option>
</wa-dropdown-item>
<wa-divider></wa-divider>
<wa-option value="auto">
<wa-icon class="only-light" slot="start" name="sun" variant="regular"></wa-icon>
<wa-icon class="only-dark" slot="start" name="moon" variant="regular"></wa-icon>
<wa-dropdown-item value="auto">
<wa-icon slot="icon" name="sun-bright" variant="regular" class="only-light icon-embiggen"></wa-icon>
<wa-icon slot="icon" name="moon-stars" variant="regular" class="only-dark icon-embiggen"></wa-icon>
System
</wa-option>
</wa-select>
</wa-dropdown-item>
</wa-dropdown>
<wa-tooltip for="color-scheme-selector-trigger" id="color-scheme-tooltip">Select Color Scheme</wa-tooltip>
<script>
// Immediately set the correct value from storage
document.querySelectorAll('wa-select.color-scheme-selector').forEach(el => {
el.setAttribute('value', localStorage.getItem('color-scheme') || 'auto');
// Handle dropdown selection and trigger input event for color-scheme.js
document.querySelectorAll('wa-dropdown.color-scheme-selector').forEach(el => {
el.addEventListener('wa-select', (event) => {
const selectedValue = event.detail.item.value;
// Trigger input event for color-scheme.js
el.value = selectedValue;
el.dispatchEvent(new Event('input', { bubbles: true }));
});
});
</script>

View File

@@ -0,0 +1,8 @@
<wa-button id="github-repo-button" href="https://github.com/shoelace-style/webawesome" rel="noopener noreferrer" target="_blank" appearance="plain">
<wa-icon family="brands" name="github" label="View Repository on GitHub" class="icon-embiggen"></wa-icon>
</wa-button>
<wa-tooltip for="github-repo-button" distance="2">View on GitHub</wa-tooltip>
<wa-button id="github-star-button" href="https://github.com/shoelace-style/webawesome/stargazers" rel="noopener noreferrer" target="_blank" appearance="plain">
<wa-icon name="star" variant="regular" label="Star Repository on GitHub" class="icon-embiggen"></wa-icon>
</wa-button>
<wa-tooltip for="github-star-button" distance="2">Star on GitHub</wa-tooltip>

View File

@@ -21,9 +21,7 @@
<script type="module" src="/dist/webawesome.loader.js"></script>
<link id="theme-stylesheet" rel="stylesheet" href="/dist/styles/themes/default.css" render="blocking" fetchpriority="high" />
{% for palette in themer.palettes %}
<link rel="stylesheet" href="/dist/styles/color/palettes/{{palette.filename}}" />
{% endfor %}
<link rel="stylesheet" href="/dist/styles/webawesome.css" />
<script type="module">

View File

@@ -1,3 +1 @@
<svg width="20" height="15" viewBox="0 0 20 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.63 1.625C11.63 2.27911 11.2435 2.84296 10.6865 3.10064L14 6L17.2622 5.34755C17.0968 5.10642 17 4.81452 17 4.5C17 3.67157 17.6716 3 18.5 3C19.3284 3 20 3.67157 20 4.5C20 5.31157 19.3555 5.9726 18.5504 5.99917L15.0307 13.8207C14.7077 14.5384 13.9939 15 13.2068 15H6.79317C6.00615 15 5.29229 14.5384 4.96933 13.8207L1.44963 5.99917C0.64452 5.9726 0 5.31157 0 4.5C0 3.67157 0.671573 3 1.5 3C2.32843 3 3 3.67157 3 4.5C3 4.81452 2.9032 5.10642 2.73777 5.34755L6 6L9.31702 3.09761C8.76346 2.83855 8.38 2.27656 8.38 1.625C8.38 0.727537 9.10754 0 10.005 0C10.9025 0 11.63 0.727537 11.63 1.625Z" fill="var(--wa-brand-orange, #f36944)"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="15" fill="none" viewBox="0 0 20 15"><path fill="var(--wa-brand-orange, #f36944)" d="M11.63 1.625c0 .654-.387 1.218-.944 1.476L14 6l3.262-.652A1.5 1.5 0 1 1 18.55 6l-3.52 7.82A2 2 0 0 1 13.208 15H6.793a2 2 0 0 1-1.824-1.18L1.45 6a1.5 1.5 0 1 1 1.289-.652L6 6l3.317-2.902a1.625 1.625 0 1 1 2.313-1.473"/></svg>

Before

Width:  |  Height:  |  Size: 742 B

After

Width:  |  Height:  |  Size: 368 B

View File

@@ -1,13 +1 @@
<svg width="105" height="16" viewBox="0 0 105 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M78.0517 11.8597C78.464 12.2456 79.2272 12.5 79.8675 12.5C81.0605 12.5 81.9903 11.8333 81.9903 10.693C81.9903 9.84215 81.4727 9.35093 80.5078 8.94743L79.8412 8.66674C79.4815 8.51762 79.3412 8.41235 79.3412 8.19306C79.3412 7.92991 79.5605 7.82465 79.8587 7.82465C80.169 7.82465 80.3376 7.95507 80.4921 8.07458C80.5297 8.1037 80.5665 8.1322 80.6043 8.15797C80.7359 8.25446 80.8675 8.28955 80.9903 8.28955C81.3236 8.28955 81.6657 8.00008 81.6657 7.61413C81.6657 7.47378 81.6219 7.31589 81.4903 7.16677C81.3499 7.0001 80.8587 6.49134 79.8412 6.50011C78.6921 6.50011 77.8149 7.17554 77.8149 8.2106C77.8149 9.02638 78.3588 9.55268 79.2798 9.95618L79.8763 10.2193C80.2798 10.3948 80.464 10.4825 80.464 10.7544C80.464 11.0351 80.271 11.1755 79.8675 11.1755C79.3642 11.1755 79.0247 10.8964 78.8489 10.752C78.8133 10.7228 78.7844 10.699 78.7623 10.6842C78.657 10.6141 78.5342 10.579 78.4202 10.579C78.0781 10.579 77.7535 10.8421 77.7447 11.2456C77.7447 11.4737 77.8588 11.6754 78.0517 11.8597Z" fill="currentColor"/>
<path d="M97.9115 7.2808C97.9115 6.83344 97.5957 6.50012 97.1572 6.50011C96.8502 6.50011 96.6396 6.64923 96.394 7.05274L94.9642 9.35094L93.5344 7.05274C93.2888 6.64923 93.0783 6.50011 92.7713 6.50011C92.3327 6.50011 92.0169 6.83344 92.0169 7.2808V11.7369C92.0169 12.1754 92.3415 12.5 92.7713 12.5C93.2011 12.5 93.5257 12.1754 93.5257 11.7369V9.71058L94.28 10.9123C94.4906 11.2456 94.6835 11.3772 94.9642 11.3772C95.2449 11.3772 95.4379 11.2456 95.6484 10.9123L96.4028 9.71058V11.7369C96.4028 12.1754 96.7273 12.5 97.1572 12.5C97.587 12.5 97.9115 12.1754 97.9115 11.7369L97.9115 7.2808Z" fill="currentColor"/>
<path d="M100.516 11.6316C100.516 12.0702 100.84 12.3947 101.279 12.3947L104.033 12.3947C104.428 12.3947 104.726 12.1053 104.726 11.7105C104.726 11.3246 104.437 11.0351 104.033 11.0351L102.024 11.0351V10.0264L103.235 10.0264C103.603 10.0264 103.875 9.75445 103.875 9.3948C103.875 9.03516 103.603 8.76324 103.235 8.76324L102.024 8.76324V7.96501L103.928 7.96501C104.323 7.96501 104.621 7.67554 104.621 7.28081C104.621 6.89485 104.331 6.60539 103.928 6.60539L101.279 6.60538C100.84 6.60538 100.516 6.92994 100.516 7.36853V11.6316Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M86.8778 6.50011C88.6322 6.50011 90.0094 7.82465 90.0094 9.50006C90.0094 11.1842 88.6322 12.5 86.8778 12.5C85.1235 12.5 83.7639 11.1842 83.7639 9.50006C83.7639 7.81588 85.1323 6.50011 86.8778 6.50011ZM86.8866 7.88605C85.948 7.88605 85.3077 8.54393 85.3077 9.50006C85.3077 10.4649 85.9393 11.1141 86.8866 11.1141C87.8164 11.1141 88.4655 10.4474 88.4655 9.50006C88.4655 8.56148 87.8076 7.88605 86.8866 7.88605Z" fill="currentColor"/>
<path d="M72.1721 12.3947C71.7335 12.3947 71.4089 12.0702 71.4089 11.6316V7.36852C71.4089 6.92993 71.7335 6.60538 72.1721 6.60538L74.8211 6.60538C75.2246 6.60538 75.5141 6.89485 75.5141 7.2808C75.5141 7.67553 75.2159 7.965 74.8211 7.965L72.9177 7.965V8.76323L74.1282 8.76323C74.4966 8.76323 74.7685 9.03515 74.7685 9.3948C74.7685 9.75444 74.4966 10.0264 74.1282 10.0264L72.9177 10.0264V11.0351L74.9264 11.0351C75.3299 11.0351 75.6194 11.3246 75.6194 11.7105C75.6194 12.1053 75.3211 12.3947 74.9264 12.3947L72.1721 12.3947Z" fill="currentColor"/>
<path d="M69.4429 7.23694C69.443 6.83344 69.1009 6.50012 68.6886 6.50012C68.364 6.50012 68.1009 6.68432 67.9868 7.00011L66.943 9.8597L65.9781 7.07028C65.8465 6.70187 65.5834 6.50011 65.2325 6.50011C64.8816 6.50011 64.6185 6.70187 64.4869 7.07028L63.522 9.8597L62.4694 6.97379C62.3641 6.67555 62.101 6.50011 61.7764 6.50011C61.3642 6.50011 61.0221 6.83344 61.0221 7.23694C61.0221 7.3422 61.0396 7.43869 61.101 7.57904L62.8115 11.9912C62.9343 12.3246 63.1799 12.5 63.5132 12.5C63.8378 12.5 64.0834 12.3246 64.2062 11.9912L65.2325 9.21059L66.2588 11.9912C66.3816 12.3246 66.6272 12.5 66.9518 12.5C67.2851 12.5 67.5307 12.3246 67.6535 11.9912L69.364 7.57904C69.4166 7.44747 69.4429 7.35098 69.4429 7.23694Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M60.0269 11.4123C60.0795 11.5439 60.1058 11.6755 60.1058 11.7807C60.1058 12.193 59.7901 12.5 59.3602 12.5C59.0357 12.5 58.7901 12.3158 58.6497 11.9561L58.5269 11.6491L56.4568 11.6491L56.334 11.9561C56.1936 12.3158 55.948 12.5 55.6235 12.5C55.1936 12.5 54.8779 12.193 54.8779 11.7807C54.8779 11.6755 54.9042 11.5439 54.9568 11.4123L56.7726 7.0001C56.9041 6.67555 57.1498 6.50011 57.4919 6.50011C57.834 6.50011 58.0796 6.67555 58.2111 7.00011L60.0269 11.4123ZM57.4919 8.74568L56.9041 10.4386L58.0796 10.4386L57.4919 8.74568Z" fill="currentColor"/>
<path d="M35.6665 6.50013C36.0788 6.50013 36.4209 6.83346 36.4209 7.23696C36.4209 7.35099 36.3946 7.44748 36.3419 7.57906L34.6314 11.9912C34.5086 12.3246 34.263 12.5 33.9297 12.5C33.6051 12.5 33.3595 12.3246 33.2367 11.9912L32.2104 9.2106L31.1841 11.9912C31.0613 12.3246 30.8157 12.5 30.4912 12.5C30.1578 12.5 29.9122 12.3246 29.7894 11.9912L28.0789 7.57906C28.0175 7.43871 28 7.34222 28 7.23696C28 6.83346 28.3421 6.50013 28.7544 6.50013C29.0789 6.50013 29.3421 6.67557 29.4473 6.97381L30.4999 9.85971L31.4648 7.07029C31.5964 6.70188 31.8596 6.50013 32.2104 6.50013C32.5613 6.50013 32.8245 6.70188 32.956 7.07029L33.9209 9.85971L34.9648 7.00012C35.0788 6.68434 35.3419 6.50013 35.6665 6.50013Z" fill="currentColor"/>
<path d="M38.3868 11.6316C38.3868 12.0702 38.7114 12.3947 39.15 12.3947H41.9043C42.299 12.3947 42.5973 12.1052 42.5973 11.7105C42.5973 11.3246 42.3078 11.0351 41.9043 11.0351H39.8956V10.0263H41.1061C41.4745 10.0263 41.7464 9.75442 41.7464 9.39478C41.7464 9.03514 41.4745 8.76321 41.1061 8.76321H39.8956V7.96498H41.799C42.1938 7.96498 42.492 7.67552 42.492 7.28079C42.492 6.89483 42.2025 6.60536 41.799 6.60536H39.15C38.7114 6.60536 38.3868 6.92992 38.3868 7.36851V11.6316Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.5021 10.6754C49.5021 10.0176 49.1425 9.53512 48.5372 9.28952C48.7653 9.03514 48.8881 8.70181 48.8881 8.31585C48.8881 7.31587 48.0723 6.60536 46.932 6.60536H45.6075C45.1689 6.60536 44.8443 6.92992 44.8443 7.36851V11.6316C44.8443 12.0702 45.1689 12.3947 45.6075 12.3947H47.546C48.6776 12.3947 49.5021 11.6754 49.5021 10.6754ZM46.2917 7.87727H46.8355C47.1864 7.87727 47.4145 8.07024 47.4145 8.38603C47.4145 8.70181 47.1864 8.89479 46.8355 8.89479H46.2917V7.87727ZM48.0285 10.614C48.0285 10.9386 47.818 11.1228 47.4496 11.1228H46.2917V10.1053H47.4496C47.818 10.1053 48.0285 10.2895 48.0285 10.614Z" fill="currentColor"/>
<path d="M11.63 1.625C11.63 2.27911 11.2435 2.84296 10.6865 3.10064L14 6L17.2622 5.34755C17.0968 5.10642 17 4.81452 17 4.5C17 3.67157 17.6716 3 18.5 3C19.3284 3 20 3.67157 20 4.5C20 5.31157 19.3555 5.9726 18.5504 5.99917L15.0307 13.8207C14.7077 14.5384 13.9939 15 13.2068 15H6.79317C6.00615 15 5.29229 14.5384 4.96933 13.8207L1.44963 5.99917C0.64452 5.9726 0 5.31157 0 4.5C0 3.67157 0.671573 3 1.5 3C2.32843 3 3 3.67157 3 4.5C3 4.81452 2.9032 5.10642 2.73777 5.34755L6 6L9.31702 3.09761C8.76346 2.83855 8.38 2.27656 8.38 1.625C8.38 0.727537 9.10754 0 10.005 0C10.9025 0 11.63 0.727537 11.63 1.625Z" fill="var(--wa-brand-orange, #F36944)"/>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="105" height="16" fill="none" viewBox="0 0 105 16"><path fill="currentColor" d="M78.052 11.86c.412.386 1.175.64 1.816.64 1.193 0 2.122-.667 2.122-1.807 0-.85-.517-1.342-1.482-1.746l-.667-.28c-.36-.15-.5-.255-.5-.474 0-.263.22-.368.518-.368.31 0 .479.13.633.25q.057.044.112.083a.64.64 0 0 0 .386.132c.334 0 .676-.29.676-.676a.66.66 0 0 0-.176-.447C81.35 7 80.86 6.49 79.841 6.5c-1.149 0-2.026.676-2.026 1.71 0 .816.544 1.343 1.465 1.746l.596.263c.404.176.588.264.588.535 0 .281-.193.422-.596.422-.504 0-.843-.28-1.02-.424q-.053-.045-.086-.068a.63.63 0 0 0-.342-.105.673.673 0 0 0-.675.667c0 .228.114.43.307.614M97.912 7.28c0-.447-.316-.78-.755-.78-.307 0-.517.15-.763.553l-1.43 2.298-1.43-2.298c-.245-.404-.456-.553-.763-.553-.438 0-.754.333-.754.78v4.457a.74.74 0 0 0 .754.763.74.74 0 0 0 .755-.763V9.71l.754 1.201c.21.334.403.465.684.465.28 0 .474-.131.684-.465l.755-1.201v2.026a.74.74 0 0 0 .754.763.74.74 0 0 0 .755-.763zM100.516 11.632c0 .438.324.763.763.763h2.754a.67.67 0 0 0 .693-.684c0-.386-.289-.676-.693-.676h-2.009v-1.009h1.211a.62.62 0 0 0 .64-.631.62.62 0 0 0-.64-.632h-1.211v-.798h1.904a.67.67 0 0 0 .693-.684c0-.386-.29-.676-.693-.676h-2.649a.74.74 0 0 0-.763.764z"/><path fill="currentColor" fill-rule="evenodd" d="M86.878 6.5c1.754 0 3.131 1.325 3.131 3 0 1.684-1.377 3-3.131 3s-3.114-1.316-3.114-3 1.368-3 3.114-3m.009 1.386c-.939 0-1.58.658-1.58 1.614 0 .965.632 1.614 1.58 1.614.93 0 1.579-.667 1.579-1.614 0-.939-.658-1.614-1.58-1.614" clip-rule="evenodd"/><path fill="currentColor" d="M72.172 12.395a.74.74 0 0 1-.763-.763V7.369c0-.44.325-.764.763-.764h2.65c.403 0 .692.29.692.676a.67.67 0 0 1-.693.684h-1.903v.798h1.21a.62.62 0 0 1 .64.632.62.62 0 0 1-.64.631h-1.21v1.01h2.008c.404 0 .693.289.693.675a.67.67 0 0 1-.693.684zM69.443 7.237a.75.75 0 0 0-.754-.737.72.72 0 0 0-.702.5l-1.044 2.86-.965-2.79c-.131-.368-.395-.57-.745-.57-.351 0-.615.202-.746.57l-.965 2.79-1.053-2.886c-.105-.298-.368-.474-.693-.474a.75.75 0 0 0-.754.737c0 .105.018.202.079.342l1.71 4.412c.123.334.369.509.702.509.325 0 .57-.175.693-.509l1.026-2.78 1.027 2.78c.123.334.368.509.693.509.333 0 .579-.175.701-.509l1.711-4.412a.9.9 0 0 0 .079-.342"/><path fill="currentColor" fill-rule="evenodd" d="M60.027 11.412c.053.132.079.263.079.369 0 .412-.316.719-.746.719-.324 0-.57-.184-.71-.544l-.123-.307h-2.07l-.123.307c-.14.36-.386.544-.71.544-.43 0-.746-.307-.746-.72 0-.104.026-.236.079-.368L56.773 7c.131-.324.377-.5.719-.5s.588.176.72.5zm-2.535-2.666-.588 1.693h1.176z" clip-rule="evenodd"/><path fill="currentColor" d="M35.667 6.5a.75.75 0 0 1 .754.737c0 .114-.026.21-.08.342l-1.71 4.412c-.122.334-.368.509-.701.509-.325 0-.57-.175-.693-.509l-1.027-2.78-1.026 2.78c-.123.334-.368.509-.693.509-.333 0-.579-.175-.702-.509L28.08 7.58A.8.8 0 0 1 28 7.237a.75.75 0 0 1 .754-.737c.325 0 .588.176.693.474L30.5 9.86l.965-2.79c.131-.368.395-.57.745-.57.351 0 .614.202.746.57l.965 2.79L34.965 7a.72.72 0 0 1 .701-.5M38.387 11.632c0 .438.324.763.763.763h2.754c.395 0 .693-.29.693-.684 0-.386-.29-.676-.693-.676h-2.008v-1.009h1.21a.62.62 0 0 0 .64-.631.62.62 0 0 0-.64-.632h-1.21v-.798h1.903a.67.67 0 0 0 .693-.684c0-.386-.29-.676-.693-.676H39.15a.74.74 0 0 0-.763.764z"/><path fill="currentColor" fill-rule="evenodd" d="M49.502 10.675c0-.657-.36-1.14-.965-1.385.228-.255.351-.588.351-.974 0-1-.816-1.71-1.956-1.71h-1.325a.74.74 0 0 0-.763.763v4.263c0 .438.325.763.764.763h1.938c1.132 0 1.956-.72 1.956-1.72m-3.21-2.798h.544c.35 0 .578.193.578.509s-.228.509-.578.509h-.544zm1.736 2.737c0 .325-.21.509-.578.509h-1.158v-1.018h1.158c.368 0 .578.184.578.509" clip-rule="evenodd"/><path fill="var(--wa-brand-orange, #f36944)" d="M11.63 1.625c0 .654-.387 1.218-.944 1.476L14 6l3.262-.652A1.5 1.5 0 1 1 18.55 6l-3.52 7.82A2 2 0 0 1 13.208 15H6.793a2 2 0 0 1-1.824-1.18L1.45 6a1.5 1.5 0 1 1 1.289-.652L6 6l3.317-2.902a1.625 1.625 0 1 1 2.313-1.473"/></svg>

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,5 @@
{% macro plannedBadge(plannedBadgeDescription, plannedBadgeId) %}
{% set badgeId = plannedBadgeId or ("planned-badge-" + ("" | uniqueId(8))) %}
<wa-badge appearance="filled" variant="neutral" pill class="planned" id="{{ badgeId }}">Planned</wa-badge>
<wa-tooltip for="{{ badgeId }}">{{ plannedBadgeDescription or "This is a planned feature" }}</wa-tooltip>
{% endmacro %}

View File

@@ -0,0 +1,6 @@
{% macro proBadge(params) %}
{% set description = params.description or "This requires access to Web Awesome Pro" %}
{% set badgeId = params.id or ("pro-badge-" + ("" | uniqueId(8))) %}
<wa-badge appearance="accent" pill class="pro" id="{{ badgeId }}">Pro</wa-badge>
<wa-tooltip for="{{ badgeId }}">{{ description }}</wa-tooltip>
{% endmacro %}

View File

@@ -0,0 +1,5 @@
<wa-button id="search-trigger" appearance="outlined" size="small" data-search>
<wa-icon slot="start" name="magnifying-glass"></wa-icon>
Search the Docs for&hellip;
<kbd slot="end" class="wa-desktop-only">/</kbd>
</wa-button>

View File

@@ -1,9 +1,7 @@
{# Search #}
<wa-button id="search-trigger" appearance="outlined" size="small" data-search>
<wa-icon slot="start" name="magnifying-glass"></wa-icon>
Search
<kbd slot="end" class="wa-desktop-only">/</kbd>
</wa-button>
{% include "search-trigger-button.njk" %}
{% from "pro-badge.njk" import proBadge %}
{% from "planned-badge.njk" import plannedBadge %}
{# Getting started #}
<h2>Getting Started</h2>
@@ -25,6 +23,9 @@
<li><a href="/docs/resources/browser-support">Browser Support</a></li>
<li><a href="/docs/resources/contributing">Contributing</a></li>
<li><a href="/docs/resources/changelog">Changelog</a></li>
<li><a href="/license"><span class="wa-visually-hidden">Web Awesome </span>Free License</a></li>
<li><a href="/license/pro"><span class="wa-visually-hidden">Web Awesome </span>Pro License</a></li>
<li><a href="/tos">Terms of Service</a></li>
<li><a href="/docs/resources/visual-tests">Visual Tests</a></li>
</ul>
@@ -40,9 +41,9 @@
<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>
Page <wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
{{ proBadge() }}
</span>
</li>
<li><a href="/docs/components/animated-image/">Animated Image</a></li>
@@ -62,26 +63,30 @@
<li>
<a class="wa-cluster wa-gap-xs" href="/docs/components/carousel/">
Carousel
<wa-icon name="flask" aria-hidden="true"></wa-icon>
<wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
</a>
<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>
<wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
</a>
</li>
</ul>
</li>
<li><span class="is-planned wa-split">Charts <a href="https://github.com/shoelace-style/webawesome/issues/1073" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></li>
<li><a href="/docs/components/checkbox/">Checkbox</a></li>
<li><a href="/docs/components/color-picker/">Color Picker</a></li>
<li><span class="is-planned wa-split">Combobox <a href="https://github.com/shoelace-style/webawesome/issues/1074" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></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>
<wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
</a>
</li>
<li><span class="is-planned wa-split">Data Grid <a href="https://github.com/shoelace-style/webawesome/issues/1072" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></li>
<li><span class="is-planned wa-split">Datepicker <a href="https://github.com/shoelace-style/webawesome/issues/1075" target="_blank">{{ plannedBadge("A Web Awesome Kickstarter stretch goal!") }}</a></span></li>
<li><a href="/docs/components/details/">Details</a></li>
<li><a href="/docs/components/dialog/">Dialog</a></li>
<li><a href="/docs/components/divider/">Divider</a></li>
@@ -98,6 +103,7 @@
<li><a href="/docs/components/icon/">Icon</a></li>
<li><a href="/docs/components/include/">Include</a></li>
<li><a href="/docs/components/input/">Input</a></li>
<li><a href="/docs/components/intersection-observer">Intersection Observer</a></li>
<li><a href="/docs/components/mutation-observer/">Mutation Observer</a></li>
<li><a href="/docs/components/popover/">Popover</a></li>
<li><a href="/docs/components/popup/">Popup</a></li>
@@ -180,9 +186,9 @@
<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>
Page <wa-icon name="flask" aria-hidden="true" class="icon-shrink"></wa-icon>
</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
{{ proBadge() }}
</span>
</li>
</ul>
@@ -200,7 +206,7 @@
<li>
<span class="wa-split">
<a href="/docs/patterns/app/">App</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
{{ proBadge() }}
</span>
<ul>
<li>
@@ -246,7 +252,7 @@
<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>
{{ proBadge() }}
</span>
<ul>
<li>
@@ -308,7 +314,7 @@
<li>
<span class="wa-split">
<a href="/docs/patterns/ecommerce/">Ecommerce</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
{{ proBadge() }}
</span>
<ul>
<li>
@@ -349,7 +355,7 @@
<li>
<span class="wa-split">
<a href="/docs/patterns/layouts/">Layouts</a>
<wa-badge class="pro" appearance="accent" attention="none">PRO</wa-badge>
{{ proBadge() }}
</span>
<ul>
<li>
@@ -374,7 +380,7 @@
<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>
{{ proBadge({ description: "This requires an active Web Awesome Pro subscription", shrink: true }) }}
</span>
</li>
</ul>
@@ -398,3 +404,37 @@
<li><a href="/docs/tokens/component-groups/">Component Groups</a></li>
</ul>
</wa-details>
<wa-divider style="--spacing: var(--wa-space-xl);"></wa-divider>
<div class="wa-stack wa-gap-xl" id="colophon">
<div class="wa-stack wa-gap-xs">
{% include "logo-simple.njk" %}
<div class="wa-cluster wa-gap-xs">
<h2 class="wa-heading-xs">Web Awesome</h2>
<wa-badge id="version-beta-badge" variant="orange" appearance="filled" style="font-size: var(--wa-font-size-2xs);">Beta</wa-badge>
<wa-tooltip for="version-beta-badge" distance="2" style="font-size: var(--wa-font-size-xs);">Here be freshly made Awesome&hellip; and possible dragons</wa-tooltip>
</div>
<p class="wa-caption-s">Version {{ package.version }}</p>
<p class="wa-caption-s">&copy; Fonticons, Inc.</p>
</div>
<div class="wa-cluster wa-gap-0 wa-caption-s the-socials">
<h2 class="wa-visually-hidden">Web Awesome Elsewhere</h2>
<a href="https://github.com/shoelace-style/webawesome" rel="noopener noreferrer" target="_blank" class="appearance-plain">
<wa-icon family="brands" name="github" label="GitHub"></wa-icon>
</a>
<a href="https://bsky.app/profile/webawesome.com" rel="noopener noreferrer" target="_blank" class="appearance-plain">
<wa-icon family="brands" name="bluesky" label="Bluesky"></wa-icon>
</a>
<a href="https://mastodon.social/@webawesome" rel="noopener noreferrer" target="_blank" class="appearance-plain">
<wa-icon family="brands" name="mastodon" label="Mastodon"></wa-icon>
</a>
<a href="https://x.com/webawesomer" rel="noopener noreferrer" target="_blank" class="appearance-plain">
<wa-icon family="brands" name="x-twitter" label="Twitter (X)"></wa-icon>
</a>
<a href="https://www.threads.com/@web.awesome" rel="noopener noreferrer" target="_blank" class="appearance-plain">
<wa-icon family="brands" name="threads" label="Threads"></wa-icon>
</a>
</div>
</div>

View File

@@ -1,16 +1,18 @@
<wa-select appearance="filled" size="small" value="default" class="theme-selector">
<wa-icon slot="start" name="paintbrush" variant="regular"></wa-icon>
<wa-dropdown class="theme-selector" title="Select Theme">
<wa-button slot="trigger" id="theme-selector-trigger" appearance="plain">
<wa-icon name="paintbrush" variant="regular" class="icon-embiggen"></wa-icon>
</wa-button>
{# Free themes #}
{% for theme in themer.themes %}
{% if not theme.isPro %}
<wa-option
<wa-dropdown-item
value="{{ theme.filename | stripExtension }}"
data-brand="{{ theme.colorBrand.color }}"
data-palette="{{ theme.palette.filename | stripExtension }}"
>
{{ theme.name }}
</wa-option>
</wa-dropdown-item>
{% endif %}
{% endfor %}
@@ -18,24 +20,27 @@
{% for theme in themer.themes %}
{% if loop.first %}<wa-divider></wa-divider>{% endif %}
{% if theme.isPro %}
<wa-option
<wa-dropdown-item
value="{{ theme.filename | stripExtension }}"
data-brand="{{ theme.colorBrand.color }}"
data-palette="{{ theme.palette.filename | stripExtension }}"
>
{{ theme.name }}
</wa-option>
</wa-dropdown-item>
{% endif %}
{% endfor %}
</wa-select>
</wa-dropdown>
<wa-tooltip for="theme-selector-trigger" id="theme-tooltip">Select Theme</wa-tooltip>
<script>
// Immediately set the correct values from storage
document.querySelectorAll('wa-select.theme-selector').forEach(el => {
el.setAttribute('value', localStorage.getItem('theme') || 'default');
});
// Handle dropdown selection and trigger input event for theme.js
document.querySelectorAll('wa-dropdown.theme-selector').forEach(el => {
el.addEventListener('wa-select', (event) => {
const selectedValue = event.detail.item.value;
// Apply saved brand and palette classes
document.documentElement.classList.add(`wa-brand-${localStorage.getItem('brand') || 'blue'}`);
document.documentElement.classList.add(`wa-palette-${localStorage.getItem('palette') || 'default'}`);
// Trigger input event for theme.js
el.value = selectedValue;
el.dispatchEvent(new Event('input', { bubbles: true }));
});
});
</script>

View File

@@ -516,7 +516,6 @@
<wa-tag variant="brand" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag variant="brand" appearance="filled">Filled</wa-tag>
<wa-tag variant="brand" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="brand" appearance="plain">Plain</wa-tag>
</div>
</td>
<td>
@@ -525,7 +524,6 @@
<wa-tag class="wa-brand" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag class="wa-brand" appearance="filled">Filled</wa-tag>
<wa-tag class="wa-brand" appearance="outlined">Outlined</wa-tag>
<wa-tag class="wa-brand" appearance="plain">Plain</wa-tag>
</div>
</td>
</tr>
@@ -537,7 +535,6 @@
<wa-tag variant="neutral" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag variant="neutral" appearance="filled">Filled</wa-tag>
<wa-tag variant="neutral" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="neutral" appearance="plain">Plain</wa-tag>
</div>
</td>
<td>
@@ -546,7 +543,6 @@
<wa-tag class="wa-neutral" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag class="wa-neutral" appearance="filled">Filled</wa-tag>
<wa-tag class="wa-neutral" appearance="outlined">Outlined</wa-tag>
<wa-tag class="wa-neutral" appearance="plain">Plain</wa-tag>
</div>
</td>
</tr>
@@ -558,7 +554,6 @@
<wa-tag variant="success" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag variant="success" appearance="filled">Filled</wa-tag>
<wa-tag variant="success" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="success" appearance="plain">Plain</wa-tag>
</div>
</td>
<td>
@@ -567,7 +562,6 @@
<wa-tag class="wa-success" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag class="wa-success" appearance="filled">Filled</wa-tag>
<wa-tag class="wa-success" appearance="outlined">Outlined</wa-tag>
<wa-tag class="wa-success" appearance="plain">Plain</wa-tag>
</div>
</td>
</tr>
@@ -579,7 +573,6 @@
<wa-tag variant="warning" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag variant="warning" appearance="filled">Filled</wa-tag>
<wa-tag variant="warning" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="warning" appearance="plain">Plain</wa-tag>
</div>
</td>
<td>
@@ -588,7 +581,6 @@
<wa-tag class="wa-warning" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag class="wa-warning" appearance="filled">Filled</wa-tag>
<wa-tag class="wa-warning" appearance="outlined">Outlined</wa-tag>
<wa-tag class="wa-warning" appearance="plain">Plain</wa-tag>
</div>
</td>
</tr>
@@ -600,7 +592,6 @@
<wa-tag variant="danger" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag variant="danger" appearance="filled">Filled</wa-tag>
<wa-tag variant="danger" appearance="outlined">Outlined</wa-tag>
<wa-tag variant="danger" appearance="plain">Plain</wa-tag>
</div>
</td>
<td>
@@ -609,7 +600,6 @@
<wa-tag class="wa-danger" appearance="filled outlined">Filled + Outlined</wa-tag>
<wa-tag class="wa-danger" appearance="filled">Filled</wa-tag>
<wa-tag class="wa-danger" appearance="outlined">Outlined</wa-tag>
<wa-tag class="wa-danger" appearance="plain">Plain</wa-tag>
</div>
</td>
</tr>

View File

@@ -4,7 +4,7 @@
{% include 'head.njk' %}
{% block head %}{% endblock %}
</head>
<body class="layout-{{ layout | stripExtension }}">
<body class="layout-{{ layout | stripExtension }} page-{{ pageClass or page.fileSlug or 'home' }}">
{% block content %}
{{ content | safe }}
{% endblock %}

View File

@@ -11,7 +11,6 @@ export function SimulateWebAwesomeApp(str) {
},
server: {
head: '',
loginOrAvatar: '',
flashes: '',
},
});

View File

@@ -3,17 +3,30 @@ import { doViewTransition } from '../scripts/view-transitions.js';
//
// Updates the color scheme when a color scheme selector changes
//
function updateTheme(value) {
async function updateTheme(value) {
localStorage.setItem('color-scheme', value);
const isDark = value === 'dark' || (value === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches);
doViewTransition(() => {
// Disable tooltip during transition
const tooltip = document.querySelector('#color-scheme-tooltip');
if (tooltip) {
tooltip.disabled = true;
}
await doViewTransition(() => {
document.documentElement.classList.toggle('wa-dark', isDark);
});
// Sync all selectors
// Sync all selectors and update tooltip
document.querySelectorAll('.color-scheme-selector').forEach(el => (el.value = value));
// Update tooltip content and re-enable after transition completes
if (tooltip) {
const schemeText = value === 'light' ? 'Light' : value === 'dark' ? 'Dark' : 'System';
tooltip.textContent = schemeText;
tooltip.disabled = false;
}
}
// Handle changes

View File

@@ -6,7 +6,20 @@ import { doViewTransition } from '../scripts/view-transitions.js';
async function updateTheme(value, isInitialLoad = false) {
const body = document.body;
// Get brand, palette, and theme name from the selected option
const themeSelector = document.querySelector('.theme-selector');
const selectedOption = themeSelector?.querySelector(`wa-dropdown-item[value="${value}"]`);
let brand = selectedOption?.getAttribute('data-brand') || 'blue';
let palette = selectedOption?.getAttribute('data-palette') || 'default';
let themeName = selectedOption?.textContent.trim() || 'Unknown';
if (!isInitialLoad) {
// Disable tooltip during theme transition
const tooltip = document.querySelector('#theme-tooltip');
if (tooltip) {
tooltip.disabled = true;
}
// Add fade-out class
body.classList.add('theme-transitioning');
@@ -22,27 +35,29 @@ async function updateTheme(value, isInitialLoad = false) {
});
}
localStorage.setItem('theme', value);
// Handle site theme vs regular theme
let href = `/dist/styles/themes/${value}.css`;
// Get brand and palette from the selected option
const themeSelector = document.querySelector('.theme-selector');
const selectedOption = themeSelector?.querySelector(`wa-option[value="${value}"]`);
const brand = selectedOption?.getAttribute('data-brand') || 'blue';
const palette = selectedOption?.getAttribute('data-palette') || 'default';
const htmlElement = document.documentElement;
localStorage.setItem('brand', brand);
localStorage.setItem('palette', palette);
if (document.querySelector('wa-page').dataset.pageType === 'site') {
brand = 'orange';
href = `/assets/styles/theme-site.css`;
palette = 'default';
value = 'site';
} else {
localStorage.setItem('brand', brand);
localStorage.setItem('palette', palette);
localStorage.setItem('theme', value);
}
// Update theme classes
const htmlElement = document.documentElement;
const classesToRemove = Array.from(htmlElement.classList).filter(
className =>
className.startsWith('wa-theme-') || className.startsWith('wa-brand-') || className.startsWith('wa-palette-'),
);
const themeStylesheet = document.getElementById('theme-stylesheet');
const href = `/dist/styles/themes/${value}.css`;
doViewTransition(() => {
await doViewTransition(() => {
// Update the theme
if (themeStylesheet) {
themeStylesheet.href = href;
@@ -56,16 +71,26 @@ async function updateTheme(value, isInitialLoad = false) {
htmlElement.classList.add(`wa-palette-${palette}`);
// Sync all theme selectors
document.querySelectorAll('.theme-selector').forEach(el => (el.value = value));
document.querySelectorAll('.theme-selector').forEach(el => {
el.value = value;
el.setAttribute('value', value);
});
// Update tooltip content to reflect the new theme
const tooltip = document.querySelector('#theme-tooltip');
if (tooltip) {
tooltip.textContent = `${themeName} Theme`;
}
});
if (!isInitialLoad) {
// Waiting for the stylesheet and all it's imports to load is tricky. Preloading doesn't work for most themes
// because applying the new stylesheet to the document, even without adding the `wa-theme-*` class, causes jank.
// Suggestions welcome.
setTimeout(() => {
body.classList.remove('theme-transitioning');
}, 500);
// Remove transition class and re-enable tooltip after view transition completes
body.classList.remove('theme-transitioning');
const tooltip = document.querySelector('#theme-tooltip');
if (tooltip) {
tooltip.disabled = false;
}
}
}
@@ -77,5 +102,11 @@ document.addEventListener('input', event => {
});
// Initialize
const savedTheme = localStorage.getItem('theme') || 'default';
updateTheme(savedTheme, true);
function initializeTheme() {
const savedTheme = localStorage.getItem('theme') || 'default';
updateTheme(savedTheme, true);
}
initializeTheme();
document.addEventListener('turbo:render', initializeTheme);

View File

@@ -5,6 +5,7 @@
@import 'search.css';
@import 'cera-typeface.css';
@import 'theme-icons.css';
@import 'utils.css';
:root {
--wa-brand-orange: #f36944;
@@ -48,6 +49,16 @@ wa-page > header {
line-height: 1;
}
.brand-logo {
color: var(--wa-color-text-normal);
line-height: 1;
}
.brand-logo svg {
width: auto;
height: 1.75rem;
}
wa-button[data-toggle-nav] {
--text-color: currentColor;
font-size: 1rem;
@@ -59,55 +70,6 @@ wa-page > header {
padding-inline: 0.875rem;
}
}
svg {
width: auto;
height: 1.75rem;
}
#docs-branding,
#docs-toolbar {
display: flex;
align-items: center;
gap: var(--wa-space-s);
.color-scheme-selector,
.theme-selector {
max-inline-size: 20ch;
}
wa-divider:last-child {
display: none;
}
}
#github-buttons {
> wa-button {
&::part(base) {
color: var(--wa-color-on-quiet);
background-color: var(--wa-color-fill-quiet);
}
> wa-icon {
font-size: round(1.25em, 1px);
}
}
> wa-tooltip {
--wa-tooltip-arrow-size: 0;
font-size: var(--wa-font-size-xs);
}
}
#version-number {
color: var(--wa-color-text-quiet);
font-size: var(--wa-font-size-xs);
line-height: 1;
margin-block-start: var(--wa-space-2xs);
}
#version-number + wa-badge {
font-size: var(--wa-font-size-2xs);
text-transform: uppercase;
}
}
#sidebar,
@@ -188,13 +150,6 @@ wa-page > header {
margin-block-end: var(--wa-space-m);
}
/* Pro badges */
wa-badge.pro {
color: white;
background-color: var(--wa-brand-orange);
border-color: var(--wa-brand-orange);
}
#sidebar {
h2 {
color: var(--wa-color-text-quiet);
@@ -226,10 +181,30 @@ wa-badge.pro {
}
}
li wa-badge {
/* adding 1 scale below --wa-font-size-2xs to handle badge proportions in sidebar nav */
--font-size-3xs: round(calc(var(--wa-font-size-2xs) / 1.125), 1px); /* 10px */
font-size: var(--font-size-3xs);
}
wa-details {
--show-duration: 0;
--hide-duration: 0;
}
.the-socials {
/* nudge those linkies left */
margin-inline-start: calc(var(--wa-space-xs) * -1);
a[target='_blank'] {
color: var(--wa-color-text-quiet);
padding-inline: var(--wa-space-xs);
&:hover {
color: var(--wa-color-text-normal);
}
}
}
}
wa-button.delete {
@@ -249,6 +224,11 @@ wa-button.delete {
}
}
/* planned sidebar item */
.is-planned {
color: var(--wa-color-text-quiet);
}
#sidebar-close-button {
display: none;
}
@@ -270,6 +250,20 @@ wa-page::part(menu) {
scrollbar-width: thin;
}
/* smaller viewports-based navigation */
wa-page > [slot='navigation-header'] {
padding: 0;
.brand-logo svg {
height: 1.25rem;
}
/* resetting font-weight of dropdown items in .title */
wa-dropdown {
font-weight: var(--wa-font-weight-normal);
}
}
wa-page[view='mobile'] :is([slot='navigation-header'], [slot='navigation']) {
padding: 0;
@@ -280,7 +274,7 @@ wa-page[view='mobile'] :is([slot='navigation-header'], [slot='navigation']) {
/* Main content */
wa-page > main {
max-width: 80ch;
max-width: var(--content-width-s);
padding: var(--wa-space-xl);
margin-inline: auto;
}
@@ -386,27 +380,9 @@ h1.title {
}
}
/* Search trigger */
wa-button#search-trigger {
&::part(base) {
background-color: var(--wa-form-control-background-color);
border: var(--wa-form-control-border-width) var(--wa-form-control-border-style) var(--wa-form-control-border-color);
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 */
wa-page > main:has(> .search-list) {
max-width: 120ch;
max-width: var(--content-width-l);
margin-inline: auto;
}
@@ -504,7 +480,6 @@ wa-card .page-name {
width: 100%;
height: 100%;
display: block;
--background-color-hover: transparent;
font-family: var(--wa-font-family-code);
&::part(button) {
@@ -514,6 +489,7 @@ wa-card .page-name {
}
&::part(button):hover {
background-color: transparent;
cursor: copy;
}
@@ -621,7 +597,7 @@ wa-scroller:has(.component-table) {
.table-arguments,
.table-description {
min-width: 40ch;
min-width: var(--line-length-xs);
}
.table-reflect {
@@ -670,10 +646,10 @@ wa-scroller:has(.component-table) {
.page-wide {
wa-page > main {
max-width: 140ch;
max-width: var(--content-width-l);
.max-line-length {
max-width: 80ch;
max-width: var(--line-length-l);
}
}
}

View File

@@ -0,0 +1,164 @@
/* Monorepo Styles
* These styles include elements that are shared across this repo as well as others included in the Web Awesome monorepo
*/
@layer wa-utils {
:root {
/* max-width for fixed width app-based pages
* We round() these to avoid obscure component rendering bugs caused by widths with fractional pixels */
--content-width-l: round(up, 132ch, 1px);
--content-width-m: round(up, 110ch, 1px);
--content-width-s: round(up, 80ch, 1px);
--content-width-xs: round(up, 50ch, 1px);
--content-padding-inline: 4ch;
--content-flow-spacing: 8ch;
--line-length-xs: 30ch;
--line-length-s: 45ch;
--line-length-m: 66ch;
--line-length-l: 77ch;
--line-length-xl: 90ch;
--line-length-none: none;
}
/* #region brand utilities */
.logo-webawesome {
color: var(--wa-brand-orange);
}
/* #endregion */
/* #region layout utilities */
.content-container {
margin-inline: auto;
max-width: var(--max-width, var(--content-width-l));
padding-inline: var(--content-padding-inline);
}
/* #endregion */
/* #region Text utilities */
.text-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* line-length */
.line-length {
max-width: var(--line-length, none);
}
.line-length-xs {
--line-length: var(--line-length-xs);
}
.line-length-s {
--line-length: var(--line-length-s);
}
.line-length-m {
--line-length: var(--line-length-m);
}
.line-length-l {
--line-length: var(--line-length-l);
}
.line-length-xl {
--line-length: var(--line-length-xl);
}
.line-length-none {
--line-length: none;
}
/* #endregion */
/* #region shared UI */
/* pro badge */
wa-badge.pro {
color: white;
background-color: var(--wa-brand-orange);
border-color: var(--wa-brand-orange);
+ wa-tooltip {
font-size: var(--wa-font-size-xs);
--max-width: unset;
}
}
/* planned badge */
wa-badge.planned {
background-color: var(--wa-color-neutral-fill-quiet);
color: var(--wa-color-neutral-on-quiet);
+ wa-tooltip {
font-size: var(--wa-font-size-xs);
--max-width: unset;
}
}
/* search trigger */
wa-button#search-trigger {
&::part(base) {
background-color: var(--wa-form-control-background-color);
border: var(--wa-form-control-border-width) var(--wa-form-control-border-style)
var(--wa-form-control-border-color);
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;
}
/* #endregion */
/* #region funsies */
/* buttons with icon toggle on hover */
wa-button .icon-hover {
display: none;
}
wa-button:hover .icon-default {
display: none;
}
wa-button:hover .icon-hover {
display: inline-flex;
}
/* #endregion */
/* #region resets */
code.appearance-plain {
background: transparent;
border: none;
}
a.appearance-plain {
--wa-color-text-link: var(--wa-color-text-normal);
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
ul,
ol {
&.appearance-plain {
list-style: none;
padding-inline-start: 0;
li {
padding-inline-start: 0;
}
}
}
/* increasing visual size of icons in certain contexts (such as in plain buttons) */
wa-icon.icon-embiggen {
font-size: round(1.125em, 1px);
}
/* decreasing visual size of icons in certain contexts (such as in sidebar nav) */
wa-icon.icon-shrink {
font-size: round(0.875em, 1px);
}
/* #endregion */
}

View File

@@ -70,7 +70,7 @@ layout: page
{% for palette in themer.palettes %}
<div class="palette-instructions" data-palette="{{ palette.name | lower }}" {% if not loop.first %}hidden{% endif %}>
<p>
To import this palette, set <code>&lt;html class=&quot;wa-theme-{{ palette.name | lower }}&quot;&gt;</code> and import the following stylesheet:
To import this palette, set <code>&lt;html class=&quot;wa-palette-{{ palette.name | lower }}&quot;&gt;</code> and import the following stylesheet:
</p>
<pre><code class="language-html">&lt;link rel=&quot;stylesheet&quot; href=&quot;{% cdnUrl %}styles/color/palettes/{{ palette.filename }}&quot; /&gt;</code></pre>
</div>
@@ -81,7 +81,7 @@ layout: page
const paletteContainer = document.getElementById('color-palettes');
const palettePicker = document.getElementById('palette-picker');
// Set first radio as checked and add initial theme class
// Set first radio as checked and add initial palette class
const firstRadio = palettePicker.querySelector('wa-radio');
if (firstRadio) {
firstRadio.checked = true;

View File

@@ -183,6 +183,9 @@ Use the `start` and `end` slots to add presentational elements like `<wa-icon>`
Use the `with-caret` attribute to add a dropdown indicator when a button will trigger a dropdown, menu, or popover.
```html {.example}
<wa-button size="small" with-caret>
<wa-icon name="gear" label="Settings"></wa-icon>
</wa-button>
<wa-button size="small" with-caret>Small</wa-button>
<wa-button size="medium" with-caret>Medium</wa-button>
<wa-button size="large" with-caret>Large</wa-button>
@@ -251,4 +254,4 @@ This example demonstrates how to style buttons using a custom class. This is the
outline-offset: 4px;
}
</style>
```
```

View File

@@ -17,10 +17,8 @@ category: Organization
This kitten is as cute as he is playful. Bring him home today!<br />
<small class="wa-caption-m">6 weeks old</small>
<div slot="footer" class="wa-split">
<wa-button variant="brand" pill>More Info</wa-button>
<wa-rating label="Rating"></wa-rating>
</div>
<wa-button slot="footer" variant="brand" pill>More Info</wa-button>
<wa-rating slot="footer-actions" label="Rating"></wa-rating>
</wa-card>
<style>
@@ -55,14 +53,11 @@ If using SSR, you need to also use the `with-header` attribute to add a header t
```html {.example}
<wa-card class="card-header">
<div slot="header" class="wa-split">
Header Title
<wa-button appearance="plain">
<wa-icon name="gear" variant="solid" label="Settings"></wa-icon>
</wa-button>
</div>
<h3 slot="header">Header Title</h3>
This card has a header. You can put all sorts of things in it!
<wa-button appearance="plain" slot="header-actions">
<wa-icon name="gear" variant="solid" label="Settings"></wa-icon>
</wa-button>
</wa-card>
<style>
@@ -85,10 +80,9 @@ If using SSR, you need to also use the `with-footer` attribute to add a footer t
<wa-card class="card-footer">
This card has a footer. You can put all sorts of things in it!
<div slot="footer" class="wa-split">
<wa-rating></wa-rating>
<wa-button variant="brand">Preview</wa-button>
</div>
<wa-rating slot="footer"></wa-rating>
<wa-button slot="footer-actions" variant="brand">Preview</wa-button>
</wa-card>
<style>
@@ -155,3 +149,35 @@ Use the `appearance` attribute to change the card's visual appearance.
{%- endfor %}
</div>
```
### Orientation
Set the `orientation` attribute to `horizontal` to create a card with a horizontal, side-by-side layout. Make sure to set a width or maximum width for the media slot. Horizontal cards do not currently contain the header and footer slots.
<wa-callout>
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
The `actions` slot is only available for the horizontal orientation
</wa-callout>
```html {.example}
<div class="wa-grid">
<wa-card orientation="horizontal" class="horizontal-card">
<img
slot="media"
src="https://images.unsplash.com/photo-1559209172-0ff8f6d49ff7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=80"
alt="A kitten sits patiently between a terracotta pot and decorative grasses."
/>
This is a kitten, but not just any kitten. This kitten likes walking along pallets.
<wa-button slot="actions" variant="neutral" appearance="plain"
><wa-icon name="ellipsis" label="actions"></wa-icon
></wa-button>
</wa-card>
</div>
<style>
.horizontal-card {
img[slot='media'] {
max-width: 300px;
}
}
</style>
```

View File

@@ -344,7 +344,7 @@ The content of the carousel can be changed by adding or removing carousel items.
### Vertical Scrolling
Setting the `orientation` attribute to `vertical` will render the carousel in a vertical layout. If the content of your slides vary in height, you will need to set amn explicit `height` or `max-height` on the carousel using CSS.
Setting the `orientation` attribute to `vertical` will render the carousel in a vertical layout. If the content of your slides vary in height, you will need to set an explicit `height` or `max-height` on the carousel using CSS.
```html {.example}
<wa-carousel class="vertical" pagination orientation="vertical">

View File

@@ -96,7 +96,7 @@ Use the `icon` slot to add icons to [dropdown items](/docs/components/dropdown-i
Paste
</wa-dropdown-item>
<wa-dropdown-item value="delete">
<wa-dropdown-item value="delete" variant="danger">
<wa-icon slot="icon" name="trash"></wa-icon>
Delete
</wa-dropdown-item>

View File

@@ -100,7 +100,7 @@ Icons are sized relative to the current font size. To change their size, set the
### Auto Width
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 fixed `1.25em` width. Use the `auto-width` attribute to allow the icon to use its natural variable width.
```html {.example}
Without auto-width<br />

View File

@@ -0,0 +1,297 @@
---
title: Intersection Observer
description: Tracks immediate child elements and fires events as they move in and out of view.
layout: component
---
This component leverages the [IntersectionObserver API](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver) to track when its direct children enter or leave a designated root element. The `wa-intersect` event fires whenever elements cross the visibility threshold.
```html {.example}
<div id="intersection__overview">
<wa-intersection-observer threshold="1" intersect-class="visible">
<div class="box"><wa-icon name="bulb"></wa-icon></div>
</wa-intersection-observer>
</div>
<small>Scroll to see the element intersect at 100% visibility</small>
<style>
/* Container styles */
#intersection__overview {
display: flex;
flex-direction: column;
gap: 2rem;
height: 300px;
border: solid 2px var(--wa-color-surface-border);
padding: 1rem;
overflow-y: auto;
/* Spacers to demonstrate scrolling */
&::before {
content: '';
height: 260px;
flex-shrink: 0;
}
&::after {
content: '';
height: 260px;
flex-shrink: 0;
}
/* Box styles */
.box {
flex-shrink: 0;
width: 120px;
height: 120px;
background-color: var(--wa-color-neutral-fill-normal);
color: var(--wa-color-neutral-10);
display: flex;
align-items: center;
justify-content: center;
margin-inline: auto;
transition: all 50ms cubic-bezier(0.68, -0.55, 0.265, 1.55);
wa-icon {
font-size: 3rem;
stroke-width: 1px;
}
&.visible {
background-color: var(--wa-color-brand-60);
color: white;
}
}
+ small {
display: block;
text-align: center;
margin-block-start: 1rem;
}
}
</style>
```
:::info
Keep in mind that only direct children of the host element are monitored. Nested elements won't trigger intersection events.
:::
## Usage Examples
### Adding Observable Content
The intersection observer tracks only its direct children. The component uses [`display: contents`](https://developer.mozilla.org/en-US/docs/Web/CSS/display#contents) styling, which makes it seamless to integrate with flex and grid layouts from a parent container.
```html
<div style="display: flex; flex-direction: column;">
<wa-intersection-observer>
<div class="box">Box 1</div>
<div class="box">Box 2</div>
<div class="box">Box 3</div>
</wa-intersection-observer>
</div>
```
The component tracks elements as they enter and exit the root element (viewport by default) and emits the `wa-intersect` event on state changes. The event provides `event.detail.entry`, an [`IntersectionObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry) object with intersection details.
You can identify the triggering element through `entry.target`. Check `entry.isIntersecting` to determine if an element is entering or exiting the viewport.
```javascript
observer.addEventListener('wa-intersect', event => {
const entry = event.detail.entry;
if (entry.isIntersecting) {
console.log('Element entered viewport:', entry.target);
} else {
console.log('Element left viewport:', entry.target);
}
});
```
### Setting a Custom Root Element
You can observe intersections within a specific container by assigning the `root` attribute to the [root element's](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/root) ID. Apply [`rootMargin`](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin) with the `root-margin` attribute to expand or contract the observation area.
```html
<div id="scroll-container">
<wa-intersection-observer root="scroll-container" root-margin="50px 0px"> ... </wa-intersection-observer>
</div>
```
### Configuring Multiple Thresholds
Track different visibility percentages by providing multiple [`threshold`](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#threshold) values as a space-separated list.
```html
<wa-intersection-observer threshold="0 0.25 0.5 0.75 1"> ... </wa-intersection-observer>
```
### Applying Classes on Intersect
The `intersect-class` attribute automatically toggles the specified class on direct children when they become visible. This enables pure CSS styling without JavaScript event handlers.
```html {.example}
<div id="intersection__classes">
<wa-intersection-observer threshold="0.5" intersect-class="visible" root="intersection__classes">
<div class="box fade">Fade In</div>
<div class="box slide">Slide In</div>
<div class="box scale">Scale & Rotate</div>
<div class="box bounce">Bounce</div>
</wa-intersection-observer>
</div>
<small>Scroll to see elements transition at 50% visibility</small>
<style>
/* Container styles */
#intersection__classes {
display: flex;
flex-direction: column;
gap: 2rem;
height: 300px;
border: solid 2px var(--wa-color-surface-border);
padding: 1rem;
overflow-y: auto;
/* Spacers to demonstrate scrolling */
&::before {
content: '';
height: 260px;
flex-shrink: 0;
}
&::after {
content: '';
height: 260px;
flex-shrink: 0;
}
+ small {
display: block;
text-align: center;
margin-block-start: 1rem;
}
/* Shared box styles */
.box {
flex-shrink: 0;
width: 120px;
height: 120px;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
color: white;
opacity: 0;
padding: 2rem;
margin-inline: auto;
/* Fade */
&.fade {
background: var(--wa-color-brand-fill-loud);
color: var(--wa-color-brand-on-loud);
transform: translateY(30px);
transition: all 0.6s ease;
&.visible {
opacity: 1;
transform: translateY(0);
}
}
/* Slide */
&.slide {
background: var(--wa-color-brand-fill-loud);
color: var(--wa-color-brand-on-loud);
transform: translateX(-50px);
transition: all 0.5s ease;
&.visible {
opacity: 1;
transform: translateX(0);
}
}
/* Scale */
&.scale {
background: var(--wa-color-brand-fill-loud);
color: var(--wa-color-brand-on-loud);
transform: scale(0.6) rotate(-15deg);
transition: all 0.7s cubic-bezier(0.175, 0.885, 0.32, 1.275);
&.visible {
opacity: 1;
transform: scale(1) rotate(0deg);
}
}
/* Bounce In and Out */
&.bounce {
background: var(--wa-color-brand-fill-loud);
color: var(--wa-color-brand-on-loud);
opacity: 0;
transform: scale(0.8);
transition: none;
&.visible {
opacity: 1;
transform: scale(1);
animation: bounceIn 0.8s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards;
}
&:not(.visible) {
animation: bounceOut 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55) forwards;
}
}
}
}
@keyframes bounceIn {
0% {
transform: scale(0.8);
}
40% {
transform: scale(1.08);
}
65% {
transform: scale(0.98);
}
80% {
transform: scale(1.02);
}
90% {
transform: scale(0.99);
}
100% {
transform: scale(1);
}
}
@keyframes bounceOut {
0% {
transform: scale(1);
opacity: 1;
}
20% {
transform: scale(1.02);
opacity: 1;
}
40% {
transform: scale(0.98);
opacity: 0.8;
}
60% {
transform: scale(1.05);
opacity: 0.6;
}
80% {
transform: scale(0.95);
opacity: 0.3;
}
100% {
transform: scale(0.8);
opacity: 0;
}
}
</style>
```

View File

@@ -8,7 +8,7 @@ category: Utilities
Localization is handled by the browser's [`Intl.RelativeTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat). No language packs are required.
```html {.example}
<!-- Web Awesome 2 release date 🎉 -->
<!-- Shoelace 2 release date 🎉 -->
<wa-relative-time date="2020-07-15T09:17:00-04:00"></wa-relative-time>
```

View File

@@ -6,7 +6,7 @@ category: Form Controls
---
```html {.example}
<wa-textarea label="Type something', will ya"></wa-textarea>
<wa-textarea label="Type somethin', will ya"></wa-textarea>
```
:::info

View File

@@ -191,7 +191,7 @@ This gives you inline documentation, autocomplete, and type-safe validation for
```json
{
"compilerOptions": {
"types": ["node-modules/@awesome.me/webawesome/dist/custom-elements-jsx.d.ts"]
"types": ["node_modules/@awesome.me/webawesome/dist/custom-elements-jsx.d.ts"]
}
}
```
@@ -212,4 +212,4 @@ declare module 'react' {
:::details React 18 and below
React 18 and below have [poor support](https://custom-elements-everywhere.com/#react) for custom elements. For legacy versions of React, we provide React wrappers for every component. You can find the import instructions by selecting the _React_ tab from the _Importing_ section of each
component's documentation.
:::
:::

View File

@@ -56,7 +56,7 @@ To contribute new translations or improvements to existing translations, please
Regional translations are welcome! For example, if a German translation (`de`) exists it's perfectly acceptable to submit a German (Switzerland) (`de-CH`) translation.
If you have any questions, please start a [discussion](https://github.com/shoelace-style/shoelace/discussions) or ask in the [community chat](https://discord.gg/mg8f26C).
If you have any questions, please start a [discussion](https://github.com/shoelace-style/webawesome/discussions) or ask in the [community chat](https://discord.gg/mg8f26C).
:::info
Web Awesome provides a localization mechanism for component internals. This is not designed to be used as localization tool for your entire application. You should use a more appropriate tool such as [i18next](https://www.i18next.com/) if you need to localize content in your app.

View File

@@ -14,7 +14,7 @@ Furthermore, accessibility doesnt stop at the component level. Using accessib
My commitment to Web Awesome users is this: Everything we develop will be built with accessibility in mind. We will test and improve every component to the best of our ability and knowledge. We will work around upstream issues, such as browser bugs and limitations, to the best of our ability and within reason.
Were fully aware that we may not get it right every time for every user, so we invite the community to participate in this ongoing effort by submitting [issues](https://github.com/shoelace-style/shoelace/issues?q=is%3Aissue+is%3Aopen+label%3Aa11y), [pull requests](https://github.com/shoelace-style/shoelace/pulls?q=is%3Aopen+is%3Apr+label%3Aa11y), and [discussions](https://github.com/shoelace-style/shoelace/discussions). Many accessibility improvements have already been made thanks to contributors submitting code, feedback, and suggestions.
Were fully aware that we may not get it right every time for every user, so we invite the community to participate in this ongoing effort by submitting [issues](https://github.com/shoelace-style/shoelace/issues?q=is%3Aissue+is%3Aopen+label%3Aa11y), [pull requests](https://github.com/shoelace-style/shoelace/pulls?q=is%3Aopen+is%3Apr+label%3Aa11y), and [discussions](https://github.com/shoelace-style/webawesome/discussions). Many accessibility improvements have already been made thanks to contributors submitting code, feedback, and suggestions.
This is the path forward. Together, we will continue to make Web Awesome accessible to as many users as possible.

View File

@@ -4,20 +4,41 @@ description: Changes to each version of the project are documented here.
layout: page-outline
---
<p class="wa-caption-m">Last updated: <wa-format-date month="long" day="numeric" year="numeric" date="{{ lastUpdatedISO }}"></wa-format-date></p>
Web Awesome follows [Semantic Versioning](https://semver.org/). Breaking changes in components with the <wa-badge variant="brand">Stable</wa-badge> badge will not be accepted until the next major version. As such, all contributions must consider the project's roadmap and take this into consideration. Features that are deemed no longer necessary will be deprecated but not removed.
Components with the <wa-badge variant="warning">Experimental</wa-badge> badge should not be used in production. They are made available as release candidates for development and testing purposes. As such, changes to experimental components will not be subject to semantic versioning.
## Next
- Added the Kazakh translation [pr:1496]
- Added docs for code completion for VS Code and JetBrains [pr:1550]
- Added back the missing `form-control-label` part to `<wa-textarea>` for consistency with other form controls [pr:1533]
- Fixed a bug in `<wa-button>` where slotted badges weren't properly positioned in buttons with an `href` [issue:1377]
- Fixed focus outline styles in `<wa-details>` and native `<details>` [issue:1456]
- Fixed focus outline styles in `<wa-scroller>`, `<wa-dialog>`, and `<wa-drawer>` [issue:1484]
- Fixed a bug that caused icon button labels to not render in frameworks [issue:1542]
- Fixed a bug in `<wa-details>` that caused the `name` property not to reflect [pr:1538]
- Fixed a bug in `<wa-icon>` that caused icon buttons to render when non-text nodes were slotted in [issue:1475]
## 3.0.0-beta.6
- Fixed a bug in `<wa-dropdown>` that closed the dropdown event when preventing `wa-select` [issue:1432]
- Pin `@ctrl/tinycolor` to `4.1.0` due to malware in `4.1.1` and `4.1.2`. <https://socket.dev/npm/package/@ctrl/tinycolor/overview/4.1.1>
## 3.0.0-beta.5
### 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
- Changed the default width of icons to `1.25em` to match FA7's fixed-width proportions
- 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 `<wa-intersection-observer>` component
- 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]
@@ -28,8 +49,15 @@ Components with the <wa-badge variant="warning">Experimental</wa-badge> badge sh
- 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 a bug in `<wa-details>` that caused it to expand/collapse when clicking on interactive elements in the summary [issue:1252]
- Fixed `<wa-button>` to have `static` positioning by default and `relative` positioning only when used with `<wa-badge>` [pr:1346]
- Fixed spacing in `<wa-input>` when both clear and password toggle icons are present [issue:1325]
- Fixed a bug in `<wa-radio-group>` and `<wa-radio>` where changing appearances dynamically would render incorrectly [issue:1178]
- Fixed a bug in `<wa-input>` that prevented the value from changing when assigning non-string values to `value` [issue:1323]
- Fixed a bug in `<wa-color-picker>` that prevent the picker from staying in the viewport
- Fixed a bug that in `<wa-icon>` that caused `library`, `family`, `variant` and `name` to not reflect [pr:#1395]
- Fixed a bug in `<wa-format-date>` and `<wa-relative-time>` that caused spaces to appear before and after the output [#1417]
- Added horizontal orientation support with `orientation="horizontal"` for `<wa-card>`
## 3.0.0-beta.4

View File

@@ -10,14 +10,14 @@ Please be respectful of other users and remember that Web Awesome is an open sou
## Discussion Forum
The [discussion forum](https://github.com/shoelace-style/shoelace/discussions) is open to anyone with a GitHub account. This is the best place to:
The [discussion forum](https://github.com/shoelace-style/webawesome/discussions) is open to anyone with a GitHub account. This is the best place to:
- Ask for help
- Share ideas and get feedback
- Show the community what you're working on
- Learn more about the project, its values, and its roadmap
<wa-button variant="brand" href="https://github.com/shoelace-style/shoelace/discussions" target="_blank" style="margin-block-end: var(--wa-content-spacing);">
<wa-button variant="brand" href="https://github.com/shoelace-style/webawesome/discussions" target="_blank" style="margin-block-end: var(--wa-content-spacing);">
<wa-icon name="github" family="brands" slot="start"></wa-icon>
Join the Discussion
</wa-button>
@@ -36,13 +36,27 @@ The [community chat](https://discord.gg/mg8f26C) is open to the public and power
Join the Chat
</wa-button>
## Twitter
## Social Networks
Follow [@webawesomer](https://twitter.com/webawesomer) on Twitter for general updates and announcements about Web Awesome. This is a great place to say "hi" or to share something you're working on.
Follow Web Awesome on [Bluesky](https://bsky.app/profile/webawesome.com), [X (Twitter)](https://x.com/webawesomer), [Mastodon](https://mastodon.social/@webawesome), or [Threads](https://www.threads.com/@web.awesome) for general updates and announcements. This is a great place to say "hi" or to share something you're working on.
**Please avoid using Twitter for support questions.** The [discussion forum](https://github.com/shoelace-style/shoelace/discussions) is a much better place to share code snippets, screenshots, and other troubleshooting info. You'll have much better luck there, as more users will have a chance to help you.
**Please avoid using Social Networks for support questions.** The [discussion forum](https://github.com/shoelace-style/webawesome/discussions) is a much better place to share code snippets, screenshots, and other troubleshooting info. You'll have much better luck there, as more users will have a chance to help you.
<wa-button variant="brand" href="https://twitter.com/webawesomer" target="_blank" style="margin-block-end: var(--wa-content-spacing);">
<wa-icon name="twitter" family="brands" slot="start"></wa-icon>
Follow on Twitter
</wa-button>
<div class="wa-cluster wa-gap-l">
<wa-button variant="brand" href="https://bsky.app/profile/webawesome.com" rel="noopener noreferrer" target="_blank">
<wa-icon name="bluesky" family="brands" slot="start"></wa-icon>
Bluesky
</wa-button>
<wa-button variant="brand" href="https://twitter.com/webawesomer" rel="noopener noreferrer" target="_blank">
<wa-icon name="x-twitter" family="brands" slot="start"></wa-icon>
X (Twitter)
</wa-button>
<wa-button variant="brand" href="https://mastodon.social/@webawesome" rel="noopener noreferrer" target="_blank">
<wa-icon name="mastodon" family="brands" slot="start"></wa-icon>
Mastodon
</wa-button>
<wa-button variant="brand" href="https://www.threads.com/@web.awesome" rel="noopener noreferrer" target="_blank">
<wa-icon name="threads" family="brands" slot="start"></wa-icon>
Threads
</wa-button>
</div>

View File

@@ -296,6 +296,7 @@ Then use the following syntax for comments so they appear in the generated docs.
* @cssproperty --color: The component's text color.
* @cssproperty --background-color: The component's background color.
*/
@customElement('wa-example')
export default class WaExample {
// ...
}
@@ -396,7 +397,7 @@ Guidelines for writing tests:
### Running tests
Right now, tests run both "hydrated" (SSR -> client hydrated) and "client only". If you're debugging only one specific kind you can set an environment variable. For example, to run only the client tests, you can do:
Right now, tests run both "hydrated" (SSR client hydrated) and "client only". If you're debugging only one specific kind you can set an environment variable. For example, to run only the client tests, you can do:
```bash
CSR_ONLY="true" npm run test

View File

@@ -59,7 +59,6 @@ Color is organized by three main categories:
- [Foundational colors](#foundational-colors) that lay the groundwork for your theme
- [Semantic colors](#semantic-colors) that draw attention and convey meaning
## Color Scales
Color scales are determined by your [color palette](/docs/color-palettes) and are made up of the lowest level color tokens in your theme. Each token is identified by a name, like red or gray, and numerical tint based on the color's lightness. On this scale, 100 is equal to pure white and 0 is equal to pure black.
@@ -73,6 +72,7 @@ You can use these tints to ensure accessible color contrast per [WCAG 2.1 succes
You have several hand-crafted [color palettes](/docs/color-palettes) to choose from. Each palette defines 10 hues each with a scale of 11 tints using the format `--wa-color-{hue}-{tint}`.
{% for hue in ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'indigo', 'purple', 'pink', 'gray'] -%}
<div class="color-name">{{ hue | capitalize }}</div>
<ul class="color-group">
{% for tint in ['95', '90', '80', '70', '60', '50', '40', '30', '20', '10', '05'] -%}
@@ -91,6 +91,7 @@ You have several hand-crafted [color palettes](/docs/color-palettes) to choose f
Any hue can be mapped to `brand`, `neutral`, `success`, `warning`, and `danger` scales. Like the tokens in a color scale, each token is identified by its semantic group and a numerical tint using the format `--wa-color-{group}-{tint}`.
{% for group in ['brand', 'neutral', 'success', 'warning', 'danger'] -%}
<div class="color-name">{{ group | capitalize }}</div>
<ul class="color-group">
{% for tint in ['95', '90', '80', '70', '60', '50', '40', '30', '20', '10', '05'] -%}
@@ -112,19 +113,19 @@ Foundational colors lay the groundwork for the content and structure of your pro
Surfaces are background layers that other content rests on. Surface colors help convey hierarchy through a sense of elevation, where `--wa-color-surface-raised` is the closest to the user (e.g., dialogs and popup menus) and `--wa-color-surface-lowered` is the farthest away (e.g., wells).
| Custom Property | Preview |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `--wa-color-surface-raised` | <div class="swatch" style="background-color: var(--wa-color-surface-raised); box-shadow:var(--wa-shadow-s)"></div> |
| `--wa-color-surface-default` | <div class="swatch" style="background-color: var(--wa-color-surface-default)"></div> |
| `--wa-color-surface-lowered` | <div class="swatch" style="background-color: var(--wa-color-surface-lowered); box-shadow: inset var(--wa-shadow-s)"></div> |
| `--wa-color-surface-border` | <div class="swatch" style="border-color: var(--wa-color-surface-border)"></div> |
| Custom Property | Preview |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `--wa-color-surface-raised` | <div class="swatch" style="background-color: var(--wa-color-surface-raised); box-shadow:var(--wa-shadow-s)"></div> |
| `--wa-color-surface-default` | <div class="swatch" style="background-color: var(--wa-color-surface-default)"></div> |
| `--wa-color-surface-lowered` | <div class="swatch" style="background-color: var(--wa-color-surface-lowered); box-shadow: inset var(--wa-shadow-s)"></div> |
| `--wa-color-surface-border` | <div class="swatch" style="border-color: var(--wa-color-surface-border)"></div> |
### Text
Text colors are used for standard text elements. We recommend a minimum 4.5:1 contrast ratio between text colors and surface colors.
| Custom Property | Preview |
| ------------------------ | ---------------------------------------------------------- |
| Custom Property | Preview |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `--wa-color-text-normal` | <div class="swatch" value="--wa-color-text-normal" style="color: var(--wa-color-text-normal); display: inline-block;">AaBb</div> |
| `--wa-color-text-quiet` | <div class="swatch" value="--wa-color-text-normal" style="color: var(--wa-color-text-quiet); display: inline-block;">AaBb</div> |
| `--wa-color-text-link` | <div class="swatch" value="--wa-color-text-normal" style="color: var(--wa-color-text-link); display: inline-block;">AaBb</div> |
@@ -153,23 +154,23 @@ This is used alongside other [shadow tokens](/docs/tokens/shadows) to construct
Web Awesome uses a single focus color for predictable keyboard navigation. This is used alongside other [focus tokens](/docs/tokens/focus) to construct `--wa-focus-ring`. We recommend a minimum 3:1 contrast ratio against surface colors and background colors wherever possible.
| Custom Property | Preview |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| Custom Property | Preview |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `--wa-color-focus` | <div class="swatch" value="--wa-color-focus" style="outline: var(--wa-focus-ring-style) var(--wa-focus-ring-width) var(--wa-color-focus)"></div> |
#### Hover and Active
Web Awesome leverages `color-mix()` to achieve consistent hover and active states across components without the need for untold numbers of handpicked colors. Through `color-mix()`, these custom properties contextually generate hover and active colors based on the color of the component.
| Custom Property | Preview |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------- |
| `--wa-color-mix-hover` | <div class="swatch color-mix-example" value="--wa-color-mix-hover" style="--mix-color: var(--wa-color-mix-hover)"><small>mixed</small></div> |
| Custom Property | Preview |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `--wa-color-mix-hover` | <div class="swatch color-mix-example" value="--wa-color-mix-hover" style="--mix-color: var(--wa-color-mix-hover)"><small>mixed</small></div> |
| `--wa-color-mix-active` | <div class="swatch color-mix-example" value="--wa-color-mix-active" style="--mix-color: var(--wa-color-mix-active)"><small>mixed</small></div> |
## Semantic Colors
Semantic colors reinforce a specific message, intended usage, or expected results through familiar, meaningful hues. Each color is identified by its semantic group, role, and attention using the format `--wa-color-{group}-{role}-{attention}`. There are five groups of semantic colors:
- **Brand** to emphasize your brand color
- **Success** for validity or confirmation
- **Neutral** for ordinary or inactive content
@@ -177,16 +178,19 @@ Semantic colors reinforce a specific message, intended usage, or expected result
- **Danger** for errors or risk
Each group defines colors for specific roles so that colors can be easily assembled with predictable results and readable contrast. There are three roles:
- **Fill** for background colors or areas larger than a few pixels
- **Border** for borders, dividers, and other stroke-width elements
- **On** for content displayed on a fill (e.g., pair `--wa-color-danger-on-loud` with `--wa-color-danger-fill-loud`)
Finally, each color is named according to how much attention it draws. Here, we use noise as an analogy: a loud noise draws more attention than a quiet one. There are three levels of attention:
- **Quiet** draws the least attention
- **Normal** draws some attention
- **Loud** draws the most attention
{% set variants = ['brand', 'success', 'neutral', 'warning', 'danger'] %}
<table>
<thead>
<tr>

View File

@@ -174,3 +174,54 @@ This time we see an empty string, which means the boolean attribute is now prese
:::info
To wait for multiple components to update, you can use `requestAnimationFrame()` instead of awaiting each element.
:::
## Code Completion
### VS Code
Web Awesome ships with a file called `vscode.html-custom-data.json` that can be used to describe its custom elements to [Visual Studio Code](https://code.visualstudio.com/). This enables code completion for Web Awesome components (also known as “code hinting” or “IntelliSense”). To enable it, you need to tell VS Code where the file is.
1. [Install Web Awesome locally](/docs/#installing-via-npm)
2. If it doesnt already exist, create a folder called `.vscode` at the root of your project
3. If it doesnt already exist, create a file inside that folder called `settings.json`
4. Add the following to the file
```json
{
"html.customData": ["./node_modules/@awesome.me/webawesome/dist/vscode.html-custom-data.json"]
}
```
If `settings.json` already exists, simply add the above line to the root of the object. Note that you may need to restart VS Code for the changes to take effect.
If you are using WebAwesome through the [CDN](/docs/#quick-start-autoloading-via-cdn) you can manually [download the file]({% cdnUrl 'vscode.html-custom-data.json' %}]({% cdnUrl 'vscode.html-custom-data.json' %}) instead.
### JetBrains IDEs
If you are using a [JetBrains IDE](https://www.jetbrains.com/) and you are installing Web Awesome from NPM, the editor will automatically detect the web-types.json file from the package and you should immediately see component information in your editor.
If you are installing from the CDN, you can [download a local copy]({% cdnUrl 'web-types.json' %}) and add it to the root of your project. Be sure to add a reference to the web-types.json file in your package.json in order for your editor to properly detect it.
```json
{
...
"web-types": "./web-types.json"
...
}
```
If you are using types from multiple projects, you can add an array of references.
```json
{
...
"web-types": [
...,
"./web-types.json"
]
...
}
```
### Other Editors
Most popular editors support custom code completion with a bit of configuration. Please [submit a feature request](https://github.com/shoelace-style/webawesome/issues/new/choose) for your editor of choice. PRs are also welcome!

View File

@@ -20,7 +20,7 @@ tags: layoutUtilities
}
</style>
Web Awesome includes classes to set the `align-items` property of flex and grid containers. They can be used alongside other Web Awesome layout utilities, like [cluster](/docs/layout/cluster) and [stack](/docs/layout/stack), to align children in container on the container's cross axis.
Web Awesome includes classes to set the `align-items` property of flex and grid containers. They can be used alongside other Web Awesome layout utilities, like [cluster](/docs/utilities/cluster) and [stack](/docs/utilities/stack), to align children in container on the container's cross axis.
| Class Name | `align-items` Value | Preview |
| ------------------------- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |

View File

@@ -7,7 +7,7 @@ tags: styleUtilities
Often, components are shown before their logic and styles have had a chance to load, also known as a [Flash of Undefined Custom Elements](https://www.abeautifulsite.net/posts/flash-of-undefined-custom-elements/).
The FOUCE style utility (which is automatically applied if you use our [style utilities](/docs/utilities/)) automatically takes care of hiding custom elements until **both they and their contents** have been registered, up to a maximum of two seconds.
The FOUCE style utility takes care of hiding custom elements until **both they and their contents** have been registered, up to a maximum of two seconds.
In many cases, this is not enough, and you may wish to hide a broader wrapper element or even the entire page until all WA elements within it have loaded.
To do that, you can add the `wa-cloak` class to any element on the page or even apply it to the whole page by placing the class on the `<html>` element:

View File

@@ -43,6 +43,63 @@ Adding a label may seem redundant at times, but they're very helpful for unsight
</wa-card>
```
### Visually Hidden Input Parts
Sometimes you want a form control to have a cleaner, more minimal appearance by hiding the `label` or `hint` visually. However, removing these elements entirely would make the form inaccessible to users with assistive devices.
Instead, you can hide them visually while keeping them available to screen readers by adding the `wa-visually-hidden-label` or `wa-visually-hidden-hint` class.
```html {.example}
<wa-input
label="Search Articles"
type="search"
placeholder="Search for..."
class="wa-visually-hidden-label"
style="margin-block-end: 1rem;"
>
<wa-icon slot="start" name="magnifying-glass" variant="regular"></wa-icon>
</wa-input>
<wa-input
label="Phone Number"
type="tel"
hint="We'll send you a verification code"
placeholder="(555) 867-5309"
class="wa-visually-hidden-hint"
style="margin-block-end: 1rem;"
>
<wa-icon slot="start" name="phone" variant="regular"></wa-icon>
</wa-input>
<wa-select
label="Country"
hint="Select your country for shipping calculations"
class="wa-visually-hidden-hint"
style="margin-block-end: 1rem;"
>
<wa-option value="us">United States</wa-option>
<wa-option value="ca">Canada</wa-option>
<wa-option value="mx">Mexico</wa-option>
<wa-option value="uk">United Kingdom</wa-option>
<wa-option value="de">Germany</wa-option>
<wa-option value="fr">France</wa-option>
<wa-option value="wakanda">Wakanda</wa-option>
<wa-option value="genovia">Genovia</wa-option>
<wa-option value="elbonia">Elbonia</wa-option>
<wa-icon slot="start" name="globe" variant="regular"></wa-icon>
</wa-select>
<wa-input
label="Email Address"
type="email"
hint="We'll never share your email or secret identity"
placeholder="e.g. miles.morales@brooklynvisions.edu"
class="wa-visually-hidden-label wa-visually-hidden-hint"
>
<wa-icon slot="start" name="envelope" variant="regular"></wa-icon>
</wa-input>
```
### Force Visually Hidden
There are cases where you want to _always_ visually hide certain content, even when it's focused.

View File

@@ -257,11 +257,22 @@ layout: page
{% if currentUser.hasPro %}
<span style="text-align: center; width: 100%; font-size: var(--wa-font-size-l);">Thanks for being a Web Awesome Pro subscriber!</span>
{% else %}
<span><em>Psst!</em> You can pre-order Web Awesome Pro at a low, guaranteed-for-life price &mdash; but not for long. Get in while the gettins good.</span>
<wa-button class="wa-dark" size="small" href="https://www.kickstarter.com/projects/fontawesome/web-awesome">
<wa-icon slot="start" name="person-running"></wa-icon>
Pre-order WA Pro
</wa-button>
{% if App.flags.stripeEnabled %}
<div class="wa-stack wa-gap-xs">
<h3 class="wa-heading-s">Get More with Web Awesome Pro!</h3>
<p>Unlock Pro-only themes, components, patterns, and great services like the Theme Builder.</p>
</div>
<wa-button class="wa-dark" size="small" href="/purchase">
<wa-icon slot="start" name="rocket-launch"></wa-icon>
Purchase Pro
</wa-button>
{% else %}
<span><em>Psst!</em> You can pre-order Web Awesome Pro at a low, guaranteed-for-life price &mdash; but not for long. Get in while the gettins good.</span>
<wa-button class="wa-dark" size="small" href="https://www.kickstarter.com/projects/fontawesome/web-awesome">
<wa-icon slot="start" name="person-running"></wa-icon>
Pre-order WA Pro
</wa-button>
{% endif %}
{% endif %}
{% endraw %}
</div>
@@ -385,7 +396,7 @@ layout: page
<wa-icon name="hashtag" style="color: var(--wa-brand-orange);"></wa-icon>
<span>Stay in the know</span>
</h2>
<div class="wa-grid">
<div class="wa-grid" style="--min-column-size: 30ch;">
<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">
@@ -395,6 +406,15 @@ layout: page
<wa-icon name="arrow-up-right"></wa-icon>
</div>
</wa-button>
<wa-button href="https://mastodon.social/@webawesome" rel="noopener noreferrer" target="_blank" appearance="filled" class="tile">
<div class="wa-split">
<div class="wa-cluster icon-heading">
<wa-icon family="brands" name="mastodon"></wa-icon>
<h3>Mastodon</h3>
</div>
<wa-icon name="arrow-up-right"></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">

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.6",
"homepage": "https://webawesome.com/",
"author": "Web Awesome",
"license": "MIT",
@@ -29,7 +29,8 @@
"./dist/react": "./dist/react/index.js",
"./dist/react/*": "./dist/react/*",
"./dist/translations": "./dist/translations",
"./dist/translations/*": "./dist/translations/*"
"./dist/translations/*": "./dist/translations/*",
"./package.json": "./package.json"
},
"files": [
"README.md",
@@ -72,7 +73,7 @@
"node": ">=14.17.0"
},
"dependencies": {
"@ctrl/tinycolor": "^4.1.0",
"@ctrl/tinycolor": "4.1.0",
"@floating-ui/dom": "^1.6.13",
"@lit/react": "^1.0.8",
"@shoelace-style/animations": "^1.2.0",
@@ -80,8 +81,7 @@
"composed-offset-position": "^0.0.6",
"lit": "^3.2.1",
"nanoid": "^5.1.5",
"qr-creator": "^1.0.0",
"style-observer": "^0.0.7"
"qr-creator": "^1.0.0"
},
"lint-staged": {
"*.{ts,js}": [
@@ -89,6 +89,7 @@
]
},
"devDependencies": {
"@wc-toolkit/jsx-types": "^1.3.0"
"@wc-toolkit/jsx-types": "^1.3.0",
"eleventy-plugin-git-commit-date": "^0.1.3"
}
}

View File

@@ -123,6 +123,7 @@ export async function build(options = {}) {
function generateReactWrappers() {
// Used by webawesome-app to make re-rendering not miserable with extra React file generation.
if (process.env.SKIP_SLOW_STEPS === 'true') {
spinner.info('Skipping React Wrapper generation.');
return Promise.resolve();
}
@@ -162,6 +163,7 @@ export async function build(options = {}) {
async function generateTypes() {
// Used by webawesome-app to make re-rendering not miserable with extra TS compilations.
if (process.env.SKIP_SLOW_STEPS === 'true') {
spinner.info('Skipping TypeScript compiler.');
return Promise.resolve();
}

View File

@@ -178,6 +178,10 @@
aspect-ratio: 1;
}
.button.is-icon-button:has(wa-icon) {
width: auto;
}
/* Pill modifier */
:host([pill]) .button {
border-radius: var(--wa-border-radius-pill);
@@ -258,7 +262,7 @@ wa-icon[part~='caret'] {
* Badges
*/
button ::slotted(wa-badge) {
.button ::slotted(wa-badge) {
border-color: var(--wa-color-surface-default);
position: absolute;
inset-block-start: 0;

View File

@@ -11,6 +11,7 @@ import sizeStyles from '../../styles/utilities/size.css';
import variantStyles from '../../styles/utilities/variants.css';
import { LocalizeController } from '../../utilities/localize.js';
import '../icon/icon.js';
import type WaIcon from '../icon/icon.js';
import '../spinner/spinner.js';
import styles from './button.css';
@@ -175,22 +176,32 @@ export default class WaButton extends WebAwesomeFormAssociatedElement {
const nodes = this.labelSlot.assignedNodes({ flatten: true });
let hasIconLabel = false;
let hasIcon = false;
let text = '';
let hasText = false;
let hasOtherElements = false;
// If there's only an icon and no text, it's an icon button
// Check all slotted nodes
[...nodes].forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE && (node as HTMLElement).localName === 'wa-icon') {
hasIcon = true;
if (!hasIconLabel) hasIconLabel = (node as HTMLElement).hasAttribute('label');
}
if (node.nodeType === Node.ELEMENT_NODE) {
const element = node as HTMLElement;
// Concatenate text nodes
if (node.nodeType === Node.TEXT_NODE) {
text += node.textContent;
if (element.localName === 'wa-icon') {
hasIcon = true;
if (!hasIconLabel) hasIconLabel = (element as WaIcon).label !== undefined;
} else {
// Any other element type means it's not an icon button
hasOtherElements = true;
}
} else if (node.nodeType === Node.TEXT_NODE) {
// Check if text node has actual content
const text = node.textContent?.trim() || '';
if (text.length > 0) {
hasText = true;
}
}
});
this.isIconButton = text.trim() === '' && hasIcon;
// It's only an icon button if there's an icon and nothing else
this.isIconButton = hasIcon && !hasText && !hasOtherElements;
if (this.isIconButton && !hasIconLabel) {
console.warn(

View File

@@ -77,7 +77,9 @@
}
.header {
display: block;
display: flex;
align-items: center;
justify-content: space-between;
border-block-end-style: inherit;
border-block-end-color: var(--wa-color-surface-border);
border-block-end-width: var(--wa-panel-border-width);
@@ -90,7 +92,9 @@
}
.footer {
display: block;
display: flex;
align-items: center;
justify-content: space-between;
border-block-start-style: inherit;
border-block-start-color: var(--wa-color-surface-border);
border-block-start-width: var(--wa-panel-border-width);
@@ -102,3 +106,27 @@
:host(:not([with-media])) .media {
display: none;
}
/* Orientation Styles */
:host([orientation='horizontal']) {
flex-direction: row;
.media {
border-start-start-radius: var(--inner-border-radius);
border-end-start-radius: var(--inner-border-radius);
border-start-end-radius: 0;
object-fit: cover;
}
}
:host([orientation='horizontal']) ::slotted([slot='body']) {
display: block;
height: 100%;
margin: 0;
}
:host([orientation='horizontal']) ::slotted([slot='actions']) {
display: flex;
align-items: center;
padding: var(--spacing);
}

View File

@@ -15,6 +15,9 @@ import styles from './card.css';
* @slot header - An optional header for the card.
* @slot footer - An optional footer for the card.
* @slot media - An optional media section to render at the start of the card.
* @slot actions - An optional actions section to render at the end for the horizontal card.
* @slot header-actions - An optional actions section to render in the header of the vertical card.
* @slot footer-actions - An optional actions section to render in the footer of the vertical card.
*
* @csspart media - The container that wraps the card's media.
* @csspart header - The container that wraps the card's header.
@@ -42,6 +45,10 @@ export default class WaCard extends WebAwesomeElement {
/** Renders the card with a footer. Only needed for SSR, otherwise is automatically added. */
@property({ attribute: 'with-footer', type: Boolean, reflect: true }) withFooter = false;
/** Renders the card's orientation **/
@property({ reflect: true })
orientation: 'horizontal' | 'vertical' = 'vertical';
updated() {
// Enable the respective slots when detected
if (!this.withHeader && this.hasSlotController.test('header')) this.withHeader = true;
@@ -50,11 +57,27 @@ export default class WaCard extends WebAwesomeElement {
}
render() {
// Horizontal Orientation
if (this.orientation === 'horizontal') {
return html`
<slot name="media" part="media" class="media"></slot>
<slot part="body" class="body"></slot>
<slot name="actions" part="actions" class="actions"></slot>
`;
}
// Vertical Orientation
return html`
<slot name="media" part="media" class="media"></slot>
<slot name="header" part="header" class="header"></slot>
<header part="header" class="header">
<slot name="header"></slot>
<slot name="header-actions"></slot>
</header>
<slot part="body" class="body"></slot>
<slot name="footer" part="footer" class="footer"></slot>
<footer part="footer" class="footer">
<slot name="footer"></slot>
<slot name="footer-actions"></slot>
</footer>
`;
}
}

View File

@@ -1327,6 +1327,10 @@ export default class WaColorPicker extends WebAwesomeFormAssociatedElement {
distance="0"
skidding="0"
sync="width"
flip
flip-fallback-strategy="best-fit"
shift
shift-padding="10"
aria-disabled=${this.disabled ? 'true' : 'false'}
@wa-after-show=${this.handleAfterShow}
@wa-after-hide=${this.handleAfterHide}

View File

@@ -6,29 +6,6 @@
display: block;
}
:host summary {
display: flex;
align-items: center;
justify-content: space-between;
user-select: none;
-webkit-user-select: none;
cursor: pointer;
&::marker,
&::-webkit-details-marker {
display: none;
}
&:focus {
outline: none;
}
&:focus-visible {
outline: var(--wa-focus-ring);
outline-offset: calc(var(--spacing) + var(--wa-focus-ring-offset));
}
}
details {
display: block;
overflow-anchor: none;
@@ -77,15 +54,16 @@ details {
cursor: not-allowed;
}
:host summary {
summary {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--spacing);
padding: var(--spacing); /* Add padding here */
border-radius: calc(var(--wa-panel-border-radius) - var(--wa-panel-border-width));
user-select: none;
-webkit-user-select: none;
cursor: pointer;
padding: var(--spacing); /* Add padding here */
&::marker,
&::-webkit-details-marker {
@@ -98,10 +76,15 @@ details {
&:focus-visible {
outline: var(--wa-focus-ring);
outline-offset: calc(var(--spacing) + var(--wa-focus-ring-offset));
outline-offset: calc(var(--wa-panel-border-width) + var(--wa-focus-ring-offset));
}
}
:host([open]) summary {
border-end-start-radius: 0;
border-end-end-radius: 0;
}
/* 'Start' icon placement */
:host([icon-placement='start']) summary {
flex-direction: row-reverse;

View File

@@ -24,6 +24,13 @@ describe('<wa-details>', () => {
});
});
it('should reflect the name property', async () => {
const el = await fixture<WaDetails>(html`<wa-details></wa-details>`);
el.name = 'test';
await el.updateComplete;
expect(el.getAttribute('name')).to.equal('test');
});
it('should be visible with the open attribute', async () => {
const el = await fixture<WaDetails>(html`
<wa-details open>

View File

@@ -7,9 +7,10 @@ import { WaAfterShowEvent } from '../../events/after-show.js';
import { WaHideEvent } from '../../events/hide.js';
import { WaShowEvent } from '../../events/show.js';
import { animate, parseDuration } from '../../internal/animate.js';
import { getTargetElement, waitForEvent } from '../../internal/event.js';
import { waitForEvent } from '../../internal/event.js';
import { watch } from '../../internal/watch.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import { WebAwesomeFormAssociatedElement } from '../../internal/webawesome-form-associated-element.js';
import { LocalizeController } from '../../utilities/localize.js';
import '../icon/icon.js';
import styles from './details.css';
@@ -69,7 +70,7 @@ export default class WaDetails extends WebAwesomeElement {
@property() summary: string;
/** Groups related details elements. When one opens, others with the same name will close. */
@property() name: string;
@property({ reflect: true }) name: string;
/** Disables the details so it can't be toggled. */
@property({ type: Boolean, reflect: true }) disabled = false;
@@ -112,9 +113,27 @@ export default class WaDetails extends WebAwesomeElement {
}
private handleSummaryClick(event: MouseEvent) {
let targetElement = getTargetElement(event);
const eventPath = event.composedPath() as HTMLElement[];
if (targetElement?.closest('a, button, wa-button, input, wa-input, textarea, wa-textarea, select, wa-select')) {
// Check if any element in the path is interactive
const hasInteractiveElement = eventPath.some(element => {
if (!(element instanceof HTMLElement)) return false;
// Check native interactive elements
const tagName = element.tagName?.toLowerCase();
if (['a', 'button', 'input', 'textarea', 'select'].includes(tagName)) {
return true;
}
// Check for Web Awesome form controls
if (element instanceof WebAwesomeFormAssociatedElement) {
return !('disabled' in element) || !element.disabled;
}
return false;
});
if (hasInteractiveElement) {
// Let interactive elements handle their own clicks, fixes #309
return;
}

View File

@@ -111,6 +111,15 @@
padding: var(--spacing);
overflow: auto;
-webkit-overflow-scrolling: touch;
&:focus {
outline: none;
}
&:focus-visible {
outline: var(--wa-focus-ring);
outline-offset: var(--wa-focus-ring-offset);
}
}
.footer {

View File

@@ -37,6 +37,7 @@ import styles from './dialog.css';
* behavior such as data loss.
* @event wa-after-hide - Emitted after the dialog closes and all animations are complete.
*
* @csspart dialog - The dialog's internal `<dialog>` element.
* @csspart header - The dialog's header. This element wraps the title and header actions.
* @csspart header-actions - Optional actions to add to the header. Works best with `<wa-button>`.
* @csspart title - The dialog's title.
@@ -224,7 +225,7 @@ export default class WaDialog extends WebAwesomeElement {
<header part="header" class="header">
<h2 part="title" class="title" id="title">
<!-- If there's no label, use an invisible character to prevent the header from collapsing -->
<slot name="label"> ${this.label.length > 0 ? this.label : String.fromCharCode(65279)} </slot>
<slot name="label"> ${this.label.length > 0 ? this.label : String.fromCharCode(8203)} </slot>
</h2>
<div part="header-actions" class="header-actions">
<slot name="header-actions"></slot>

View File

@@ -175,6 +175,15 @@
padding: var(--spacing);
overflow: auto;
-webkit-overflow-scrolling: touch;
&:focus {
outline: none;
}
&:focus-visible {
outline: var(--wa-focus-ring);
outline-offset: var(--wa-focus-ring-offset);
}
}
.footer {

View File

@@ -38,6 +38,7 @@ import styles from './drawer.css';
* the drawer has been closed programmatically. Avoid using this unless closing the drawer will result in destructive
* behavior such as data loss.
*
* @csspart dialog - The drawer's internal `<dialog>` element.
* @csspart header - The drawer's header. This element wraps the title and header actions.
* @csspart header-actions - Optional actions to add to the header. Works best with `<wa-button>`.
* @csspart title - The drawer's title.
@@ -241,7 +242,7 @@ export default class WaDrawer extends WebAwesomeElement {
<header part="header" class="header">
<h2 part="title" class="title" id="title">
<!-- If there's no label, use an invisible character to prevent the header from collapsing -->
<slot name="label"> ${this.label.length > 0 ? this.label : String.fromCharCode(65279)} </slot>
<slot name="label"> ${this.label.length > 0 ? this.label : String.fromCharCode(8203)} </slot>
</h2>
<div part="header-actions" class="header-actions">
<slot name="header-actions"></slot>

View File

@@ -66,23 +66,22 @@ export default class WaFormatDate extends WebAwesomeElement {
return undefined;
}
return html`
<time datetime=${date.toISOString()}>
${this.localize.date(date, {
weekday: this.weekday,
era: this.era,
year: this.year,
month: this.month,
day: this.day,
hour: this.hour,
minute: this.minute,
second: this.second,
timeZoneName: this.timeZoneName,
timeZone: this.timeZone,
hour12: hour12,
})}
</time>
`;
const displayDate = this.localize.date(date, {
weekday: this.weekday,
era: this.era,
year: this.year,
month: this.month,
day: this.day,
hour: this.hour,
minute: this.minute,
second: this.second,
timeZoneName: this.timeZoneName,
timeZone: this.timeZone,
hour12: hour12,
});
// No whitespace before or after
return html`<time datetime=${date.toISOString()}>${displayDate}</time>`;
}
}

View File

@@ -46,7 +46,7 @@ export default class WaIcon extends WebAwesomeElement {
@state() private svg: SVGElement | HTMLTemplateResult | null = null;
/** The name of the icon to draw. Available names depend on the icon library being used. */
@property() name?: string;
@property({ reflect: true }) name?: string;
/**
* The family of icons to choose from. For Font Awesome Free, valid options include `classic` and `brands`. For
@@ -54,17 +54,17 @@ export default class WaIcon extends WebAwesomeElement {
* A valid kit code must be present to show pro icons via CDN. You can set `<html data-fa-kit-code="...">` to provide
* one.
*/
@property() family: string;
@property({ reflect: true }) family: string;
/**
* The name of the icon's variant. For Font Awesome, valid options include `thin`, `light`, `regular`, and `solid` for
* the `classic` and `sharp` families. Some variants require a Font Awesome Pro subscription. Custom icon libraries
* may or may not use this property.
*/
@property() variant: string;
@property({ reflect: true }) 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;
@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;
@@ -82,7 +82,7 @@ export default class WaIcon extends WebAwesomeElement {
@property() label = '';
/** The name of a registered custom icon library. */
@property() library = 'default';
@property({ reflect: true }) library = 'default';
connectedCallback() {
super.connectedCallback();

View File

@@ -1,7 +1,7 @@
import { getKitCode } from '../../utilities/base-path.js';
import type { IconLibrary } from './library.js';
const FA_VERSION = '7.0.0';
const FA_VERSION = '7.0.1';
function getIconUrl(name: string, family: string, variant: string) {
const kitCode = getKitCode();

View File

@@ -372,7 +372,7 @@ export default class WaInput extends WebAwesomeFormAssociatedElement {
min=${ifDefined(this.min)}
max=${ifDefined(this.max)}
step=${ifDefined(this.step as number)}
.value=${live(this.value || '')}
.value=${live(this.value ?? '')}
autocapitalize=${ifDefined(this.autocapitalize)}
autocomplete=${ifDefined(this.autocomplete)}
autocorrect=${ifDefined(this.autocorrect)}

View File

@@ -0,0 +1,3 @@
:host {
display: contents;
}

View File

@@ -0,0 +1,9 @@
import { expect, fixture, html } from '@open-wc/testing';
describe('<wa-intersection-observer>', () => {
it('should render a component', async () => {
const el = await fixture(html` <wa-intersection-observer></wa-intersection-observer> `);
expect(el).to.exist;
});
});

View File

@@ -0,0 +1,200 @@
import { html } from 'lit';
import { customElement, property } from 'lit/decorators.js';
import { WaIntersectEvent } from '../../events/intersect.js';
import { clamp } from '../../internal/math.js';
import { parseSpaceDelimitedTokens } from '../../internal/parse.js';
import { watch } from '../../internal/watch.js';
import WebAwesomeElement from '../../internal/webawesome-element.js';
import styles from './intersection-observer.css';
/**
* @summary Tracks immediate child elements and fires events as they move in and out of view.
* @documentation https://webawesome.com/docs/components/intersection-observer
* @status stable
* @since 2.0
*
* @slot - Elements to track. Only immediate children of the host are monitored.
*
* @event {{ entry: IntersectionObserverEntry }} wa-intersect - Fired when a tracked element begins or ceases intersecting.
*/
@customElement('wa-intersection-observer')
export default class WaIntersectionObserver extends WebAwesomeElement {
static css = styles;
private intersectionObserver: IntersectionObserver | null = null;
private observedElements = new Map<Element, boolean>();
/** Element ID to define the viewport boundaries for tracked targets. */
@property() root: string | null = null;
/** Offset space around the root boundary. Accepts values like CSS margin syntax. */
@property({ attribute: 'root-margin' }) rootMargin = '0px';
/** One or more space-separated values representing visibility percentages that trigger the observer callback. */
@property() threshold = '0';
/**
* CSS class applied to elements during intersection. Automatically removed when elements leave
* the viewport, enabling pure CSS styling based on visibility state.
*/
@property({ attribute: 'intersect-class' }) intersectClass = '';
/** If enabled, observation ceases after initial intersection. */
@property({ type: Boolean, reflect: true }) once = false;
/** Deactivates the intersection observer functionality. */
@property({ type: Boolean, reflect: true }) disabled = false;
connectedCallback() {
super.connectedCallback();
if (!this.disabled) {
this.updateComplete.then(() => {
this.startObserver();
});
}
}
disconnectedCallback() {
super.disconnectedCallback();
this.stopObserver();
}
private handleSlotChange() {
if (!this.disabled) {
this.startObserver();
}
}
/** Converts threshold property string into numeric array. */
private parseThreshold(): number[] {
const tokens = parseSpaceDelimitedTokens(this.threshold);
return tokens.map((token: string) => {
const num = parseFloat(token);
return isNaN(num) ? 0 : clamp(num, 0, 1);
});
}
/** Locates and returns the root element using the specified ID. */
private resolveRoot(): Element | null {
if (!this.root) return null;
try {
const doc = this.getRootNode() as Document | ShadowRoot;
const target = doc.getElementById(this.root);
if (!target) {
console.warn(`Root element with ID "${this.root}" could not be found.`, this);
}
return target;
} catch {
console.warn(`Invalid selector for root: "${this.root}"`, this);
return null;
}
}
/** Initializes or reinitializes the intersection observer instance. */
private startObserver() {
this.stopObserver();
// Skip setup if functionality is disabled
if (this.disabled) return;
// Convert threshold string to numeric values
const threshold = this.parseThreshold();
// Locate the root boundary element
const rootElement = this.resolveRoot();
// Set up unified observer for all child elements
this.intersectionObserver = new IntersectionObserver(
entries => {
entries.forEach(entry => {
const wasIntersecting = this.observedElements.get(entry.target) ?? false;
const isIntersecting = entry.isIntersecting;
// Record current intersection state
this.observedElements.set(entry.target, isIntersecting);
// Toggle intersection class based on visibility
if (this.intersectClass) {
if (isIntersecting) {
entry.target.classList.add(this.intersectClass);
} else {
entry.target.classList.remove(this.intersectClass);
}
}
// Emit the intersection event
const changeEvent = new WaIntersectEvent({ entry });
this.dispatchEvent(changeEvent);
if (isIntersecting && !wasIntersecting) {
// When once mode is active, cease tracking after first intersection
if (this.once) {
this.intersectionObserver?.unobserve(entry.target);
this.observedElements.delete(entry.target);
}
}
});
},
{
root: rootElement,
rootMargin: this.rootMargin,
threshold,
},
);
// Begin tracking all immediate child elements
const slot = this.shadowRoot!.querySelector('slot');
if (slot !== null) {
const elements = slot.assignedElements({ flatten: true });
elements.forEach(element => {
this.intersectionObserver?.observe(element);
// Set initial non-intersecting state
this.observedElements.set(element, false);
});
}
}
/** Halts the intersection observer and cleans up. */
private stopObserver() {
// Clear intersection classes from all tracked elements before stopping
if (this.intersectClass) {
this.observedElements.forEach((_, element) => {
element.classList.remove(this.intersectClass);
});
}
this.intersectionObserver?.disconnect();
this.intersectionObserver = null;
this.observedElements.clear();
}
@watch('disabled', { waitUntilFirstUpdate: true })
handleDisabledChange() {
if (this.disabled) {
this.stopObserver();
} else {
this.startObserver();
}
}
@watch('root', { waitUntilFirstUpdate: true })
@watch('rootMargin', { waitUntilFirstUpdate: true })
@watch('threshold', { waitUntilFirstUpdate: true })
handleOptionsChange() {
this.startObserver();
}
render() {
return html` <slot @slotchange=${this.handleSlotChange}></slot> `;
}
}
declare global {
interface HTMLElementTagNameMap {
'wa-intersection-observer': WaIntersectionObserver;
}
}

View File

@@ -18,31 +18,19 @@
margin-inline-start: var(--wa-form-control-required-content-offset);
}
.button-group {
display: flex;
}
[part~='form-control-input'] {
display: flex;
flex-direction: column;
flex-wrap: wrap;
gap: 0.75em;
gap: 0; /* Radios handle their own spacing */
}
/* Horizontal */
:host([orientation='horizontal']) [part~='form-control-input'] {
flex-direction: row;
gap: 1em;
}
/* Help text */
[part~='hint'] {
margin-block-start: 0.5em;
}
/* Radios have the "button" appearance */
:host fieldset.has-radio-buttons {
[part~='form-control-input'] {
gap: 0;
}
}

View File

@@ -57,8 +57,6 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
private readonly hasSlotController = new HasSlotController(this, 'hint', 'label');
@state() hasRadioButtons = false;
@query('slot:not([name])') defaultSlot: HTMLSlotElement;
/**
@@ -197,11 +195,9 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
private async syncRadioElements() {
const radios = this.getAllRadios();
let hasRadioButtons = false;
// Add data attributes to support styling
// Set positioning data attributes and properties
radios.forEach((radio, index) => {
if (radio.appearance === 'button') hasRadioButtons = true;
radio.setAttribute('size', this.size);
radio.toggleAttribute('data-wa-radio-horizontal', this.orientation !== 'vertical');
radio.toggleAttribute('data-wa-radio-vertical', this.orientation === 'vertical');
@@ -213,9 +209,6 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
(radio as WaRadio).forceDisabled = this.disabled;
});
// If at least one radio button exists, we assume it's a radio button group
this.hasRadioButtons = hasRadioButtons;
await Promise.all(
radios.map(async radio => {
await radio.updateComplete;
@@ -349,7 +342,6 @@ export default class WaRadioGroup extends WebAwesomeFormAssociatedElement {
'form-control': true,
'form-control-radio-group': true,
'form-control-has-label': hasLabel,
'has-radio-buttons': this.hasRadioButtons,
})}
role="radiogroup"
aria-labelledby="label"

View File

@@ -31,6 +31,41 @@
margin-block-start: 0.5em;
}
/* Default spacing for default appearance radios */
:host([appearance='default']) {
margin-block: 0.375em; /* Half of the original 0.75em gap on each side */
}
:host([appearance='default'][data-wa-radio-horizontal]) {
margin-block: 0;
margin-inline: 0.5em; /* Half of the original 1em gap on each side */
}
/* Remove margin from first/last items to prevent extra space */
:host([appearance='default'][data-wa-radio-first]) {
margin-block-start: 0;
margin-inline-start: 0;
}
:host([appearance='default'][data-wa-radio-last]) {
margin-block-end: 0;
margin-inline-end: 0;
}
/* Button appearance have no spacing, they get handled by the overlap margins below */
:host([appearance='button']) {
margin: 0;
align-items: center;
min-height: var(--wa-form-control-height);
background-color: var(--wa-color-surface-default);
border: var(--wa-form-control-border-width) var(--wa-form-control-border-style) var(--wa-form-control-border-color);
border-radius: var(--wa-border-radius-m);
padding: 0 var(--wa-form-control-padding-inline);
transition:
background-color var(--wa-transition-fast),
border-color var(--wa-transition-fast);
}
/* Default appearance */
:host([appearance='default']) {
.control {
@@ -66,6 +101,13 @@
}
}
/* Button appearance */
:host([appearance='button']) {
.control {
display: none;
}
}
/* Checked */
:host(:state(checked)) .control {
color: var(--checked-icon-color);
@@ -85,23 +127,6 @@
cursor: not-allowed;
}
/* Button appearance */
:host([appearance='button']) {
align-items: center;
min-height: var(--wa-form-control-height);
background-color: var(--wa-color-surface-default);
border: var(--wa-form-control-border-width) var(--wa-form-control-border-style) var(--wa-form-control-border-color);
border-radius: var(--wa-border-radius-m);
padding: 0 var(--wa-form-control-padding-inline);
transition:
background-color var(--wa-transition-fast),
border-color var(--wa-transition-fast);
.control {
display: none;
}
}
/* Horizontal grouping - remove inner border radius */
:host([appearance='button'][data-wa-radio-horizontal][data-wa-radio-inner]) {
border-radius: 0;
@@ -153,7 +178,7 @@
outline-offset: var(--wa-focus-ring-offset);
}
/* Remove inner borders and handle overlap */
/* Button overlap margins */
:host([appearance='button'][data-wa-radio-horizontal]:not([data-wa-radio-first])) {
margin-inline-start: calc(-1 * var(--wa-form-control-border-width));
}

View File

@@ -111,7 +111,6 @@ export default class WaRadio extends WebAwesomeFormAssociatedElement {
// We override `setValue` because we don't want to set form values from here. We want to do that in "RadioGroup" itself.
}
// Update the handleClick method (around line 75)
private handleClick = () => {
if (!this.disabled && !this.forceDisabled) {
this.checked = true;

View File

@@ -99,7 +99,8 @@ export default class WaRelativeTime extends WebAwesomeElement {
this.updateTimeout = setTimeout(() => this.requestUpdate(), nextInterval);
}
return html` <time datetime=${this.isoTime}>${this.relativeTime}</time> `;
// No whitespace before or after
return html`<time datetime=${this.isoTime}>${this.relativeTime}</time>`;
}
}

View File

@@ -10,7 +10,6 @@
position: relative;
max-width: 100%;
isolation: isolate;
overflow: hidden;
}
:host([orientation='vertical']) {

View File

@@ -493,6 +493,10 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
this.displayInput.focus();
}
private handleComboboxClick(event: MouseEvent) {
event.preventDefault();
}
private handleComboboxMouseDown(event: MouseEvent) {
const path = event.composedPath();
const isButton = path.some(el => el instanceof Element && el.tagName.toLowerCase() === 'wa-button');
@@ -944,6 +948,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
slot="anchor"
@keydown=${this.handleComboboxKeyDown}
@mousedown=${this.handleComboboxMouseDown}
@click=${this.handleComboboxClick}
>
<slot part="start" name="start" class="start"></slot>

View File

@@ -317,9 +317,3 @@ declare global {
'wa-split-panel': WaSplitPanel;
}
}
declare global {
interface HTMLElementTagNameMap {
'wa-split-panel': WaSplitPanel;
}
}

View File

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

View File

@@ -64,7 +64,7 @@ function syncCheckboxes(changedTreeItem: WaTreeItem, initialSync = false) {
*
* @csspart base - The component's base wrapper.
*
* @cssproperty [--indent-size=var(--wa-spacing-m)] - The size of the indentation for nested items.
* @cssproperty [--indent-size=var(--wa-space-m)] - The size of the indentation for nested items.
* @cssproperty [--indent-guide-color=var(--wa-color-surface-border)] - The color of the indentation line.
* @cssproperty [--indent-guide-offset=0] - The amount of vertical spacing to leave between the top and bottom of the
* indentation line's starting position.

View File

@@ -11,6 +11,7 @@ export type { WaExpandEvent } from './expand.js';
export type { WaFinishEvent } from './finish.js';
export type { WaHideEvent } from './hide.js';
export type { WaHoverEvent } from './hover.js';
export type { WaIntersectEvent } from './intersect.js';
export type { WaInvalidEvent } from './invalid.js';
export type { WaLazyChangeEvent } from './lazy-change.js';
export type { WaLazyLoadEvent } from './lazy-load.js';

View File

@@ -0,0 +1,19 @@
/** Emitted when an element's intersection state changes. */
export class WaIntersectEvent extends Event {
readonly detail?: WaIntersectEventDetail;
constructor(detail?: WaIntersectEventDetail) {
super('wa-intersect', { bubbles: false, cancelable: false, composed: true });
this.detail = detail;
}
}
interface WaIntersectEventDetail {
entry?: IntersectionObserverEntry;
}
declare global {
interface GlobalEventHandlersEventMap {
'wa-intersect': WaIntersectEvent;
}
}

View File

@@ -2,7 +2,7 @@ export class WaSelectEvent extends Event {
readonly detail;
constructor(detail: WaSelectEventDetail) {
super('wa-select', { bubbles: true, cancelable: false, composed: true });
super('wa-select', { bubbles: true, cancelable: true, composed: true });
this.detail = detail;
}
}

View File

@@ -11,17 +11,3 @@ export function waitForEvent(el: HTMLElement, eventName: string) {
el.addEventListener(eventName, done);
});
}
export function getTargetElement(event: Event) {
if (event.target instanceof Node) {
switch (event.target.nodeType) {
case Node.TEXT_NODE:
case Node.COMMENT_NODE:
return event.target.parentNode as Element;
case Node.ELEMENT_NODE:
return event.target as Element;
}
}
return null;
}

View File

@@ -1,4 +1,5 @@
@import url('base.css');
@import url('../variants.css');
@layer wa-color-palette {
.wa-palette-bright {

View File

@@ -1,4 +1,5 @@
@import url('base.css');
@import url('../variants.css');
@layer wa-color-palette {
:where(:root),

View File

@@ -1,4 +1,5 @@
@import url('base.css');
@import url('../variants.css');
@layer wa-color-palette {
.wa-palette-shoelace,

View File

@@ -1,3 +1,6 @@
@import url('utilities/size.css');
@import url('utilities/variants.css');
@layer wa-native {
/* #region General ~~~~~~~~~~~~~~~~~~~~~~~~~ */
html {
@@ -407,6 +410,8 @@
padding: var(--wa-space-m);
border-radius: calc(var(--wa-panel-border-radius) - var(--wa-panel-border-width));
cursor: pointer;
user-select: none;
-webkit-user-select: none;
@@ -421,7 +426,7 @@
&:focus-visible {
outline: var(--wa-focus-ring);
outline-offset: var(--wa-focus-ring-offset);
outline-offset: calc(var(--wa-panel-border-width) + var(--wa-focus-ring-offset));
}
}
@@ -430,6 +435,9 @@
summary {
margin-inline: calc(-1 * var(--wa-space-m));
border-end-start-radius: 0;
border-end-end-radius: 0;
}
}

View File

@@ -1,4 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Crimson+Pro:ital,wght@0,200..900;1,200..900&family=Quicksand:wght@300..700&display=swap');
@import url('../color/palettes/bright.css'); /* To use this palette, add class="wa-palette-bright" to the <html> element */
@import url('https://fonts.bunny.net/css2?family=Crimson+Pro:ital,wght@0,200..900;1,200..900&family=Quicksand:wght@300..700&display=swap');
@layer wa-theme {
.wa-theme-awesome,

View File

@@ -1,5 +1,4 @@
@import url('../color/palettes/default.css');
@import url('../color/variants.css');
@layer wa-theme {
:where(:root),

View File

@@ -1,3 +1,5 @@
@import url('../color/palettes/shoelace.css'); /* To use this palette, add class="wa-palette-shoelace" to the <html> element */
@layer wa-theme {
.wa-theme-shoelace,
.wa-theme-shoelace.wa-light,

View File

@@ -1,6 +1,8 @@
@layer wa-utilities {
.wa-visually-hidden:not(:focus-within),
.wa-visually-hidden-force {
.wa-visually-hidden-force,
.wa-visually-hidden-hint::part(hint),
.wa-visually-hidden-label::part(label) {
position: absolute !important;
width: 1px !important;
height: 1px !important;

View File

@@ -0,0 +1,45 @@
import { registerTranslation } from '@shoelace-style/localize';
import type { Translation } from '../utilities/localize.js';
const translation: Translation = {
$code: 'kk',
$name: 'Қазақ',
$dir: 'ltr',
carousel: 'Карусель',
clearEntry: 'Жазбаны жою',
close: 'Жабу',
copied: 'Көшірілді',
copy: 'Көшіру',
currentValue: 'Қазіргі мән',
error: 'Қате',
goToSlide: (slide, count) => `${slide}/${count} слайдқа өту`,
hidePassword: 'Құпиясөзді жасыру',
loading: 'Жүктелуде',
nextSlide: 'Келесі слайд',
numOptionsSelected: num => {
if (num === 0) return 'Ештеңе таңдалмады';
if (num < 6 || num === 7) return `${num}-еу таңдалды`;
if (num === 6) return `${num}-ау таңдалды`;
return `${num} таңдалды`;
},
pauseAnimation: 'Анимацияны тоқтату',
playAnimation: 'Анимацияны ойнату',
previousSlide: 'Алдыңғы слайд',
progress: 'Прогресс',
remove: 'Жою',
resize: 'Өлшемін өзгерту',
scrollableRegion: 'Көтеру/түсіруге болатын аймақ (скролл)',
scrollToEnd: 'Соңына түсіру',
scrollToStart: 'Басына көтеру',
selectAColorFromTheScreen: 'Экраннан түсті таңдаңыз',
showPassword: 'Құпиясөзді көрсету',
slideNum: slide => `${slide}-слайд`,
toggleColorFormat: 'Түс пішімін ауыстыру',
zoomIn: 'Жақындату',
zoomOut: 'Алыстату',
};
registerTranslation(translation);
export default translation;

View File

@@ -1,5 +1,9 @@
#!/bin/bash
echo "Running the build!"
git clone "https://konnorrogers:$GITHUB_ACCESS_TOKEN@github.com/shoelace-style/webawesome-pro" packages/webawesome-pro
if [[ "$CLONE_PRO" != "false" ]]; then
git clone "https://konnorrogers:$GITHUB_ACCESS_TOKEN@github.com/shoelace-style/webawesome-pro" packages/webawesome-pro
fi
cd packages/webawesome-pro && npm run build