Compare commits

...

266 Commits

Author SHA1 Message Date
Lea Verou
3dc526c948 Support inheritance and initial values 2025-01-21 15:26:45 -05:00
Lea Verou
e3560dcf98 Do not reflect default values
- Add `default` descriptor
- Do not reflect attributes when equal to their default value
- Patch getter return value to return default value when empty
- Use it in button `appearance`
2025-01-21 15:16:11 -05:00
Cory LaViska
f2bb2c84a0 fix nested tab groups (#576) 2025-01-21 12:54:38 -05:00
Cory LaViska
13b3342017 fix slot names (#577) 2025-01-21 12:52:41 -05:00
Cory LaViska
d1c1d689ce ensure fix works on backers website (#579) 2025-01-21 12:36:54 -05:00
Cory LaViska
44e5e37a2b 3.0.0-alpha.9 2025-01-17 10:40:54 -05:00
Cory LaViska
566aae927d fix typo 2025-01-17 10:39:18 -05:00
Lea Verou
7258c001a7 Demo for mixing and matching (#565) 2025-01-17 10:38:03 -05:00
Lea Verou
7a70940c6a Update changelog, remove .wa-callout from alpha 2025-01-16 18:27:47 -05:00
Lea Verou
45f4edc426 Fix #561 2025-01-16 16:50:28 -05:00
Lea Verou
da32015f27 Basic mixing and matching docs (#560) 2025-01-16 16:31:24 -05:00
Lea Verou
03d8238edb Add missing :state(blank) docs 2025-01-16 16:17:50 -05:00
Lindsay M
34f8744493 Fix missing mild palette doc and links (#557) 2025-01-16 16:09:52 -05:00
Lindsay M
fa3fe5f753 Theme files housekeeping, closes #519 (#552)
* Reorg Glossy theme

* Reorg Playful theme

* Remove redundant dark mode tokens
2025-01-16 16:09:28 -05:00
Lindsay M
fc6c7de1fd Fix contrast issues with Bright teal (#556) 2025-01-16 16:09:03 -05:00
Lea Verou
0037712549 Matter Ripple MVP (#558)
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-01-16 16:05:50 -05:00
Lea Verou
5301945bfa Filled inputs 2025-01-16 14:48:56 -05:00
Lea Verou
1298651dd8 Floating labels on select 2025-01-16 14:48:56 -05:00
Lea Verou
5f9695fde1 Floating labels on textarea 2025-01-16 14:48:56 -05:00
Lea Verou
2eb2597efe Floating labels for input 2025-01-16 14:48:56 -05:00
lindsaym-fa
431e82261b Initial floating label attempt 2025-01-16 14:48:56 -05:00
Lea Verou
df51149d0a Show contrast ratios in contrast pair tables 2025-01-16 13:18:26 -05:00
Lindsay M
fba0b11343 Add Matter theme (#547)
* Add Matter theme

* Add Matter to alpha build

* Add changelog

* Fix incorrect palette name

* Make loud fills darker in light mode
2025-01-16 12:08:51 -05:00
Lea Verou
3618e93490 Reintroduce --border-width and --border-radius, fixes #531 2025-01-16 10:36:03 -05:00
Lea Verou
cfa95307d1 Quick proof of concept contrast tests 2025-01-16 10:22:01 -05:00
Lea Verou
15344c2a2a Appease Turbo for the color scheme picker too, fixes #520 2025-01-16 10:15:52 -05:00
lindsaym-fa
3974aa5130 Decrease line height on swatches 2025-01-16 10:15:16 -05:00
lindsaym-fa
a6702ad6d2 Revise Color tokens doc and link to palettes 2025-01-16 10:15:16 -05:00
lindsaym-fa
ecf21adddc Fix punctuation 2025-01-16 10:15:16 -05:00
Lea Verou
52c24fc3b7 Add color palette to theme pages 2025-01-16 10:15:16 -05:00
Lea Verou
d464714d7b Rudimentary palette icons 2025-01-16 10:15:16 -05:00
Lea Verou
7d089bbe2f Palette Docs 2025-01-16 10:15:16 -05:00
Lea Verou
71914afc91 defaultPalette -> palette 2025-01-16 10:15:16 -05:00
Lindsay M
9d139e3fa0 Minor style update for checkboxes in wa-tree-item (#542)
* Use theme value line height for tree item checkbox

* Apply theme checkbox styles to selected tree items
2025-01-16 09:30:35 -05:00
Lindsay M
db3039e9fe Fix green-40 in classic color palette (#548) 2025-01-16 09:26:06 -05:00
Lindsay M
9494b9bb67 Improve default tooltip styles (#543)
* Use inverted colors for tooltips

* Remove redundant tooltip overrides from themes
2025-01-16 04:35:08 -05:00
Lea Verou
7e1f4f0351 Separate meaningful theme parts out (#526)
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-01-15 17:32:36 -05:00
Lindsay M
5ebe4f4d3e Finalize playful theme, closes #490 (#527)
* Finalize Playful theme

* Add changelog, add to alpha

* Add playful theme to alpha build

* Touchup and tweaks

* Tweak hover mix color in `wa-dark`

* Avoid transforming buttons in button groups

* Final touchup

---------

Co-authored-by: Lea Verou <lea@verou.me>
2025-01-15 17:13:48 -05:00
Lea Verou
dfb9d53a25 Checkbox improvements
- Added `part="control", fixes #529
- Removed wrapper div which is no longer needed
- Removed `form-control--has-hint` class which is no longer used anywhere
2025-01-15 15:03:58 -05:00
Lindsay M
c2c1a2ff5b Add missing Glossy and Premium themes to alpha build (#528) 2025-01-15 10:45:43 -05:00
Lindsay M
ac86c037a1 Finalize Glossy theme, closes #491 (#525)
* Initial glassy theme progress

* Add fallback to slider thumb box shadow

* Remove redundant `wa-dark` styles and refactor shadows

* Rename to 'Glossy' since it fits the vibe better
2025-01-14 18:44:31 -05:00
Lea Verou
6b07c9a040 Native callout (#513)
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-01-14 14:56:03 -05:00
Lea Verou
24a76f6a7c Color palette housekeeping (#523) 2025-01-14 14:54:34 -05:00
Lea Verou
89c0667e9c Improve maintainability of color docs 2025-01-14 14:44:30 -05:00
Lea Verou
434084ea4e Playful: refer to rudimentary palette 2025-01-14 14:32:39 -05:00
Lea Verou
1738c6345b Fix #514 for reals this time 2025-01-14 13:02:37 -05:00
Lea Verou
0ac7916a1b Attempt to fix #514 2025-01-14 13:02:37 -05:00
Lea Verou
e7979991e3 Update docs to lean into the "tokens" terminology in lieu of "properties"
Co-Authored-By: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2025-01-14 12:31:24 -05:00
Lea Verou
07f70098f8 Theming -> Design Tokens 2025-01-14 12:31:24 -05:00
Lindsay M
17146698db Finalize Premium theme, closes #489 (#510)
* Finalize Premium theme

* Improve theme compatibility of dark mode shadows

* Improve theme compatibility of code examples

* Add comments

* Revert dark mode shadow color changes (to be addressed separately)

* Revert dark mode shadow color change

* Clean up redundant `wa-dark` properties
2025-01-14 11:56:30 -05:00
Lea Verou
bf852b1296 Fix #515 2025-01-14 11:29:36 -05:00
Lea Verou
e367c0ef29 Open sidebar group on overview pages, fixes #507 2025-01-14 10:20:04 -05:00
Lea Verou
01210ef364 Implement .wa-invert, closes #497 (#508) 2025-01-14 10:04:27 -05:00
Lea Verou
40648e15fb Refactor: library.system.ts to export supported icons (#505) 2025-01-13 16:37:54 -05:00
Cory LaViska
ab67ecfad3 add native icon to search (#498) 2025-01-13 14:48:51 -05:00
Lea Verou
a07f6280a3 Themes category in docs (#477)
Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-01-13 13:14:12 -05:00
Lea Verou
6822b25772 Rewrite color scheme logic (#481)
- Minimize needless swaps
- Centralize logic
- Use an actual `<wa-select>` rather than hacking it with `<wa-dropdown>`
- Move shared includes to shared template
- Rewrite critical theme JS
- Refactor of theme picker code
- Utilize view transitions better and use them for color scheme too
- Do not store default value in localStorage
- Removed unused `*-wide` templates
- Fixed #482
2025-01-10 15:32:28 -05:00
Konnor Rogers
200188b0c3 properly report build failures (#485)
* properly report build failures

* prettier
2025-01-10 13:29:14 -05:00
Lea Verou
bc6fe95f13 npm run build:alpha:serve per @KonnorRogers suggestion 2025-01-10 13:13:01 -05:00
Lea Verou
3a33fa208a Add command for testing the build without having to push to Vercel 2025-01-10 13:13:01 -05:00
Lea Verou
3ec4e6de07 Fix build 2025-01-10 13:13:01 -05:00
Lea Verou
eb07dc1410 Use passthrough copy (#474) 2025-01-09 17:24:18 -05:00
Lindsay M
5bfeb8044e Theme showcase improvements (#480)
* Presentation improvements

* Change `-webkit-text-size-adjust` to supported value (`none` isn't a supported keyword on iOS)

* Try using `text-size-adjust`

* Throwing caution to the wind

* Give up on `text-size-adjust` and add 1-column view
2025-01-09 13:31:31 -05:00
lindsaym-fa
aa915c3e28 Doc revisions 2025-01-09 11:57:35 -05:00
Lea Verou
c79457a607 Attempt at better style isolation between themes
Still doesn't quite fix #475 but might be a nudge in the right direction.
2025-01-09 11:57:35 -05:00
Lea Verou
419f0610e4 Template-tweaks
- Move breadcrumbs to separate template
- Rename `beforeContent` to `header`
- Move breadcrumbs inside header
2025-01-09 02:26:01 -05:00
Cory LaViska
7ab5ca8640 3.0.0-alpha.8 2025-01-08 18:30:48 -05:00
Cory LaViska
c39faff936 update version (#473) 2025-01-08 18:17:31 -05:00
Lindsay M
6d31db57f6 Revise and add showcase to Themes doc (#456)
* Initial progress

* Make responsive

* quick fix to show theme name/description

* Small styling tweaks

* Documentation updates

* Revisions and improvements

* Avoid using static URLs 'cause that's ridiculous

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-01-08 17:33:09 -05:00
Lea Verou
21ed4f82b0 Improve UX of Layout section 2025-01-08 17:13:38 -05:00
Lea Verou
844e374a72 Fix #470 2025-01-08 16:23:34 -05:00
Lea Verou
e5f4c14608 Fix native select caret positioning, fixes #411 2025-01-08 15:58:33 -05:00
Lea Verou
1ad963f5ad wa-card styling fixes 2025-01-08 15:36:12 -05:00
Lea Verou
4476117932 Add default layout as a failsafe 2025-01-08 15:20:26 -05:00
Lindsay M
e52a7a5ce5 Pre-release theme touchup (#465)
* Fix themed card styles

* Improve lowered surface colors across themes
2025-01-08 15:04:27 -05:00
Lindsay M
fa66f4262d Fix mobile theme selector; fixes #440 (#446)
* Fix styling

* Fix mobile theme selector label
2025-01-08 15:01:20 -05:00
Lea Verou
a87f3627bb Fix #451 without changing logic/specificity 2025-01-08 15:00:45 -05:00
Cory LaViska
06e432589f change migration => tailspin (#463) 2025-01-08 13:59:27 -05:00
Cory LaViska
b4c4074ae1 fix mobile color picker bug (#462) 2025-01-08 13:49:57 -05:00
Lea Verou
19042fcca4 Decouple dark mode & theme, fixes #445 closes #385 (#457)
Co-authored-by: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2025-01-08 12:50:29 -05:00
Lea Verou
8541369ae1 Fix #437 regression (#458) 2025-01-08 12:33:19 -05:00
Kelsey Jackson
31cfdf5704 Fixed radio button styling regression (#443)
* fixed styling regression

* Import missing appearance utilities

* Fix up radio button theme styles

* tweaked based on feedback

---------

Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-01-08 12:07:28 -05:00
Lindsay M
3511a60b93 Fix missing select styles, improve consistency (#450)
* Refactor for consistency, fix missing theme styles

* Remove unused custom properties from docs

* Add missing custom property to docs

* Add UI test case
2025-01-08 12:04:22 -05:00
Lindsay M
e55e091192 Fix caret color on slider tooltips (#448) 2025-01-08 12:03:16 -05:00
Lindsay M
09df23dff8 Use theme properties for color picker border (#449) 2025-01-08 10:02:18 -05:00
Lea Verou
f4a88c3b3a Harmonize updated() definitions
- Use proper type
- Use same argument name
- Ensure `super.updated()` is called
2025-01-07 17:39:56 -05:00
Cory LaViska
559efcd1d2 Fix switch's submitted value; fixes #409 (#442)
* fix switch's submitted value; fixes #409

* update tests
2025-01-07 17:01:27 -05:00
Lindsay M
e046015ed5 Theme cleanup (#414)
* formatting, docs tweaks

* FA theme cleanup

* Revert removal of `--wa-form-control-height-*`

* Classic theme cleanup

* Use consistent selectors for dark mode

* Clean slate for additional themes

* Retire depth stylesheets

* Move header styles for themer out of themes

* Missed instance of dark mode selector

* Migration theme cleanup

* Brutalist theme cleanup

* Changelog for new themes

* Playful theme cleanup

* Formatting

* Default theme update

* Add tests for form theming

* Fix test typo

* Change misnamed `multiplier` properties to `scale`

* Active theme cleanup

* Mellow theme cleanup

* Cleanup unused FA styles

* Glassy theme progress

* Add checked styles to glassy

* Fix typo

* Final FA theme cleanup

* Rename FA theme to 'Awesome', allow in alpha

* Final brutalist theme cleanup

* A few more brutalist tweaks

* One last brutalist tweak

* Final mellow theme cleanup

* Final Tailwind theme cleanup

* Final active theme cleanup

* Some classic theme cleanup

* Remove unused `--wa-form-control-height-*`

* Rename `--wa-form-control-resting-color` to `border-color`

* Touch up callout `appearance` styles

* Add more themes to alpha

* Add changelog for removal of `--wa-form-control-height-*`

* Clean up colors

* Final classic theme cleanup

* Add new themes to alpha build

* Re-add teal (used by Awesome theme)

* sync mobile/desktop theme pickers and don't dup IDs

* Remove `color/standard.css` (duplicates `/themes/default/color.css`)

* add view transition

* Add premium theme for later cleanup

* Accommodate new tag `appearance` styles

* Revise `--wa-form-control-height-*` changelog entry

Co-authored-by: Lea Verou <lea@verou.me>

* Improve `--wa-border-width-scale` description

Co-authored-by: Lea Verou <lea@verou.me>

* Better border docs

* Premium tweaks

---------

Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
Co-authored-by: Lea Verou <lea@verou.me>
2025-01-07 15:41:57 -05:00
Lea Verou
44dbdd14cc Separate WebAwesomeFormAssociatedElement (and friends) into a separate file 2025-01-07 14:23:20 -05:00
lindsaym-fa
5e3fed605e Add changelog 2025-01-07 11:56:19 -05:00
Lea Verou
4b4f2247c5 [Tag] Add appearance, closes #435 2025-01-07 11:56:19 -05:00
Lea Verou
eca15dc7fc Revamp <wa-card> HTML & CSS, fix #431 (#433)
Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
2025-01-07 10:12:32 -05:00
Lea Verou
eca444bbaa [Callout] Add appearance & size, closes #422 (#432)
Co-authored-by: lindsaym-fa <dev@lindsaym.design>
2025-01-07 09:38:28 -05:00
Lea Verou
f39308dbc5 Allow customization of outlined styles, fixes #412 (#426) 2025-01-06 17:35:57 -05:00
Lea Verou
fc84e1a50d Replace M form control height with size-dependent height (#425) 2025-01-06 17:10:11 -05:00
Lea Verou
ef7d47e2b9 [Docs] Move commonalities across blocks to a single base layout (#424) 2025-01-06 17:01:29 -05:00
Lea Verou
a9af3172ad Rename Range to Slider (#428) 2025-01-06 16:44:43 -05:00
konnorrogers
cde8bea97a test commit 2025-01-06 13:24:54 -05:00
Kelsey Jackson
33b4045dad tweaked the tag component (#407)
* tweaked the tag component

* updated based on feedback

* updated to remove span

* changed display to initial

* prettier

---------

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>
2025-01-06 13:23:47 -05:00
Cory LaViska
bc4ad39f2e Fix tests (#410)
* skip broken test

* add middleware to follow new stylesheet imports

* fix avatar tests

* update badge tests

* fix button tests

* skip carousel test

* fix checkbox tests

* fix details test

* update radio button tests

* fix input tests

* fix progress bar tests

* update

* fix range tests

* fix select tests

* restore wrapper div to pass a11y tests

* fix switch tests

* fix tag tests

* fix textarea tests

* fix tooltip tests

* skips

* fix tree item tests

* [DRAFT]: test fixes (#421)

* working on some stuff..

* add a small delay for menu-item

* prettier

* add a small delay for menu-item

* prettier

* add a small delay for menu-item

* add a small delay for menu-item

* add a small delay for menu-item

* prettier

* Empty commit

* add a small delay for menu-item

* always build with alpha

* always build with alpha

* move to alpha builds

---------

Co-authored-by: Konnor Rogers <konnor5456@gmail.com>
2025-01-06 13:13:34 -05:00
Konnor Rogers
b868b1e8fc fix alpha builds (#423)
* fix alpha builds

* Update docs/_includes/sidebar-group.njk

Co-authored-by: Lea Verou <lea@verou.me>

* Update docs/_includes/sidebar-group.njk

Co-authored-by: Lea Verou <lea@verou.me>

---------

Co-authored-by: Lea Verou <lea@verou.me>
2025-01-06 12:53:47 -05:00
Lea Verou
e916d771b0 Ensure --box-shadow & --border-width defaults are always set on the root stylable element, fixes #419 2025-01-06 12:41:28 -05:00
lindsaym-fa
bd6fe74c7d Fix missing input value styles 2025-01-04 16:42:45 -05:00
Lea Verou
ac7437894a Automate all overviews, fix bugs with filtering 2025-01-03 20:17:19 -05:00
Lea Verou
55ebe6e20b Add e-commerce tag, for overview 2025-01-03 20:14:51 -05:00
Lea Verou
e6388e7671 Let sort filter provide missing values so we can specify large values to place elements at the end 2025-01-03 19:20:49 -05:00
Lea Verou
9a21ae6f52 Make sure unlisted page cards never show up 2025-01-03 19:02:31 -05:00
Lea Verou
cd3386ce78 Exclude unlisted pages properly 2025-01-03 18:51:16 -05:00
Lea Verou
26b9bbb515 Automate Theming listing 2025-01-03 18:44:11 -05:00
Lea Verou
bda0ec0313 Overviews don't need to be MD files
And having them as MD files can insert pointless `<p>` tags if we're not careful, which can cause weird bugs.
2025-01-03 18:27:07 -05:00
Lea Verou
2490fbeaca attr filter for nicer optional attributes 2025-01-03 18:12:41 -05:00
Lea Verou
297149021e Add {% markdown %} paired shortcode 2025-01-03 17:45:26 -05:00
Lea Verou
c700c3ec09 Components index doesn't actually need to be a MD file
And having it as a MD file can insert pointless `<p>` tags if we're not careful, which can cause weird bugs.
2025-01-03 16:13:02 -05:00
Lea Verou
b383d8bf2d Move e-commerce patterns under E-commerce
As discussed on Slack with @kelseythejackson
2025-01-03 16:08:24 -05:00
Lea Verou
1dcf895be1 Don’t render children on the top level as well 2025-01-03 16:00:36 -05:00
Lea Verou
19fd55ca97 fix: noAlpha, not isAlpha 2025-01-03 15:58:42 -05:00
Lea Verou
fa094d924d Automate sidebar listings 2025-01-03 15:52:58 -05:00
Lea Verou
2a957e6316 Add layout and isAlpha to pattern pages automatically 2025-01-03 15:52:27 -05:00
Lea Verou
90b6a9a8ac Add status as computed data on component pages 2025-01-03 15:02:36 -05:00
Lea Verou
99fdd90601 [Select] Remove leftover code
The select uses the appearance utils, so this is done automatically.
2025-01-03 14:23:09 -05:00
Lea Verou
ecaa461638 [Select] Remove leftover code, rel #413
This was meant to be deleted, since there’s already `min-height: var(--wa-form-control-height);` above it which already responds to size.
2025-01-03 14:14:39 -05:00
lindsaym-fa
d3a65ee35d Fix typo 2025-01-03 09:37:39 -05:00
lindsaym-fa
8ab1489cc4 Simplify shadow scales 2025-01-02 15:59:04 -05:00
lindsaym-fa
093c42ce66 Revise changelog for border radius and width tokens 2025-01-02 15:50:09 -05:00
lindsaym-fa
ed3e7014e3 Simplify border radius scale 2025-01-02 15:37:09 -05:00
Cory LaViska
7db62766dc update changelog 2025-01-02 10:23:43 -05:00
Cory LaViska
2de515bce7 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2025-01-02 10:23:07 -05:00
Cory LaViska
80949c2988 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2025-01-02 10:23:05 -05:00
Konnor Rogers
c7a35afefb fix wa-split utility (#395) 2025-01-02 10:12:44 -05:00
Cory LaViska
89dd462720 backport SL-2318 2025-01-02 10:02:10 -05:00
Cory LaViska
ce40d5e997 Merge pull request #396 from shoelace-style/konnorrogers/fix-switch-checked-property
Fix switch dirty checking to behave like checkbox
2025-01-02 09:33:03 -05:00
Cory LaViska
752cbb2f16 Merge branch 'next' into konnorrogers/fix-switch-checked-property 2025-01-02 09:32:54 -05:00
Cory LaViska
2048df8a40 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2025-01-02 09:31:29 -05:00
Cory LaViska
beace5a611 backport SL-2329 2025-01-02 09:31:26 -05:00
Konnor Rogers
1a8908acf7 prettier 2024-12-23 16:39:32 -05:00
Konnor Rogers
812badd721 fix switch 2024-12-23 16:39:16 -05:00
Lea Verou
8142da95d8 Update sidebar.njk 2024-12-23 02:20:39 -05:00
Lea Verou
546c9c67b4 Hide cheatsheet from components sidebar 2024-12-23 02:18:59 -05:00
Lea Verou
d5fe23ab39 Add missing icons 2024-12-23 02:17:39 -05:00
Lea Verou
3b10933151 Automate listing in components index page 2024-12-23 02:15:48 -05:00
Lea Verou
51a416718d sidebar should be using components tag 2024-12-23 02:15:25 -05:00
Lea Verou
08f327c224 [docs.css] Remove duplicate code, use CSS nesting for .index.grid 2024-12-23 01:58:10 -05:00
Konnor Rogers
b196ccc0bc Merge pull request #394 from shoelace-style/next
next -> alpha
2024-12-22 06:14:28 -05:00
Konnor Rogers
c62eed16aa fix missing components and format number (#393) 2024-12-22 06:12:44 -05:00
Lea Verou
e982c10987 Move grouping logic to separate subtemplate and use it on layout too 2024-12-20 18:29:28 -05:00
Lea Verou
23af07bcd5 Temp fix for spacing issue 2024-12-20 17:49:44 -05:00
Lea Verou
6aca515024 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-20 17:44:12 -05:00
Lea Verou
7d3f8b175c Separate native styles page for elements that correspond to a separate WA component 2024-12-20 17:44:10 -05:00
Cory LaViska
e2acfd106f fix padding in codepen examples 2024-12-20 15:39:30 -05:00
Cory LaViska
cfd282df4b update version 2024-12-20 14:05:02 -05:00
Cory LaViska
d0567c7ae9 3.0.0-alpha.7 2024-12-20 14:04:13 -05:00
Lea Verou
f076dd1afa Usage -> Installation 2024-12-20 14:02:35 -05:00
Lea Verou
83fb761d41 Rename applied.css to docs and add some docs on usage 2024-12-20 14:01:14 -05:00
Cory LaViska
fd337dd1ee not true anymore 2024-12-20 13:40:39 -05:00
Lea Verou
22883021e9 Fix typo 2024-12-20 13:37:10 -05:00
Lea Verou
02b72f991b Mark rounding utils as WIP and change title to Rounding 2024-12-20 13:32:40 -05:00
Lea Verou
84734a56b6 Add class names to utility class pages 2024-12-20 13:20:06 -05:00
Cory LaViska
c159964490 update changelog 2024-12-20 13:17:22 -05:00
Cory LaViska
5c8e044f4d 3.0.0-alpha.6 2024-12-20 13:16:45 -05:00
Lea Verou
a238880dbe Allow utilities to have statuses too 2024-12-20 13:14:37 -05:00
Lea Verou
307c989e3b Add examples for native buttons in button group 2024-12-20 13:06:17 -05:00
Cory LaViska
c33d17b4a2 fix search styles 2024-12-20 12:59:58 -05:00
lindsaym-fa
9d3e2bd214 Fix giant homepage icons (#380) 2024-12-20 12:46:30 -05:00
Lea Verou
6e99787425 Add properties for border-radius overrides and use them to fix #348 in a better way, also closes #379 and improves #374 2024-12-20 12:26:47 -05:00
Lea Verou
43a1179513 Automate layout page listing 2024-12-20 12:00:43 -05:00
Lea Verou
8887056651 If you say pill, we should assume you really mean it :P Fixes #378 2024-12-20 11:44:29 -05:00
Lea Verou
ec3251d0c6 Utilities index pages 2024-12-20 11:37:15 -05:00
Lea Verou
f5ac87c8a3 Cards for native styles 2024-12-20 11:22:21 -05:00
Lea Verou
a3d8f712ce Remove visually-hidden component, add its icon to the util 2024-12-20 11:22:21 -05:00
Cory LaViska
0fdf4e0f4d Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-20 11:19:05 -05:00
Lea Verou
013cf46be8 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-20 11:10:59 -05:00
Lea Verou
cbd74eded2 Native <progress> styles 2024-12-20 11:10:57 -05:00
lindsaym-fa
960c6d8da3 Add descriptions for utilities 2024-12-20 11:07:51 -05:00
Cory LaViska
ef81c77c60 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-20 11:05:43 -05:00
Cory LaViska
01918ca784 fix button alignment in button groups 2024-12-20 11:05:32 -05:00
Lea Verou
b0bb014167 Statuses 2024-12-20 10:58:45 -05:00
Lea Verou
9f12c1d9ab Temp workaround for #376 2024-12-20 10:55:53 -05:00
lindsaym-fa
4456a8df5c Add descriptions for native styles 2024-12-20 10:36:22 -05:00
Cory LaViska
8e7816f308 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-20 10:33:12 -05:00
Cory LaViska
3861041bc1 fixes #350 2024-12-20 10:33:10 -05:00
Lea Verou
e29ae5d18e No, button groups shouldn't wrap 2024-12-20 10:15:29 -05:00
Cory LaViska
6ef2e92923 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-20 10:07:30 -05:00
Cory LaViska
562fec9ac7 fix component section in alpha 2024-12-20 10:07:27 -05:00
Cory LaViska
b38568f5c5 fix dropdown examples 2024-12-20 10:07:19 -05:00
Lea Verou
c0012f5b94 Fix dropdown in button-group rounding, closes #348 2024-12-20 10:03:03 -05:00
lindsaym-fa
41ee75bbfe Fix capitalization 2024-12-20 09:45:23 -05:00
Lea Verou
54f7916ddb Simplify progress bar CSS & DOM (still doesn't fix the transition in Safari but working on it) 2024-12-20 08:41:14 -05:00
Konnor Rogers
e170b488ea fix label position docs (#371) 2024-12-19 22:08:53 -05:00
Lea Verou
cd172ede8c Docs for visually hidden util, remove visually hidden component per #232 2024-12-19 21:15:33 -05:00
Konnor Rogers
d1b38af039 fix textarea jank (#370)
* fix textarea jank

* prettier
2024-12-19 20:52:05 -05:00
Lea Verou
506fb2588b Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-19 19:49:13 -05:00
Lea Verou
123a8c331f Restrict what default slot things <wa-page> adds spacing to, related to #331 2024-12-19 19:49:11 -05:00
Lea Verou
1a1847eeb5 Update search dialog styles to new simpler structure, closes #331 2024-12-19 19:48:38 -05:00
Konnor Rogers
835326a2db fix delayed button loading (#369)
* fix delayed button loading

* fix delayed button loading
2024-12-19 19:13:08 -05:00
lindsaym-fa
1905ca9b77 Capitalize "Style Utilities" 2024-12-19 18:54:12 -05:00
lindsaym-fa
fc3688df97 Fix closable tab example (#363) 2024-12-19 17:55:57 -05:00
Lea Verou
107f074f99 Page utils & native styles 2024-12-19 17:34:32 -05:00
lindsaym-fa
5d3e58bde0 Fix #361 2024-12-19 16:58:06 -05:00
lindsaym-fa
f5b8f2257d Fix specificity of gap and align-items in layout utilities 2024-12-19 16:51:55 -05:00
Lea Verou
52c0fdf6de Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-19 16:37:57 -05:00
Lea Verou
c2c42f56ba Docs for size utils 2024-12-19 16:37:55 -05:00
lindsaym-fa
328d6989d9 Set default color for dark theme 2024-12-19 16:34:36 -05:00
lindsaym-fa
49465c9a1d Fix form control label margin 2024-12-19 16:26:06 -05:00
lindsaym-fa
394a028973 Consolidate native form styles 2024-12-19 15:58:31 -05:00
lindsaym-fa
431d23d420 Fix range disabled and focus styles 2024-12-19 15:46:30 -05:00
Lea Verou
c230a42053 Fix filename 2024-12-19 15:30:48 -05:00
Lea Verou
378f100729 Update changelog.md 2024-12-19 15:30:38 -05:00
Cory LaViska
87314f8864 Merge pull request #364 from shoelace-style/konnorrogers/fix-safari-placeholder
fix safari placeholder
2024-12-19 15:01:47 -05:00
konnorrogers
70a8fc6425 fix safari placeholder 2024-12-19 14:28:35 -05:00
Konnor Rogers
486b0649e0 fix code demo with empty slot (#360)
* fix code demo with empty slot

* prettier
2024-12-19 14:12:55 -05:00
Lea Verou
63a2367cc5 Docs for color and appearance variants 2024-12-19 14:04:15 -05:00
Lea Verou
995d0f2af4 First stab at variant utils docs 2024-12-19 13:50:12 -05:00
Lindsay M
874bb5cbf6 Fix missing input and textarea styles in Firefox and Safari (#339)
* initial fix

* fix disabled styles in all browsers

* simpler fix
2024-12-19 13:32:30 -05:00
Lea Verou
15495bd9bd Automate theming sidebar block 2024-12-19 13:05:59 -05:00
Cory LaViska
f4678e12c6 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-19 12:43:31 -05:00
Cory LaViska
2bf7ebbb71 fixes #343; fixes #341 2024-12-19 12:43:29 -05:00
Lea Verou
68e53a4ef1 Automatic util listing on sidebar 2024-12-19 12:40:04 -05:00
Lea Verou
0f0b9d50cd Move all utilities under /utilities/
Co-Authored-By: Lindsay M <126139086+lindsaym-fa@users.noreply.github.com>
2024-12-19 12:40:04 -05:00
Lea Verou
5d13583da7 Update sort filter to take multiple keys into account in order of priority, default to order, then title
And use `order` on Page
2024-12-19 12:40:04 -05:00
Lea Verou
f99f32d054 Refactor: sort filter 2024-12-19 12:40:04 -05:00
Lea Verou
39acaeba70 Refactor: move sort filter to filters.js 2024-12-19 12:40:04 -05:00
Cory LaViska
e87c725e07 fixes #344 2024-12-19 12:38:49 -05:00
Cory LaViska
31a3421709 fixes #332 2024-12-19 12:15:34 -05:00
Cory LaViska
5d1fb7c477 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-19 11:19:51 -05:00
Lea Verou
13e606c1cb Native color-picker styles 2024-12-19 10:16:23 -05:00
lindsaym-fa
42dd64f397 Fix layout and add description to Native Styles 2024-12-19 10:13:16 -05:00
Kelsey Jackson
53e87e4dcd Remove :required content styles for native elements
* fixed label ::after

* removed label styles
2024-12-19 10:00:39 -05:00
Lea Verou
dabaef3fab The big rename nobody wants to do :P 2024-12-19 04:03:44 -05:00
Lea Verou
d5939efc30 Refactor table styles
- Use hueless color tokens so it can be used with variants (and add example)
- Fix hover effect on zebra rows
- Reduce padding a bit
- Shorten utility class
- CSS nesting
2024-12-19 03:53:54 -05:00
Lea Verou
d345878de6 Remove *--disabled classes, use regular selectors 2024-12-19 03:24:18 -05:00
lindsaym-fa
609578ff30 Fix typo 2024-12-19 03:08:37 -05:00
lindsaym-fa
648137a964 Add native select styles and share with <wa-select> 2024-12-19 03:06:31 -05:00
Lea Verou
cd487bf8be Use :dir() in CSS rather than custom RTL classes 2024-12-19 02:17:55 -05:00
Lea Verou
239ddcf75d Simplify RTL handling with logical properties 2024-12-19 02:13:17 -05:00
Lea Verou
ad2e945e44 Merge branch 'next' of https://github.com/shoelace-style/webawesome into next 2024-12-19 02:01:39 -05:00
Lea Verou
11f7adefc2 Remove no longer needed hasFocus in all but color-picker 2024-12-19 02:01:30 -05:00
lindsaym-fa
909986b520 Tweak checkbox styles 2024-12-19 01:44:52 -05:00
lindsaym-fa
8de5fc9580 *Actually* add radio styles 2024-12-19 01:44:28 -05:00
lindsaym-fa
197aedcc70 Add radio styles and share with <wa-radio> 2024-12-19 01:43:56 -05:00
Lea Verou
491533e09c Merge textarea & input styles
Also simplify textarea component DOM
2024-12-19 01:38:39 -05:00
Lea Verou
474d8d7c7b Remove wa-off 2024-12-19 01:38:07 -05:00
Lea Verou
8d83076ef2 Fix transition 2024-12-19 00:59:00 -05:00
Lea Verou
e69632ff60 [Input] Several improvements
- Simplify styles and DOM
- Add `.wa-text-field` utility class
- Eliminate `--border-color` (except when set by appearance utils), `--border-style`, `--border-radius`
2024-12-19 00:39:23 -05:00
Lea Verou
996fa6df57 Import appearance helpers in elements with newly acquired appearance attribute 2024-12-19 00:39:23 -05:00
Konnor Rogers
239782a7d8 add proper dependencies to wa-page (#337)
* add proper dependencies to wa-page

* add proper dependencies to wa-page
2024-12-18 23:40:14 -05:00
Konnor Rogers
7d3a629a1e fix host context selectors for unsupported browsers (#335)
* fix host context selectors

* fix textarea value being lost

* fix textarea

* fix example

* fix textarea value being lost
2024-12-18 23:27:50 -05:00
lindsaym-fa
067ae799fd Add native textarea styles and share with <wa-textarea> 2024-12-18 22:33:24 -05:00
Lea Verou
ea165cb477 Now that all sizeable form controls use the size util, simplify form-control.css 2024-12-18 21:42:55 -05:00
Lea Verou
d33b5c4870 [Switch] Simplify DOM & CSS 2024-12-18 21:33:52 -05:00
Lea Verou
96db264724 [Switch] Use size utils 2024-12-18 21:09:22 -05:00
Lea Verou
dda4575aa4 [color-picker] Use size util 2024-12-18 21:06:52 -05:00
Lea Verou
2322762cc6 [Input] Remove unnecessary classes, simplify DOM 2024-12-18 20:56:30 -05:00
Lea Verou
4a14eb3282 Calculate form control height in size util 2024-12-18 20:48:25 -05:00
Lea Verou
931faf911c Use size helper in input 2024-12-18 20:34:55 -05:00
Lea Verou
f4db1e37e0 No need for fallback any more 2024-12-18 20:34:45 -05:00
Lea Verou
833b7b1207 Update tag.css 2024-12-18 20:33:47 -05:00
Lea Verou
622ee91323 Fix tag glitch 2024-12-18 20:12:28 -05:00
Lea Verou
d206414825 Make size utils root-level so there's always a default value 2024-12-18 20:09:31 -05:00
Lea Verou
73d26ece05 Clean up CSS structure 2024-12-18 19:40:52 -05:00
Lea Verou
3b90a1cc31 Native slider! 2024-12-18 19:36:26 -05:00
Lea Verou
289ce105dc Fix build 2024-12-18 18:59:39 -05:00
Lea Verou
deb2752d35 Refactor range styles to prepare for native ranges 2024-12-18 18:58:21 -05:00
lindsaym-fa
df4393e033 Fix native label spacing 2024-12-18 18:09:58 -05:00
Konnor Rogers
cf34747701 fix layout demo and custom states support (#318)
* fix demo

* fix linting errors

* remove jinja, run prettier

* prettier
2024-12-18 17:08:38 -05:00
lindsaym-fa
ad467f0691 Add native details styles and share with <wa-details> 2024-12-18 17:02:25 -05:00
Cory LaViska
60f2b9657b remove base from docs 2024-12-18 15:09:46 -05:00
450 changed files with 11125 additions and 12373 deletions

View File

@@ -31,7 +31,7 @@ jobs:
- name: Lint
run: npm run prettier
- name: Build
run: npm run build
run: npm run build:alpha
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run CSR tests

View File

@@ -30,7 +30,7 @@ jobs:
run: npm run prettier
- name: Build
run: npm run build
run: npm run build:alpha
- name: Install Playwright
run: npx playwright install --with-deps

View File

@@ -59,6 +59,8 @@ To generate a production build, run the following command.
npm run build
```
You can also run `npm run build:serve` to start an [`http-server`](https://www.npmjs.com/package/http-server) instance on `http://localhost:4000` after the build completes, so you can preview the production build.
### Creating New Components
To scaffold a new component, run the following command, replacing `wa-tag-name` with the desired tag name.

View File

@@ -20,6 +20,15 @@ const packageData = JSON.parse(await readFile('./package.json', 'utf-8'));
const isAlpha = process.argv.includes('--alpha');
const isDev = process.argv.includes('--develop');
const globalData = {
package: packageData,
isAlpha,
layout: 'page.njk',
};
const passThroughExtensions = ['js', 'css', 'png', 'svg', 'jpg', 'mp4'];
const passThrough = [...passThroughExtensions.map(ext => 'docs/**/*.' + ext)];
export default function (eleventyConfig) {
// NOTE - alpha setting removes certain pages
if (isAlpha) {
@@ -32,8 +41,9 @@ export default function (eleventyConfig) {
}
// Add template data
eleventyConfig.addGlobalData('package', packageData);
eleventyConfig.addGlobalData('isAlpha', isAlpha);
for (let name in globalData) {
eleventyConfig.addGlobalData(name, globalData[name]);
}
// Template filters - {{ content | filter }}
eleventyConfig.addFilter('inlineMarkdown', content => markdown.renderInline(content || ''));
@@ -43,20 +53,14 @@ export default function (eleventyConfig) {
eleventyConfig.addFilter(name, filters[name]);
}
eleventyConfig.addFilter('sort', (arr, key = 'data.title') => {
key = key.split('.');
return arr.sort((a, b) => {
let aVal = key.reduce((obj, i) => obj?.[i], a);
let bVal = key.reduce((obj, i) => obj?.[i], b);
return aVal.localeCompare(bVal);
});
});
// Shortcodes - {% shortCode arg1, arg2 %}
eleventyConfig.addShortcode('cdnUrl', location => {
return `https://early.webawesome.com/webawesome@${packageData.version}/dist/` + location.replace(/^\//, '');
});
// Paired shortcodes - {% shortCode %}content{% endShortCode %}
eleventyConfig.addPairedShortcode('markdown', content => markdown.render(content || ''));
// Helpers
// Remove elements that have [data-alpha="remove"]
@@ -154,9 +158,18 @@ export default function (eleventyConfig) {
// eleventyConfig.addPlugin(formatCodePlugin());
// }
eleventyConfig.addPassthroughCopy({
'docs/assets': 'assets',
});
for (let glob of passThrough) {
eleventyConfig.addPassthroughCopy(glob);
}
return {
markdownTemplateEngine: 'njk',
dir: {
input: 'docs',
includes: '_includes',
layouts: '_layouts',
},

1
docs/_data/hues.json Normal file
View File

@@ -0,0 +1 @@
["red", "yellow", "green", "teal", "blue", "indigo", "violet", "gray"]

1
docs/_data/palettes.js Normal file
View File

@@ -0,0 +1 @@
export { default as default } from '../../src/styles/color/palettes.js';

File diff suppressed because one or more lines are too long

View File

@@ -1,91 +1,25 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{ description }}">
{% include 'head.njk' %}
<meta name="theme-color" content="#f36944">
{% if noindex %}<meta name="robots" content="noindex">{% endif %}
<title>{{ title }}</title>
<link rel="icon" href="/assets/images/webawesome-logo.svg" />
<link rel="apple-touch-icon" href="/assets/images/app-icon.png">
{# Scripts #}
{# Hydration stuff #}
<script src="/assets/scripts/hydration-errors.js"></script>
<link rel="stylesheet" href="/assets/styles/hydration-errors.css">
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm"></script>
<script type="module" src="/assets/scripts/code-examples.js"></script>
<script type="module" src="/assets/scripts/color-scheme.js"></script>
<script type="module" src="/assets/scripts/copy-code.js"></script>
<script type="module" src="/assets/scripts/preset-theme.js"></script>
<script type="module" src="/assets/scripts/scroll.js"></script>
<script type="module" src="/assets/scripts/turbo.js"></script>
<script type="module" src="/assets/scripts/search.js"></script>
<script type="module" src="/assets/scripts/outline.js"></script>
<script defer data-domain="backers.webawesome.com" src="https://plausible.io/js/script.js"></script>
{# Web Awesome #}
<script type="module" src="/dist/webawesome.ssr-loader.js"></script>
<link rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/default.css" />
<link rel="stylesheet" href="/dist/styles/applied.css" />
<link id="color-stylesheet" rel="stylesheet" href="/dist/styles/utilities.css" />
<link rel="stylesheet" href="/dist/styles/forms.css" />
{# Docs styles #}
<link rel="stylesheet" href="/assets/styles/docs.css" />
{# Set the theme to prevent flashing #}
<script>
function getColorScheme() {
return localStorage.getItem('colorScheme') || 'auto';
}
function getPresetTheme () {
return localStorage.getItem('presetTheme') || 'default';
}
function isDark() {
const colorScheme = getColorScheme()
if (colorScheme === 'auto') {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
return colorScheme === 'dark';
}
const oldStylesheet = document.querySelector("#theme-stylesheet")
const newStylesheet = document.createElement("link")
let preset = getPresetTheme()
newStylesheet.href = `/dist/styles/themes/${preset}.css`
newStylesheet.rel = "preload"
newStylesheet.as = "style"
document.head.append(newStylesheet)
function updateStylesheet () {
newStylesheet.rel = "stylesheet"
newStylesheet.id = "theme-stylesheet"
requestAnimationFrame(() => oldStylesheet.remove())
}
newStylesheet.addEventListener("load", updateStylesheet)
document.documentElement.classList.toggle(
`wa-theme-${preset}-dark`,
isDark()
);
</script>
</head>
<body class="layout-{{ layout | stripExtension }}">
<!-- use view="desktop" as default to reduce layout jank on desktop site. -->
<wa-page view="desktop" disable-navigation-toggle="">
<header slot="header">
<header slot="header" class="wa-split">
{# Logo #}
<div id="docs-branding">
{# Nav toggle #}
@@ -94,16 +28,16 @@
</wa-button>
<a href="/" aria-label="Web Awesome">
<span class="only-desktop">{% include "logo.njk" %}</span>
<span class="only-mobile">{% include "logo-simple.njk" %}</span>
<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="only-desktop">{{ package.version }}</small>
<wa-badge variant="warning" appearance="filled" class="only-desktop">Alpha</wa-badge>
</div>
<div id="docs-toolbar">
<div id="docs-toolbar" class="wa-cluster wa-gap-xs">
{# Desktop selectors #}
<div class="only-desktop">
<div class="only-desktop wa-cluster wa-gap-xs">
{% include "preset-theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
</div>
@@ -120,8 +54,8 @@
{# Sidebar #}
{% if hasSidebar %}
{# Mobile selectors #}
<div class="only-mobile" slot="navigation-header">
<div style="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));">
<div class="wa-mobile-only" slot="navigation-header">
<div class="wa-cluster wa-gap-xs">
{% include "preset-theme-selector.njk" %}
{% include "color-scheme-selector.njk" %}
</div>
@@ -149,22 +83,12 @@
</details>
</nav>
{% set breadcrumbs = page.url | breadcrumbs %}
{% if breadcrumbs.length > 0 %}
<wa-breadcrumb id="docs-breadcrumbs">
{% for crumb in breadcrumbs %}
<wa-breadcrumb-item href="{{ crumb.url }}">{{ crumb.title }}</wa-breadcrumb-item>
{% endfor %}
<wa-breadcrumb-item>{# Current page #}</wa-breadcrumb-item>
</wa-breadcrumb>
{% else %}
{% endif %}
{% block beforeContent %}{% endblock %}
{% block header %}
{% include 'breadcrumbs.njk' %}
<h1 class="title">{{ title }}</h1>
{% endblock %}
{% block content %}
<h1 class="title">{{ title }}</h1>
{{ content | safe }}
{% endblock %}

View File

@@ -0,0 +1,10 @@
{% set breadcrumbs = page.url | breadcrumbs %}
{% if breadcrumbs.length > 0 %}
<wa-breadcrumb id="docs-breadcrumbs">
{% for crumb in breadcrumbs %}
<wa-breadcrumb-item href="{{ crumb.url }}">{{ crumb.title }}</wa-breadcrumb-item>
{% endfor %}
<wa-breadcrumb-item>{# Current page #}</wa-breadcrumb-item>
</wa-breadcrumb>
{% else %}
{% endif %}

View File

@@ -1,15 +1,19 @@
{# Color scheme selector #}
<wa-dropdown id="color-scheme-selector">
<wa-button slot="trigger" appearance="filled" size="small" pill caret title="Press \ to toggle">
<wa-select class="color-scheme-selector" appearance="filled" size="small" value="auto" pill title="Press \ to toggle">
<wa-icon class="only-light" slot="prefix" name="sun" variant="regular"></wa-icon>
<wa-icon class="only-dark" slot="prefix" name="moon" variant="regular"></wa-icon>
<wa-option value="light">
<wa-icon slot="prefix" name="sun" variant="regular"></wa-icon>
Light
</wa-option>
<wa-option value="dark">
<wa-icon slot="prefix" name="moon" variant="regular"></wa-icon>
Dark
</wa-option>
<wa-divider></wa-divider>
<wa-option value="auto">
<wa-icon class="only-light" slot="prefix" name="sun" variant="regular"></wa-icon>
<wa-icon class="only-dark" slot="prefix" name="moon" variant="regular"></wa-icon>
<span class="only-light">Light</span>
<span class="only-dark">Dark</span>
</wa-button>
<wa-menu>
<wa-menu-item type="checkbox" value="light">Light</wa-menu-item>
<wa-menu-item type="checkbox" value="dark">Dark</wa-menu-item>
<wa-divider></wa-divider>
<wa-menu-item type="checkbox" value="auto">System</wa-menu-item>
</wa-menu>
</wa-dropdown>
System
</wa-option>
</wa-select>

View File

@@ -0,0 +1,40 @@
<table class="colors wa-palette-{{ paletteId }}">
<thead>
<tr>
<th></th>
{% for tint_bg in tints -%}
{% for tint_fg in tints | reverse -%}
{% if (tint_fg - tint_bg) | abs == difference %}
<th>{{ tint_fg }} on {{ tint_bg }}</th>
{% endif %}
{%- endfor -%}
{%- endfor %}
</tr>
</thead>
{% for hue in hues -%}
<tr>
<th>{{ hue | capitalize }}</th>
{% for tint_bg in tints -%}
{% set color_bg = palettes[paletteId][hue][tint_bg] %}
{% for tint_fg in tints | reverse -%}
{% set color_fg = palettes[paletteId][hue][tint_fg] %}
{% if (tint_fg - tint_bg) | abs == difference %}
<td>
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}-{{ tint_bg }}); color: var(--wa-color-{{ hue }}-{{ tint_fg }})">
{% set contrast_wcag = '' %}
{% if color_fg and color_bg %}
{% set contrast_wcag = color_bg.contrast(color_fg, 'WCAG21') %}
{% endif %}
{% if contrast_wcag %}
{{ contrast_wcag | number({maximumSignificantDigits: 2}) }}
{% else %}
{{ tint_fg }} on {{ tint_bg }}
{% endif %}
</div>
</td>
{% endif %}
{%- endfor -%}
{%- endfor -%}
</tr>
{%- endfor %}
</table>

View File

@@ -0,0 +1,12 @@
{# Cards for pages listed by category #}
<section id="grid" class="index-grid">
{% for category, pages in allPages | groupByTags(categories) -%}
<h2 class="index-category">{{ category | getCategoryTitle(categories) }}</h2>
{%- for page in pages -%}
{%- if not page.data.parent or listChildren -%}
{% include "page-card.njk" %}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
</section>

49
docs/_includes/head.njk Normal file
View File

@@ -0,0 +1,49 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{ description }}">
{% if noindex %}<meta name="robots" content="noindex">{% endif %}
<title>{{ title }}</title>
{# Dark mode #}
<script>
let colorScheme = localStorage.colorScheme;
let isDark = localStorage.colorScheme === "dark";
if (!colorScheme || colorScheme === "auto") {
isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
}
document.documentElement.classList.toggle('wa-dark', isDark);
</script>
<link rel="icon" href="/assets/images/webawesome-logo.svg" />
<link rel="apple-touch-icon" href="/assets/images/app-icon.png">
{# Scripts #}
{# Hydration stuff #}
<script src="/assets/scripts/hydration-errors.js"></script>
<link rel="stylesheet" href="/assets/styles/hydration-errors.css">
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm"></script>
{# Web Awesome #}
<script type="module" src="/dist/webawesome.ssr-loader.js"></script>
<script type="module" src="/assets/scripts/theme-picker.js"></script>
{# Preset Theme #}
{% if forceTheme %}
<link id="theme-stylesheet" rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/{{ forceTheme }}.css" render="blocking" fetchpriority="high" />
{% else %}
<noscript><link id="theme-stylesheet" rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/default.css" render="blocking" fetchpriority="high" /></noscript>
<script>
{
let preset = localStorage.presetTheme ?? 'default';
let script = document.currentScript;
script.insertAdjacentHTML('beforebegin', `<link id="theme-stylesheet" rel="stylesheet" id="theme-stylesheet" href="/dist/styles/themes/${ preset }.css" render="blocking" fetchpriority="high" />`);
}
</script>
<script type="module" src="/assets/scripts/preset-theme-picker.js"></script>
{% endif %}
<link rel="stylesheet" href="/dist/styles/webawesome.css" />
<link id="color-stylesheet" rel="stylesheet" href="/dist/styles/utilities.css" />
<link rel="stylesheet" href="/dist/styles/forms.css" />

View File

@@ -0,0 +1,18 @@
<wa-tab-group>
<wa-tab panel="html">In HTML</wa-tab>
<wa-tab panel="css">In CSS</wa-tab>
<wa-tab-panel name="html">
Simply add the following code to the `<head>` of your page:
```html
<link rel="stylesheet" href="{% cdnUrl stylesheet %}" />
```
</wa-tab-panel>
<wa-tab-panel name="css">
Simply add the following code at the top of your CSS file:
```css
@import url('{% cdnUrl stylesheet %}');
```
</wa-tab-panel>
</wa-tab-group>

View File

@@ -0,0 +1,10 @@
{%- if not page.data.unlisted -%}
<a href="{{ page.url }}"{{ page.data.keywords | attr('data-keywords') }}>
<wa-card with-header>
<div slot="header">
{% include "svgs/" + (page.data.icon or "thumbnail-placeholder") + ".njk" %}
</div>
<span class="page-name">{{ page.data.title }}</span>
</wa-card>
</a>
{% endif %}

View File

@@ -1,5 +1,5 @@
<div id="page_slots_demo">
<link rel="stylesheet" href="/assets/examples/page-demo/demo.css">
<link rel="stylesheet" href="./demo.css">
{% set slots = components.page.slots %}
<fieldset id="page_slots_fieldset">
@@ -22,5 +22,5 @@
<script type="module">
const cacheBust = new Date().toString()
import(`/assets/examples/page-demo/demo.js?${cacheBust}`)
import(`./demo.js?${cacheBust}`)
</script>

View File

@@ -1,18 +1,9 @@
{# Preset theme selector #}
<wa-dropdown id="preset-theme-selector">
<wa-button slot="trigger" appearance="filled" size="small" pill caret>
<wa-icon slot="prefix" name="paintbrush" variant="regular"></wa-icon>
<span id="preset-theme-selector__text">Default</span>
</wa-button>
<wa-menu>
<wa-menu-item type="checkbox" value="default">Default</wa-menu-item>
<wa-menu-item type="checkbox" value="classic">Classic</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="fa">Font Awesome</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="active">Active</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="brutalist">Brutalism</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="glassy">Glassy</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="migration">Migration</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="playful">Playful</wa-menu-item>
<wa-menu-item data-alpha="remove" type="checkbox" value="premium">Premium</wa-menu-item>
</wa-menu>
</wa-dropdown>
<wa-select appearance="filled" size="small" value="default" pill class="preset-theme-selector">
<wa-icon slot="prefix" name="paintbrush" variant="regular"></wa-icon>
{% for theme in collections.theme | sort %}
<wa-option value="{{ theme.page.fileSlug }}"{{ ' data-alpha="remove"' if theme.noAlpha }}>
{{ theme.data.title }}
</wa-option>
{% endfor %}
</wa-select>

View File

@@ -0,0 +1,22 @@
{# Some collections (like "patterns") will not have any items in the alpha build for example. So this checks to make sure the collection exists. #}
{% if collections[tag] -%}
{% set groupUrl %}/docs/{{ tag }}/{% endset %}
<wa-details {{ ((tag in (tags or [])) or (groupUrl in page.url)) | attr('open') }}>
<h2 slot="summary">
{% if groupUrl | getCollectionItemFromUrl %}
<a href="{{ groupUrl }}" title="Overview">{{ title or (tag | capitalize) }}
<wa-icon name="grid-2"></wa-icon>
</a>
{% else %}
{{ title or (tag | capitalize) }}
{% endif %}
</h2>
<ul>
{% for page in collections[tag] | sort %}
{% if not page.data.parent -%}
{% include 'sidebar-link.njk' %}
{%- endif %}
{% endfor %}
</ul>
</wa-details>
{%- endif %}

View File

@@ -0,0 +1,16 @@
{% if not (isAlpha and page.data.noAlpha) and page.fileSlug != tag and not page.data.unlisted -%}
<li>
<a href="{{ page.url }}">{{ page.data.title }}</a>
{% if page.data.status == 'experimental' %}<wa-icon name="flask"></wa-icon>{% endif %}
{% if page.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
{% set children = page.data.children %}
{% if children.length > 0 %}
<ul>
{% for page in children %}
{% include 'sidebar-link.njk' %}
{% endfor %}
</ul>
{% endif %}
</li>
{%- endif %}

View File

@@ -3,7 +3,6 @@
<ul>
<li><a href="/docs/installation">Installation</a></li>
<li><a href="/docs/usage">Usage</a></li>
<li><a href="/docs/themes">Themes</a></li>
<li><a href="/docs/customizing">Customizing</a></li>
<li><a href="/docs/form-controls">Form Controls</a></li>
<li><a href="/docs/localization">Localization</a></li>
@@ -19,132 +18,15 @@
<li><a href="/docs/resources/changelog">Changelog</a></li>
</ul>
{# Components #}
<wa-details{{ ' open' if '/components/' in page.url }}>
<h2 slot=summary>
<a href="/docs/components/" title="Overview">Components
<wa-icon name="grid-2"></wa-icon>
</a>
</h2>
<ul>
{% for component in collections.component | sort %}
{% if not component.data.parent and not (isAlpha and component.data.isAlpha) %}
<li>
<a href="/docs/components/{{ component.fileSlug }}">{{ component.data.title }}</a>
{% if components[component.fileSlug].status == 'experimental' %}<wa-icon name="flask"></wa-icon>{% endif %}
{% if component.data.isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
<ul>
{% for child in collections.component | sort %}
{% if child.data.parent == component.fileSlug and not (isAlpha and child.data.isAlpha) %}
<li>
<a href="/docs/components/{{ child.fileSlug }}">{{ child.data.title }}</a>
</li>
{% endif %}
{% endfor %}
</ul>
</li>
{% endif %}
{% endfor %}
</ul>
</wa-details>
<wa-details{{ ' open' if '/essentials/' in page.url }}>
<h2 slot=summary>
<a href="/docs/essentials/" title="Overview">Essentials
<wa-icon name="grid-2"></wa-icon>
</a>
</h2>
<ul>
{% for page in collections.essentials | sort %}
<li>
<a href="/docs/essentials/{{ page.fileSlug }}">{{ page.data.title }}</a>
</li>
{% endfor %}
</ul>
</wa-details>
{# Layout #}
{% if not isAlpha %}
<h2>
<a href="/docs/layout" title="Overview">Layout
<wa-icon name="grid-2"></wa-icon>
</a>
</h2>
<ul>
<li><a href="/docs/components/page">Page</a></li>
<li><a href="/docs/layout/cluster">Cluster</a></li>
<li><a href="/docs/layout/flank">Flank</a></li>
<li><a href="/docs/layout/frame">Frame</a></li>
<li><a href="/docs/layout/grid">Grid</a></li>
<li><a href="/docs/layout/split">Split</a></li>
<li><a href="/docs/layout/stack">Stack</a></li>
</ul>
{% endif %}
{# Patterns #}
{% if not isAlpha %}
<h2>Patterns</h2>
<ul>
<li><a href="/docs/patterns/app">Web App</a></li>
<li><a href="/docs/patterns/ecommerce">E-commerce</a>
<ul>
<li><a href="/docs/patterns/ecommerce-product-review">Product Reviews</a></li>
<li><a href="/docs/patterns/ecommerce-product-list">Product Lists</a></li>
<li><a href="/docs/patterns/ecommerce-category-preview">Category Previews</a></li>
<li><a href="/docs/patterns/ecommerce-shopping-cart">Shopping Carts</a></li>
<li><a href="/docs/patterns/ecommerce-category-filter">Category Filters</a></li>
<li><a href="/docs/patterns/ecommerce-product-detail">Product Detail</a></li>
<li><a href="/docs/patterns/ecommerce-order-summary">Order Summaries</a></li>
<li><a href="/docs/patterns/ecommerce-order-history">Order History</a></li>
</ul>
</li>
<li><a href="/docs/patterns/blog">Blog</a></li>
<li><a href="/docs/patterns/news">News</a></li>
</ul>
{% endif %}
{# Theming #}
<h2>
<a href="/docs/theming" title="Overview">Theming
<wa-icon name="grid-2"></wa-icon>
</a>
</h2>
<ul>
<li>
<a href="/docs/theming/color">Color</a>
</li>
<li>
<a href="/docs/theming/typography">Typography</a>
</li>
<li>
<a href="/docs/theming/space">Space</a>
</li>
<li>
<a href="/docs/theming/borders">Borders</a>
</li>
<li>
<a href="/docs/theming/focus">Focus</a>
</li>
<li>
<a href="/docs/theming/shadows">Shadows</a>
</li>
<li>
<a href="/docs/theming/transitions">Transitions</a>
</li>
<li>
<a href="/docs/theming/component-groups">Component Groups</a>
</li>
</ul>
{# Style Utilities #}
{% if not isAlpha %}
<h2>Style Utilities</h2>
<ul>
<li><a href="/docs/style-utilities/align-items">Align Items</a></li>
<li><a href="/docs/style-utilities/border-radius">Border Radius</a></li>
<li><a href="/docs/style-utilities/gap">Gap</a></li>
<li><a href="/docs/style-utilities/text">Text</a></li>
</ul>
{% endif %}
{% for tag, title in {
'themes': 'Themes',
'components': 'Components',
'native': 'Native Styles',
'utilities': 'Style Utilities',
'layout': 'Layout',
'patterns': 'Patterns',
'palettes': 'Color Palettes',
'tokens': 'Design Tokens'
} %}
{% include 'sidebar-group.njk' %}
{% endfor %}

25
docs/_includes/status.njk Normal file
View File

@@ -0,0 +1,25 @@
{% if since -%}
<wa-badge variant="neutral">Since {{ since }}</wa-badge>
{% endif -%}
{%- if status %}
{%- if status == "wip" %}
<wa-badge variant="danger">
<wa-icon name="pickaxe"></wa-icon>
Work In Progress
</wa-badge>
{%- elif status == "experimental" %}
<wa-badge variant="warning">
<wa-icon name="flask"></wa-icon>
Experimental
</wa-badge>
{%- elif status == "stable" %}
<wa-badge variant="brand">Stable</wa-badge>
{%- else %}
<wa-badge>{{ status}}</wa-badge>
{%- endif -%}
{%- endif %}
{%- if isPro %}
<wa-badge class="pro">PRO</wa-badge>
{%- endif -%}

View File

@@ -0,0 +1,24 @@
{% set paletteId = page.fileSlug %}
{% set tints = [80, 60, 40, 20] %}
{% set width = 20 %}
{% set height = 13 %}
{% set gap_x = 3 %}
{% set gap_y = 3 %}
<svg viewBox="0 0 {{ (width + gap_x) * hues|length }} {{ (height + gap_y) * tints|length }}" fill="none" xmlns="http://www.w3.org/2000/svg" class="wa-palette-{{ paletteId }} palette-icon">
<style>
@import url('/dist/styles/color/{{ paletteId }}.css') layer(palette.{{ paletteId }});
.palette-icon {
height: 8ch;
}
</style>
{% for hue in hues -%}
{% set hueIndex = loop.index0 %}
{% for tint in tints -%}
<rect x="{{ hueIndex * (width + gap_x) }}" y="{{ loop.index0 * (height + gap_y) }}"
width="{{ width }}" height="{{ height }}"
fill="var(--wa-color-{{ hue }}-{{ tint }})" rx="4" />
{%- endfor %}
{% endfor %}
</svg>

View File

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 337 B

View File

Before

Width:  |  Height:  |  Size: 596 B

After

Width:  |  Height:  |  Size: 596 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

Before

Width:  |  Height:  |  Size: 502 B

After

Width:  |  Height:  |  Size: 502 B

View File

Before

Width:  |  Height:  |  Size: 790 B

After

Width:  |  Height:  |  Size: 790 B

View File

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 697 B

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,144 @@
<div class="showcase-examples-wrapper" aria-hidden="true" data-no-outline>
<div class="showcase-examples">
<wa-card with-header with-footer>
<div slot="header" class="wa-split">
<h3 class="wa-heading-m">Your Cart</h3>
<wa-icon-button name="xmark" tabindex="-1"></wa-icon-button>
</div>
<div class="wa-stack wa-gap-xl">
<div class="wa-flank">
<wa-avatar shape="rounded" style="--size: 3em; --background-color: var(--wa-color-green-60); --text-color: var(--wa-color-green-95);">
<wa-icon slot="icon" name="sword-laser" family="duotone" style="font-size: 1.5em;"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<div class="wa-split wa-gap-2xs">
<strong>Initiate Saber</strong>
<strong>$179.99</strong>
</div>
<div class="wa-split wa-gap-2xs wa-caption-m">
<span>Green</span>
<a href="#" tabindex="-1">Remove</a>
</div>
</div>
</div>
<wa-divider></wa-divider>
<div class="wa-flank">
<wa-avatar shape="rounded" style="--size: 3em; --background-color: var(--wa-color-teal-60); --text-color: var(--wa-color-teal-95);">
<wa-icon slot="icon" name="robot-astromech" family="duotone" style="font-size: 1.5em;"></wa-icon>
</wa-avatar>
<div class="wa-stack wa-gap-2xs">
<div class="wa-split wa-gap-2xs">
<strong>Repair Droid</strong>
<strong>$3,049.99</strong>
</div>
<div class="wa-split wa-gap-2xs wa-caption-m">
<span>R-series</span>
<a href="#" tabindex="-1">Remove</a>
</div>
</div>
</div>
</div>
<div slot="footer" class="wa-stack">
<div class="wa-split">
<strong>Subtotal</strong>
<strong>$3,229.98</strong>
</div>
<span class="wa-caption-m">Shipping and taxes calculated at checkout.</span>
<wa-button tabindex="-1" variant="brand">
<wa-icon slot="prefix" name="shopping-bag"></wa-icon>
Checkout
</wa-button>
</div>
</wa-card>
<wa-card>
<wa-avatar shape="rounded" style="--size: 1.9lh; float: left; margin-right: var(--wa-space-m);">
<wa-icon slot="icon" name="hat-wizard" family="duotone" style="font-size: 1.75em;"></wa-icon>
</wa-avatar>
<p class="wa-body-l" style="margin: 0;">&ldquo;All we have to decide is what to do with the time that is given to us. There are other forces at work in this world, Frodo, besides the will of evil.&rdquo;</p>
</wa-card>
<wa-card>
<div class="wa-stack">
<h3 class="wa-heading-m">Sign In</h3>
<wa-input tabindex="-1" label="Email" placeholder="ddjarin@mandalore.gov">
<wa-icon slot="prefix" name="envelope" variant="regular"></wa-icon>
</wa-input>
<wa-input tabindex="-1" label="Password" type="password">
<wa-icon slot="prefix" name="lock" variant="regular"></wa-icon>
</wa-input>
<wa-button tabindex="-1" variant="brand">Sign In</wa-button>
<a href="#" tabindex="-1" class="wa-body-s">I forgot my password</a>
</div>
</wa-card>
<wa-card with-footer>
<div class="wa-stack">
<div class="wa-split">
<h3 class="wa-heading-m">To-Do</h3>
<wa-icon-button tabindex="-1" name="plus" label="Add task"></wa-icon-button>
</div>
<wa-checkbox tabindex="-1" checked>Umbrella for Adelard</wa-checkbox>
<wa-checkbox tabindex="-1" checked>Waste-paper basket for Dora</wa-checkbox>
<wa-checkbox tabindex="-1" checked>Pen and ink for Milo</wa-checkbox>
<wa-checkbox tabindex="-1">Mirror for Angelica</wa-checkbox>
<wa-checkbox tabindex="-1">Silver spoons for Lobelia</wa-checkbox>
</div>
<div slot="footer">
<a href="" tabindex="-1">View all completed</a>
</div>
</wa-card>
<wa-card>
<div class="wa-stack">
<div class="wa-frame wa-border-radius-m" style="align-self: center; max-inline-size: 25ch;">
<img src="https://images.unsplash.com/photo-1667514627762-521b1c815a89?q=20" alt="Album art">
</div>
<div class="wa-flank:end wa-align-items-start">
<div class="wa-stack wa-gap-3xs">
<div class="wa-cluster wa-gap-xs" style="height: 2.25em;">
<strong>The Stone Troll</strong>
<small><wa-badge variant="neutral" appearance="filled">E</wa-badge></small>
</div>
<span class="wa-caption-m">Samwise G</span>
</div>
<wa-icon-button tabindex="-1" name="ellipsis" label="Options"></wa-icon-button>
</div>
<div class="wa-stack wa-gap-2xs">
<wa-progress-bar value="34" style="height: 0.5em"></wa-progress-bar>
<div class="wa-split">
<span class="wa-caption-xs">1:01</span>
<span class="wa-caption-xs">-1:58</span>
</div>
</div>
<div class="wa-grid wa-align-items-center" style="--min-column-size: 1em; justify-items: center;">
<wa-icon-button tabindex="-1" name="backward" label="Skip backward"></wa-icon-button>
<wa-icon-button tabindex="-1" name="pause" style="font-size: var(--wa-font-size-2xl);" label="Pause"></wa-icon-button>
<wa-icon-button tabindex="-1" name="forward" label="Skip forward"></wa-icon-button>
</div>
</div>
</wa-card>
<wa-card>
<div class="wa-stack">
<h3 class="wa-heading-m">Chalmun's Spaceport Cantina</h3>
<div class="wa-cluster wa-gap-xs">
<wa-rating value="4.6" read-only></wa-rating>
<strong>4.6</strong>
<span>(419 reviews)</span>
</div>
<div class="wa-cluster wa-gap-xs">
<div class="wa-cluster wa-gap-3xs">
<wa-icon name="dollar" style="color: var(--wa-color-green-60);"></wa-icon>
<wa-icon name="dollar" style="color: var(--wa-color-green-60);"></wa-icon>
<wa-icon name="dollar" style="color: var(--wa-color-green-60);"></wa-icon>
</div>
<span class="wa-caption-m">&bull;</span>
<wa-tag size="small">Cocktail Bar</wa-tag>
<wa-tag size="small">Gastropub</wa-tag>
<wa-tag size="small">Local Fare</wa-tag>
<wa-tag size="small">Gluten Free</wa-tag>
</div>
<div class="wa-flank wa-gap-xs">
<wa-icon name="location-dot"></wa-icon>
<a href="#" class="wa-caption-m" tabindex="-1">Mos Eisley, Tatooine</a>
</div>
</div>
</wa-card>
</div>
</div>

View File

@@ -1,62 +1,11 @@
<!DOCTYPE html>
<html lang="en" data-fa-kit-code="b10bfbde90" data-cdn-url="{% cdnUrl %}">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{ description }}">
{% if noindex %}<meta name="robots" content="noindex">{% endif %}
<title>{{ title }}</title>
<link rel="icon" href="/assets/images/webawesome-logo.svg" />
<link rel="apple-touch-icon" href="/assets/images/app-icon.png">
{# Scripts #}
{# Hydration stuff #}
<script src="/assets/scripts/hydration-errors.js"></script>
<link rel="stylesheet" href="/assets/styles/hydration-errors.css">
<link rel="preconnect" href="https://cdn.jsdelivr.net">
<script type="module" src="https://cdn.jsdelivr.net/npm/@hotwired/turbo@8.0.10/+esm"></script>
{# Web Awesome #}
<script type="module" src="/dist/webawesome.ssr-loader.js"></script>
<link rel="stylesheet" id="theme-stylesheet" />
<link rel="stylesheet" href="/dist/styles/applied.css" />
<link id="color-stylesheet" rel="stylesheet" href="/dist/styles/utilities.css" />
<link rel="stylesheet" href="/dist/styles/forms.css" />
{# Set the theme to prevent flashing #}
<script>
function getColorScheme() {
return localStorage.getItem('colorScheme') || 'auto';
}
function getPresetTheme () {
return localStorage.getItem('presetTheme') || 'default';
}
function isDark() {
const colorScheme = getColorScheme()
if (colorScheme === 'auto') {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}
return colorScheme === 'dark';
}
const stylesheet = document.getElementById("theme-stylesheet")
let preset = getPresetTheme()
stylesheet.href = `/dist/styles/themes/${preset}.css`
document.documentElement.classList.toggle(
`wa-theme-${preset}-dark`,
isDark()
);
</script>
{% include 'head.njk' %}
</head>
<body class="layout-{{ layout | stripExtension }}">
{% block beforeContent %}{% endblock %}
{% block header %}{% endblock %}
{% block content %}
{{ content | safe }}

38
docs/_layouts/block.njk Normal file
View File

@@ -0,0 +1,38 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends '../_includes/base.njk' %}
{# Component header #}
{% block header %}
{% include 'breadcrumbs.njk' %}
<h1 class="title">{{ title }}</h1>
<div class="block-info">
{% set snippets = (elements or element or snippets or snippet) | dict %}
{% for snippet, link in snippets %}
{% if snippet %}
<code class="class">
{%- if link -%}
<a href="{{ link }}">{{ snippet }}</a>
{%- else -%}
{{ snippet }}
{%- endif-%}
</code>
{%- endif %}
{% endfor %}
{% include '../_includes/status.njk' %}
</div>
{% if description %}
<p class="summary">
{{ description | inlineMarkdown | safe }}
</p>
{% endif %}
{% block notes %}{% endblock %}
{% endblock %}
{# Content #}
{% block content %}
{{ content | safe }}
{% endblock %}

View File

@@ -1,42 +1,17 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends '../_layouts/block.njk' %}
{% set component = components[page.fileSlug] %}
{% set description = component.summary %}
{% extends '../_includes/base.njk' %}
{# Component header #}
{% block beforeContent %}
<h1 class="title">{{ title }}</h1>
<div class="component-info">
<code class="tag">&lt;{{ component.tagName }}&gt;</code>
<wa-badge variant="neutral">Since {{ component.since }}</wa-badge>
<wa-badge
{% if component.status == 'stable' %}variant="brand"{% endif %}
{% if component.status == 'experimental' %}variant="warning"{% endif %}
>
{{ component.status }}
</wa-badge>
{% if isPro %}<wa-badge class="pro">PRO</wa-badge>{% endif %}
</div>
<p class="summary">
{{ component.summary | inlineMarkdown | safe }}
</p>
{% if essentials %}
{% block notes %}
{% if native %}
<wa-callout variant="success">
<wa-icon slot="icon" name="lightbulb" variant="regular"></wa-icon>
Just want the styles?
Check out <a href="/docs/essentials/{{ essentials }}/">{{ ('/docs/essentials/' + essentials + '/') | getTitleFromUrl }} essentials</a>!
Check out the <a href="/docs/native/{{ native }}/">{{ ('/docs/native/' + native + '/') | getTitleFromUrl }} native styles</a>!
</wa-callout>
{% endif %}
{% endblock %}
{# Content #}
{% block content %}
{{ content | safe }}
{% endblock %}
{# Component API #}
{% block afterContent %}
{# Slots #}

View File

@@ -1,54 +1,23 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends '../_includes/base.njk' %}
{% extends '../_layouts/block.njk' %}
{# Component header #}
{% block beforeContent %}
<h1 class="title">{{ title }}</h1>
<div class="component-info">
{% for tag, url in elements %}
<code class="tag"><a href="{{ url }}">{{ tag }}</a></code>
{% endfor %}
{% if since %}<wa-badge variant="neutral">Since {{ since }}</wa-badge>{% endif %}
{% if status %}
<wa-badge
{% if status == 'stable' %}variant="brand"{% endif %}
{% if status == 'experimental' %}variant="warning"{% endif %}
>
{{ status }}
</wa-badge>
{% endif %}
{% if isPro %}
<wa-badge class="pro">PRO</wa-badge>
{% endif %}
</div>
{% if description -%}
<p class="summary">{{ description | inlineMarkdown | safe }}</p>
{%- endif %}
{% block notes %}
{% if component %}
<wa-callout variant="success">
<wa-icon slot="icon" name="lightbulb" variant="regular"></wa-icon>
Want to do more?
Check out the {% for name in (component | toArray) -%}
Check out the {% for name in (component | toList) -%}
{{ ' and ' if loop.last and not loop.first }}<a href="/docs/components/{{ name }}"><code>&lt;wa-{{ name }}&gt;</code></a>{{ ', ' if not loop.last }}
{%- endfor %} component{{ 's' if (component | isArray) }}</a>!
{%- endfor %} component{{ 's' if (component | isList) }}</a>!
</wa-callout>
{% endif %}
{% endblock %}
{# Content #}
{% block content %}
{{ content | safe }}
{% endblock %}
{# Component API #}
{% block afterContent %}
{# Slots #}
{% if css_file %}
<h2>Using these styles</h2>
<p>If you want to use these styles without using the entirety of Web Awesome Essentials, you can include the following CSS files:</p>
<p>If you want to use these styles without using the entirety of Web Awesome Native Styles, you can include the following CSS files:</p>
{% endif %}

View File

@@ -0,0 +1,25 @@
---
layout: page-outline
tags: ["overview"]
---
{% set forTag = forTag or (page.url | split('/') | last) %}
{% if description %}
<div class="index-summary">{{ description | markdown | safe }}</div>
{% endif %}
<div id="block-filter">
<wa-input type="search" placeholder="Search {{ title }}" clearable autofocus>
<wa-icon slot="prefix" name="search"></wa-icon>
</wa-input>
</div>
{% set allPages = collections[forTag] %}
{% include "grouped-pages.njk" %}
<link href="/assets/styles/filter.css" rel="stylesheet">
<script type="module" src="/assets/scripts/filter.js"></script>
{% if content | trim %}
<br> {# Temp fix for spacing issue #}
{{ content | safe }}
{% endif %}

View File

@@ -1,4 +0,0 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends "../_includes/base-wide.njk" %}

119
docs/_layouts/palette.njk Normal file
View File

@@ -0,0 +1,119 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{# {% set forceTheme = page.fileSlug %} #}
{% extends '../_layouts/block.njk' %}
{% set paletteId = page.fileSlug %}
{% block afterContent %}
<style>@import url('/dist/styles/color/{{ paletteId }}.css') layer(palette.{{ paletteId }});</style>
{% set tints = ["95", "90", "80", "70", "60", "50", "40", "30", "20", "10", "05"] %}
<table class="colors wa-palette-{{ paletteId }}">
<thead>
<tr>
<th></th>
{% for tint in tints -%}
<th>{{ tint }}</th>
{%- endfor %}
</tr>
</thead>
{% for hue in hues -%}
<tr>
<th>{{ hue | capitalize }}</th>
{% for tint in tints -%}
<td>
<div class="color swatch" style="background-color: var(--wa-color-{{ hue }}-{{ tint }})">
<wa-copy-button value="--wa-color-{{ hue }}-{{ tint }}" copy-label="--wa-color-{{ hue }}-{{ tint }}"></wa-copy-button>
</div>
</td>
{%- endfor -%}
</tr>
{%- endfor %}
</table>
<h2>Used By</h2>
<section class="index-grid">
{% for page in collections.theme %}
{%- if page.data.palette == paletteId -%}
{% include "page-card.njk" %}
{%- endif -%}
{% endfor %}
</section>
{% markdown %}
## Color Contrast
Web Awesome color scales are designed to guarantee certain contrast ratios,
both per [WCAG 2.1 success criteria](https://www.w3.org/TR/WCAG21/#contrast-minimum)
as well as the emergent APCA specification _(planned)_,
so you can ensure that text is both legible to all users, and legally conformant.
### Level 1
A difference of `40` ensures a minimum **3:1** contrast ratio, suitable for large text and icons (AA).
{% endmarkdown %}
{% set difference = 40 %}
{% include "contrast-table.njk" %}
{% markdown %}
This also goes for a difference of `45`:
{% endmarkdown %}
{% set difference = 45 %}
{% include "contrast-table.njk" %}
{% markdown %}
### Level 2
A difference of `50` ensures a minimum **4.5:1** contrast ratio, suitable for normal text (AA) and large text (AAA)
{% endmarkdown %}
{% set difference = 50 %}
{% include "contrast-table.njk" %}
{% markdown %}
This also goes for a difference of `55`:
{% endmarkdown %}
{% set difference = 55 %}
{% include "contrast-table.njk" %}
{% markdown %}
### Level 3
A difference of `60` ensures a minimum **7:1** contrast ratio, suitable for all text (AAA)
{% endmarkdown %}
{% set difference = 60 %}
{% include "contrast-table.njk" %}
{% markdown %}
This also goes for a difference of `65`:
{% endmarkdown %}
{% set difference = 65 %}
{% include "contrast-table.njk" %}
{% markdown %}
## How to use this palette
If you are using a Web Awesome theme that uses this palette, it will already be included.
To use a different palette than a theme default, or to use it in a custom theme, you can import this palette directly from the Web Awesome CDN.
{% set stylesheet = 'styles/color/' + page.fileSlug + '.css' %}
{% include 'import-stylesheet-code.md.njk' %}
{% endmarkdown %}
{% endblock %}

View File

@@ -1,4 +0,0 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{% extends "../_includes/base.njk" %}

150
docs/_layouts/theme.njk Normal file
View File

@@ -0,0 +1,150 @@
{% set hasSidebar = true %}
{% set hasOutline = true %}
{# {% set forceTheme = page.fileSlug %} #}
{% extends '../_includes/base.njk' %}
{% block header %}
<iframe src='{{ page.url }}demo.html' id="demo"></iframe>
<p id="mix_and_match" class="wa-gap-m">
<strong>
<wa-icon name="merge" slot="prefix"></wa-icon>
Remix
<wa-icon-button href="#remixing" name="circle-question" slot="suffix" variant="regular" label="How to use?"></wa-icon-button>
</strong>
<wa-select name="colors" label="Colors from…" size="small">
<wa-icon name="palette" slot="prefix" variant="regular"></wa-icon>
<wa-option value="">(Theme default)</wa-option>
<wa-divider></wa-divider>
{% for theme in collections.theme | sort %}
{% if theme.fileSlug !== page.fileSlug %}
<wa-option value="{{ theme.fileSlug }}">{{ theme.data.title }}</wa-option>
{% endif %}
{% endfor %}
</wa-select>
<wa-select name="palette" label="Palette" size="small">
<wa-icon name="swatchbook" slot="prefix" variant="regular"></wa-icon>
<wa-option value="">(Theme default)</wa-option>
<wa-divider></wa-divider>
{% for p in collections.palette | sort %}
{% if p.fileSlug !== palette %}
<wa-option value="{{ p.fileSlug }}">{{ p.data.title }}</wa-option>
{% endif %}
{% endfor %}
</wa-select>
<wa-select name="typography" label="Typography from…" size="small">
<wa-icon name="font-case" slot="prefix"></wa-icon>
<wa-option value="">(Theme default)</wa-option>
<wa-divider></wa-divider>
{% for theme in collections.theme | sort %}
{% if theme.fileSlug !== page.fileSlug %}
<wa-option value="{{ theme.fileSlug }}">{{ theme.data.title }}</wa-option>
{% endif %}
{% endfor %}
</wa-select>
</p>
<script>
document.querySelector('#mix_and_match').addEventListener('wa-change', function(event) {
let selects = document.querySelectorAll('#mix_and_match wa-select');
let url = new URL(demo.src);
for (let select of selects) {
url.searchParams.set(select.name, select.value);
}
demo.src = url;
});
</script>
<h2>Default Color Palette</h2>
{% set paletteURL = '/docs/palettes/' + palette + '/' %}
{% set themePage = page %}
{% set page = paletteURL | getCollectionItemFromUrl %}
<div class="index-grid">
{% include 'page-card.njk' %}
</div>
{% set page = themePage %}
{% endblock %}
{% block afterContent %}
{% markdown %}
## How to use this theme
You can import this theme from the Web Awesome CDN.
{% set stylesheet = 'styles/themes/' + page.fileSlug + '.css' %}
{% include 'import-stylesheet-code.md.njk' %}
### Remixing { #remixing }
If you want to combine the **colors** from this theme with another theme, you can import this CSS file *after* the other themes CSS file:
{% set stylesheet = 'styles/themes/' + page.fileSlug + '/color.css' %}
{% include 'import-stylesheet-code.md.njk' %}
To use the **typography** from this theme with another theme, you can import this CSS file *after* the other themes CSS file:
{% set stylesheet = 'styles/themes/' + page.fileSlug + '/typography.css' %}
{% include 'import-stylesheet-code.md.njk' %}
<wa-callout variant="warning">
<wa-icon slot="icon" name="triangle-exclamation" variant="regular"></wa-icon>
Please note that not all combinations will look good — once youre mixing and matching, youre on your own!
</wa-callout>
## Dark mode
To activate the dark color scheme of the theme on any element and its contents, apply the class `wa-dark` to it.
This means you can use different color schemes throughout the page.
Here, we use the default theme with a dark sidebar:
```html
<html>
<head>
<link rel="stylesheet" href="path/to/web-awesome/dist/styles/themes/default.css" />
</head>
<body>
<nav class="wa-dark">
<!-- dark-themed sidebar -->
</nav>
<!-- light-themed content -->
</body>
</html>
```
You can apply the class to the `<html>` element on your page to activate the dark color scheme for the entire page.
```html
<html class="wa-dark">
<head>
<link rel="stylesheet" href="path/to/web-awesome/dist/styles/themes/{{ page.fileSlug }}.css" />
<!-- other links, scripts, and metadata -->
</head>
<body>
<!-- page content -->
</body>
</html>
```
### Detecting Color Scheme Preference
Web Awesome's themes have both light and dark styles built in.
However, Web Awesome doesn't try to auto-detect the user's light/dark mode preference.
This should be done at the application level.
As a best practice, to provide a dark theme in your app, you should:
- Check for [`prefers-color-scheme`](https://stackoverflow.com/a/57795495/567486) and use its value by default
- Allow the user to override the setting in your app
- Remember the user's preference and restore it on subsequent logins
Web Awesome avoids using the `prefers-color-scheme` media query because not all apps support dark mode, and it would break things for the ones that don't.
{% endmarkdown %}
{% endblock %}

View File

@@ -38,8 +38,12 @@ export function getTitleFromUrl(url, collection) {
return item?.data.title || '';
}
export function split(text, separator) {
return (text + '').split(separator).filter(Boolean);
}
export function breadcrumbs(url, { withCurrent = false } = {}) {
const parts = url.split('/').filter(Boolean);
const parts = split(url, '/');
const ret = [];
while (parts.length) {
@@ -70,10 +74,211 @@ export function breadcrumbs(url, { withCurrent = false } = {}) {
return ret;
}
export function isArray(value) {
return Array.isArray(value);
export function isObject(value) {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
export function toArray(value) {
return isArray(value) ? value : [value];
export function isList(value) {
return Array.isArray(value) || value instanceof Set;
}
/** Get an Array or Set */
export function toList(value) {
return isList(value) ? value : [value];
}
/**
* Convert any value to something that can be iterated over with a for key, value loop.
* Arrays and sets will be converted to a Map of value -> undefined
*/
export function dict(value) {
if (value instanceof Map || isObject(value)) {
return value;
}
let list = toList(value);
return new Map([...list].map(item => [item, undefined]));
}
export function deepValue(obj, key) {
key = Array.isArray(key) ? key : key.split('.');
return key.reduce((subObj, property) => subObj?.[property], obj);
}
export function number(value, options) {
if (typeof value !== 'number' && isNaN(value)) {
return value;
}
let lang = options?.lang ?? 'en';
if (options?.lang) {
delete options.lang;
}
if (!options || Object.keys(options).length === 0) {
options = { maximumSignificantDigits: 3 };
}
return Number(value).toLocaleString(lang, options);
}
export function isNumeric(value) {
return typeof value === 'number' || (typeof value === 'string' && !isNaN(value));
}
export function isString(value) {
return typeof value === 'string';
}
export function isEmpty(value) {
return value === null || value === undefined || value === '';
}
function compare(a, b) {
let isEmptyA = isEmpty(a);
let isEmptyB = isEmpty(b);
if (isEmptyA) {
if (isEmptyB) {
return 0;
} else {
return 1;
}
} else if (isEmptyB) {
return -1;
}
// Both strings, and at least one non-numeric
if (isNumeric(a) || isNumeric(b)) {
return a - b;
}
return (a + '').localeCompare(b);
}
/** Sort an array of objects by one or more of their properties */
export function sort(arr, by = { 'data.order': 1, 'data.title': '' }) {
let keys = Array.isArray(by) ? by : Object.keys(by);
return arr.sort((a, b) => {
let aValues = keys.map(key => deepValue(a, key) ?? by[key]);
let bValues = keys.map(key => deepValue(b, key) ?? by[key]);
for (let i = 0; i < aValues.length; i++) {
let aVal = aValues[i];
let bVal = bValues[i];
let result = compare(aVal, bVal);
// They are not equal in terms of comparison OR we're at the last key
if (result !== 0 || i === aValues.length - 1) {
return result;
}
}
});
}
/**
* Group an 11ty collection (or any array of objects with a `data.tags` property) by certain tags.
* @param {object[]} collection
* @param { Object<string, string> | (string | Object<string, string>)[]} [tags] The tags to group by. If not provided/empty, defaults to grouping by all tags.
* @returns { Object.<string, object[]> } An object with keys for each tag, and an array of items for each tag.
*/
export function groupByTags(collection, tags) {
if (!collection) {
console.error(`Empty collection passed to groupByTags() to group by ${JSON.stringify(tags)}`);
}
if (!tags) {
// Default to grouping by union of all tags
tags = Array.from(new Set(collection.flatMap(item => item.data.tags)));
} else if (Array.isArray(tags)) {
// May contain objects of one-off tag -> label mappings
tags = tags.map(tag => (typeof tag === 'object' ? Object.keys(tag)[0] : tag));
} else if (typeof tags === 'object') {
// tags is an object of tags to labels, so we just want the keys
tags = Object.keys(tags);
}
let ret = Object.fromEntries(tags.map(tag => [tag, []]));
ret.other = [];
for (let item of collection) {
let categorized = false;
for (let tag of tags) {
if (item.data.tags.includes(tag)) {
ret[tag].push(item);
categorized = true;
}
}
if (!categorized) {
ret.other.push(item);
}
}
// Remove empty categories
for (let category in ret) {
if (ret[category].length === 0) {
delete ret[category];
}
}
return ret;
}
export function getCategoryTitle(category, categories) {
let title;
if (Array.isArray(categories)) {
// Find relevant entry
// [{id: "Title"}, id2, ...]
title = categories.find(entry => typeof entry === 'object' && entry?.[category])?.[category];
} else if (typeof categories === 'object') {
// {id: "Title", id2: "Title 2", ...}
title = categories[category];
}
if (title) {
return title;
}
// Capitalized
return category.charAt(0).toUpperCase() + category.slice(1);
}
const IDENTITY = x => x;
/**
* Helper to print out one or more HTML attributes, especially conditional ones.
* Usage in 11ty:
* - Single attribute: `<foo{{ value | attr(name) }}>`
* - Multiple attributes: `<foo{{ { name1: value1, name2: value2 } | attr }}>`
*
* @overload
* @param {any} value - The attribute value If falsey, the attribute is not printed. If `true` the attribute is printed without a value.
* @param {string} name - The name of the attribute
*
* @overload
* @param {Object<string, any>} obj - Map of attribute names to values
*
* @returns {string} The attribute string. No `| safe` is needed.
*/
export function attr(value, name) {
const safe = this?.env.filters.safe ?? IDENTITY;
if (arguments.length === 1 && value && typeof value === 'object') {
// Called with a single object argument of names to values
let ret = Object.entries(obj)
.map(([name, value]) => attr(value, name))
.join('');
return safe(ret);
}
if (!value) {
// false, "", null, undefined
return '';
}
let ret = ' ' + name + (value === true ? '' : `="${value}"`);
return safe(ret);
}

View File

Before

Width:  |  Height:  |  Size: 698 KiB

After

Width:  |  Height:  |  Size: 698 KiB

View File

Before

Width:  |  Height:  |  Size: 241 KiB

After

Width:  |  Height:  |  Size: 241 KiB

View File

Before

Width:  |  Height:  |  Size: 786 KiB

After

Width:  |  Height:  |  Size: 786 KiB

View File

Before

Width:  |  Height:  |  Size: 716 KiB

After

Width:  |  Height:  |  Size: 716 KiB

View File

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 148 KiB

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

Before

Width:  |  Height:  |  Size: 438 KiB

After

Width:  |  Height:  |  Size: 438 KiB

View File

@@ -19,10 +19,10 @@ document.addEventListener('click', event => {
const html =
`<script type="module" src="${cdnUrl}webawesome.loader.js"></script>\n` +
`<link rel="stylesheet" href="${cdnUrl}styles/themes/default.css">\n` +
`<link rel="stylesheet" href="${cdnUrl}styles/applied.css">\n` +
`<link rel="stylesheet" href="${cdnUrl}styles/webawesome.css">\n` +
`<link rel="stylesheet" href="${cdnUrl}styles/utilities.css">\n\n` +
`${code.textContent}`;
const css = 'html > body {\n font: 16px sans-serif;\n padding: 2rem;\n}';
const css = 'html > body {\n padding: 2rem !important;\n}';
const js = '';
const form = document.createElement('form');

View File

@@ -1,59 +0,0 @@
//
// Color scheme selector
//
(() => {
function setColorScheme(newColorScheme) {
colorScheme = newColorScheme;
localStorage.setItem('colorScheme', colorScheme);
const presetTheme = window.getPresetTheme();
// Update the UI
updateSelection();
// Toggle the dark mode class
document.documentElement.classList.toggle(`wa-theme-${presetTheme}-dark`, window.isDark());
}
function updateSelection() {
const menu = document.querySelector('#color-scheme-selector wa-menu');
if (!menu) return;
[...menu.querySelectorAll('wa-menu-item')].forEach(async item => {
await customElements.whenDefined(item.localName);
await item.updateComplete;
item.checked = item.getAttribute('value') === colorScheme;
});
}
let colorScheme = window.getColorScheme();
// Selection is not preserved when changing page, so update when opening dropdown
document.addEventListener('wa-show', event => {
const colorSchemeSelector = event.target.closest('#color-scheme-selector');
if (!colorSchemeSelector) return;
updateSelection();
});
// Listen for selections
document.addEventListener('wa-select', event => {
const menu = event.target.closest('#color-scheme-selector wa-menu');
if (!menu) return;
setColorScheme(event.detail.item.value);
});
// Update the color scheme when the preference changes
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => setColorScheme(colorScheme));
// Toggle with backslash
document.addEventListener('keydown', event => {
if (
event.key === '\\' &&
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
) {
event.preventDefault();
setColorScheme(window.isDark() ? 'light' : 'dark');
}
});
// Set the initial color scheme and sync the UI
setColorScheme(colorScheme);
})();

View File

@@ -0,0 +1,25 @@
function updateResults(input) {
const filter = input.value.toLowerCase().trim();
let filtered = Boolean(filter);
for (let grid of document.querySelectorAll('.index-grid')) {
grid.classList.toggle('filtered', filtered);
for (let item of grid.querySelectorAll('a:has(> wa-card)')) {
let isMatch = true;
if (filter) {
const content = item.textContent.toLowerCase() + ' ' + (item.getAttribute('data-keywords') + ' ');
isMatch = content.includes(filter);
}
item.hidden = !isMatch;
}
}
}
document.documentElement.addEventListener('wa-input', e => {
if (e.target?.matches('#block-filter wa-input')) {
updateResults(e.target);
}
});

View File

@@ -0,0 +1,52 @@
import { domChange, nextFrame, ThemeAspect } from './theme-picker.js';
const presetTheme = new ThemeAspect({
defaultValue: 'default',
key: 'presetTheme',
picker: 'wa-select.preset-theme-selector',
applyChange(options = {}) {
const oldStylesheets = [...document.querySelectorAll('#theme-stylesheet')];
const oldStylesheet = oldStylesheets.pop();
if (oldStylesheets.length > 0) {
// Remove all but the last one
for (let stylesheet of oldStylesheets) {
stylesheet.remove();
}
}
const href = `/dist/styles/themes/${this.value}.css`;
if (!oldStylesheet || oldStylesheet.getAttribute('href') !== href) {
const newStylesheet = document.createElement('link');
Object.assign(newStylesheet, { href, id: 'theme-stylesheet', rel: 'preload', as: 'style' });
oldStylesheet.after(newStylesheet);
newStylesheet.addEventListener(
'load',
e => {
domChange(
async instant => {
// Swap stylesheets
newStylesheet.rel = 'stylesheet';
if (instant) {
// If no VT, delay by 1 frame to make it smoother
await nextFrame();
}
oldStylesheet.remove();
},
{ behavior: 'smooth', ...options },
);
},
{ once: true },
);
}
},
});
window.addEventListener('turbo:render', e => {
presetTheme.applyChange({ behavior: 'instant' });
});

View File

@@ -1,86 +0,0 @@
//
// Preset theme selector
//
(() => {
function setPresetTheme(newPresetTheme) {
presetTheme = newPresetTheme;
localStorage.setItem('presetTheme', presetTheme);
const stylesheet = document.getElementById('theme-stylesheet');
const newStylesheet = Object.assign(document.createElement('link'), {
href: `/dist/styles/themes/${presetTheme}.css`,
rel: 'preload',
as: 'style',
});
newStylesheet.addEventListener(
'load',
() => {
newStylesheet.rel = 'stylesheet';
newStylesheet.id = stylesheet.id;
requestAnimationFrame(() => {
stylesheet.remove();
});
},
{ once: true },
);
document.head.append(newStylesheet);
// Update the UI
updateSelection();
// Toggle the dark mode class
document.documentElement.classList.toggle(`wa-theme-${presetTheme}-dark`, window.isDark());
}
function updateSelection(container = document) {
const menu = container.querySelector('#preset-theme-selector wa-menu');
if (!menu) return;
[...menu.querySelectorAll('wa-menu-item')].forEach(async item => {
const isChecked = item.getAttribute('value') === presetTheme;
if (isChecked) {
container.querySelector('#preset-theme-selector__text').textContent = item.innerText;
}
await customElements.whenDefined(item.localName);
await item.updateComplete;
item.checked = isChecked;
});
}
let presetTheme = window.getPresetTheme();
// Selection is not preserved when changing page, so update when opening dropdown
document.addEventListener('wa-show', event => {
const presetThemeSelector = event.target.closest('#preset-theme-selector');
if (!presetThemeSelector) return;
updateSelection();
});
// Listen for selections
document.addEventListener('wa-select', event => {
const menu = event.target.closest('#preset-theme-selector wa-menu');
if (!menu) return;
setPresetTheme(event.detail.item.value);
});
// Update the color scheme when the preference changes
window.matchMedia('(prefers-preset-theme: dark)').addEventListener('change', () => setPresetTheme(presetTheme));
updateSelection();
/**
* Without this, there's a flash of the incorrect preset theme.
*/
function updateSelectionBeforeTurboLoad(e) {
const newElement = e.detail.newBody || e.detail.newFrame || e.detail.newStream;
if (!newElement) {
return;
}
updateSelection(newElement);
}
['turbo:before-render', 'turbo:before-stream-render', 'turbo:before-frame-render'].forEach(eventName => {
document.addEventListener(eventName, updateSelectionBeforeTurboLoad);
});
})();

View File

@@ -9,6 +9,7 @@ const icons = {
component: 'puzzle-piece',
document: 'file',
home: 'house',
native: 'code',
theme: 'palette',
};
let searchTimeout;
@@ -166,6 +167,7 @@ async function updateResults(query = '') {
li.setAttribute('data-selected', index === 0 ? 'true' : 'false');
if (page.url === '/') icon = icons.home;
if (page.url.startsWith('/docs/native')) icon = icons.native;
if (page.url.startsWith('/docs/components')) icon = icons.component;
if (page.url.startsWith('/docs/theme') || page.url.startsWith('/docs/restyle')) icon = icons.theme;

View File

@@ -0,0 +1,37 @@
/**
* Sync iframe height with its content page (for same-origin iframes)
* NOT CURRENTLY USED ANYWHERE
*/
for (let iframe of document.querySelectorAll('iframe')) {
if (iframe.contentDocument) {
// Already loaded
syncIframeHeight(iframe);
}
iframe.onload = () => {
console.log('iframe loaded');
if (iframe.contentDocument) {
// Same origin
iframe.contentWindow.iframe = iframe;
syncIframeHeight(iframe);
const resizeObserver = new ResizeObserver(entries => {
for (let entry of entries) {
if (entry.target === iframe.contentDocument.body) {
syncIframeHeight(iframe);
}
}
});
resizeObserver.observe(iframe.contentDocument.body);
window.addEventListener('turbo:render', syncIframeHeight(iframe));
}
};
}
function syncIframeHeight(iframe) {
iframe.style.height = '0px';
requestAnimationFrame(() => {
iframe.style.height = iframe.contentDocument.body.scrollHeight + 'px';
});
}

View File

@@ -0,0 +1,119 @@
// Helper for view transitions
export function domChange(fn, { behavior = 'smooth' } = {}) {
const canUseViewTransitions =
document.startViewTransition && !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (canUseViewTransitions && behavior === 'smooth') {
document.startViewTransition(fn);
} else {
fn(true);
}
}
export function nextFrame() {
return new Promise(resolve => requestAnimationFrame(resolve));
}
export class ThemeAspect {
constructor(options) {
Object.assign(this, options);
this.set();
// Update when local storage changes.
// That way changes in one window will propagate to others (including iframes).
window.addEventListener('storage', event => {
if (event.key === this.key) {
this.set();
}
});
// Listen for selections
document.addEventListener('wa-change', event => {
const picker = event.target.closest(this.picker);
if (picker) {
this.set(picker.value);
}
});
['turbo:before-render', 'turbo:before-stream-render', 'turbo:before-frame-render'].forEach(eventName => {
document.addEventListener(eventName, e => {
const newElement = e.detail.newBody || e.detail.newFrame || e.detail.newStream;
if (newElement) {
this.syncUI(newElement);
}
});
});
}
get() {
return localStorage.getItem(this.key) ?? this.defaultValue;
}
computed = {};
get computedValue() {
if (this.value in this.computed) {
return this.computed[this.value];
}
return this.value;
}
set(value = this.get()) {
if (value === this.value) {
return;
}
this.value = value;
if (this.value === this.defaultValue) {
localStorage.removeItem(this.key);
} else {
localStorage.setItem(this.key, this.value);
}
this.applyChange();
this.syncUI();
}
syncUI(container = document) {
for (let picker of container.querySelectorAll(this.picker)) {
picker.setAttribute('value', this.value);
picker.value = this.value;
}
}
}
const colorScheme = new ThemeAspect({
defaultValue: 'auto',
key: 'colorScheme',
picker: 'wa-select.color-scheme-selector',
computed: {
get auto() {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
},
},
applyChange() {
// Toggle the dark mode class
domChange(() => {
let dark = this.computedValue === 'dark';
document.documentElement.classList.toggle(`wa-dark`, dark);
});
},
});
// Update the color scheme when the preference changes
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => colorScheme.set());
// Toggle color scheme with backslash
document.addEventListener('keydown', event => {
if (
event.key === '\\' &&
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
) {
event.preventDefault();
colorScheme.set(theming.colorScheme.resolvedValue === 'dark' ? 'light' : 'dark');
}
});

View File

@@ -1,6 +1,6 @@
.code-example {
border: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
border-radius: var(--wa-border-radius-m);
border-radius: var(--wa-border-radius-l);
color: var(--wa-color-text-normal);
margin-block-end: var(--wa-flow-spacing);
}
@@ -41,8 +41,8 @@
border-bottom: none;
pre {
border-bottom-right-radius: var(--wa-border-radius-m);
border-bottom-left-radius: var(--wa-border-radius-m);
border-bottom-right-radius: var(--wa-border-radius-l);
border-bottom-left-radius: var(--wa-border-radius-l);
}
}
@@ -62,11 +62,11 @@
&:first-of-type {
border-left: none;
border-bottom-left-radius: var(--wa-border-radius-m);
border-bottom-left-radius: var(--wa-border-radius-l);
}
&:last-of-type {
border-bottom-right-radius: var(--wa-border-radius-m);
border-bottom-right-radius: var(--wa-border-radius-l);
}
&:focus-visible {

View File

@@ -1,6 +1,12 @@
pre {
background-color: var(--wa-color-gray-20);
color: white;
/* Ensures a discernible background color in dark mode
* Useful for themes that use gray-20 as --wa-color-surface-default */
.wa-dark & {
background-color: var(--wa-color-surface-lowered);
}
}
.code-comment,
.code-prolog,

View File

@@ -6,7 +6,7 @@ wa-copy-button.copy-button {
right: 0.25rem;
font-family: var(--wa-font-family-body);
color: var(--wa-color-gray-80);
border-radius: var(--wa-border-radius-s);
border-radius: var(--wa-border-radius-m);
padding: 0.25rem;
&:hover {

View File

@@ -10,8 +10,8 @@
--wa-brand-grey: #30323b;
}
html.wa-theme-default-dark .only-light,
html:not(.wa-theme-default-dark) .only-dark {
.wa-dark .only-light,
.only-dark:not(.wa-dark, .wa-dark *) {
display: none;
}
@@ -22,7 +22,7 @@ wa-page {
/* Header */
wa-page::part(header) {
background-color: var(--wa-color-surface-default);
border-bottom: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
border-bottom: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-surface-border);
}
wa-page::part(body) {
@@ -34,10 +34,6 @@ wa-page::part(header-actions) {
}
wa-page > header {
flex: 1 1 auto;
display: flex;
align-items: center;
justify-content: space-between;
padding-inline: var(--wa-space-xl);
a[href='/'] {
@@ -81,7 +77,7 @@ wa-page > header {
}
wa-button#search-trigger {
--background-color: var(--wa-form-control-background-color);
--border-color: var(--wa-form-control-resting-color);
--border-color: var(--wa-form-control-border-color);
}
#search-trigger kbd {
font-size: var(--wa-font-size-2xs);
@@ -104,17 +100,9 @@ wa-page > header {
wa-details {
border: none;
background: none;
}
wa-details::part(header) {
padding: 0;
}
wa-details::part(content) {
padding-inline: 0;
padding-block-end: 0;
}
ul {
border-inline-start: var(--wa-border-width-s) solid var(--wa-color-surface-border);
font-size: var(--wa-font-size-s);
@@ -223,6 +211,20 @@ wa-page::part(menu) {
scrollbar-width: thin;
}
wa-page[view='mobile'] :is([slot='navigation-header'], [slot='navigation']) {
padding: 0;
& wa-details::part(icon) {
padding-inline: var(--wa-space-xs); /* aligns details icons with drawer close icon */
}
}
[slot='navigation-header'] wa-menu {
font-family: var(--wa-font-family-body);
font-size: var(--wa-font-size-m);
font-weight: var(--wa-font-weight-normal);
}
/* Main content */
wa-page > main {
max-width: 80ch;
@@ -238,7 +240,7 @@ h1.title wa-badge {
}
}
.component-info {
.block-info {
margin-block-end: var(--wa-flow-spacing);
}
@@ -269,7 +271,7 @@ h1.title wa-badge {
display: flex;
gap: 1rem;
border: var(--wa-border-style) var(--wa-border-width-s);
border-radius: var(--wa-border-radius-m);
border-radius: var(--wa-border-radius-l);
padding: 1rem;
margin-block-end: var(--wa-flow-spacing);
@@ -329,8 +331,48 @@ wa-page > main:has(> .index-grid) {
.index-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(20ch, 100%), 1fr));
grid-template-columns: repeat(auto-fit, minmax(min(22ch, 100%), 1fr));
gap: var(--wa-space-2xl);
margin-block-end: var(--wa-space-3xl);
a {
border-radius: var(--wa-border-radius-l);
text-decoration: none;
}
wa-card {
box-shadow: none;
--spacing: var(--wa-space-m);
inline-size: 100%;
&:hover {
--border-color: var(--wa-color-brand-border-loud);
border-color: var(--border-color);
box-shadow: 0 0 0 var(--wa-border-width-s) var(--border-color);
.page-name {
color: var(--wa-color-brand-on-quiet);
}
}
[slot='header'] {
display: flex;
}
&::part(header) {
background-color: var(--wa-color-neutral-fill-quiet);
border-bottom: none;
display: flex;
align-items: center;
justify-content: center;
min-block-size: calc(6rem + var(--spacing));
}
}
.page-name {
font-size: var(--wa-font-size-s);
font-weight: var(--wa-font-weight-action);
}
}
.index-category {
@@ -339,123 +381,93 @@ wa-page > main:has(> .index-grid) {
margin-block-start: var(--wa-space-2xl);
}
.index-grid a {
border-radius: var(--wa-border-radius-m);
}
.index-grid wa-card {
--box-shadow: none;
--spacing: var(--wa-space-m);
inline-size: 100%;
}
.index-grid wa-card:hover {
--border-color: var(--wa-color-brand-border-loud);
--box-shadow: 0 0 0 var(--wa-border-width-s) var(--border-color);
& .page-name {
color: var(--wa-color-brand-on-quiet);
}
}
.index-grid wa-card [slot='header'] {
display: flex;
}
.index-grid wa-card::part(header) {
background-color: var(--wa-color-neutral-fill-quiet);
border-bottom: none;
display: flex;
align-items: center;
justify-content: center;
min-block-size: calc(6rem + var(--spacing));
}
.index-grid .page-name {
font-size: var(--wa-font-size-s);
font-weight: var(--wa-font-weight-action);
}
/* Index Pages */
wa-page > main:has(> .index-grid) {
max-width: 120ch;
margin-inline: auto;
}
.index-summary {
max-inline-size: 80ch;
}
.index-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(20ch, 100%), 1fr));
gap: var(--wa-space-2xl);
}
.index-category {
grid-column: 1 / -1;
margin-block-end: 0;
margin-block-start: var(--wa-space-2xl);
}
.index-grid a {
border-radius: var(--wa-border-radius-m);
}
.index-grid wa-card {
--box-shadow: none;
--spacing: var(--wa-space-m);
inline-size: 100%;
}
.index-grid wa-card:hover {
--border-color: var(--wa-color-brand-border-loud);
--box-shadow: 0 0 0 var(--wa-border-width-s) var(--border-color);
& .page-name {
color: var(--wa-color-brand-on-quiet);
}
}
.index-grid wa-card [slot='header'] {
display: flex;
}
.index-grid wa-card::part(header) {
background-color: var(--wa-color-neutral-fill-quiet);
border-bottom: none;
display: flex;
align-items: center;
justify-content: center;
min-block-size: calc(6rem + var(--spacing));
}
.index-grid .page-name {
font-size: var(--wa-font-size-s);
font-weight: var(--wa-font-weight-action);
}
/* Swatches */
.swatch {
position: relative;
display: flex;
align-items: center;
justify-content: center;
background-color: transparent;
border-color: var(--wa-color-neutral-border-normal);
border-style: var(--wa-border-style);
border-width: var(--wa-border-width-s);
border-radius: var(--wa-border-radius-s);
border-radius: var(--wa-border-radius-m);
box-sizing: border-box;
line-height: 2.5;
height: 2.5em;
padding-inline: var(--wa-space-xs);
min-height: 2.5em;
padding: var(--wa-space-xs);
font-weight: var(--wa-font-weight-semibold);
line-height: var(--wa-line-height-condensed);
&.color {
border-color: transparent;
}
wa-copy-button {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
--background-color-hover: transparent;
font-family: var(--wa-font-family-code);
&::part(button) {
display: block;
height: 100%;
width: 100%;
}
&::part(button):hover {
cursor: copy;
}
&::part(copy-icon),
&::part(success-icon),
&::part(error-icon) {
opacity: 0 !important;
}
}
}
table.colors {
thead {
th {
text-align: center;
padding-block: 0;
}
}
tbody {
tr {
border: none;
&:hover {
background: transparent;
}
}
th {
width: 0;
vertical-align: middle;
text-align: right;
}
td {
padding-inline: var(--wa-space-3xs);
padding-block: var(--wa-space-s);
}
}
}
/* Layout Examples */
.layout-example-boundary {
border: var(--wa-border-width-s) dashed var(--wa-color-neutral-border-normal);
border-radius: var(--wa-border-radius-m);
border-radius: var(--wa-border-radius-l);
padding: var(--wa-space-s);
}
.layout-example-block {
background-color: var(--wa-color-indigo-60);
border-radius: var(--wa-border-radius-s);
border-radius: var(--wa-border-radius-m);
min-block-size: 4rem;
min-inline-size: 4rem;
}
@@ -491,14 +503,9 @@ wa-page > main:has(> .index-grid) {
/** desktop */
@media screen and not (max-width: 768px) {
wa-page [data-toggle-nav],
wa-page .only-mobile {
display: none;
}
/* Navigation sidebar */
wa-page::part(navigation) {
border-right: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
border-right: var(--wa-border-style) var(--wa-panel-border-width) var(--wa-color-surface-border);
}
wa-page > #sidebar {
@@ -513,3 +520,39 @@ wa-page > main:has(> .index-grid) {
padding: var(--wa-space-3xl);
}
}
.layout-theme {
wa-page > main {
max-width: 140ch;
.max-line-length {
max-width: 80ch;
}
}
iframe {
width: 100%;
min-height: 16lh;
height: 65vh;
max-height: 21lh;
}
#mix_and_match {
strong {
display: flex;
align-items: center;
gap: var(--wa-space-2xs);
margin-top: 1.2em;
}
wa-select::part(label) {
margin-block-end: 0;
}
wa-select[value='']::part(display-input),
wa-option[value=''] {
font-style: italic;
color: var(--wa-color-text-quiet);
}
}
}

View File

@@ -0,0 +1,37 @@
wa-card#drawer-card::part(header) {
--spacing: 0;
justify-content: flex-end;
overflow: hidden;
}
#block-filter {
margin-block-end: var(--wa-space-xl);
}
.index-grid.filtered {
h2 {
/* Hide headings while filtering */
display: none;
}
&:not(:has(> a:not([hidden]))) {
/* Were filtering and there are no results */
&::before {
content: var(--empty-message);
grid-column: 1 / -1;
color: var(--wa-color-on-quiet);
font-style: italic;
font-weight: var(--wa-font-weight-action);
}
/* Show empty state when there's a search filter and no results */
&[data-empty] {
--empty-message: attr(data-empty);
}
&:not([data-empty]) {
--empty-message: 'No results';
}
}
}

View File

@@ -18,7 +18,7 @@
.diff-grid > * {
height: 100%;
}
.diff-dialog::part(dialog) {
.diff-dialog {
max-width: 90vw;
width: 90vw;
}

View File

@@ -31,6 +31,9 @@
}
@media screen and (max-width: 1199px) {
wa-page [slot='aside'] {
display: none;
}
#outline {
padding-block: 0.25rem;
margin-block-end: -1rem;
@@ -42,5 +45,6 @@
#outline-expandable {
display: block;
margin-block-end: var(--wa-space-xl);
}
}

View File

@@ -1,13 +1,14 @@
#site-search {
--width: 38rem;
width: 38rem;
position: absolute;
top: 0;
border-radius: var(--wa-border-radius-l);
padding: 0;
margin: 0 auto;
overflow: hidden;
&::part(dialog) {
position: absolute;
top: 0;
border-radius: var(--wa-border-radius-m);
padding: 0;
margin: 10rem auto;
overflow: hidden;
&::part(base) {
margin-block: 10rem;
}
&::part(body) {
@@ -18,21 +19,22 @@
justify-content: center;
gap: 0.5rem;
}
@media screen and (max-width: 900px) {
max-width: calc(100% - 2rem);
&::part(base) {
margin-block: 1rem;
}
}
}
#site-search-container {
display: flex;
flex-direction: column;
max-height: calc(100vh - 20rem);
}
@media screen and (max-width: 900px) {
#site-search::part(dialog) {
max-width: calc(100% - 2rem);
margin-block: 1rem;
}
#site-search-container {
@media screen and (max-width: 900px) {
max-height: calc(100dvh - 2rem);
}
}
@@ -229,8 +231,8 @@ header {
gap: 2rem;
color: var(--wa-color-text-quiet);
border-top: var(--wa-panel-border-style) var(--wa-panel-border-width) var(--wa-color-neutral-border-quiet);
border-bottom-left-radius: var(--wa-border-radius-m);
border-bottom-right-radius: var(--wa-border-radius-m);
border-bottom-left-radius: var(--wa-border-radius-l);
border-bottom-right-radius: var(--wa-border-radius-l);
padding: 1rem;
kbd {

View File

@@ -1,5 +1,14 @@
/* #region Custom Styles */
@container preview (min-width: 0) {
/* Theme Builder Headers
* These styles control the appearance of the header of the theme builder,
* allowing each theme to have a unique hero section.
*/
/* #region Default */
html.wa-theme-default .preview-container {
container-name: default-theme;
}
@container default-theme (min-width: 0) {
.hero-background {
height: 47rem;
background-color: var(--wa-color-brand-fill-loud);
@@ -22,7 +31,7 @@
}
.hero wa-button[variant='brand'] {
--background: var(--wa-color-neutral-fill-quiet);
--background-color: var(--wa-color-neutral-fill-quiet);
--text-color: var(--wa-color-neutral-on-normal);
}
@@ -41,10 +50,733 @@
}
/* responsive */
@container preview (min-width: 1040px) {
@container default-theme (min-width: 1040px) {
.hero-background::after {
background-position: right bottom;
background-size: 90%;
}
}
/* #endregion */
/* #region Tailspin */
html.wa-theme-tailspin .preview-container {
container-name: tailspin-theme;
}
@container tailspin-theme (min-width: 0) {
.project-header {
background: var(--wa-color-surface-default);
}
.hero {
--hero-background-color: var(--wa-color-surface-default);
--hero-lines-color: color-mix(in oklab, var(--wa-color-neutral-fill-normal), transparent 30%);
background: linear-gradient(to top, var(--wa-color-surface-lowered), transparent 40%),
radial-gradient(circle at 10% 70%, color-mix(in oklab, var(--wa-color-red-50) 16%, transparent), transparent 30%),
radial-gradient(
circle at 40% 50%,
color-mix(in oklab, var(--wa-color-indigo-40) 16%, transparent),
transparent 40%
),
radial-gradient(circle at 80% 25%, color-mix(in oklab, var(--wa-color-red-50) 8%, transparent), transparent 20%),
radial-gradient(
circle at 80% 80%,
color-mix(in oklab, var(--wa-color-indigo-40) 16%, transparent),
transparent 40%
),
radial-gradient(circle at 90% 30%, color-mix(in oklab, var(--wa-color-red-60) 8%, transparent), transparent 10%),
linear-gradient(176deg, var(--hero-background-color), transparent 6rem),
linear-gradient(90deg, var(--hero-background-color), transparent),
repeating-linear-gradient(
var(--hero-lines-color),
var(--hero-lines-color) 1px,
transparent 1px,
transparent 10rem,
var(--hero-lines-color) 10rem
),
repeating-linear-gradient(
90deg,
var(--hero-lines-color),
var(--hero-lines-color) 1px,
transparent 1px,
transparent 10rem,
var(--hero-lines-color) 10rem
),
var(--hero-background-color);
& .title {
padding-block: calc(var(--wa-space-3xl) * 2) calc(var(--wa-space-3xl) * 10);
& .hero-title {
font-size: calc((var(--wa-font-size-4xl) * 1.125) * 1.125);
margin-block: 0 var(--wa-space-3xl);
}
}
}
.badge-stock {
position: absolute;
top: var(--wa-space-l);
left: var(--wa-space-l);
}
.message-composer wa-card {
&::part(footer) {
border: none;
}
& wa-icon-button {
color: var(--wa-color-base-50);
}
}
.products {
margin-top: calc(var(--wa-space-3xl) * -8);
}
pre.codeblock {
background-color: var(--wa-color-neutral-fill-normal);
}
}
/* #endregion */
/* #region Brutalist */
html.wa-theme-brutalist .preview-container {
container-name: brutalist-theme;
}
@container brutalist-theme (min-width: 0) {
.overlap {
background: var(--wa-color-surface-lowered) url('/assets/images/themer/brutalist/hero.png') 50% 3% no-repeat;
}
.strata.hero {
height: 42rem;
padding-top: 8rem;
padding-right: 50%;
--wa-font-weight-heading: var(--wa-font-weight-normal);
}
.hero wa-button {
--background: var(--wa-color-neutral-fill-loud);
margin-block-start: var(--wa-space-xl);
font-size: var(--wa-font-size-l);
}
/* imitating the large button styles */
.hero wa-button::part(label) {
padding: 0 var(--wa-space-l);
}
.strata.products {
margin-top: -20rem;
padding-top: 10rem;
}
.product-card .badge-stock {
position: absolute;
top: 0;
left: 0;
}
.product-card::part(footer) {
--wa-shadow-offset-x-s: 0;
--wa-shadow-offset-y-s: 0;
border-width: 0;
text-align: right;
}
.product-card wa-button::part(prefix) {
padding-inline-start: var(--wa-space-xs);
}
.product-card wa-button::part(suffix) {
padding-inline-end: var(--wa-space-xs);
}
.product-card wa-button:not(:last-child) {
margin-inline-end: var(--wa-space-xs);
}
/* imitating the rounded avatar */
.blog wa-avatar {
background-color: transparent;
}
.blog wa-avatar::part(image) {
border: var(--wa-border-width-s) solid var(--wa-color-brand-fill-loud);
border-radius: var(--wa-border-radius-circle);
}
.blog .landscape-frame {
box-shadow: var(--wa-shadow-s);
border: var(--wa-panel-border-width) var(--wa-panel-border-style) var(--wa-color-surface-border);
margin-block-end: var(--wa-shadow-offset-y-s);
}
.post-meta .categories {
display: flex;
flex-direction: column;
}
.message-composer wa-card::part(header) {
background-color: var(--wa-color-neutral-fill-loud);
}
.message-composer .grouped-buttons {
--wa-color-neutral-border-quiet: color-mix(in oklab, var(--wa-color-gray-30), white 40%);
}
.message-composer [slot='header'] wa-icon-button::part(base) {
color: var(--wa-color-neutral-on-loud);
}
.message-composer .grouped-buttons wa-icon-button::part(base):hover {
background-color: var(--wa-color-neutral-fill-normal);
color: var(--wa-color-text-normal);
}
.message-composer wa-tooltip::part(body) {
background-color: var(--wa-color-brand-fill-loud);
color: var(--wa-color-brand-on-loud);
}
.message-composer wa-tooltip::part(base__arrow) {
--arrow-color: var(--wa-color-brand-fill-loud);
}
.message-composer wa-card::part(footer) {
border-width: 0;
--padding: 0 var(--wa-space-s) var(--wa-space-s) var(--wa-space-s);
}
.support-table th {
background-color: var(--wa-color-neutral-fill-loud);
color: var(--wa-color-neutral-on-loud);
}
.support-table th wa-checkbox {
--background: transparent;
--border-color: var(--wa-color-neutral-on-loud);
--border-color-checked: var(--wa-color-neutral-on-loud);
}
.checkout-form {
font-size: var(--wa-font-size-s);
}
.checkout-form .square-frame {
box-shadow: var(--wa-shadow-s);
border: var(--wa-panel-border-width) var(--wa-panel-border-style) var(--wa-color-surface-border);
}
.wa-theme-brutalist.wa-dark {
& p a::before {
background: var(--wa-color-yellow-40);
}
& wa-rating {
--symbol-color: color-mix(in oklab, var(--wa-color-base-80), transparent 50%);
--symbol-color-active: var(--wa-color-gray-80);
}
& wa-alert {
&[variant='brand'] {
--icon-color: var(--wa-color-brand-on-quiet);
}
&[variant='success'] {
--icon-color: var(--wa-color-success-on-quiet);
}
&[variant='warning'] {
--icon-color: var(--wa-color-warning-on-quiet);
}
&[variant='danger'] {
--icon-color: var(--wa-color-danger-on-quiet);
}
&[variant='neutral'] {
--icon-color: var(--wa-color-neutral-on-quiet);
}
}
}
.preview-container pre {
border-inline-start: var(--wa-panel-border-width) var(--wa-panel-border-style) var(--wa-color-neutral-border-quiet);
}
p a,
a.highlite-link {
position: relative;
--wa-link-decoration-default: none;
--wa-link-decoration-hover: none;
&:before {
position: absolute;
z-index: -1;
content: '';
background: var(--wa-color-yellow-80);
width: 100%;
bottom: 0;
height: 50%;
opacity: 0.7;
transition: all var(--wa-transition-fast) ease-in-out;
}
&:hover:before {
height: 100%;
}
}
}
@container brutalist-theme (min-width: 1040px) and (max-width: 1140px) {
.product-card wa-button {
font-size: 80%;
}
}
/* #endregion */
/* #region Playful */
html.wa-theme-playful .preview-container {
container-name: playful-theme;
}
@container playful-theme (min-width: 0) {
.project-header {
color: var(--wa-color-success-on-normal);
}
.hero-background {
position: absolute;
z-index: -1;
top: -60rem;
left: 50%;
width: 250rem;
height: 250rem;
transform: translate(-50%, -50%);
flex-shrink: 0;
border-radius: 50%;
background: linear-gradient(180deg, var(--wa-color-green-90) 69.42%, var(--wa-color-green-80) 100%);
}
.hero-background::after {
background: url(/assets/images/themer/playful/hero.png) 0 50% no-repeat;
content: '';
position: absolute;
width: 520px;
height: 600px;
transform: translateX(-50%);
left: 50%;
bottom: 33rem;
}
.strata.hero {
padding-top: 19rem;
text-align: center;
}
.hero .hero-title {
color: var(--wa-color-success-on-normal);
font-size: var(--wa-font-size-4xl);
}
.hero .hero-cta {
font-size: var(--wa-font-size-l);
}
.product-card .badge-stock {
position: absolute;
top: var(--wa-space-xl);
right: var(--wa-space-xl);
}
.product-card {
--wa-panel-border-radius: var(--wa-border-radius-l);
}
.product-card::part(footer) {
border-width: 0;
}
.product-card wa-button {
margin-inline-end: var(--wa-space-xs);
}
.blog wa-avatar {
--size: 2rem;
}
.blog .landscape-frame {
border-radius: var(--wa-border-radius-l);
box-shadow: var(--wa-shadow-s);
}
.message-composer wa-card {
--background: var(--wa-color-surface-raised);
}
.message-composer wa-card::part(header) {
--wa-color-neutral-border-quiet: var(--wa-color-gray-70);
border-width: 0;
background-color: var(--wa-color-neutral-fill-quiet);
}
&:not(.wa-theme-premium.wa-dark) .message-composer wa-card {
--wa-color-neutral-fill-quiet: var(--wa-color-gray-90);
}
.message-composer wa-icon-button {
color: var(--wa-text-color-normal);
font-size: var(--wa-font-size-l);
}
.message-composer wa-card::part(footer) {
padding-top: 0;
}
.product-detail .price {
font-weight: var(--wa-font-weight-bold);
}
.support-table wa-card {
background: var(--wa-color-surface-raised);
}
.support-table th {
font-size: var(--wa-font-size-s);
font-weight: var(--wa-font-weight-bold);
background-color: var(--wa-color-surface-lowered);
}
.support-table tr {
border-top-color: var(--wa-color-surface-lowered);
}
.support-table .excerpt {
color: var(--wa-color-text-quiet);
}
.order-item img {
border-radius: var(--wa-border-radius-m);
}
.checkout-form {
font-size: var(--wa-font-size-s);
}
.checkout-form h2 {
font-size: var(--wa-font-size-3xl);
}
.checkout-form wa-input::part(form-control-label),
.checkout-form wa-select::part(form-control-label) {
font-size: var(--wa-font-size-s);
padding-block-end: var(--wa-space-xs);
}
.wa-theme-playful.wa-dark {
& .hero-background {
background: linear-gradient(180deg, var(--wa-color-green-60) 69.42%, var(--wa-color-green-30) 100%);
}
& .message-composer wa-card {
border-color: var(--wa-color-gray-30);
}
& .message-composer wa-card::part(header) {
background: var(--wa-color-gray-40);
}
& .message-composer wa-card::part(footer) {
border-top: 0;
}
& .message-composer .tools .grouped-buttons:not(:last-of-type) {
--wa-color-neutral-border-quiet: var(--wa-color-gray-40);
}
& .support-table th {
background: var(--wa-color-surface-lowered);
}
}
}
/* responsive */
@container playful-theme (min-width: 1040px) and (max-width: 1140px) {
.product-card wa-button {
font-size: 80%;
margin-inline-end: 0;
}
}
/* #endregion */
/* #region Active */
html.wa-theme-active .preview-container {
container-name: active-theme;
}
@container active-theme (min-width: 0) {
.hero-background::after {
backdrop-filter: brightness(0.8);
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.hero-background {
background: linear-gradient(
var(--wa-color-green-80) 20%,
var(--wa-color-primary-80) 80.5%,
var(--wa-color-base-10) 80.5%,
var(--wa-color-primary-80) 100%
);
background: url(/assets/images/themer/active/hero.png) 50% 0px / cover no-repeat;
height: 40rem;
position: absolute;
top: 0;
left: 0;
right: 0;
z-index: -1;
}
.strata.hero {
height: 24rem;
}
.hero .title {
text-align: right;
margin-inline-start: 55%;
}
.hero .hero-title {
font-style: italic;
font-weight: var(--wa-font-weight-black);
font-size: var(--wa-font-size-2xl);
}
.hero wa-button[variant='brand'] {
--background: var(--wa-color-neutral-fill-quiet);
--text-color: var(--wa-color-neutral-on-normal);
}
wa-rating {
--symbol-color-active: var(--wa-color-brand-on-quiet);
}
}
/* responsive */
@container preview (min-width: 1100px) {
.hero-background {
height: 47rem;
}
.strata.hero {
height: 30rem;
}
.hero .title {
margin-block-start: 10%;
}
}
/* #endregion */
/* #region Premium */
html.wa-theme-premium .preview-container {
container-name: premium-theme;
}
@container premium-theme (min-width: 0) {
.project-header {
background-color: var(--wa-color-warning-fill-normal);
}
.strata.hero {
height: 60rem;
background: var(--wa-color-warning-fill-normal) url('/assets/images/themer/premium/hero.png') -4rem 12rem no-repeat;
background-size: cover;
padding-top: var(--wa-space-2xl);
padding-left: var(--wa-space-s);
text-align: right;
}
.hero .hero-title {
color: var(--wa-color-warning-on-normal);
font-style: italic;
}
.blog wa-avatar {
border-radius: var(--wa-border-radius-circle);
overflow: hidden;
}
.strata.products {
margin-top: -25rem;
padding-top: 10rem;
background: linear-gradient(0deg, var(--wa-color-surface-lowered) 80%, rgba(255, 255, 255, 0) 100%);
}
.product-card .badge-stock {
position: absolute;
top: var(--wa-space-xl);
right: var(--wa-space-xl);
}
.product-card wa-rating {
--symbol-size: var(--wa-font-size-m);
}
.product-card .title {
font-size: var(--wa-font-size-2xl);
}
.product-card .description {
color: var(--wa-color-text-quiet);
}
.product-card::part(footer) {
border-width: 0;
}
.product-card wa-button:not(:last-child) {
margin-inline-end: var(--wa-space-xs);
}
.blog .authors a {
--wa-color-text-link: var(--wa-color-text-quiet);
--wa-link-decoration-default: none;
}
.message-composer wa-card {
background: var(--wa-color-surface-raised);
}
.message-composer wa-card::part(header) {
border-width: 0;
background-color: var(--wa-color-neutral-fill-quiet);
}
&:not(.wa-theme-premium.wa-dark) .message-composer wa-card {
--wa-color-neutral-fill-quiet: var(--wa-color-base-95);
}
.message-composer wa-card::part(footer) {
border-width: 0;
--padding: var(--wa-space-s) var(--wa-space-xl);
}
.message-composer .grouped-buttons wa-icon-button::part(base) {
block-size: var(--wa-form-control-height-s);
inline-size: var(--wa-form-control-height-s);
justify-content: center;
}
.message-composer .grouped-buttons wa-icon-button::part(base):hover {
background-color: var(--wa-color-neutral-fill-normal);
color: var(--wa-color-text-normal);
}
.support-table th {
text-transform: uppercase;
font-weight: var(--wa-font-weight-normal);
color: var(--wa-color-text-quiet);
background-color: var(--wa-color-surface-lowered);
}
.support-table th:first-child {
border-radius: var(--wa-border-radius-l) 0 0 0;
}
.support-table th:last-child {
border-radius: 0 var(--wa-border-radius-l) 0 0;
}
.support-table tr {
--wa-color-surface-border: var(--wa-color-surface-lowered);
}
.checkout-form wa-input::part(form-control-label),
.checkout-form wa-select::part(form-control-label) {
font-size: var(--wa-font-size-s);
margin-block-end: var(--wa-space-xs);
}
.order-item .finish {
color: var(--wa-color-text-quiet);
font-size: var(--wa-font-size-s);
font-style: italic;
}
.wa-theme-premium.wa-dark {
& .message-composer .tools .grouped-buttons:not(:last-of-type) {
--wa-color-neutral-border-quiet: var(--wa-color-base-40);
}
& .preview-container pre,
& .preview-container code {
background-color: var(--wa-color-base-20);
}
/* syntax highlighting */
& .token {
&.selector {
color: var(--wa-color-green-80);
}
&.tag {
color: var(--wa-color-primary-80);
}
&.punctuation {
color: var(--wa-color-base-95);
}
&.attr-name {
color: var(--wa-color-green-80);
}
&.attr-value {
color: var(--wa-color-yellow-80);
}
}
}
.preview-container pre,
.preview-container code {
background-color: var(--wa-color-base-90);
font-size: var(--font-size-m);
}
/* syntax highlighting */
.token {
&.selector {
color: var(--wa-color-green-30);
}
&.tag {
color: var(--wa-color-primary-30);
}
&.punctuation {
color: var(--wa-color-base-10);
}
&.attr-name {
color: var(--wa-color-green-30);
}
&.attr-value {
color: var(--wa-color-yellow-30);
}
}
}
/* responsive */
@container preview (min-width: 1040px) {
.strata.hero {
background: var(--wa-color-warning-fill-normal) url('/assets/images/themer/premium/hero.png') -4rem 35% no-repeat;
padding-top: 15rem;
padding-left: 50%;
}
.strata.products {
margin-top: -25rem;
padding-top: 10rem;
background: linear-gradient(0deg, var(--wa-color-surface-lowered) 60%, rgba(255, 255, 255, 0) 100%);
}
}
/* #endregion */

View File

@@ -1,7 +1,8 @@
---
title: Animated Image
description: A component for displaying animated GIFs and WEBPs that play and pause on interaction.
tags: component
tags: [imagery, niche]
icon: animated-image
---
```html {.example}

View File

@@ -1,7 +1,8 @@
---
title: Animation
description: Animate elements declaratively with nearly 100 baked-in presets, or roll your own with custom keyframes.
tags: component
tags: [helpers, primitives]
icon: animation
---
To animate an element, wrap it in `<wa-animation>` and set an animation `name`. The animation will not start until you add the `play` attribute. Refer to the [properties table](#properties) for a list of all animation options.
@@ -196,4 +197,3 @@ Animations won't play until you apply the `play` attribute. You can omit it init
animation.play = true;
});
</script>
```

View File

@@ -1,7 +1,8 @@
---
title: Avatar
description: Avatars are used to represent a person or object.
tags: component
tags: [imagery, apps, content]
icon: avatar
---
By default, a generic icon will be shown. You can personalize avatars by adding custom icons, initials, and images. You should always provide a `label` for assistive devices.

View File

@@ -1,7 +1,8 @@
---
title: Badge
description: Badges are used to draw attention and display statuses or counts.
tags: component
tags: [feedback, content]
icon: badge
---
```html {.example}
@@ -127,4 +128,3 @@ When including badges in menu items, use the `suffix` slot to make sure they're
<wa-menu-item>Comments <wa-badge slot="suffix" variant="neutral" pill>4</wa-badge></wa-menu-item>
<wa-menu-item>Replies <wa-badge slot="suffix" variant="neutral" pill>12</wa-badge></wa-menu-item>
</wa-menu>
```

View File

@@ -1,7 +1,8 @@
---
title: Breadcrumb
description: Breadcrumbs provide a group of links so users can easily navigate a website's hierarchy.
tags: component
tags: [navigation]
icon: breadcrumb
---
Breadcrumbs are usually placed before a page's main content with the current page shown last to indicate the user's position in the navigation.
@@ -171,4 +172,3 @@ Alternatively, you can place dropdown menus in a prefix or suffix slot.
</wa-dropdown>
</wa-breadcrumb-item>
</wa-breadcrumb>
```

View File

@@ -1,7 +1,8 @@
---
title: Button Group
description: Button groups can be used to group related buttons into sections.
tags: component
tags: [actions, forms, apps]
icon: button-group
---
```html {.example}
@@ -139,15 +140,17 @@ Pill buttons are supported through the button's `pill` attribute.
</wa-button-group>
```
### Dropdowns in Button Groups
### Dropdowns and Native Buttons in Button Groups
Dropdowns can be placed inside button groups as long as the trigger is an `<wa-button>` element.
Other elements can also be placed inside button groups:
- Native buttons as long as their [native styles](/docs/native/button) are included
- Dropdowns as long as the trigger is either a `<wa-button>`, or a `<button>` with [native styles](/docs/native/button) included.
```html {.example}
<wa-button-group label="Example Button Group">
<wa-button>Button</wa-button>
<wa-button>Button</wa-button>
<wa-dropdown>
<button>Native Button</button>
<wa-dropdown hoist>
<wa-button slot="trigger" caret>Dropdown</wa-button>
<wa-menu>
<wa-menu-item>Item 1</wa-menu-item>
@@ -165,9 +168,9 @@ Create a split button using a button and a dropdown. Use a [visually hidden](/do
```html {.example}
<wa-button-group label="Example Button Group">
<wa-button variant="brand">Save</wa-button>
<wa-dropdown placement="bottom-end">
<wa-dropdown placement="bottom-end" hoist>
<wa-button slot="trigger" variant="brand" caret>
<wa-visually-hidden>More options</wa-visually-hidden>
<span class="wa-visually-hidden">More options</span>
</wa-button>
<wa-menu>
<wa-menu-item>Save</wa-menu-item>

View File

@@ -1,8 +1,9 @@
---
title: Button
description: Buttons represent actions that are available to the user.
tags: component
essentials: button
tags: [actions, forms]
native: button
icon: button
---
```html {.example}
@@ -28,35 +29,37 @@ Use the `variant` attribute to set the button's semantic variant.
Use the `appearance` attribute to change the button's visual appearance.
```html {.example}
<div style="margin-block-end: 1rem;">
<wa-button appearance="accent" variant="neutral">Accent</wa-button>
<wa-button appearance="filled" variant="neutral">Filled</wa-button>
<wa-button appearance="outlined" variant="neutral">Outlined</wa-button>
<wa-button appearance="plain" variant="neutral">Text</wa-button>
</div>
<div style="margin-block-end: 1rem;">
<wa-button appearance="accent" variant="brand">Accent</wa-button>
<wa-button appearance="filled" variant="brand">Filled</wa-button>
<wa-button appearance="outlined" variant="brand">Outlined</wa-button>
<wa-button appearance="plain" variant="brand">Text</wa-button>
</div>
<div style="margin-block-end: 1rem;">
<wa-button appearance="accent" variant="success">Accent</wa-button>
<wa-button appearance="filled" variant="success">Filled</wa-button>
<wa-button appearance="outlined" variant="success">Outlined</wa-button>
<wa-button appearance="plain" variant="success">Text</wa-button>
</div>
<div style="margin-block-end: 1rem;">
<wa-button appearance="accent" variant="warning">Accent</wa-button>
<wa-button appearance="filled" variant="warning">Filled</wa-button>
<wa-button appearance="outlined" variant="warning">Outlined</wa-button>
<wa-button appearance="plain" variant="warning">Text</wa-button>
</div>
<div>
<wa-button appearance="accent" variant="danger">Accent</wa-button>
<wa-button appearance="filled" variant="danger">Filled</wa-button>
<wa-button appearance="outlined" variant="danger">Outlined</wa-button>
<wa-button appearance="plain" variant="danger">Text</wa-button>
<div class="wa-stack">
<div class="wa-gap-m">
<wa-button appearance="accent" variant="neutral">Accent</wa-button>
<wa-button appearance="outlined" variant="neutral">Outlined</wa-button>
<wa-button appearance="filled" variant="neutral">Filled</wa-button>
<wa-button appearance="plain" variant="neutral">Plain</wa-button>
</div>
<div class="wa-gap-m">
<wa-button appearance="accent" variant="brand">Accent</wa-button>
<wa-button appearance="outlined" variant="brand">Outlined</wa-button>
<wa-button appearance="filled" variant="brand">Filled</wa-button>
<wa-button appearance="plain" variant="brand">Plain</wa-button>
</div>
<div class="wa-gap-m">
<wa-button appearance="accent" variant="success">Accent</wa-button>
<wa-button appearance="outlined" variant="success">Outlined</wa-button>
<wa-button appearance="filled" variant="success">Filled</wa-button>
<wa-button appearance="plain" variant="success">Plain</wa-button>
</div>
<div class="wa-gap-m">
<wa-button appearance="accent" variant="warning">Accent</wa-button>
<wa-button appearance="outlined" variant="warning">Outlined</wa-button>
<wa-button appearance="filled" variant="warning">Filled</wa-button>
<wa-button appearance="plain" variant="warning">Plain</wa-button>
</div>
<div class="wa-gap-m">
<wa-button appearance="accent" variant="danger">Accent</wa-button>
<wa-button appearance="outlined" variant="danger">Outlined</wa-button>
<wa-button appearance="filled" variant="danger">Filled</wa-button>
<wa-button appearance="plain" variant="danger">Plain</wa-button>
</div>
</div>
```

View File

@@ -1,7 +1,9 @@
---
title: Callout
description: Callouts are used to display important messages inline.
tags: component
tags: [feedback, content]
icon: callout
native: callout
---
```html {.example}
@@ -57,6 +59,71 @@ Set the `variant` attribute to change the callout's variant.
</wa-callout>
```
### Appearance
Use the `appearance` attribute to change the callout's visual appearance (the default is `outlined filled`).
```html {.example}
<wa-callout variant="brand" appearance="outlined accent">
<wa-icon slot="icon" name="check-to-slot"></wa-icon>
This <strong>accent</strong> callout is also <strong>outlined</strong>
</wa-callout>
<br />
<wa-callout variant="brand" appearance="accent">
<wa-icon slot="icon" name="square-check"></wa-icon>
This <strong>accent</strong> callout draws attention without an outline
</wa-callout>
<br />
<wa-callout variant="brand" appearance="outlined filled">
<wa-icon slot="icon" name="fill-drip" variant="regular"></wa-icon>
This callout is both <strong>filled</strong> and <strong>outlined</strong>
</wa-callout>
<br />
<wa-callout variant="brand" appearance="filled">
<wa-icon slot="icon" name="fill" variant="regular"></wa-icon>
This callout is only <strong>filled</strong>
</wa-callout>
<br />
<wa-callout variant="brand" appearance="outlined">
<wa-icon slot="icon" name="lines-leaning" variant="regular"></wa-icon>
Here's an <strong>outlined</strong> callout
</wa-callout>
<br />
<wa-callout variant="brand" appearance="plain">
<wa-icon slot="icon" name="font" variant="regular"></wa-icon>
No bells and whistles on this <strong>plain</strong> callout
</wa-callout>
```
### Sizes
Use the `size` attribute to change a callout's size.
```html {.example}
<wa-callout variant="brand" appearance="outlined accent" size="large">
<wa-icon slot="icon" name="circle-info" variant="solid"></wa-icon>
This is meant to be very emphasized.
</wa-callout>
<wa-callout>
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
Normal-sized callout.
</wa-callout>
<wa-callout variant="plain" appearance="plain" size="small">
<wa-icon slot="icon" name="circle-info" variant="regular"></wa-icon>
Just a small tip!
</wa-callout>
```
### Without Icons
Icons are optional. Simply omit the `icon` slot if you don't want them.

View File

@@ -1,7 +1,8 @@
---
title: Card
description: Cards can be used to group related subjects in a container.
tags: component
tags: [organization, layout]
icon: card
---
```html {.example}
@@ -59,7 +60,8 @@ Basic cards aren't very exciting, but they can display any content you want them
### Card with Header
Headers can be used to display titles and more. Use the `with-header` attribute to add a header to the card.
Headers can be used to display titles and more.
If using SSR, you need to also use the `with-header` attribute to add a header to the card (if not, it is added automatically).
```html {.example}
<wa-card with-header class="card-header">
@@ -94,7 +96,8 @@ Headers can be used to display titles and more. Use the `with-header` attribute
### Card with Footer
Footers can be used to display actions, summaries, or other relevant content. Use the `with-footer` attribute to add a footer to the card.
Footers can be used to display actions, summaries, or other relevant content.
If using SSR, you need to also use the `with-footer` attribute to add a footer to the card (if not, it is added automatically).
```html {.example}
<wa-card with-footer class="card-footer">
@@ -121,7 +124,8 @@ Footers can be used to display actions, summaries, or other relevant content. Us
### Images
Card images are displayed atop the card and will stretch to fit. Use the `with-image` attribute to add an image to the card.
Card images are displayed atop the card and will stretch to fit.
If using SSR, you need to also use the `with-image` attribute to add an image to the card (if not, it is added automatically).
```html {.example}
<wa-card with-image class="card-image">

View File

@@ -3,6 +3,7 @@ title: Carousel Item
description: A carousel item represent a slide within a carousel.
tags: component
parent: carousel
icon: carousel-item
---
```html {.example}

View File

@@ -1,7 +1,8 @@
---
title: Carousel
description: Carousels display an arbitrary number of content slides along a horizontal or vertical axis.
tags: component
tags: [imagery, disclosure]
icon: carousel
---
```html {.example}

View File

@@ -1,6 +1,7 @@
---
title: Component Cheatsheet
layout: docs
unlisted: true
---
<style>
@@ -44,7 +45,7 @@ table code {
}
}
</script>
<script type="module" src="/assets/scripts/cheatsheet.js"></script>
<script type="module" src="./cheatsheet.js"></script>
{% for type, all in componentsBy -%}
{% set typeTitle = "CSS custom properties" if type == "cssProperty" else ("CSS parts" if type == "cssPart" else (type | title) + "s") %}
@@ -64,15 +65,21 @@ table code {
<tr>
<th><code>{{ name }}{{ "()" if type == "method" }}</code></th>
<td>
{% set componentLinks = [] %}
{% for component in thingComponents %}
{%- set link -%}
<a href="../{{ component.slug }}"><code>&lt;{{ component.tagName }}&gt;</code></a>
{%- endset -%}
{# https://giuliachiola.dev/posts/add-items-to-an-array-in-nunjucks/ #}
{% set componentLinks = (componentLinks.push(link), componentLinks) %}
{%- endfor -%}
{% if thingComponents.length > 1 %}
<details open>
<summary><strong>{{ thingComponents.length }}</strong> components</summary>
{% endif %}
{% for component in thingComponents %}
<a href="../{{ component.slug }}"><code>&lt;{{ component.tagName }}&gt;</code></a>
{%- endfor -%}
{% if thingComponents.length > 1 %}
{{ componentLinks | safe }}
</details>
{% else %}
{{ componentLinks | safe }}
{% endif %}
</td>
</tr>

View File

@@ -1,7 +1,9 @@
---
title: Checkbox
description: Checkboxes allow the user to toggle an option on or off.
tags: component
tags: [inputs, forms]
native: checkbox
icon: checkbox
---
```html {.example}

View File

@@ -174,7 +174,7 @@ i.e. the previews of demos using the `viewport` attribute, but also opening demo
Just setting `border-radius` or `border` should work as expected:
```html{.example}
<wa-code-demo style="border: 2px dotted var(--wa-color-blue-50); border-radius: var(--wa-border-radius-s)">
<wa-code-demo style="border: 2px dotted var(--wa-color-blue-50); border-radius: var(--wa-border-radius-m)">
<pre><code class="language-html">
&lt;button&gt;Click me!&lt;/button&gt;
&lt;wa-button&gt;Click me!&lt;/wa-button&gt;

View File

@@ -1,7 +1,9 @@
---
title: Color Picker
description: Color pickers allow the user to select a color.
tags: component
tags: [inputs, forms]
native: input
icon: color-picker
---
```html {.example}
@@ -37,10 +39,12 @@ Set the color picker's format with the `format` attribute. Valid options include
To prevent users from toggling the format themselves, add the `no-format-toggle` attribute.
```html {.example}
<wa-color-picker format="hex" value="#4a90e2" label="Select a color"></wa-color-picker>
<wa-color-picker format="rgb" value="rgb(80, 227, 194)" label="Select a color"></wa-color-picker>
<wa-color-picker format="hsl" value="hsl(290, 87%, 47%)" label="Select a color"></wa-color-picker>
<wa-color-picker format="hsv" value="hsv(55, 89%, 97%)" label="Select a color"></wa-color-picker>
<div class="wa-grid" style="--min-column-size: 12ch;">
<wa-color-picker format="hex" value="#4a90e2" label="Pick a hex color"></wa-color-picker>
<wa-color-picker format="rgb" value="rgb(80, 227, 194)" label="Pick an RGB color"></wa-color-picker>
<wa-color-picker format="hsl" value="hsl(290, 87%, 47%)" label="Pick an HSL color"></wa-color-picker>
<wa-color-picker format="hsv" value="hsv(55, 89%, 97%)" label="Pick an HSV color"></wa-color-picker>
</div>
```
### Swatches

View File

@@ -1,3 +1,11 @@
{
"layout": "component.njk"
"layout": "component.njk",
"tags": ["components"],
"eleventyComputed": {
"component": "{{ components[page.fileSlug] }}",
"description": "{{ components[page.fileSlug].summary }}",
"status": "{{ components[page.fileSlug].status }}",
"since": "{{ components[page.fileSlug].since }}",
"element": "<{{ components[page.fileSlug].tagName }}>"
}
}

View File

@@ -1,7 +1,8 @@
---
title: Copy Button
description: Copies data to the clipboard when the user clicks the button.
tags: component
tags: [actions, apps]
icon: copy-button
---
```html {.example}

View File

@@ -1,8 +1,9 @@
---
title: Details
description: Details show a brief summary and expand to show additional content.
tags: component
essentials: details
tags: [organization, apps, content, disclosure]
icon: details
native: details
---
<!-- cspell:dictionaries lorem-ipsum -->

View File

@@ -1,8 +1,10 @@
---
title: Dialog
description: 'Dialogs, sometimes called "modals", appear above the page and require the user''s immediate attention.'
tags: component
essentials: dialog
tags: [organization, apps, disclosure]
icon: dialog
native: dialog
keywords: modal
---
<!-- cspell:dictionaries lorem-ipsum -->

View File

@@ -1,7 +1,8 @@
---
title: Divider
description: Dividers are used to visually separate or group elements.
tags: component
tags: [organization, content, forms]
icon: divider
---
```html {.example}

View File

@@ -1,7 +1,8 @@
---
title: Drawer
description: Drawers slide in from a container to expose additional options and information.
tags: component
tags: [organization, disclosure]
icon: drawer
---
<!-- cspell:dictionaries lorem-ipsum -->

View File

@@ -1,7 +1,8 @@
---
title: Dropdown
description: 'Dropdowns expose additional content that "drops down" in a panel.'
tags: component
tags: [actions, apps]
icon: dropdown
---
Dropdowns consist of a trigger and a panel. By default, activating the trigger will expose the panel and interacting outside of the panel will close it.

View File

@@ -1,7 +1,8 @@
---
title: Format Bytes
description: Formats a number as a human readable bytes value.
tags: component
tags: [helpers, content, inline]
icon: format-bytes
---
```html {.example}

View File

@@ -1,7 +1,8 @@
---
title: Format Date
description: Formats a date/time using the specified locale and options.
tags: component
tags: [helpers, content, inline]
icon: format-date
---
Localization is handled by the browser's [`Intl.DateTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). No language packs are required.

View File

@@ -1,7 +1,8 @@
---
title: Format Number
description: Formats a number using the specified locale and options.
tags: component
tags: [helpers, content, inline]
icon: format-number
---
Localization is handled by the browser's [`Intl.NumberFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat). No language packs are required.

View File

@@ -1,7 +1,8 @@
---
title: Icon Button
description: Icons buttons are simple, icon-only buttons that can be used for actions and in toolbars.
tags: component
tags: [actions, apps]
icon: icon-button
---
For a full list of icons that come bundled with Web Awesome, refer to the [icon component](/docs/components/icon).

View File

@@ -1,7 +1,8 @@
---
title: Icon
description: Icons are symbols that can be used to represent various options within an application.
tags: component
tags: [imagery, apps, popular]
icon: icon
---
Web Awesome comes bundled with over 2,000 free icons courtesy of [Font Awesome](https://fontawesome.com/). These icons are part of the `default` icon library. Font Awesome Pro users can unlock additional icon families. Or, if you prefer, you can register your own [custom icon library](#icon-library).

View File

@@ -1,7 +1,8 @@
---
title: Image Comparer
description: Compare visual differences between similar photos with a sliding panel.
tags: component
tags: [imagery, niche]
icon: image-comparer
---
For best results, use images that share the same dimensions. The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)

View File

@@ -1,7 +1,8 @@
---
title: Include
description: Includes give you the power to embed external HTML files into the page.
tags: component
tags: [helpers, primitives]
icon: include
---
Included files are asynchronously requested using `window.fetch()`. Requests are cached, so the same file can be included multiple times, but only one request will be made.

View File

@@ -1,492 +0,0 @@
---
title: Components
description: Browse the library of customizable, framework-friendly web components included in Web Awesome.
layout: page-outline
---
<p class="index-summary">Components are the essential building blocks to create intuitive, cohesive experiences. Browse the library of customizable, framework-friendly web components included in Web Awesome.</p>
<div id="component-filter">
<wa-input type="search" placeholder="Search components" clearable autofocus></wa-input>
</div>
<div id="component-grid" class="index-grid">
<h2 class="index-category">Actions</h2>
<a href="/docs/components/button">
<wa-card with-header>
<div slot="header">
{% include "svgs/button.njk" %}
</div>
<span class="page-name">Button</span>
</wa-card>
</a>
<a href="/docs/components/button-group">
<wa-card with-header>
<div slot="header">
{% include "svgs/button-group.njk" %}
</div>
<span class="page-name">Button Group</span>
</wa-card>
</a>
<a href="/docs/components/copy-button">
<wa-card with-header>
<div slot="header">
{% include "svgs/copy-button.njk" %}
</div>
<span class="page-name">Copy Button</span>
</wa-card>
</a>
<a href="/docs/components/dropdown">
<wa-card with-header>
<div slot="header">
{% include "svgs/dropdown.njk" %}
</div>
<span class="page-name">Dropdown</span>
</wa-card>
</a>
<a href="/docs/components/icon-button">
<wa-card with-header>
<div slot="header">
{% include "svgs/icon-button.njk" %}
</div>
<span class="page-name">Icon Button</span>
</wa-card>
</a>
<a href="/docs/components/menu">
<wa-card with-header>
<div slot="header">
{% include "svgs/menu.njk" %}
</div>
<span class="page-name">Menu</span>
</wa-card>
</a>
<a href="/docs/components/qr-code">
<wa-card with-header>
<div slot="header">
{% include "svgs/qr-code.njk" %}
</div>
<span class="page-name">QR Code</span>
</wa-card>
</a>
<h2 class="index-category" style="grid-column: 1 / -1">Feedback and Status</h2>
<a href="/docs/components/badge">
<wa-card with-header>
<div slot="header">
{% include "svgs/badge.njk" %}
</div>
<span class="page-name">Badge</span>
</wa-card>
</a>
<a href="/docs/components/callout">
<wa-card with-header>
<div slot="header">
{% include "svgs/callout.njk" %}
</div>
<span class="page-name">Callout</span>
</wa-card>
</a>
<a href="/docs/components/progress-bar">
<wa-card with-header>
<div slot="header">
{% include "svgs/progress-bar.njk" %}
</div>
<span class="page-name">Progress Bar</span>
</wa-card>
</a>
<a href="/docs/components/progress-ring">
<wa-card with-header>
<div slot="header">
{% include "svgs/progress-ring.njk" %}
</div>
<span class="page-name">Progress Ring</span>
</wa-card>
</a>
<a href="/docs/components/skeleton">
<wa-card with-header>
<div slot="header">
{% include "svgs/skeleton.njk" %}
</div>
<span class="page-name">Skeleton</span>
</wa-card>
</a>
<a href="/docs/components/spinner" data-keywords="loader">
<wa-card with-header>
<div slot="header">
{% include "svgs/spinner.njk" %}
</div>
<span class="page-name">Spinner</span>
</wa-card>
</a>
<a href="/docs/components/tag">
<wa-card with-header>
<div slot="header">
{% include "svgs/tag.njk" %}
</div>
<span class="page-name">Tag</span>
</wa-card>
</a>
<a href="/docs/components/tooltip">
<wa-card with-header>
<div slot="header">
{% include "svgs/tooltip.njk" %}
</div>
<span class="page-name">Tooltip</span>
</wa-card>
</a>
<h2 class="index-category">Imagery</h2>
<a href="/docs/components/animated-image">
<wa-card with-header>
<div slot="header">
{% include "svgs/animated-image.njk" %}
</div>
<span class="page-name">Animated Image</span>
</wa-card>
</a>
<a href="/docs/components/avatar">
<wa-card with-header>
<div slot="header">
{% include "svgs/avatar.njk" %}
</div>
<span class="page-name">Avatar</span>
</wa-card>
</a>
<a href="/docs/components/carousel">
<wa-card with-header>
<div slot="header">
{% include "svgs/carousel.njk" %}
</div>
<span class="page-name">Carousel</span>
</wa-card>
</a>
<a href="/docs/components/icon">
<wa-card with-header>
<div slot="header">
{% include "svgs/icon.njk" %}
</div>
<span class="page-name">Icon</span>
</wa-card>
</a>
<a href="/docs/components/image-comparer">
<wa-card with-header>
<div slot="header">
{% include "svgs/image-comparer.njk" %}
</div>
<span class="page-name">Image Comparer</span>
</wa-card>
</a>
<h2 class="index-category">Inputs</h2>
<a href="/docs/components/checkbox">
<wa-card with-header>
<div slot="header">
{% include "svgs/checkbox.njk" %}
</div>
<span class="page-name">Checkbox</span>
</wa-card>
</a>
<a href="/docs/components/color-picker">
<wa-card with-header>
<div slot="header">
{% include "svgs/color-picker.njk" %}
</div>
<span class="page-name">Color Picker</span>
</wa-card>
</a>
<a href="/docs/components/input" data-keywords="textfield text field">
<wa-card with-header>
<div slot="header">
{% include "svgs/input.njk" %}
</div>
<span class="page-name">Input</span>
</wa-card>
</a>
<a href="/docs/components/radio-group">
<wa-card with-header>
<div slot="header">
{% include "svgs/radio-group.njk" %}
</div>
<span class="page-name">Radio Group</span>
</wa-card>
</a>
<a href="/docs/components/range">
<wa-card with-header>
<div slot="header">
{% include "svgs/range.njk" %}
</div>
<span class="page-name">Range</span>
</wa-card>
</a>
<a href="/docs/components/rating">
<wa-card with-header>
<div slot="header">
{% include "svgs/rating.njk" %}
</div>
<span class="page-name">Rating</span>
</wa-card>
</a>
<a href="/docs/components/select">
<wa-card with-header>
<div slot="header">
{% include "svgs/select.njk" %}
</div>
<span class="page-name">Select</span>
</wa-card>
</a>
<a href="/docs/components/switch" data-keywords="toggle">
<wa-card with-header>
<div slot="header">
{% include "svgs/switch.njk" %}
</div>
<span class="page-name">Switch</span>
</wa-card>
</a>
<a href="/docs/components/textarea">
<wa-card with-header>
<div slot="header">
{% include "svgs/textarea.njk" %}
</div>
<span class="page-name">Textarea</span>
</wa-card>
</a>
<h2 class="index-category">Navigation</h2>
<a href="/docs/components/breadcrumb">
<wa-card with-header>
<div slot="header">
{% include "svgs/breadcrumb.njk" %}
</div>
<span class="page-name">Breadcrumb</span>
</wa-card>
</a>
<a href="/docs/components/tab-group">
<wa-card with-header>
<div slot="header">
{% include "svgs/tab-group.njk" %}
</div>
<span class="page-name">Tab Group</span>
</wa-card>
</a>
<a href="/docs/components/tree">
<wa-card with-header>
<div slot="header">
{% include "svgs/tree.njk" %}
</div>
<span class="page-name">Tree</span>
</wa-card>
</a>
<h2 class="index-category">Organization</h2>
<a href="/docs/components/card">
<wa-card with-header>
<div slot="header">
{% include "svgs/card.njk" %}
</div>
<span class="page-name">Card</span>
</wa-card>
</a>
<a href="/docs/components/details">
<wa-card with-header>
<div slot="header">
{% include "svgs/details.njk" %}
</div>
<span class="page-name">Details</span>
</wa-card>
</a>
<a href="/docs/components/dialog" data-keywords="modal">
<wa-card with-header>
<div slot="header">
{% include "svgs/dialog.njk" %}
</div>
<span class="page-name">Dialog</span>
</wa-card>
</a>
<a href="/docs/components/divider">
<wa-card with-header>
<div slot="header">
{% include "svgs/divider.njk" %}
</div>
<span class="page-name">Divider</span>
</wa-card>
</a>
<a href="/docs/components/drawer">
<wa-card with-header id="drawer-card">
<div slot="header">
{% include "svgs/drawer.njk" %}
</div>
<span class="page-name">Drawer</span>
</wa-card>
</a>
<a href="/docs/components/page">
<wa-card with-header>
<div slot="header">
{% include "svgs/page.njk" %}
</div>
<span class="page-name">Page</span>
</wa-card>
</a>
<a href="/docs/components/split-panel">
<wa-card with-header>
<div slot="header">
{% include "svgs/split-panel.njk" %}
</div>
<span class="page-name">Split Panel</span>
</wa-card>
</a>
<h2 class="index-category">Utilities</h2>
<a href="/docs/components/animation">
<wa-card with-header>
<div slot="header">
{% include "svgs/animation.njk" %}
</div>
<span class="page-name">Animation</span>
</wa-card>
</a>
<a href="/docs/components/format-bytes">
<wa-card with-header>
<div slot="header">
{% include "svgs/format-bytes.njk" %}
</div>
<span class="page-name">Format Bytes</span>
</wa-card>
</a>
<a href="/docs/components/format-date">
<wa-card with-header>
<div slot="header">
{% include "svgs/format-date.njk" %}
</div>
<span class="page-name">Format Date</span>
</wa-card>
</a>
<a href="/docs/components/format-number">
<wa-card with-header>
<div slot="header">
{% include "svgs/format-number.njk" %}
</div>
<span class="page-name">Format Number</span>
</wa-card>
</a>
<a href="/docs/components/include">
<wa-card with-header>
<div slot="header">
{% include "svgs/include.njk" %}
</div>
<span class="page-name">Include</span>
</wa-card>
</a>
<a href="/docs/components/mutation-observer">
<wa-card with-header>
<div slot="header">
{% include "svgs/mutation-observer.njk" %}
</div>
<span class="page-name">Mutation Observer</span>
</wa-card>
</a>
<a href="/docs/components/popup">
<wa-card with-header>
<div slot="header">
{% include "svgs/popup.njk" %}
</div>
<span class="page-name">Popup</span>
</wa-card>
</a>
<a href="/docs/components/relative-time">
<wa-card with-header>
<div slot="header">
{% include "svgs/relative-time.njk" %}
</div>
<span class="page-name">Relative Time</span>
</wa-card>
</a>
<a href="/docs/components/resize-observer">
<wa-card with-header>
<div slot="header">
{% include "svgs/resize-observer.njk" %}
</div>
<span class="page-name">Resize Observer</span>
</wa-card>
</a>
<a href="/docs/components/visually-hidden">
<wa-card with-header>
<div slot="header">
{% include "svgs/visually-hidden.njk" %}
</div>
<span class="page-name">Visually Hidden</span>
</wa-card>
</a>
</div>
<div id="component-filter-empty" hidden>
No results
</div>
<script type="module">
const container = document.getElementById('component-filter');
const empty = document.getElementById('component-filter-empty');
const grid = document.getElementById('component-grid');
const input = container.querySelector('wa-input');
function updateResults() {
const filter = input.value.toLowerCase().trim();
// Hide headings while filtering
grid.querySelectorAll('h2').forEach(heading => {
heading.hidden = filter === '' ? false : true;
});
// Show matching components
grid.querySelectorAll('a').forEach(link => {
const content = link.textContent.toLowerCase();
const keywords = link.getAttribute('data-keywords') || '';
const isMatch = filter === '' || (content + keywords).includes(filter);
link.classList.toggle('hidden', !isMatch);
});
// Show empty state when there's a search filter and no results
if (filter !== '' && grid.querySelector('a:not(.hidden)') === null) {
empty.hidden = false;
} else {
empty.hidden = true;
}
}
input.addEventListener('wa-input', updateResults);
</script>
<style>
wa-card#drawer-card::part(header) {
--spacing: 0;
justify-content: flex-end;
overflow: hidden;
}
#component-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: var(--wa-space-m);
margin-block-start: var(--wa-space-2xl);
> a {
position: static;
visibility: visible;
&.hidden {
display: block;
position: absolute;
visibility: hidden;
}
}
}
#component-filter-empty {
border: dashed var(--wa-border-width-m) var(--wa-color-neutral-border-quiet);
border-radius: var(--wa-border-radius-m);
font-size: var(--wa-font-size-l);
color: var(--wa-color-text-quiet);
text-align: center;
padding-block: var(--wa-space-2xl);
margin-block-start: 0
}
</style>

View File

@@ -0,0 +1,14 @@
---
title: Components
description: Components are the essential building blocks to create intuitive, cohesive experiences. Browse the library of customizable, framework-friendly web components included in Web Awesome.
layout: overview
categories:
- actions
- feedback: 'Feedback & Status'
- imagery
- inputs
- navigation
- organization
- helpers: 'Utilities'
override:tags: []
---

View File

@@ -1,8 +1,10 @@
---
title: Input
description: Inputs collect data from the user.
tags: component
essentials: input
tags: [inputs, forms]
icon: input
native: input
keywords: textfield text field
---
```html {.example}
@@ -133,33 +135,35 @@ Use the `prefix` and `suffix` slots to add icons.
Use [CSS parts](#css-parts) to customize the way form controls are drawn. This example uses CSS grid to position the label to the left of the control, but the possible orientations are nearly endless. The same technique works for inputs, textareas, radio groups, and similar form controls.
```html {.example}
<wa-input class="label-on-left" label="Name" hint="Enter your name"></wa-input>
<wa-input class="label-on-left" label="Email" type="email" hint="Enter your email"></wa-input>
<wa-textarea class="label-on-left" label="Bio" hint="Tell us something about yourself"></wa-textarea>
<div class="label-on-left">
<wa-input label="Name" hint="Enter your name"></wa-input>
<wa-input label="Email" type="email" hint="Enter your email"></wa-input>
<wa-textarea label="Bio" hint="Tell us something about yourself"></wa-textarea>
</div>
<style>
.label-on-left {
--label-width: 3.75rem;
--gap-width: 1rem;
}
.label-on-left + .label-on-left {
margin-top: var(--wa-space-m);
}
.label-on-left::part(form-control) {
display: grid;
grid: auto / var(--label-width) 1fr;
gap: var(--wa-space-3xs) var(--gap-width);
grid-template-columns: auto 1fr;
gap: var(--wa-space-l);
align-items: center;
}
.label-on-left::part(form-control-label) {
text-align: right;
}
wa-input, wa-textarea {
grid-column: 1 / -1;
grid-row-end: span 2;
display: grid;
grid-template-columns: subgrid;
gap: 0 var(--wa-space-l);
align-items: center;
}
.label-on-left::part(hint) {
grid-column-start: 2;
::part(label) {
text-align: right;
}
::part(hint) {
grid-column: 2;
}
}
</style>
```

View File

@@ -3,6 +3,7 @@ title: Menu Item
description: Menu items provide options for the user to pick from in a menu.
tags: component
parent: menu
icon: menu
---
```html {.example}

Some files were not shown because too many files have changed in this diff Show More