mirror of
https://github.com/shoelace-style/webawesome.git
synced 2026-01-20 07:54:14 +00:00
Compare commits
242 Commits
v2.0.0-bet
...
context-me
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ee519d40a | ||
|
|
6bc17d48c3 | ||
|
|
a1263f1b9d | ||
|
|
d69ebab765 | ||
|
|
0504946dac | ||
|
|
fbd6691711 | ||
|
|
aec17da6b0 | ||
|
|
639533662d | ||
|
|
a340ce4a68 | ||
|
|
6e5fe64e8b | ||
|
|
84bdbb84b8 | ||
|
|
f91ffb6cb4 | ||
|
|
13815199a3 | ||
|
|
98c20ff551 | ||
|
|
479b6b9081 | ||
|
|
c640d2ea77 | ||
|
|
715547d2fd | ||
|
|
8a914a536b | ||
|
|
f56b6c0648 | ||
|
|
25aa8318d9 | ||
|
|
72f2cbe9e8 | ||
|
|
fc7836084a | ||
|
|
60d9d9202b | ||
|
|
a9df468282 | ||
|
|
0bba773c3e | ||
|
|
7be03ae623 | ||
|
|
d4741532f5 | ||
|
|
10f31efefa | ||
|
|
be662ddf32 | ||
|
|
ff84beaade | ||
|
|
8dba8fa5fb | ||
|
|
3a3f5552a7 | ||
|
|
88cba353c0 | ||
|
|
a2851370bb | ||
|
|
7c0ef7dcf0 | ||
|
|
fb6d5d89b8 | ||
|
|
45ceff4c08 | ||
|
|
6169abc700 | ||
|
|
c09e12d13e | ||
|
|
6152e15e10 | ||
|
|
79910b2ae8 | ||
|
|
c347df7c17 | ||
|
|
e9e2b35c59 | ||
|
|
8ae753c396 | ||
|
|
d2c94321f2 | ||
|
|
4c10f8a537 | ||
|
|
9a19cc2173 | ||
|
|
c4cbc894f5 | ||
|
|
449f5e6c7f | ||
|
|
34447a3f2f | ||
|
|
eee97d7dba | ||
|
|
f16392947a | ||
|
|
c3adf92b49 | ||
|
|
a6580b018d | ||
|
|
00c843c7ce | ||
|
|
5fe55a4db9 | ||
|
|
4ca998c346 | ||
|
|
42b3e2cc11 | ||
|
|
59fb8db6be | ||
|
|
664beafefa | ||
|
|
04443a64e2 | ||
|
|
92dedf3386 | ||
|
|
2ba5fb9820 | ||
|
|
222235159b | ||
|
|
1061bd5e0d | ||
|
|
ccec9a8348 | ||
|
|
bf9e06e67d | ||
|
|
1e03d222c5 | ||
|
|
3722f46b8e | ||
|
|
8d7bf97127 | ||
|
|
d26c1a6407 | ||
|
|
f296ff8476 | ||
|
|
a75a71994a | ||
|
|
7d1373a1d1 | ||
|
|
23abc50015 | ||
|
|
5e28d1131a | ||
|
|
a141e64a69 | ||
|
|
e12ee97bd9 | ||
|
|
ebd84642e1 | ||
|
|
888ac2ea0d | ||
|
|
37068c922c | ||
|
|
eec24d2ed1 | ||
|
|
8fa9d629a3 | ||
|
|
ef22dd7dc4 | ||
|
|
3f12624b78 | ||
|
|
d6fa67374c | ||
|
|
d4183cf718 | ||
|
|
4ad0480039 | ||
|
|
7188425ac0 | ||
|
|
c83581cf47 | ||
|
|
f8fa29f157 | ||
|
|
f2a4db6291 | ||
|
|
a4aff0b1e9 | ||
|
|
f5c2e0b425 | ||
|
|
2f88c55ec0 | ||
|
|
db7075a91a | ||
|
|
8ac007ba9a | ||
|
|
111fa8397c | ||
|
|
0ef4e92a96 | ||
|
|
9123afac18 | ||
|
|
1b5dca52e3 | ||
|
|
bc3e9c43da | ||
|
|
ded01cfd8a | ||
|
|
c737b7494f | ||
|
|
47aff56e71 | ||
|
|
15ce341d81 | ||
|
|
7476204258 | ||
|
|
e083b1a02e | ||
|
|
fa74fc54e3 | ||
|
|
fbbeec6d2f | ||
|
|
b4192364f6 | ||
|
|
c7dc82947f | ||
|
|
c38fd3986c | ||
|
|
35d7926e18 | ||
|
|
86e06ce1e6 | ||
|
|
1a08f063a6 | ||
|
|
740208ed76 | ||
|
|
521f6fe3f1 | ||
|
|
f43d490763 | ||
|
|
898179b645 | ||
|
|
8c3888da02 | ||
|
|
e1471ec9a1 | ||
|
|
eac07a51ba | ||
|
|
753000b56a | ||
|
|
8ab2907c3f | ||
|
|
723ee80c8f | ||
|
|
e1c003c8df | ||
|
|
96c82dc69f | ||
|
|
0dd9483797 | ||
|
|
4da110087d | ||
|
|
7f75a64647 | ||
|
|
71d7f6fd98 | ||
|
|
42595f241f | ||
|
|
c67c84dfda | ||
|
|
2ba6a3b097 | ||
|
|
0456ad96fb | ||
|
|
0ab87b03fa | ||
|
|
54fc41e175 | ||
|
|
261e824290 | ||
|
|
802363e1da | ||
|
|
1054d5bb74 | ||
|
|
f5d143710e | ||
|
|
c025208bf5 | ||
|
|
7306e39f3e | ||
|
|
0d30d183df | ||
|
|
cd504a4127 | ||
|
|
bba41402aa | ||
|
|
e1f129abc5 | ||
|
|
7e6c6924f2 | ||
|
|
185fc4c942 | ||
|
|
5f7c6b307f | ||
|
|
a9f80467c3 | ||
|
|
89fb1a8804 | ||
|
|
54bfce0d5d | ||
|
|
dca1d1b413 | ||
|
|
4b07ee40a7 | ||
|
|
d8644c940b | ||
|
|
7df70abb48 | ||
|
|
6e3c5c0388 | ||
|
|
6cbe2e288b | ||
|
|
1f95c6ca6e | ||
|
|
ac6ae43449 | ||
|
|
ba3117f435 | ||
|
|
fd449f68d9 | ||
|
|
574947656c | ||
|
|
5b1b704d1d | ||
|
|
abbdb207e0 | ||
|
|
2d89fc945f | ||
|
|
25b130ce2c | ||
|
|
ca098eb171 | ||
|
|
f6ccd119e8 | ||
|
|
7b1f99b41a | ||
|
|
4193ee1980 | ||
|
|
c718012c3e | ||
|
|
aca5c8af73 | ||
|
|
2d4a699790 | ||
|
|
fc0475b2c5 | ||
|
|
0f6e13b8c9 | ||
|
|
c60cfae677 | ||
|
|
ded05cf079 | ||
|
|
c360d471cd | ||
|
|
382a39e6ed | ||
|
|
bfa1499889 | ||
|
|
053a5e9bd7 | ||
|
|
3677f6cf0f | ||
|
|
03fb75f030 | ||
|
|
8e209d2767 | ||
|
|
0cf77a4115 | ||
|
|
14368c4ce2 | ||
|
|
e74838fdc1 | ||
|
|
3f64b13d70 | ||
|
|
613f4b6440 | ||
|
|
1bfa4c6ba8 | ||
|
|
9089473cf0 | ||
|
|
687eb7d0dc | ||
|
|
52cb8adf65 | ||
|
|
06f241adb1 | ||
|
|
f5ba173156 | ||
|
|
5bd7bfb4ce | ||
|
|
e4413dceee | ||
|
|
f644454080 | ||
|
|
16f4b485b5 | ||
|
|
679dd4578c | ||
|
|
00bf318ee9 | ||
|
|
da3415d029 | ||
|
|
147a8d2f57 | ||
|
|
a1d354ac15 | ||
|
|
1fb0e41603 | ||
|
|
f121c119f0 | ||
|
|
f4c472e7de | ||
|
|
719d62b670 | ||
|
|
165306f56a | ||
|
|
248bb32977 | ||
|
|
dfb9127052 | ||
|
|
5933e948e1 | ||
|
|
624f6ef5a1 | ||
|
|
2865b546fa | ||
|
|
9d7c3b2af9 | ||
|
|
033896dfc2 | ||
|
|
10d95ba8e6 | ||
|
|
43f74583ea | ||
|
|
36d499f253 | ||
|
|
4c6e61e6dd | ||
|
|
0829af77c0 | ||
|
|
f3281d3985 | ||
|
|
5cd5567292 | ||
|
|
c0102a1658 | ||
|
|
c173d0d76e | ||
|
|
d7dd4b82da | ||
|
|
f9010cf3ca | ||
|
|
a0d2dbf685 | ||
|
|
d679d27043 | ||
|
|
9c0641dcad | ||
|
|
af852a088c | ||
|
|
76f04c0b0e | ||
|
|
27376df5f2 | ||
|
|
fd285dbd6f | ||
|
|
76e1d4b403 | ||
|
|
51dbc1a1ee | ||
|
|
7095236116 | ||
|
|
17df0e3cd3 | ||
|
|
76df2fd204 |
40
.github/ISSUE_TEMPLATE/bug_report.md
vendored
40
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,38 +1,36 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Create a report to help us improve.
|
||||
about: Create a bug report to help us fix a demonstrable problem with code in the library.
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: claviska
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
### Describe the bug
|
||||
A bug is _a demonstrable problem_ caused by code in the library. Please provide a clear and concise description of what the bug is here.
|
||||
|
||||
**To Reproduce**
|
||||
### To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
### Demo
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
If the bug isn't obvious, please provide a link to a CodePen or Fiddle with a minimal reproduction. Bugs that have repros get attention faster than those that don't.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
Tip: use the CodePen button on any example in the docs!
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
### Screenshots
|
||||
If applicable, add screenshots to help explain the bug.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
### Browser / OS
|
||||
- OS: [e.g. Mac, Windows]
|
||||
- Browser [e.g. Chrome, Firefox, Safari]
|
||||
- Browser version [e.g. 22]
|
||||
|
||||
### Additional information
|
||||
Provide any additional information about the bug here.
|
||||
|
||||
15
.github/ISSUE_TEMPLATE/feature_request.md
vendored
15
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -7,14 +7,11 @@ assignees: claviska
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
### What issue are you having?
|
||||
Provide a clear and concise description of the problem you're facing.
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
### Describe the solution you'd like
|
||||
How would you like to see the library solve it?
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
### Describe alternatives you've considered
|
||||
In what ways have you tried to solve this with the current version?
|
||||
|
||||
31
.github/workflows/node.js.yml
vendored
Normal file
31
.github/workflows/node.js.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
||||
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ next ]
|
||||
pull_request:
|
||||
branches: [ next ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14.x, 16.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm run build --if-present
|
||||
- run: npm test
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
.DS_Store
|
||||
.cache
|
||||
docs/dist
|
||||
docs/search.json
|
||||
dist
|
||||
examples
|
||||
node_modules
|
||||
|
||||
@@ -23,7 +23,7 @@ Twitter: [@shoelace_style](https://twitter.com/shoelace_style)
|
||||
|
||||
## Shoemakers 🥾
|
||||
|
||||
Shoemakers, or "Shoelace developers," can use this documentation to learn how to build Shoelace from source. You will need Node >= 12.10.0 to build and run the project locally.
|
||||
Shoemakers, or "Shoelace developers," can use this documentation to learn how to build Shoelace from source. You will need Node >= 14 to build and run the project locally. It is preferred, but not required, to use npm 7.
|
||||
|
||||
**You don't need to do any of this to use Shoelace!** This page is for people who want to contribute to the project, tinker with the source, or create a custom build of Shoelace.
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import commentParser from 'comment-parser';
|
||||
|
||||
const packageData = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
||||
const { name, description, version, author, homepage, license } = packageData;
|
||||
const noDash = string => string.replace(/^\s?-/, '').trim();
|
||||
|
||||
export default {
|
||||
globs: ['src/components/**/*.ts'],
|
||||
@@ -47,7 +48,7 @@ export default {
|
||||
}
|
||||
classDoc['animations'].push({
|
||||
name: t.name,
|
||||
description: t.description
|
||||
description: noDash(t.description)
|
||||
});
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Not Found
|
||||
|
||||
Sorry, I couldn't find that page.
|
||||
<img class="not-found-image" src="/assets/images/undraw-not-found.svg" alt="Cute monsters hiding behind a tree">
|
||||
|
||||
Sorry, I couldn't find that page. Have you tried pressing <kbd>/</kbd> to search?
|
||||
|
||||
@@ -14,13 +14,17 @@
|
||||
- [Alert](/components/alert)
|
||||
- [Avatar](/components/avatar)
|
||||
- [Badge](/components/badge)
|
||||
- [Breadcrumb](/components/breadcrumb)
|
||||
- [Breadcrumb Item](/components/breadcrumb-item)
|
||||
- [Button](/components/button)
|
||||
- [Button Group](/components/button-group)
|
||||
- [Card](/components/card)
|
||||
- [Checkbox](/components/checkbox)
|
||||
- [Color Picker](/components/color-picker)
|
||||
- [Context Menu](/components/context-menu)
|
||||
- [Details](/components/details)
|
||||
- [Dialog](/components/dialog)
|
||||
- [Divider](/components/divider)
|
||||
- [Drawer](/components/drawer)
|
||||
- [Dropdown](/components/dropdown)
|
||||
- [Form](/components/form)
|
||||
@@ -29,7 +33,6 @@
|
||||
- [Image Comparer](/components/image-comparer)
|
||||
- [Input](/components/input)
|
||||
- [Menu](/components/menu)
|
||||
- [Menu Divider](/components/menu-divider)
|
||||
- [Menu Item](/components/menu-item)
|
||||
- [Menu Label](/components/menu-label)
|
||||
- [Progress Bar](/components/progress-bar)
|
||||
@@ -52,11 +55,13 @@
|
||||
<!--plop:component-->
|
||||
|
||||
- Utilities
|
||||
- [Animated Image](/components/animated-image)
|
||||
- [Animation](/components/animation)
|
||||
- [Format Bytes](/components/format-bytes)
|
||||
- [Format Date](/components/format-date)
|
||||
- [Format Number](/components/format-number)
|
||||
- [Include](/components/include)
|
||||
- [Mutation Observer](/components/mutation-observer)
|
||||
- [Relative Time](/components/relative-time)
|
||||
- [Resize Observer](/components/resize-observer)
|
||||
- [Responsive Media](/components/responsive-media)
|
||||
@@ -71,5 +76,6 @@
|
||||
- [Z-index](/tokens/z-index)
|
||||
|
||||
- Tutorials
|
||||
- [Integrating with Laravel](/tutorials/integrating-with-laravel)
|
||||
- [Integrating with NextJS](/tutorials/integrating-with-nextjs)
|
||||
- [Integrating with Rails](/tutorials/integrating-with-rails)
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 709 KiB After Width: | Height: | Size: 688 KiB |
BIN
docs/assets/images/tie.webp
Normal file
BIN
docs/assets/images/tie.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
1
docs/assets/images/undraw-not-found.svg
Normal file
1
docs/assets/images/undraw-not-found.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.8 KiB |
BIN
docs/assets/images/walk.gif
Normal file
BIN
docs/assets/images/walk.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
@@ -11,7 +11,7 @@
|
||||
border-bottom: none;
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
background-color: rgb(var(--sl-color-neutral-1000));
|
||||
background-color: rgb(var(--sl-color-neutral-0));
|
||||
min-width: 20rem;
|
||||
max-width: 100%;
|
||||
padding: 1.5rem 3.25rem 1.5rem 1.5rem;
|
||||
@@ -40,22 +40,13 @@
|
||||
width: 1.75rem;
|
||||
font-size: 20px;
|
||||
color: rgb(var(--sl-color-neutral-600));
|
||||
background-color: rgb(var(--sl-color-neutral-1000));
|
||||
background-color: rgb(var(--sl-color-neutral-0));
|
||||
border-left: solid 1px rgb(var(--sl-color-neutral-200));
|
||||
border-top-right-radius: 3px;
|
||||
cursor: ew-resize;
|
||||
transition: 250ms background-color;
|
||||
}
|
||||
|
||||
.code-block__resizer:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 1px rgb(var(--sl-color-primary-400)),
|
||||
0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
background-color: rgb(var(--sl-color-primary-50));
|
||||
color: rgb(var(--sl-color-primary-600));
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.code-block__preview {
|
||||
padding-right: 1.5rem;
|
||||
@@ -92,7 +83,7 @@
|
||||
min-width: 2.5rem;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
background: rgb(var(--sl-color-neutral-1000));
|
||||
background: rgb(var(--sl-color-neutral-0));
|
||||
font: inherit;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 500;
|
||||
@@ -129,14 +120,13 @@
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.code-block__button:focus {
|
||||
.code-block__button:focus-visible {
|
||||
outline: none;
|
||||
color: rgb(var(--sl-color-primary-600));
|
||||
border-color: rgb(var(--sl-color-primary-400));
|
||||
border-right-color: transparent;
|
||||
background-color: rgb(var(--sl-color-primary-50));
|
||||
box-shadow: 0 0 0 1px rgb(var(--sl-color-primary-400)),
|
||||
0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
box-shadow: 0 0 0 1px rgb(var(--sl-color-primary-400)), var(--sl-focus-ring);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
@@ -174,6 +164,7 @@
|
||||
text-transform: uppercase;
|
||||
padding: 8px;
|
||||
user-select: none;
|
||||
transition: 0.1s all;
|
||||
}
|
||||
|
||||
.markdown-section .docsify-copy-code-button.copied {
|
||||
@@ -202,10 +193,11 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.markdown-section .docsify-copy-code-button:focus {
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-neutral-500) / var(--sl-focus-ring-alpha));
|
||||
.markdown-section .docsify-copy-code-button:focus-visible {
|
||||
box-shadow: 0 0 0 3px rgb(var(--sl-color-neutral-500) / 50%);
|
||||
}
|
||||
|
||||
.markdown-section .docsify-copy-code-button:active {
|
||||
background-color: rgb(var(--sl-color-neutral-600));
|
||||
transform: scale(0.92);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,22 @@
|
||||
hook.afterEach(function (html, next) {
|
||||
const domParser = new DOMParser();
|
||||
const doc = domParser.parseFromString(html, 'text/html');
|
||||
const codePenButton = `
|
||||
<button type="button" class="code-block__button code-block__button--codepen" title="Edit on CodePen">
|
||||
<svg
|
||||
width="138"
|
||||
height="26"
|
||||
viewBox="0 0 138 26"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.3"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path d="M80 6h-9v14h9 M114 6h-9 v14h9 M111 13h-6 M77 13h-6 M122 20V6l11 14V6 M22 16.7L33 24l11-7.3V9.3L33 2L22 9.3V16.7z M44 16.7L33 9.3l-11 7.4 M22 9.3l11 7.3 l11-7.3 M33 2v7.3 M33 16.7V24 M88 14h6c2.2 0 4-1.8 4-4s-1.8-4-4-4h-6v14 M15 8c-1.3-1.3-3-2-5-2c-4 0-7 3-7 7s3 7 7 7 c2 0 3.7-0.8 5-2 M64 13c0 4-3 7-7 7h-5V6h5C61 6 64 9 64 13z" />
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
|
||||
[...doc.querySelectorAll('code[class^="lang-"]')].map(code => {
|
||||
if (code.classList.contains('preview')) {
|
||||
@@ -44,7 +60,7 @@
|
||||
<div class="code-block">
|
||||
<div class="code-block__preview">
|
||||
${code.textContent}
|
||||
<div class="code-block__resizer" role="slider" tabindex="0">
|
||||
<div class="code-block__resizer">
|
||||
<sl-icon name="grip-vertical"></sl-icon>
|
||||
</div>
|
||||
</div>
|
||||
@@ -66,11 +82,7 @@
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<button type="button" class="code-block__button code-block__button--codepen" title="Edit on CodePen">
|
||||
<svg width="138" height="26" viewBox="0 0 138 26" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M80 6h-9v14h9 M114 6h-9 v14h9 M111 13h-6 M77 13h-6 M122 20V6l11 14V6 M22 16.7L33 24l11-7.3V9.3L33 2L22 9.3V16.7z M44 16.7L33 9.3l-11 7.4 M22 9.3l11 7.3 l11-7.3 M33 2v7.3 M33 16.7V24 M88 14h6c2.2 0 4-1.8 4-4s-1.8-4-4-4h-6v14 M15 8c-1.3-1.3-3-2-5-2c-4 0-7 3-7 7s3 7 7 7 c2 0 3.7-0.8 5-2 M64 13c0 4-3 7-7 7h-5V6h5C61 6 64 9 64 13z"/>
|
||||
</svg>
|
||||
</button>
|
||||
${!code.classList.contains('no-codepen') ? codePenButton : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -101,7 +113,6 @@
|
||||
startWidth = parseInt(document.defaultView.getComputedStyle(preview).width, 10);
|
||||
preview.classList.add('code-block__preview--dragging');
|
||||
event.preventDefault();
|
||||
resizer.focus();
|
||||
document.documentElement.addEventListener('mousemove', dragMove, false);
|
||||
document.documentElement.addEventListener('touchmove', dragMove, false);
|
||||
document.documentElement.addEventListener('mouseup', dragStop, false);
|
||||
@@ -120,26 +131,10 @@
|
||||
document.documentElement.removeEventListener('touchend', dragStop, false);
|
||||
};
|
||||
|
||||
const handleKeyDown = event => {
|
||||
if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {
|
||||
const currentWidth = preview.clientWidth;
|
||||
const maxWidth = preview.parentElement.clientWidth;
|
||||
const incr = event.shiftKey ? 100 : 10;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
if (event.key === 'ArrowLeft') setWidth(currentWidth - incr);
|
||||
if (event.key === 'ArrowRight') setWidth(currentWidth + incr);
|
||||
if (event.key === 'Home') setWidth(0);
|
||||
if (event.key === 'End') setWidth(maxWidth);
|
||||
}
|
||||
};
|
||||
|
||||
const setWidth = width => (preview.style.width = width + 'px');
|
||||
|
||||
resizer.addEventListener('mousedown', dragStart);
|
||||
resizer.addEventListener('touchstart', dragStart);
|
||||
resizer.addEventListener('keydown', handleKeyDown);
|
||||
}, false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Attribute</th>
|
||||
<th>Description</th>
|
||||
<th>Reflects</th>
|
||||
<th>Type</th>
|
||||
@@ -21,18 +20,40 @@
|
||||
<tbody>
|
||||
${props
|
||||
.map(prop => {
|
||||
const hasAttribute = !!prop.attribute;
|
||||
const isAttributeDifferent = prop.attribute !== prop.name;
|
||||
let attributeInfo = '';
|
||||
|
||||
if (!hasAttribute) {
|
||||
attributeInfo = `<br><small>(property only)</small>`;
|
||||
} else if (isAttributeDifferent) {
|
||||
attributeInfo = `
|
||||
<br>
|
||||
<sl-tooltip content="This attribute is different than the property">
|
||||
<small>
|
||||
<code class="nowrap">
|
||||
${escapeHtml(prop.attribute)}
|
||||
</code>
|
||||
</small>
|
||||
</sl-tooltip>`;
|
||||
}
|
||||
|
||||
return `
|
||||
<tr>
|
||||
<td class="nowrap"><code>${escapeHtml(prop.name)}</code></td>
|
||||
<td class="nowrap">${prop.attribute ? `<code>${escapeHtml(prop.attribute)}</code>` : '-'}</td>
|
||||
<td>${escapeHtml(prop.description)}</td>
|
||||
<td>
|
||||
<code class="nowrap">${escapeHtml(prop.name)}</code>
|
||||
${attributeInfo}
|
||||
</td>
|
||||
<td>
|
||||
${escapeHtml(prop.description)}
|
||||
</td>
|
||||
<td style="text-align: center;">${
|
||||
prop.reflects ? '<sl-icon label="yes" name="check"></sl-icon>' : ''
|
||||
}</td>
|
||||
<td>${prop.type?.text ? `<code>${escapeHtml(prop.type?.text || '')}</code>` : '-'}</td>
|
||||
<td>${prop.default ? `<code>${escapeHtml(prop.default)}</code>` : '-'}</td>
|
||||
</tr>
|
||||
`;
|
||||
`;
|
||||
})
|
||||
.join('')}
|
||||
</tbody>
|
||||
@@ -55,12 +76,12 @@
|
||||
${events
|
||||
.map(
|
||||
event => `
|
||||
<tr>
|
||||
<td><code class="nowrap">${escapeHtml(event.name)}</code></td>
|
||||
<td>${escapeHtml(event.description)}</td>
|
||||
<td>${event.type?.text ? `<code>${escapeHtml(event.type?.text)}` : '-'}</td>
|
||||
</tr>
|
||||
`
|
||||
<tr>
|
||||
<td><code class="nowrap">${escapeHtml(event.name)}</code></td>
|
||||
<td>${escapeHtml(event.description)}</td>
|
||||
<td>${event.type?.text ? `<code>${escapeHtml(event.type?.text)}` : '-'}</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
@@ -146,11 +167,11 @@
|
||||
${styles
|
||||
.map(
|
||||
style => `
|
||||
<tr>
|
||||
<td><code>${escapeHtml(style.name)}</code></td>
|
||||
<td>${escapeHtml(style.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
<tr>
|
||||
<td><code>${escapeHtml(style.name)}</code></td>
|
||||
<td>${escapeHtml(style.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
@@ -172,11 +193,11 @@
|
||||
${parts
|
||||
.map(
|
||||
part => `
|
||||
<tr>
|
||||
<td class="nowrap"><code>${escapeHtml(part.name)}</code></td>
|
||||
<td>${escapeHtml(part.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
<tr>
|
||||
<td class="nowrap"><code>${escapeHtml(part.name)}</code></td>
|
||||
<td>${escapeHtml(part.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
@@ -198,11 +219,11 @@
|
||||
${animations
|
||||
.map(
|
||||
animation => `
|
||||
<tr>
|
||||
<td class="nowrap"><code>${escapeHtml(animation.name)}</code></td>
|
||||
<td>${escapeHtml(animation.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
<tr>
|
||||
<td class="nowrap"><code>${escapeHtml(animation.name)}</code></td>
|
||||
<td>${escapeHtml(animation.description)}</td>
|
||||
</tr>
|
||||
`
|
||||
)
|
||||
.join('')}
|
||||
</tbody>
|
||||
@@ -255,6 +276,9 @@
|
||||
metadata.modules?.map(module => {
|
||||
module.declarations?.map(declaration => {
|
||||
if (declaration.customElement) {
|
||||
// Generate the dist path based on the src path and attach it to the component
|
||||
declaration.path = module.path.replace(/^src\//, 'dist/').replace(/\.ts$/, '.js');
|
||||
|
||||
allComponents.push(declaration);
|
||||
}
|
||||
});
|
||||
@@ -429,6 +453,41 @@
|
||||
`;
|
||||
}
|
||||
|
||||
if (component.path) {
|
||||
/* prettier-ignore */
|
||||
result += `
|
||||
## Importing
|
||||
|
||||
<sl-tab-group>
|
||||
<sl-tab slot="nav" panel="cdn" active>CDN</sl-tab>
|
||||
<sl-tab slot="nav" panel="bundler">Bundler</sl-tab>
|
||||
<sl-tab slot="nav" panel="react">React</sl-tab>
|
||||
|
||||
<sl-tab-panel name="cdn">\n
|
||||
To import this component from [the CDN](https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace):
|
||||
|
||||
\`\`\`js
|
||||
import 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@${metadata.package.version}/${component.path}';
|
||||
\`\`\`
|
||||
</sl-tab-panel>
|
||||
|
||||
<sl-tab-panel name="bundler">\n
|
||||
To import this component using [a bundler](/getting-started/installation#bundling):
|
||||
\`\`\`js
|
||||
import '@shoelace-style/shoelace/${component.path}';
|
||||
\`\`\`
|
||||
</sl-tab-panel>
|
||||
|
||||
<sl-tab-panel name="react">\n
|
||||
To import this component using [\`@shoelace-style/react\`](https://www.npmjs.com/package/@shoelace-style/react):
|
||||
\`\`\`js
|
||||
import '@shoelace-style/react/dist/${component.tagName.replace(/^sl-/, '')}';
|
||||
\`\`\`
|
||||
</sl-tab-panel>
|
||||
</sl-tab-group>
|
||||
`;
|
||||
}
|
||||
|
||||
// Strip whitespace so markdown doesn't process things as code blocks
|
||||
return result.replace(/^ +| +$/gm, '');
|
||||
});
|
||||
|
||||
1310
docs/assets/plugins/search/lunr.min.js
vendored
Normal file
1310
docs/assets/plugins/search/lunr.min.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
172
docs/assets/plugins/search/search.css
Normal file
172
docs/assets/plugins/search/search.css
Normal file
@@ -0,0 +1,172 @@
|
||||
body.site-search-visible {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.sidebar .search-box {
|
||||
margin: 1.25rem 26px;
|
||||
}
|
||||
|
||||
.sidebar .search-box kbd {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* Site search */
|
||||
.site-search {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.site-search[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.site-search__overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgb(var(--sl-overlay-background-color) / var(--sl-overlay-opacity));
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.site-search__panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 460px;
|
||||
max-height: calc(100vh - 20rem);
|
||||
background-color: rgb(var(--sl-surface-base-alt));
|
||||
border-radius: var(--sl-border-radius-large);
|
||||
box-shadow: var(--sl-shadow-x-large);
|
||||
margin: 10rem auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
.site-search__panel {
|
||||
max-width: 100%;
|
||||
max-height: calc(92vh - 120px); /* allow iOS browser chrome */
|
||||
margin: 4vh var(--sl-spacing-medium);
|
||||
}
|
||||
}
|
||||
|
||||
.site-search__input::part(base) {
|
||||
border: none;
|
||||
background: transparent;
|
||||
border-radius: var(--sl-border-radius-large);
|
||||
}
|
||||
|
||||
.site-search__input:focus-within::part(base) {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.site-search__input {
|
||||
--sl-input-height-large: 4rem;
|
||||
}
|
||||
|
||||
.site-search__body {
|
||||
flex: 1 1 auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.site-search--has-results .site-search__body {
|
||||
border-top: solid 1px rgb(var(--sl-color-neutral-200));
|
||||
}
|
||||
|
||||
.site-search__results {
|
||||
display: none;
|
||||
line-height: var(--sl-line-height-dense);
|
||||
list-style: none;
|
||||
padding: var(--sl-spacing-x-small) 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.site-search--has-results .site-search__results {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.site-search__results a {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
padding: var(--sl-spacing-x-small) var(--sl-spacing-large);
|
||||
}
|
||||
|
||||
.site-search__results li a:hover,
|
||||
.site-search__results li a:hover small {
|
||||
background-color: rgb(var(--sl-color-neutral-100));
|
||||
}
|
||||
|
||||
.site-search__results li[aria-selected='true'] a,
|
||||
.site-search__results li[aria-selected='true'] a small,
|
||||
.site-search__results li[aria-selected='true'] a sl-icon {
|
||||
outline: none;
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
background-color: rgb(var(--sl-color-primary-600));
|
||||
}
|
||||
|
||||
.site-search__results h3 {
|
||||
font-weight: var(--sl-font-weight-semibold);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.site-search__results small {
|
||||
display: block;
|
||||
color: rgb(var(--sl-color-neutral-600));
|
||||
}
|
||||
|
||||
.site-search__result {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.site-search__result a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--sl-spacing-medium);
|
||||
}
|
||||
|
||||
.site-search__result-icon {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
color: rgb(var(--sl-color-neutral-400));
|
||||
font-size: var(--sl-font-size-x-large);
|
||||
}
|
||||
|
||||
.site-search__result-description {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.site-search__empty {
|
||||
display: none;
|
||||
border-top: solid 1px rgb(var(--sl-color-neutral-200));
|
||||
text-align: center;
|
||||
padding: var(--sl-spacing-x-large);
|
||||
}
|
||||
|
||||
.site-search--no-results .site-search__empty {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.site-search__footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: var(--sl-spacing-large);
|
||||
border-top: solid 1px rgb(var(--sl-color-neutral-200));
|
||||
border-bottom-left-radius: inherit;
|
||||
border-bottom-right-radius: inherit;
|
||||
padding: var(--sl-spacing-medium);
|
||||
}
|
||||
|
||||
.site-search__footer small {
|
||||
color: rgb(var(--sl-color-neutral-700));
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) {
|
||||
.site-search__footer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
293
docs/assets/plugins/search/search.js
Normal file
293
docs/assets/plugins/search/search.js
Normal file
@@ -0,0 +1,293 @@
|
||||
(() => {
|
||||
if (!window.$docsify) {
|
||||
throw new Error('Docsify must be loaded before installing this plugin.');
|
||||
}
|
||||
|
||||
window.$docsify.plugins.push((hook, vm) => {
|
||||
// Append the search box to the sidebar
|
||||
hook.mounted(function () {
|
||||
const appName = document.querySelector('.sidebar .app-name');
|
||||
const searchBox = document.createElement('div');
|
||||
searchBox.classList.add('search-box');
|
||||
searchBox.innerHTML = `
|
||||
<sl-input
|
||||
type="search"
|
||||
placeholder="Search"
|
||||
clearable
|
||||
pill
|
||||
>
|
||||
<sl-icon slot="prefix" name="search"></sl-icon>
|
||||
<kbd slot="suffix" title="Press / to search">/</kbd>
|
||||
</sl-input>
|
||||
`;
|
||||
const searchBoxInput = searchBox.querySelector('sl-input');
|
||||
|
||||
appName.insertAdjacentElement('afterend', searchBox);
|
||||
|
||||
// Show the search panel when the search is clicked
|
||||
searchBoxInput.addEventListener('mousedown', event => {
|
||||
event.preventDefault();
|
||||
show();
|
||||
});
|
||||
|
||||
// Show the search panel when a key is pressed
|
||||
searchBoxInput.addEventListener('keydown', event => {
|
||||
if (event.key === 'Tab') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass the character that was typed through to the search input
|
||||
if (event.key.length === 1) {
|
||||
event.preventDefault();
|
||||
input.value = event.key;
|
||||
show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Append the search panel to the body
|
||||
const siteSearch = document.createElement('div');
|
||||
siteSearch.classList.add('site-search');
|
||||
siteSearch.hidden = true;
|
||||
siteSearch.innerHTML = `
|
||||
<div class="site-search__overlay"></div>
|
||||
<div class="site-search__panel">
|
||||
<header class="site-search__header">
|
||||
<sl-input
|
||||
class="site-search__input"
|
||||
type="search"
|
||||
placeholder="Search this site"
|
||||
size="large"
|
||||
clearable
|
||||
>
|
||||
<sl-icon slot="prefix" name="search"></sl-icon>
|
||||
</sl-input>
|
||||
</header>
|
||||
<div class="site-search__body">
|
||||
<ul class="site-search__results"></ul>
|
||||
<div class="site-search__empty">No results found.</div>
|
||||
</div>
|
||||
<footer class="site-search__footer">
|
||||
<small><kbd>↑</kbd> <kbd>↓</kbd> navigate</small>
|
||||
<small><kbd>↲</kbd> select</small>
|
||||
<small><kbd>esc</kbd> close</small>
|
||||
</footer>
|
||||
</div>
|
||||
`;
|
||||
document.body.append(siteSearch);
|
||||
|
||||
const searchButtons = [...document.querySelectorAll('[data-site-search]')];
|
||||
const overlay = siteSearch.querySelector('.site-search__overlay');
|
||||
const panel = siteSearch.querySelector('.site-search__panel');
|
||||
const input = siteSearch.querySelector('.site-search__input');
|
||||
const results = siteSearch.querySelector('.site-search__results');
|
||||
const animationDuration = 150;
|
||||
const searchDebounce = 200;
|
||||
let isShowing = false;
|
||||
let searchTimeout;
|
||||
let searchIndex;
|
||||
let map;
|
||||
|
||||
// Load search data
|
||||
const searchData = fetch('../../../search.json')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
searchIndex = lunr.Index.load(data.searchIndex);
|
||||
map = data.map;
|
||||
});
|
||||
|
||||
async function show() {
|
||||
isShowing = true;
|
||||
document.body.classList.add('site-search-visible');
|
||||
siteSearch.hidden = false;
|
||||
input.focus();
|
||||
updateResults();
|
||||
|
||||
await Promise.all([
|
||||
panel.animate(
|
||||
[
|
||||
{ opacity: 0, transform: 'scale(.9)' },
|
||||
{ opacity: 1, transform: 'scale(1)' }
|
||||
],
|
||||
{ duration: animationDuration }
|
||||
).finished,
|
||||
overlay.animate([{ opacity: 0 }, { opacity: 1 }], { duration: animationDuration }).finished
|
||||
]);
|
||||
|
||||
document.addEventListener('mousedown', handleDocumentMouseDown);
|
||||
document.addEventListener('keydown', handleDocumentKeyDown);
|
||||
document.addEventListener('focusin', handleDocumentFocusIn);
|
||||
}
|
||||
|
||||
async function hide() {
|
||||
isShowing = false;
|
||||
document.body.classList.remove('site-search-visible');
|
||||
|
||||
await Promise.all([
|
||||
panel.animate(
|
||||
[
|
||||
{ opacity: 1, transform: 'scale(1)' },
|
||||
{ opacity: 0, transform: 'scale(.9)' }
|
||||
],
|
||||
{ duration: animationDuration }
|
||||
).finished,
|
||||
overlay.animate([{ opacity: 1 }, { opacity: 0 }], { duration: animationDuration }).finished
|
||||
]);
|
||||
|
||||
siteSearch.hidden = true;
|
||||
input.value = '';
|
||||
updateResults();
|
||||
|
||||
document.removeEventListener('mousedown', handleDocumentMouseDown);
|
||||
document.removeEventListener('keydown', handleDocumentKeyDown);
|
||||
document.removeEventListener('focusin', handleDocumentFocusIn);
|
||||
}
|
||||
|
||||
function handleInput() {
|
||||
// Debounce search queries
|
||||
clearTimeout(searchTimeout);
|
||||
searchTimeout = setTimeout(() => updateResults(input.value), searchDebounce);
|
||||
}
|
||||
|
||||
function handleDocumentFocusIn(event) {
|
||||
// Close when focus leaves the panel
|
||||
if (event.target.closest('.site-search__panel') !== panel) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
function handleDocumentMouseDown(event) {
|
||||
// Close when clicking outside of the panel
|
||||
if (event.target.closest('.site-search__overlay') === overlay) {
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
function handleDocumentKeyDown(event) {
|
||||
// Close when pressing escape
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle keyboard selections
|
||||
if (['ArrowDown', 'ArrowUp', 'Home', 'End', 'Enter'].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
|
||||
const currentEl = results.querySelector('[aria-selected="true"]');
|
||||
const items = [...results.querySelectorAll('li')];
|
||||
const index = items.indexOf(currentEl);
|
||||
let nextEl;
|
||||
|
||||
if (items.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.key) {
|
||||
case 'ArrowUp':
|
||||
nextEl = items[Math.max(0, index - 1)];
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
nextEl = items[Math.min(items.length - 1, index + 1)];
|
||||
break;
|
||||
case 'Home':
|
||||
nextEl = items[0];
|
||||
break;
|
||||
case 'End':
|
||||
nextEl = items[items.length - 1];
|
||||
break;
|
||||
case 'Enter':
|
||||
currentEl?.querySelector('a')?.click();
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the selected item
|
||||
items.map(item => {
|
||||
if (item === nextEl) {
|
||||
item.setAttribute('aria-selected', 'true');
|
||||
nextEl.scrollIntoView({ block: 'nearest' });
|
||||
} else {
|
||||
item.setAttribute('aria-selected', 'false');
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function updateResults(query = '') {
|
||||
try {
|
||||
await searchIndex;
|
||||
|
||||
const hasQuery = query.length > 0;
|
||||
let matches = hasQuery ? searchIndex.search(`${query}`) : [];
|
||||
|
||||
// Fall back to a fuzzy search if no matches are found
|
||||
if (matches.length === 0 && hasQuery) {
|
||||
matches = searchIndex.search(`${query}~2`);
|
||||
}
|
||||
|
||||
let hasResults = hasQuery && matches.length > 0;
|
||||
siteSearch.classList.toggle('site-search--has-results', hasQuery && hasResults);
|
||||
siteSearch.classList.toggle('site-search--no-results', hasQuery && !hasResults);
|
||||
panel.setAttribute('aria-expanded', hasQuery && hasResults ? 'true' : 'false');
|
||||
|
||||
results.innerHTML = '';
|
||||
|
||||
matches.map((match, index) => {
|
||||
const page = map[match.ref];
|
||||
const li = document.createElement('li');
|
||||
const a = document.createElement('a');
|
||||
let icon = 'file-text';
|
||||
|
||||
if (page.url.includes('getting-started/')) icon = 'lightbulb';
|
||||
if (page.url.includes('resources/')) icon = 'book';
|
||||
if (page.url.includes('components/')) icon = 'puzzle';
|
||||
if (page.url.includes('tokens/')) icon = 'palette2';
|
||||
if (page.url.includes('utilities/')) icon = 'wrench';
|
||||
if (page.url.includes('tutorials/')) icon = 'joystick';
|
||||
|
||||
a.href = $docsify.routerMode === 'hash' ? `/#/${page.url}` : `/${page.url}`;
|
||||
a.innerHTML = `
|
||||
<div class="site-search__result-icon">
|
||||
<sl-icon name="${icon}" aria-hidden="true"></sl-icon>
|
||||
</div>
|
||||
<div class="site-search__result__details">
|
||||
<h3>${page.title}</h3>
|
||||
<small>${page.url}</small>
|
||||
</div>
|
||||
`;
|
||||
|
||||
li.classList.add('site-search__result');
|
||||
li.setAttribute('aria-selected', index === 0 ? 'true' : 'false');
|
||||
li.appendChild(a);
|
||||
results.appendChild(li);
|
||||
});
|
||||
} catch {
|
||||
// Ignore query errors as the user types
|
||||
}
|
||||
}
|
||||
|
||||
// Show the search panel slash is pressed outside of a form element
|
||||
document.addEventListener('keydown', event => {
|
||||
if (
|
||||
!isShowing &&
|
||||
event.key === '/' &&
|
||||
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
|
||||
) {
|
||||
event.preventDefault();
|
||||
show();
|
||||
}
|
||||
});
|
||||
|
||||
input.addEventListener('sl-input', handleInput);
|
||||
|
||||
// Close when a result is selected
|
||||
results.addEventListener('click', event => {
|
||||
if (event.target.closest('a')) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -1,14 +0,0 @@
|
||||
(() => {
|
||||
if (!window.$docsify) {
|
||||
throw new Error('Docsify must be loaded before installing this plugin.');
|
||||
}
|
||||
|
||||
window.$docsify.plugins.push((hook, vm) => {
|
||||
hook.mounted(function () {
|
||||
// Move search below the app name
|
||||
const appName = document.querySelector('.sidebar .app-name');
|
||||
const search = document.querySelector('.sidebar .search');
|
||||
appName.insertAdjacentElement('afterend', search);
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -9,9 +9,21 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.theme-picker sl-menu-label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.theme-picker sl-menu-label kbd {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.theme-picker {
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
}
|
||||
|
||||
.theme-picker sl-menu-label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,13 +43,14 @@
|
||||
const dropdown = document.createElement('sl-dropdown');
|
||||
dropdown.classList.add('theme-picker');
|
||||
dropdown.innerHTML = `
|
||||
<sl-button size="small" slot="trigger" caret>
|
||||
<sl-button size="small" pill slot="trigger" caret>
|
||||
<sl-icon name="sun" label="Select Theme"></sl-icon>
|
||||
</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-label>Toggle <kbd>\\</kbd></sl-menu-label>
|
||||
<sl-menu-item value="light">Light</sl-menu-item>
|
||||
<sl-menu-item value="dark">Dark</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item value="auto">Auto</sl-menu-item>
|
||||
</sl-menu>
|
||||
`;
|
||||
@@ -63,6 +64,19 @@
|
||||
// Update the theme when the preference changes
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addListener(event => setTheme(theme));
|
||||
|
||||
// Toggle themes when pressing backslash
|
||||
document.addEventListener('keydown', event => {
|
||||
if (
|
||||
event.key === '\\' &&
|
||||
!event.composedPath().some(el => ['input', 'textarea'].includes(el?.tagName?.toLowerCase()))
|
||||
) {
|
||||
event.preventDefault();
|
||||
|
||||
setTheme(isDark() ? 'light' : 'dark');
|
||||
show();
|
||||
}
|
||||
});
|
||||
|
||||
// Set the intial theme and sync the UI
|
||||
setTheme(theme);
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ body {
|
||||
font-size: var(--sl-font-size-medium);
|
||||
font-weight: var(--sl-font-weight-normal);
|
||||
letter-spacing: var(--sl-letter-spacing-normal);
|
||||
background-color: rgb(var(--sl-color-neutral-1000));
|
||||
background-color: rgb(var(--sl-surface-base));
|
||||
color: rgb(var(--sl-color-neutral-800));
|
||||
line-height: var(--sl-line-height-normal);
|
||||
}
|
||||
@@ -32,13 +32,12 @@ strong {
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar {
|
||||
background: rgb(var(--sl-color-neutral-1000));
|
||||
background-color: rgb(var(--sl-surface-base));
|
||||
border-right: solid 1px rgb(var(--sl-color-neutral-200));
|
||||
}
|
||||
|
||||
.sidebar .app-name {
|
||||
padding: 0 1.5rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.sidebar-version {
|
||||
@@ -55,94 +54,6 @@ strong {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Search */
|
||||
.sidebar .search {
|
||||
position: relative;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.sidebar .search input[type='search'] {
|
||||
background-color: rgb(var(--sl-input-background-color));
|
||||
border: solid 1px rgb(var(--sl-input-border-color));
|
||||
border-radius: var(--sl-border-radius-pill);
|
||||
color: rgb(var(--sl-input-color));
|
||||
padding-left: 1rem;
|
||||
padding-right: 2rem;
|
||||
margin: 0 1.25rem;
|
||||
transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow;
|
||||
}
|
||||
|
||||
.sidebar .search input[type='search']::placeholder {
|
||||
color: rgb(var(--sl-input-placeholder-color));
|
||||
}
|
||||
|
||||
.sidebar .search input[type='search']:hover {
|
||||
background-color: rgb(var(--sl-input-background-color-hover));
|
||||
border-color: rgb(var(--sl-input-border-color-hover));
|
||||
color: rgb(var(--sl-input-color-hover));
|
||||
}
|
||||
|
||||
.sidebar .search input[type='search']:focus {
|
||||
background-color: rgb(var(--sl-input-background-color-focus));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
border-color: rgb(var(--sl-input-border-color-focus));
|
||||
color: rgb(var(--sl-input-color-focus));
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.sidebar .input-wrap {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: 0 0.25rem;
|
||||
}
|
||||
|
||||
.sidebar .clear-button {
|
||||
position: absolute;
|
||||
right: 34px;
|
||||
top: 7px;
|
||||
width: 22px !important;
|
||||
height: 22px !important;
|
||||
}
|
||||
|
||||
.sidebar .clear-button svg {
|
||||
transform: scale(0.75) !important;
|
||||
}
|
||||
|
||||
.sidebar .clear-button svg circle {
|
||||
fill: rgb(var(--sl-color-neutral-400));
|
||||
}
|
||||
|
||||
.sidebar .clear-button svg path {
|
||||
stroke: rgb(var(--sl-color-neutral-1000));
|
||||
}
|
||||
|
||||
.sidebar .clear-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.search .results-panel {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.search .matching-post {
|
||||
border-bottom: solid 1px rgb(var(--sl-color-neutral-600)) !important;
|
||||
padding: 0.25rem 1.5rem;
|
||||
}
|
||||
|
||||
.search .matching-post a {
|
||||
display: block;
|
||||
border-radius: inherit;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.search .matching-post h2 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.search .matching-post p {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Sidebar toggle */
|
||||
.sidebar-toggle {
|
||||
top: 0.25rem;
|
||||
@@ -150,13 +61,21 @@ strong {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: var(--sl-border-radius-medium);
|
||||
background-color: rgb(var(--sl-color-neutral-1000));
|
||||
background-color: rgb(var(--sl-surface-base));
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.sidebar-toggle:hover .sidebar-toggle-button {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.sidebar-toggle:active .sidebar-toggle-button span {
|
||||
background-color: rgb(var(--sl-color-primary-600));
|
||||
}
|
||||
|
||||
.sidebar-toggle:focus {
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
box-shadow: var(--sl-focus-ring);
|
||||
}
|
||||
|
||||
.sidebar-toggle span:last-child {
|
||||
@@ -241,6 +160,11 @@ strong {
|
||||
max-width: 22rem;
|
||||
}
|
||||
|
||||
.markdown-section .splash-start h1:first-of-type {
|
||||
font-size: var(--sl-font-size-large);
|
||||
margin: 0 0 0.5rem 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1040px) {
|
||||
.splash {
|
||||
display: block;
|
||||
@@ -277,7 +201,7 @@ strong {
|
||||
}
|
||||
|
||||
.anchor span {
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
}
|
||||
|
||||
.markdown-section blockquote {
|
||||
@@ -326,7 +250,7 @@ strong {
|
||||
}
|
||||
|
||||
.markdown-section h1 {
|
||||
font-size: var(--sl-font-size-xx-large);
|
||||
font-size: var(--sl-font-size-2x-large);
|
||||
}
|
||||
|
||||
.markdown-section h2 {
|
||||
@@ -367,12 +291,19 @@ strong {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.markdown-section tr:nth-child(2n) code {
|
||||
background-color: rgb(var(--sl-color-neutral-100));
|
||||
}
|
||||
|
||||
kbd,
|
||||
.markdown-section kbd {
|
||||
font-family: var(--sl-font-mono);
|
||||
font-size: 87.5%;
|
||||
background-color: rgb(var(--sl-color-neutral-50));
|
||||
border-radius: var(--sl-border-radius-small);
|
||||
border: solid 1px rgb(var(--sl-color-neutral-200));
|
||||
padding: 2px 4px;
|
||||
box-shadow: inset 0 1px 0 rgb(var(--sl-color-neutral-0));
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
@@ -502,6 +433,11 @@ strong {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.markdown-section table sl-tooltip code {
|
||||
border-bottom: dashed 1px rgb(var(--sl-color-neutral-300));
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* Iframes */
|
||||
.markdown-section iframe {
|
||||
border: none;
|
||||
@@ -521,7 +457,7 @@ strong {
|
||||
.markdown-section p.warn:before {
|
||||
content: '!';
|
||||
border-radius: 100%;
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
left: -12px;
|
||||
@@ -596,11 +532,18 @@ strong {
|
||||
}
|
||||
|
||||
.repo-button--twitter sl-icon {
|
||||
color: rgb(var(--sl-color-sky-600));
|
||||
color: rgb(var(--sl-color-sky-500));
|
||||
}
|
||||
|
||||
body[data-page^='tokens/'] .table-wrapper td:first-child,
|
||||
body[data-page^='tokens/'] .table-wrapper td:first-child code {
|
||||
@media screen and (max-width: 400px) {
|
||||
:not(.sidebar-buttons) > .repo-button {
|
||||
width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
body[data-page^='/tokens/'] .table-wrapper td:first-child,
|
||||
body[data-page^='/tokens/'] .table-wrapper td:first-child code {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -647,13 +590,14 @@ body[data-page^='tokens/'] .table-wrapper td:first-child code {
|
||||
border-radius: 3px;
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
/* Color palettes */
|
||||
.color-palette {
|
||||
display: grid;
|
||||
grid-template-columns: 200px repeat(11, 1fr);
|
||||
gap: 1rem var(--sl-spacing-xx-small);
|
||||
gap: 1rem var(--sl-spacing-2x-small);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
@@ -679,7 +623,7 @@ body[data-page^='tokens/'] .table-wrapper td:first-child code {
|
||||
}
|
||||
|
||||
.color-palette__swatch--border {
|
||||
box-shadow: inset 0 0 0 1px rgb(var(--sl-color-neutral-0) / 10%);
|
||||
box-shadow: inset 0 0 0 1px rgb(var(--sl-color-neutral-1000) / 10%);
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
@@ -691,3 +635,9 @@ body[data-page^='tokens/'] .table-wrapper td:first-child code {
|
||||
grid-column-start: span 6;
|
||||
}
|
||||
}
|
||||
|
||||
.not-found-image {
|
||||
display: block;
|
||||
max-width: 460px;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
63
docs/components/animated-image.md
Normal file
63
docs/components/animated-image.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Animated Image
|
||||
|
||||
[component-header:sl-animated-image]
|
||||
|
||||
A component for displaying animated GIFs and WEBPs that play and pause on interaction.
|
||||
|
||||
```html preview
|
||||
<sl-animated-image
|
||||
src="/assets/images/walk.gif"
|
||||
alt="Animation of untied shoes walking on pavement"
|
||||
></sl-animated-image>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### WEBP Images
|
||||
|
||||
Both GIF and WEBP images are supported.
|
||||
|
||||
```html preview
|
||||
<sl-animated-image
|
||||
src="/assets/images/tie.webp"
|
||||
alt="Animation of a shoe being tied"
|
||||
></sl-animated-image>
|
||||
```
|
||||
|
||||
### Setting a Width and Height
|
||||
|
||||
To set a custom size, apply a width and/or height to the host element.
|
||||
|
||||
```html preview
|
||||
<sl-animated-image
|
||||
src="/assets/images/walk.gif"
|
||||
alt="Animation of untied shoes walking on pavement"
|
||||
style="width: 150px; height: 200px;"
|
||||
>
|
||||
</sl-animated-image>
|
||||
```
|
||||
|
||||
### Customizing the Control Box
|
||||
|
||||
You can change the appearance and location of the control box by targeting the `control-box` part in your styles.
|
||||
|
||||
```html preview
|
||||
<sl-animated-image
|
||||
src="/assets/images/walk.gif"
|
||||
alt="Animation of untied shoes walking on pavement"
|
||||
class="animated-image-custom-control-box"
|
||||
></sl-animated-image>
|
||||
|
||||
<style>
|
||||
.animated-image-custom-control-box::part(control-box) {
|
||||
top: auto;
|
||||
right: auto;
|
||||
bottom: 1rem;
|
||||
left: 1rem;
|
||||
background-color: deeppink;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-animated-image]
|
||||
@@ -169,7 +169,7 @@ Supply your own [keyframe formats](https://developer.mozilla.org/en-US/docs/Web/
|
||||
.animation-keyframes .box {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: rgb(var(--sl-color-primary-500));
|
||||
background-color: rgb(var(--sl-color-primary-600));
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
@@ -78,7 +78,7 @@ You can group avatars with a few lines of CSS.
|
||||
}
|
||||
|
||||
.avatar-group sl-avatar::part(base) {
|
||||
border: solid 2px rgb(var(--sl-color-neutral-1000));
|
||||
border: solid 2px rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
20
docs/components/breadcrumb-item.md
Normal file
20
docs/components/breadcrumb-item.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Breadcrumb Item
|
||||
|
||||
[component-header:sl-breadcrumb-item]
|
||||
|
||||
Breadcrumb Items are used inside [breadcrumbs](/components/breadcrumb) to represent different links.
|
||||
|
||||
```html preview
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item>
|
||||
<sl-icon slot="prefix" name="house"></sl-icon>
|
||||
Home
|
||||
</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Clothing</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Shirts</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
```
|
||||
|
||||
?> Additional demonstrations can be found in the [breadcrumb examples](/components/breadcrumb).
|
||||
|
||||
[component-metadata:sl-breadcrumb-item]
|
||||
132
docs/components/breadcrumb.md
Normal file
132
docs/components/breadcrumb.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Breadcrumb
|
||||
|
||||
[component-header:sl-breadcrumb]
|
||||
|
||||
Breadcrumbs provide a group of links so users can easily navigate a website's hierarchy.
|
||||
|
||||
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.
|
||||
|
||||
```html preview
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item>Catalog</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Clothing</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Women's</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Shirts & Tops</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Breadcrumb Links
|
||||
|
||||
By default, breadcrumb items are rendered as buttons so you can use them to navigate single-page applications. In this case, you'll need to add event listeners to handle clicks.
|
||||
|
||||
For websites, you'll probably want to use links instead. You can make any breadcrumb item a link by applying an `href` attribute to it. Now, when the user activates it, they'll be taken to the corresponding page — no event listeners required.
|
||||
|
||||
```html preview
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item href="https://example.com/home">
|
||||
Homepage
|
||||
</sl-breadcrumb-item>
|
||||
|
||||
<sl-breadcrumb-item href="https://example.com/home/services">
|
||||
Our Services
|
||||
</sl-breadcrumb-item>
|
||||
|
||||
<sl-breadcrumb-item href="https://example.com/home/services/digital">
|
||||
Digital Media
|
||||
</sl-breadcrumb-item>
|
||||
|
||||
<sl-breadcrumb-item href="https://example.com/home/services/digital/web-design">
|
||||
Web Design
|
||||
</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
```
|
||||
|
||||
### Custom Separators
|
||||
|
||||
Use the `separator` slot to change the separator that goes between breadcrumb items. Icons work well, but you can also use text or an image.
|
||||
|
||||
```html preview
|
||||
<sl-breadcrumb>
|
||||
<sl-icon name="dot" slot="separator"></sl-icon>
|
||||
<sl-breadcrumb-item>First</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Second</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Third</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-breadcrumb>
|
||||
<sl-icon name="arrow-right" slot="separator"></sl-icon>
|
||||
<sl-breadcrumb-item>First</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Second</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Third</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
|
||||
<br>
|
||||
|
||||
<sl-breadcrumb>
|
||||
<span slot="separator">/</span>
|
||||
<sl-breadcrumb-item>First</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Second</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Third</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
```
|
||||
|
||||
### Prefixes
|
||||
|
||||
Use the `prefix` slot to add content before any breadcrumb item.
|
||||
|
||||
```html preview
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item>
|
||||
<sl-icon slot="prefix" name="house"></sl-icon>
|
||||
Home
|
||||
</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Articles</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Traveling</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
```
|
||||
|
||||
### Suffixes
|
||||
|
||||
Use the `suffix` slot to add content after any breadcrumb item.
|
||||
|
||||
```html preview
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item>Documents</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Policies</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>
|
||||
Security
|
||||
<sl-icon slot="suffix" name="shield-lock"></sl-icon>
|
||||
</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
```
|
||||
|
||||
### With Dropdowns
|
||||
|
||||
Dropdown menus can be placed in a prefix or suffix slot to provide additional options.
|
||||
|
||||
```html preview
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item>Homepage</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Our Services</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Digital Media</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>
|
||||
Web Design
|
||||
<sl-dropdown slot="suffix">
|
||||
<sl-button slot="trigger" size="small" circle>
|
||||
<sl-icon label="More options" name="three-dots"></sl-icon>
|
||||
</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item checked>Web Design</sl-menu-item>
|
||||
<sl-menu-item>Web Development</sl-menu-item>
|
||||
<sl-menu-item>Marketing</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
```
|
||||
|
||||
[component-metadata:sl-breadcrumb]
|
||||
@@ -116,7 +116,7 @@ Pill buttons are supported through the button's `pill` attribute.
|
||||
|
||||
### Dropdowns in Button Groups
|
||||
|
||||
Dropdowns can be placed inside button groups as long as the trigger is a `<sl-button>` element.
|
||||
Dropdowns can be placed inside button groups as long as the trigger is an `<sl-button>` element.
|
||||
|
||||
```html preview
|
||||
<sl-button-group>
|
||||
|
||||
@@ -33,6 +33,19 @@ Use the `size` attribute to change a button's size.
|
||||
<sl-button size="large">Large</sl-button>
|
||||
```
|
||||
|
||||
### Outline Buttons
|
||||
|
||||
Use the `outline` attribute to draw outlined buttons with transparent backgrounds.
|
||||
|
||||
```html preview
|
||||
<sl-button type="default" outline>Default</sl-button>
|
||||
<sl-button type="primary" outline>Primary</sl-button>
|
||||
<sl-button type="success" outline>Success</sl-button>
|
||||
<sl-button type="neutral" outline>Neutral</sl-button>
|
||||
<sl-button type="warning" outline>Warning</sl-button>
|
||||
<sl-button type="danger" outline>Danger</sl-button>
|
||||
```
|
||||
|
||||
### Pill Buttons
|
||||
|
||||
Use the `pill` attribute to give buttons rounded edges.
|
||||
|
||||
140
docs/components/context-menu.md
Normal file
140
docs/components/context-menu.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# Context Menu
|
||||
|
||||
[component-header:sl-context-menu]
|
||||
|
||||
Context menus offer additional options through a menu that opens at the pointer's location, usually activated by a right-click.
|
||||
|
||||
Context menus are designed to work with [menus](/components/menu) and [menu items](/components/menu-item). The menu must include `slot="menu"`. Other content you provide will be part of the context menu's target area.
|
||||
|
||||
```html preview
|
||||
<sl-context-menu>
|
||||
<div style="height: 200px; background: rgb(var(--sl-color-neutral-100)); display: flex; align-items: center; justify-content: center; padding: 1rem;">
|
||||
Right-click to activate the context menu
|
||||
</div>
|
||||
|
||||
<sl-menu slot="menu">
|
||||
<sl-menu-item value="undo">Undo</sl-menu-item>
|
||||
<sl-menu-item value="redo">Redo</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
<sl-menu-item value="delete">Delete</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-context-menu>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Handling Selections
|
||||
|
||||
The [menu component](/components/menu) emits an `sl-select` event when a menu item is selected. You can use this to handle selections. The selected item will be available in `event.detail.item`.
|
||||
|
||||
```html preview
|
||||
<div class="context-menu-selections">
|
||||
<sl-context-menu>
|
||||
<div style="height: 200px; background: rgb(var(--sl-color-neutral-100)); display: flex; align-items: center; justify-content: center; padding: 1rem;">
|
||||
Right-click to activate the context menu
|
||||
</div>
|
||||
|
||||
<sl-menu slot="menu">
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-context-menu>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.context-menu-selections');
|
||||
const menu = container.querySelector('sl-menu');
|
||||
const result = container.querySelector('.result');
|
||||
|
||||
menu.addEventListener('sl-select', event => {
|
||||
console.log(`You selected: ${event.detail.item.value}`);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Inline
|
||||
|
||||
The context menu uses `display: contents`, so it will assume the shape of the content you slot in.
|
||||
|
||||
```html preview
|
||||
<sl-context-menu>
|
||||
<span style="background: rgb(var(--sl-color-neutral-100)); padding: .5rem 1rem;">
|
||||
Right-click here
|
||||
</span>
|
||||
|
||||
<sl-menu slot="menu">
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-context-menu>
|
||||
```
|
||||
|
||||
### Placement
|
||||
|
||||
The preferred placement of the context menu can be set with the `placement` attribute. Note that the actual position may vary to ensure the menu remains in the viewport.
|
||||
|
||||
```html preview
|
||||
<sl-context-menu placement="top-end">
|
||||
<div style="height: 200px; background: rgb(var(--sl-color-neutral-100)); display: flex; align-items: center; justify-content: center; padding: 1rem;">
|
||||
Right-click to activate the context menu
|
||||
</div>
|
||||
|
||||
<sl-menu slot="menu">
|
||||
<sl-menu-item value="undo">Undo</sl-menu-item>
|
||||
<sl-menu-item value="redo">Redo</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
<sl-menu-item value="delete">Delete</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-context-menu>
|
||||
```
|
||||
|
||||
### Detecting the Target Item
|
||||
|
||||
A single context menu can wrap a number of items. To detect the item that activated the context menu...
|
||||
|
||||
TODO
|
||||
|
||||
```html preview
|
||||
<div class="context-menu-detecting">
|
||||
<sl-context-menu>
|
||||
<ul>
|
||||
<li>Item 1</li>
|
||||
<li>Item 2</li>
|
||||
<li>Item 3</li>
|
||||
<li>Item 4</li>
|
||||
<li>Item 5</li>
|
||||
</ul>
|
||||
|
||||
<sl-menu slot="menu">
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-context-menu>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.context-menu-detecting ul {
|
||||
max-width: 300px;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.context-menu-detecting li {
|
||||
background: rgb(var(--sl-color-neutral-100));
|
||||
padding: .5rem 1rem;
|
||||
margin: 0 0 2px 0;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-context-menu]
|
||||
@@ -57,7 +57,7 @@ Details are designed to function independently, but you can simulate a group or
|
||||
|
||||
<style>
|
||||
.details-group-example sl-details:not(:last-of-type) {
|
||||
margin-bottom: var(--sl-spacing-xx-small);
|
||||
margin-bottom: var(--sl-spacing-2x-small);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
71
docs/components/divider.md
Normal file
71
docs/components/divider.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Divider
|
||||
|
||||
[component-header:sl-divider]
|
||||
|
||||
Dividers are used to visually separate or group elements.
|
||||
|
||||
```html preview
|
||||
<sl-divider></sl-divider>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Width
|
||||
|
||||
Use the `--width` custom property to change the width of the divider.
|
||||
|
||||
```html preview
|
||||
<sl-divider style="--width: 4px;"></sl-divider>
|
||||
```
|
||||
|
||||
### Color
|
||||
|
||||
Use the `--color` custom property to change the color of the divider.
|
||||
|
||||
```html preview
|
||||
<sl-divider style="--color: tomato;"></sl-divider>
|
||||
```
|
||||
|
||||
### Spacing
|
||||
|
||||
Use the `--spacing` custom property to change the amount of space between the divider and it's neighboring elements.
|
||||
|
||||
```html preview
|
||||
<div style="text-align: center;">
|
||||
Above
|
||||
<sl-divider style="--spacing: 2rem;"></sl-divider>
|
||||
Below
|
||||
</div>
|
||||
```
|
||||
|
||||
### Vertical
|
||||
|
||||
Add the `vertical` attribute to draw the divider in a vertical orientation. The divider will span the full height of its container. Vertical dividers work especially well inside of a flex container.
|
||||
|
||||
```html preview
|
||||
<div style="display: flex; align-items: center; height: 2rem;">
|
||||
First
|
||||
<sl-divider vertical></sl-divider>
|
||||
Middle
|
||||
<sl-divider vertical></sl-divider>
|
||||
Last
|
||||
</div>
|
||||
```
|
||||
|
||||
### Menu Dividers
|
||||
|
||||
Use dividers in [menus](/components/menu) to visually group menu items.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-item value="1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="2">Option 2</sl-menu-item>
|
||||
<sl-menu-item value="3">Option 3</sl-menu-item>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item value="4">Option 4</sl-menu-item>
|
||||
<sl-menu-item value="5">Option 5</sl-menu-item>
|
||||
<sl-menu-item value="6">Option 6</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
[component-metadata:sl-divider]
|
||||
@@ -15,10 +15,10 @@ Dropdowns are designed to work well with [menus](/components/menu) to provide a
|
||||
<sl-menu-item>Dropdown Item 1</sl-menu-item>
|
||||
<sl-menu-item>Dropdown Item 2</sl-menu-item>
|
||||
<sl-menu-item>Dropdown Item 3</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item checked>Checked</sl-menu-item>
|
||||
<sl-menu-item disabled>Disabled</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item>
|
||||
Prefix
|
||||
<sl-icon slot="prefix" name="gift"></sl-icon>
|
||||
@@ -33,6 +33,33 @@ Dropdowns are designed to work well with [menus](/components/menu) to provide a
|
||||
|
||||
## Examples
|
||||
|
||||
### Getting the Selected Item
|
||||
|
||||
When dropdowns are used with [menus](/components/menu), you can listen for the `sl-select` event to determine which menu item was selected. The menu item element will be exposed in `event.detail.item`. You can set `value` props to make it easier to identify commands.
|
||||
|
||||
```html preview
|
||||
<div class="dropdown-selection">
|
||||
<sl-dropdown>
|
||||
<sl-button slot="trigger" caret>Edit</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.dropdown-selection');
|
||||
const dropdown = container.querySelector('sl-dropdown');
|
||||
|
||||
dropdown.addEventListener('sl-select', event => {
|
||||
const selectedItem = event.detail.item;
|
||||
console.log(selectedItem.value);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Placement
|
||||
|
||||
The preferred placement of the dropdown can be set with the `placement` attribute. Note that the actual position may vary to ensure the panel remains in the viewport.
|
||||
@@ -44,7 +71,7 @@ The preferred placement of the dropdown can be set with the `placement` attribut
|
||||
<sl-menu-item>Cut</sl-menu-item>
|
||||
<sl-menu-item>Copy</sl-menu-item>
|
||||
<sl-menu-item>Paste</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item>Find</sl-menu-item>
|
||||
<sl-menu-item>Replace</sl-menu-item>
|
||||
</sl-menu>
|
||||
@@ -62,7 +89,7 @@ The distance from the panel to the trigger can be customized using the `distance
|
||||
<sl-menu-item>Cut</sl-menu-item>
|
||||
<sl-menu-item>Copy</sl-menu-item>
|
||||
<sl-menu-item>Paste</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item>Find</sl-menu-item>
|
||||
<sl-menu-item>Replace</sl-menu-item>
|
||||
</sl-menu>
|
||||
@@ -80,7 +107,7 @@ The offset of the panel along the trigger can be customized using the `skidding`
|
||||
<sl-menu-item>Cut</sl-menu-item>
|
||||
<sl-menu-item>Copy</sl-menu-item>
|
||||
<sl-menu-item>Paste</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item>Find</sl-menu-item>
|
||||
<sl-menu-item>Replace</sl-menu-item>
|
||||
</sl-menu>
|
||||
@@ -121,57 +148,4 @@ Dropdown panels will be clipped if they're inside a container that has `overflow
|
||||
</style>
|
||||
```
|
||||
|
||||
### Getting the Selected Item
|
||||
|
||||
When dropdowns are used with [menus](/components/menu), you can listen for the `sl-select` event to determine which menu item was selected. The menu item element will be exposed in `event.detail.item`. You can set `value` props to make it easier to identify commands.
|
||||
|
||||
```html preview
|
||||
<div class="dropdown-selection">
|
||||
<sl-dropdown>
|
||||
<sl-button slot="trigger" caret>Edit</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.dropdown-selection');
|
||||
const dropdown = container.querySelector('sl-dropdown');
|
||||
|
||||
dropdown.addEventListener('sl-select', event => {
|
||||
const selectedItem = event.detail.item;
|
||||
console.log(selectedItem.value);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
Alternatively, you can listen for the `click` event on individual menu items. Note that, using this approach, disabled menu items will still emit a `click` event.
|
||||
|
||||
```html preview
|
||||
<div class="dropdown-selection-alt">
|
||||
<sl-dropdown>
|
||||
<sl-button slot="trigger" caret>Edit</sl-button>
|
||||
<sl-menu>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.dropdown-selection-alt');
|
||||
const cut = container.querySelector('sl-menu-item[value="cut"]');
|
||||
const copy = container.querySelector('sl-menu-item[value="copy"]');
|
||||
const paste = container.querySelector('sl-menu-item[value="paste"]');
|
||||
|
||||
cut.addEventListener('click', () => console.log('cut'));
|
||||
copy.addEventListener('click', () => console.log('copy'));
|
||||
paste.addEventListener('click', () => console.log('paste'));
|
||||
</script>
|
||||
```
|
||||
|
||||
[component-metadata:sl-dropdown]
|
||||
|
||||
@@ -186,8 +186,8 @@ The `invalid` attribute reflects the form control's validity, so you can style i
|
||||
border-color: rgb(var(--sl-color-danger-500));
|
||||
}
|
||||
|
||||
.custom-input[invalid] {
|
||||
--focus-ring: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-danger-500) / var(--sl-focus-ring-alpha));
|
||||
.custom-input[invalid]:focus-within::part(base) {
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-danger-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
@@ -385,7 +385,7 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
|
||||
|
||||
### Remix Icon
|
||||
|
||||
This will register the [Remix Icon](https://remixicon.com/) library using the jsDelivr CDN. This library has two variations: line (default) and fill (`*-fill`). It also groups icons by categories, so the name must include the category and icon separated by a slash. A mutator function is required to set the SVG's `fill` to `currentColor`.
|
||||
This will register the [Remix Icon](https://remixicon.com/) library using the jsDelivr CDN. This library groups icons by categories, so the name must include the category and icon separated by a slash, as well as the `-line` or `-fill` suffix as needed. A mutator function is required to set the SVG's `fill` to `currentColor`.
|
||||
|
||||
Icons in this library are licensed under the [Apache 2.0 License](https://github.com/Remix-Design/RemixIcon/blob/master/License).
|
||||
|
||||
@@ -395,21 +395,21 @@ Icons in this library are licensed under the [Apache 2.0 License](https://github
|
||||
|
||||
registerIconLibrary('remixicon', {
|
||||
resolver: name => {
|
||||
const match = name.match(/^(.*?)\/(.*?)(-(fill))?$/);
|
||||
const match = name.match(/^(.*?)\/(.*?)?$/);
|
||||
match[1] = match[1].charAt(0).toUpperCase() + match[1].slice(1);
|
||||
return `https://cdn.jsdelivr.net/npm/remixicon@2.5.0/icons/${match[1]}/${match[2]}${match[3] || '-line'}.svg`;
|
||||
return `https://cdn.jsdelivr.net/npm/remixicon@2.5.0/icons/${match[1]}/${match[2]}.svg`;
|
||||
},
|
||||
mutator: svg => svg.setAttribute('fill', 'currentColor')
|
||||
});
|
||||
</script>
|
||||
|
||||
<div style="font-size: 24px;">
|
||||
<sl-icon library="remixicon" name="business/cloud"></sl-icon>
|
||||
<sl-icon library="remixicon" name="design/brush"></sl-icon>
|
||||
<sl-icon library="remixicon" name="business/pie-chart"></sl-icon>
|
||||
<sl-icon library="remixicon" name="development/bug"></sl-icon>
|
||||
<sl-icon library="remixicon" name="media/image"></sl-icon>
|
||||
<sl-icon library="remixicon" name="system/alert"></sl-icon>
|
||||
<sl-icon library="remixicon" name="business/cloud-line"></sl-icon>
|
||||
<sl-icon library="remixicon" name="design/brush-line"></sl-icon>
|
||||
<sl-icon library="remixicon" name="business/pie-chart-line"></sl-icon>
|
||||
<sl-icon library="remixicon" name="development/bug-line"></sl-icon>
|
||||
<sl-icon library="remixicon" name="media/image-line"></sl-icon>
|
||||
<sl-icon library="remixicon" name="system/alert-line"></sl-icon>
|
||||
<br>
|
||||
<sl-icon library="remixicon" name="business/cloud-fill"></sl-icon>
|
||||
<sl-icon library="remixicon" name="design/brush-fill"></sl-icon>
|
||||
|
||||
@@ -8,7 +8,7 @@ Included files are asynchronously requested using `window.fetch()`. Requests are
|
||||
|
||||
The included content will be inserted into the `<sl-include>` element's default slot so it can be easily accessed and styled through the light DOM.
|
||||
|
||||
```html preview
|
||||
```html preview no-codepen
|
||||
<sl-include src="/assets/examples/include.html"></sl-include>
|
||||
```
|
||||
|
||||
|
||||
@@ -42,6 +42,14 @@ Add the `toggle-password` attribute to add a toggle button that will show the pa
|
||||
<sl-input type="password" placeholder="Password Toggle" size="large" toggle-password></sl-input>
|
||||
```
|
||||
|
||||
### Filled Inputs
|
||||
|
||||
Add the `filled` attribute to draw a filled input.
|
||||
|
||||
```html preview
|
||||
<sl-input placeholder="Type something" filled></sl-input>
|
||||
```
|
||||
|
||||
### Pill
|
||||
|
||||
Use the `pill` attribute to give inputs rounded edges.
|
||||
@@ -54,6 +62,18 @@ Use the `pill` attribute to give inputs rounded edges.
|
||||
<sl-input placeholder="Large" size="large" pill></sl-input>
|
||||
```
|
||||
|
||||
### Input Types
|
||||
|
||||
The `type` attribute controls the type of input the browser renders.
|
||||
|
||||
```html preview
|
||||
<sl-input type="email" Placeholder="Email"></sl-input>
|
||||
<br>
|
||||
<sl-input type="number" Placeholder="Number"></sl-input>
|
||||
<br>
|
||||
<sl-input type="date" Placeholder="Date"></sl-input>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable an input.
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# Menu Divider
|
||||
|
||||
[component-header:sl-menu-divider]
|
||||
|
||||
Menu dividers are used to visually group menu items.
|
||||
|
||||
```html preview
|
||||
<sl-menu
|
||||
style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);"
|
||||
>
|
||||
<sl-menu-item value="1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="2">Option 2</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item value="3">Option 3</sl-menu-item>
|
||||
<sl-menu-item value="4">Option 4</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-menu-item value="5">Option 5</sl-menu-item>
|
||||
<sl-menu-item value="6">Option 6</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
[component-metadata:sl-menu-divider]
|
||||
@@ -5,16 +5,14 @@
|
||||
Menu items provide options for the user to pick from in a menu.
|
||||
|
||||
```html preview
|
||||
<sl-menu
|
||||
style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);"
|
||||
>
|
||||
<sl-menu style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-item>Option 1</sl-menu-item>
|
||||
<sl-menu-item>Option 2</sl-menu-item>
|
||||
<sl-menu-item>Option 3</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item checked>Checked</sl-menu-item>
|
||||
<sl-menu-item disabled>Disabled</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item>
|
||||
Prefix Icon
|
||||
<sl-icon slot="prefix" name="gift"></sl-icon>
|
||||
@@ -26,4 +24,82 @@ Menu items provide options for the user to pick from in a menu.
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Checked
|
||||
|
||||
Use the `checked` attribute to draw menu items in a checked state.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-item>Option 1</sl-menu-item>
|
||||
<sl-menu-item checked>Option 2</sl-menu-item>
|
||||
<sl-menu-item>Option 3</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Add the `disabled` attribute to disable the menu item so it cannot be selected.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-item>Option 1</sl-menu-item>
|
||||
<sl-menu-item disabled>Option 2</sl-menu-item>
|
||||
<sl-menu-item>Option 3</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
### Prefix & Suffix
|
||||
|
||||
Add content to the start and end of menu items using the `prefix` and `suffix` slots.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-item>
|
||||
<sl-icon slot="prefix" name="house"></sl-icon>
|
||||
Home
|
||||
</sl-menu-item>
|
||||
|
||||
<sl-menu-item>
|
||||
<sl-icon slot="prefix" name="envelope"></sl-icon>
|
||||
Messages
|
||||
<sl-badge slot="suffix" type="primary" pill>12</sl-badge>
|
||||
</sl-menu-item>
|
||||
|
||||
<sl-divider></sl-divider>
|
||||
|
||||
<sl-menu-item>
|
||||
<sl-icon slot="prefix" name="gear"></sl-icon>
|
||||
Settings
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
```
|
||||
|
||||
### Value & Selection
|
||||
|
||||
The `value` attribute can be used to assign a hidden value, such as a unique identifier, to a menu item. When an item is selected, the `sl-select` event will be emitted and a reference to the item will be available at `event.detail.item`. You can use this reference to access the selected item's value, its checked state, and more.
|
||||
|
||||
```html preview
|
||||
<sl-menu class="menu-value" style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-item value="opt-1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="opt-2">Option 2</sl-menu-item>
|
||||
<sl-menu-item value="opt-3">Option 3</sl-menu-item>
|
||||
</sl-menu>
|
||||
|
||||
<script>
|
||||
const menu = document.querySelector('.menu-value');
|
||||
|
||||
menu.addEventListener('sl-select', event => {
|
||||
const item = event.detail.item;
|
||||
|
||||
// Toggle checked state
|
||||
item.checked = !item.checked;
|
||||
|
||||
// Log value
|
||||
console.log(`Selected value: ${item.value}`);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
[component-metadata:sl-menu-item]
|
||||
|
||||
@@ -12,7 +12,7 @@ Menu labels are used to describe a group of menu items.
|
||||
<sl-menu-item value="apple">Apple</sl-menu-item>
|
||||
<sl-menu-item value="banana">Banana</sl-menu-item>
|
||||
<sl-menu-item value="orange">Orange</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-label>Vegetables</sl-menu-label>
|
||||
<sl-menu-item value="broccoli">Broccoli</sl-menu-item>
|
||||
<sl-menu-item value="carrot">Carrot</sl-menu-item>
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
Menus provide a list of options for the user to choose from.
|
||||
|
||||
You can use [menu items](/components/menu-item), [menu dividers](/components/menu-divider), and [menu labels](/components/menu-label) to compose a menu. Menus support keyboard interactions, including type-to-select an option.
|
||||
You can use [menu items](/components/menu-item), [menu labels](/components/menu-label), and [dividers](/components/divider) to compose a menu. Menus support keyboard interactions, including type-to-select an option.
|
||||
|
||||
```html preview
|
||||
<sl-menu style="max-width: 200px; border: solid 1px rgb(var(--sl-panel-border-color)); border-radius: var(--sl-border-radius-medium);">
|
||||
<sl-menu-item value="undo">Undo</sl-menu-item>
|
||||
<sl-menu-item value="redo">Redo</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item value="cut">Cut</sl-menu-item>
|
||||
<sl-menu-item value="copy">Copy</sl-menu-item>
|
||||
<sl-menu-item value="paste">Paste</sl-menu-item>
|
||||
|
||||
104
docs/components/mutation-observer.md
Normal file
104
docs/components/mutation-observer.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Mutation Observer
|
||||
|
||||
[component-header:sl-mutation-observer]
|
||||
|
||||
The Mutation Observer component offers a thin, declarative interface to the [`MutationObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver).
|
||||
|
||||
The mutation observer will report changes to the content it wraps through the `sl-mutation` event. When emitted, a collection of [MutationRecord](https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord) objects will be attached to `event.detail` that contains information about how it changed.
|
||||
|
||||
```html preview
|
||||
<div class="mutation-overview">
|
||||
<sl-mutation-observer attr>
|
||||
<sl-button type="primary">Click to mutate</sl-button>
|
||||
</sl-mutation-observer>
|
||||
|
||||
<br>
|
||||
👆 Click the button and watch the console
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.mutation-overview');
|
||||
const mutationObserver = container.querySelector('sl-mutation-observer');
|
||||
const button = container.querySelector('sl-button');
|
||||
const types = ['primary', 'success', 'neutral', 'warning', 'danger'];
|
||||
let clicks = 0;
|
||||
|
||||
// Change the button's type attribute
|
||||
button.addEventListener('click', () => {
|
||||
clicks++;
|
||||
button.setAttribute('type', types[clicks % types.length]);
|
||||
});
|
||||
|
||||
// Log mutations
|
||||
mutationObserver.addEventListener('sl-mutation', event => {
|
||||
console.log(event.detail);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.mutation-overview sl-button {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
?> When you create a mutation observer, you must indicate what changes it should respond to by including at least one of `attr`, `child-list`, or `char-data`. If you don't specify at least one of these attributes, no mutation events will be emitted.
|
||||
|
||||
## Examples
|
||||
|
||||
### Child List
|
||||
|
||||
Use the `child-list` attribute to watch for new child elements that are added or removed.
|
||||
|
||||
```html preview
|
||||
<div class="mutation-child-list">
|
||||
<sl-mutation-observer child-list>
|
||||
<div class="buttons">
|
||||
<sl-button type="primary">Add button</sl-button>
|
||||
</div>
|
||||
</sl-mutation-observer>
|
||||
|
||||
👆 Add and remove buttons and watch the console
|
||||
|
||||
<script>
|
||||
const container = document.querySelector('.mutation-child-list');
|
||||
const mutationObserver = container.querySelector('sl-mutation-observer');
|
||||
const buttons = container.querySelector('.buttons');
|
||||
const button = container.querySelector('sl-button[type="primary"]');
|
||||
let i = 0;
|
||||
|
||||
// Add a button
|
||||
button.addEventListener('click', () => {
|
||||
const button = document.createElement('sl-button');
|
||||
button.textContent = ++i;
|
||||
buttons.append(button);
|
||||
});
|
||||
|
||||
// Remove a button
|
||||
buttons.addEventListener('click', event => {
|
||||
const target = event.target.closest('sl-button:not([type="primary"])');
|
||||
event.stopPropagation();
|
||||
|
||||
if (target) {
|
||||
target.remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Log mutations
|
||||
mutationObserver.addEventListener('sl-mutation', event => {
|
||||
console.log(event.detail);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.mutation-child-list .buttons {
|
||||
display: flex;
|
||||
gap: .25rem;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
```
|
||||
|
||||
[component-metadata:sl-mutation-observer]
|
||||
@@ -5,7 +5,7 @@
|
||||
Progress bars are used to show the status of an ongoing operation.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar percentage="50"></sl-progress-bar>
|
||||
<sl-progress-bar value="50"></sl-progress-bar>
|
||||
```
|
||||
|
||||
## Examples
|
||||
@@ -15,15 +15,23 @@ Progress bars are used to show the status of an ongoing operation.
|
||||
Use the `--height` custom property to set the progress bar's height.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar percentage="50" style="--height: 6px;"></sl-progress-bar>
|
||||
<sl-progress-bar value="50" style="--height: 6px;"></sl-progress-bar>
|
||||
```
|
||||
|
||||
### Labels
|
||||
|
||||
Use the default slot to show a label.
|
||||
Use the `label` attribute to label the progress bar and tell assistive devices how to announce it.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar percentage="50" class="progress-bar-labels">50%</sl-progress-bar>
|
||||
<sl-progress-bar value="50" label="Upload progress"></sl-progress-bar>
|
||||
```
|
||||
|
||||
### Showing Values
|
||||
|
||||
Use the default slot to show a value.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar value="50" class="progress-bar-values">50%</sl-progress-bar>
|
||||
|
||||
<br>
|
||||
|
||||
@@ -31,27 +39,27 @@ Use the default slot to show a label.
|
||||
<sl-button circle><sl-icon name="plus"></sl-icon></sl-button>
|
||||
|
||||
<script>
|
||||
const progressBar = document.querySelector('.progress-bar-labels');
|
||||
const progressBar = document.querySelector('.progress-bar-values');
|
||||
const subtractButton = progressBar.nextElementSibling.nextElementSibling;
|
||||
const addButton = subtractButton.nextElementSibling;
|
||||
|
||||
addButton.addEventListener('click', () => {
|
||||
const percentage = Math.min(100, progressBar.percentage + 10);
|
||||
progressBar.percentage = percentage;
|
||||
progressBar.textContent = `${percentage}%`;
|
||||
const value = Math.min(100, progressBar.value + 10);
|
||||
progressBar.value = value;
|
||||
progressBar.textContent = `${value}%`;
|
||||
});
|
||||
|
||||
subtractButton.addEventListener('click', () => {
|
||||
const percentage = Math.max(0, progressBar.percentage - 10)
|
||||
progressBar.percentage = percentage;
|
||||
progressBar.textContent = `${percentage}%`;
|
||||
const value = Math.max(0, progressBar.value - 10)
|
||||
progressBar.value = value;
|
||||
progressBar.textContent = `${value}%`;
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
### Indeterminate
|
||||
|
||||
The `indeterminate` attribute can be used to inform the user that the operation is pending, but its status cannot currently be determined. In this state, `percentage` is ignored and the label, if present, will not be shown.
|
||||
The `indeterminate` attribute can be used to inform the user that the operation is pending, but its status cannot currently be determined. In this state, `value` is ignored and the label, if present, will not be shown.
|
||||
|
||||
```html preview
|
||||
<sl-progress-bar indeterminate></sl-progress-bar>
|
||||
|
||||
@@ -5,25 +5,25 @@
|
||||
Progress rings are used to show the progress of a determinate operation in a circular fashion.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring percentage="25"></sl-progress-ring>
|
||||
<sl-progress-ring value="25"></sl-progress-ring>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Size
|
||||
|
||||
Use the `size` attribute to set the diameter of the progress ring.
|
||||
Use the `--size` custom property to set the diameter of the progress ring.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring percentage="50" size="200"></sl-progress-ring>
|
||||
<sl-progress-ring value="50" style="--size: 200px;"></sl-progress-ring>
|
||||
```
|
||||
|
||||
### Stroke Width
|
||||
### Track Width
|
||||
|
||||
Use the `stroke-width` attribute to set the width of the progress ring's indicator.
|
||||
Use the `--track-width` custom property to set the width of the progress ring's track.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring percentage="50" stroke-width="10"></sl-progress-ring>
|
||||
<sl-progress-ring value="50" style="--track-width: 10px;"></sl-progress-ring>
|
||||
```
|
||||
|
||||
### Colors
|
||||
@@ -32,20 +32,28 @@ To change the color, use the `--track-color` and `--indicator-color` custom prop
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring
|
||||
percentage="50"
|
||||
value="50"
|
||||
style="
|
||||
--track-color: rgb(var(--sl-color-cyan-100));
|
||||
--indicator-color: rgb(var(--sl-color-cyan-600));
|
||||
--track-color: pink;
|
||||
--indicator-color: deeppink;
|
||||
"
|
||||
></sl-progress-ring>
|
||||
```
|
||||
|
||||
### Labels
|
||||
|
||||
Use the `label` attribute to label the progress ring and tell assistive devices how to announce it.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring value="50" label="Upload progress"></sl-progress-ring>
|
||||
```
|
||||
|
||||
### Showing Values
|
||||
|
||||
Use the default slot to show a label.
|
||||
|
||||
```html preview
|
||||
<sl-progress-ring percentage="50" size="200" class="progress-ring-labels" style="margin-bottom: .5rem;">50%</sl-progress-ring>
|
||||
<sl-progress-ring value="50" class="progress-ring-values" style="margin-bottom: .5rem;">50%</sl-progress-ring>
|
||||
|
||||
<br>
|
||||
|
||||
@@ -53,20 +61,20 @@ Use the default slot to show a label.
|
||||
<sl-button circle><sl-icon name="plus"></sl-icon></sl-button>
|
||||
|
||||
<script>
|
||||
const progressRing = document.querySelector('.progress-ring-labels');
|
||||
const progressRing = document.querySelector('.progress-ring-values');
|
||||
const subtractButton = progressRing.nextElementSibling.nextElementSibling;
|
||||
const addButton = subtractButton.nextElementSibling;
|
||||
|
||||
addButton.addEventListener('click', () => {
|
||||
const percentage = Math.min(100, progressRing.percentage + 10);
|
||||
progressRing.percentage = percentage;
|
||||
progressRing.textContent = `${percentage}%`;
|
||||
const value = Math.min(100, progressRing.value + 10);
|
||||
progressRing.value = value;
|
||||
progressRing.textContent = `${value}%`;
|
||||
});
|
||||
|
||||
subtractButton.addEventListener('click', () => {
|
||||
const percentage = Math.max(0, progressRing.percentage - 10)
|
||||
progressRing.percentage = percentage;
|
||||
progressRing.textContent = `${percentage}%`;
|
||||
const value = Math.max(0, progressRing.value - 10)
|
||||
progressRing.value = value;
|
||||
progressRing.textContent = `${value}%`;
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -14,12 +14,12 @@ Radio Groups are used to group multiple radios so they function as a single cont
|
||||
|
||||
## Examples
|
||||
|
||||
### Hiding the Fieldset
|
||||
### Showing the Fieldset
|
||||
|
||||
You can hide the fieldset and legend that wraps the radio group using the `no-fieldset` attribute. In this case, a label is still required for assistive devices to properly identify the control.
|
||||
You can show a fieldset and legend that wraps the radio group using the `fieldset` attribute.
|
||||
|
||||
```html preview
|
||||
<sl-radio-group label="Select an item" no-fieldset>
|
||||
<sl-radio-group label="Select an item" fieldset>
|
||||
<sl-radio value="1" checked>Item 1</sl-radio>
|
||||
<sl-radio value="2">Item 2</sl-radio>
|
||||
<sl-radio value="3">Item 3</sl-radio>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
Ranges allow the user to select a single value within a given range using a slider.
|
||||
|
||||
```html preview
|
||||
<sl-range min="0" max="100" step="1"></sl-range>
|
||||
<sl-range></sl-range>
|
||||
```
|
||||
|
||||
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form) instead.
|
||||
@@ -36,6 +36,17 @@ To disable the tooltip, set `tooltip` to `none`.
|
||||
<sl-range min="0" max="100" step="1" tooltip="none"></sl-range>
|
||||
```
|
||||
|
||||
### Custom Track Colors
|
||||
|
||||
You can customize the active and inactive portions of the track using the `--track-color-active` and `--track-color-inactive` custom properties.
|
||||
|
||||
```html preview
|
||||
<sl-range style="
|
||||
--track-color-active: rgb(var(--sl-color-primary-600));
|
||||
--track-color-inactive: rgb(var(--sl-color-primary-200));
|
||||
"></sl-range>
|
||||
```
|
||||
|
||||
### Custom Tooltip Formatter
|
||||
|
||||
You can change the tooltip's content by setting the `tooltipFormatter` property to a function that accepts the range's value as an argument.
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
[component-header:sl-resize-observer]
|
||||
|
||||
Resize observers offer a thin, declarative interface to the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).
|
||||
The Resize Observer component offers a thin, declarative interface to the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).
|
||||
|
||||
The resize observer will report changes to the dimensions of the elements it wraps through the `sl-resize` event. When emitted, a collection of [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry) objects will be attached to `event.detail`, containing the target element and information about its dimensions.
|
||||
The resize observer will report changes to the dimensions of the elements it wraps through the `sl-resize` event. When emitted, a collection of [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry) objects will be attached to `event.detail` that contains the target element and information about its dimensions.
|
||||
|
||||
```html preview
|
||||
<div class="resize-observer-overview">
|
||||
@@ -20,7 +20,7 @@ The resize observer will report changes to the dimensions of the elements it wra
|
||||
const resizeObserver = container.querySelector('sl-resize-observer');
|
||||
|
||||
resizeObserver.addEventListener('sl-resize', event => {
|
||||
console.log(event);
|
||||
console.log(event.detail);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ Selects allow you to choose one or more items from a dropdown menu.
|
||||
<sl-menu-item value="option-1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="option-2">Option 2</sl-menu-item>
|
||||
<sl-menu-item value="option-3">Option 3</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item value="option-4">Option 4</sl-menu-item>
|
||||
<sl-menu-item value="option-5">Option 5</sl-menu-item>
|
||||
<sl-menu-item value="option-6">Option 6</sl-menu-item>
|
||||
@@ -44,6 +44,18 @@ Use the `clearable` attribute to make the control clearable.
|
||||
</sl-select>
|
||||
```
|
||||
|
||||
### Filled Selects
|
||||
|
||||
Add the `filled` attribute to draw a filled select.
|
||||
|
||||
```html preview
|
||||
<sl-select filled>
|
||||
<sl-menu-item value="option-1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="option-2">Option 2</sl-menu-item>
|
||||
<sl-menu-item value="option-3">Option 3</sl-menu-item>
|
||||
</sl-select>
|
||||
```
|
||||
|
||||
### Pill
|
||||
|
||||
Use the `pill` attribute to give selects rounded edges.
|
||||
@@ -77,7 +89,7 @@ To allow multiple options to be selected, use the `multiple` attribute. It's a g
|
||||
<sl-menu-item value="option-1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="option-2">Option 2</sl-menu-item>
|
||||
<sl-menu-item value="option-3">Option 3</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item value="option-4">Option 4</sl-menu-item>
|
||||
<sl-menu-item value="option-5">Option 5</sl-menu-item>
|
||||
<sl-menu-item value="option-6">Option 6</sl-menu-item>
|
||||
@@ -86,7 +98,7 @@ To allow multiple options to be selected, use the `multiple` attribute. It's a g
|
||||
|
||||
### Grouping Options
|
||||
|
||||
Options can be grouped visually using menu labels and menu dividers.
|
||||
Options can be grouped visually using menu labels and dividers.
|
||||
|
||||
```html preview
|
||||
<sl-select placeholder="Select one">
|
||||
@@ -94,7 +106,7 @@ Options can be grouped visually using menu labels and menu dividers.
|
||||
<sl-menu-item value="option-1">Option 1</sl-menu-item>
|
||||
<sl-menu-item value="option-2">Option 2</sl-menu-item>
|
||||
<sl-menu-item value="option-3">Option 3</sl-menu-item>
|
||||
<sl-menu-divider></sl-menu-divider>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-label>Group 2</sl-menu-label>
|
||||
<sl-menu-item value="option-4">Option 4</sl-menu-item>
|
||||
<sl-menu-item value="option-5">Option 5</sl-menu-item>
|
||||
|
||||
@@ -12,7 +12,7 @@ Spinners are used to show the progress of an indeterminate operation.
|
||||
|
||||
### Size
|
||||
|
||||
Spinners are sized relative to the current font size. To change their size, set the `font-size` property on the spinner itself or on a parent element as shown below.
|
||||
Spinners are sized based on the current font size. To change their size, set the `font-size` property on the spinner itself or on a parent element as shown below.
|
||||
|
||||
```html preview
|
||||
<sl-spinner></sl-spinner>
|
||||
@@ -20,12 +20,12 @@ Spinners are sized relative to the current font size. To change their size, set
|
||||
<sl-spinner style="font-size: 3rem;"></sl-spinner>
|
||||
```
|
||||
|
||||
### Stroke Width
|
||||
### Track Width
|
||||
|
||||
The width of the spinner can be changed by setting the `--stroke-width` custom property.
|
||||
The width of the spinner's track can be changed by setting the `--track-width` custom property.
|
||||
|
||||
```html preview
|
||||
<sl-spinner style="font-size: 2rem; --stroke-width: 6px;"></sl-spinner>
|
||||
<sl-spinner style="font-size: 3rem; --track-width: 6px;"></sl-spinner>
|
||||
```
|
||||
|
||||
### Color
|
||||
@@ -33,7 +33,7 @@ The width of the spinner can be changed by setting the `--stroke-width` custom p
|
||||
The spinner's colors can be changed by setting the `--indicator-color` and `--track-color` custom properties.
|
||||
|
||||
```html preview
|
||||
<sl-spinner style="font-size: 2rem; --indicator-color: tomato;"></sl-spinner>
|
||||
<sl-spinner style="font-size: 3rem; --indicator-color: deeppink; --track-color: pink;"></sl-spinner>
|
||||
```
|
||||
|
||||
[component-metadata:sl-spinner]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[component-header:sl-tab-panel]
|
||||
|
||||
Tab panels are used inside tab groups to display content.
|
||||
Tab panels are used inside [tab groups](/components/tab-group) to display tabbed content.
|
||||
|
||||
```html preview
|
||||
<sl-tab-group>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[component-header:sl-tab]
|
||||
|
||||
Tabs are used inside tab groups to represent tab panels.
|
||||
Tabs are used inside [tab groups](/components/tab-group) to represent and activate [tab panels](/components/tab-panel).
|
||||
|
||||
```html preview
|
||||
<sl-tab>Tab</sl-tab>
|
||||
|
||||
@@ -34,21 +34,21 @@ Use the `pill` attribute to give tabs rounded edges.
|
||||
<sl-tag size="large" pill>Large</sl-tag>
|
||||
```
|
||||
|
||||
### Clearable
|
||||
### Removable
|
||||
|
||||
Use the `clearable` attribute to add a clear button to the tag.
|
||||
Use the `removable` attribute to add a remove button to the tag.
|
||||
|
||||
```html preview
|
||||
<div class="tags-clearable">
|
||||
<sl-tag size="small" clearable>Small</sl-tag>
|
||||
<sl-tag size="medium" clearable>Medium</sl-tag>
|
||||
<sl-tag size="large" clearable>Large</sl-tag>
|
||||
<div class="tags-removable">
|
||||
<sl-tag size="small" removable>Small</sl-tag>
|
||||
<sl-tag size="medium" removable>Medium</sl-tag>
|
||||
<sl-tag size="large" removable>Large</sl-tag>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const div = document.querySelector('.tags-clearable');
|
||||
const div = document.querySelector('.tags-removable');
|
||||
|
||||
div.addEventListener('sl-clear', event => {
|
||||
div.addEventListener('sl-remove', event => {
|
||||
const tag = event.target;
|
||||
tag.style.opacity = '0';
|
||||
setTimeout(() => tag.style.opacity = '1', 2000);
|
||||
@@ -56,7 +56,7 @@ Use the `clearable` attribute to add a clear button to the tag.
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.tags-clearable sl-tag {
|
||||
.tags-removable sl-tag {
|
||||
transition: var(--sl-transition-medium) opacity;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -30,9 +30,17 @@ Use the `placeholder` attribute to add a placeholder.
|
||||
<sl-textarea placeholder="Type something"></sl-textarea>
|
||||
```
|
||||
|
||||
### Filled Textareas
|
||||
|
||||
Add the `filled` attribute to draw a filled textarea.
|
||||
|
||||
```html preview
|
||||
<sl-textarea placeholder="Type something" filled></sl-textarea>
|
||||
```
|
||||
|
||||
### Disabled
|
||||
|
||||
Use the `disabled` attribute to disable an input.
|
||||
Use the `disabled` attribute to disable a textarea.
|
||||
|
||||
```html preview
|
||||
<sl-textarea placeholder="Textarea" disabled></sl-textarea>
|
||||
|
||||
@@ -165,7 +165,7 @@ To override it globally, set it in a root block in your stylesheet after the Sho
|
||||
|
||||
### HTML in Tooltips
|
||||
|
||||
Use the `content` slot to create tooltips with HTML content.
|
||||
Use the `content` slot to create tooltips with HTML content. Tooltips are designed only for text and presentational elements. Avoid placing interactive content, such as buttons, links, and form controls, in a tooltip.
|
||||
|
||||
```html preview
|
||||
<sl-tooltip>
|
||||
@@ -174,4 +174,29 @@ Use the `content` slot to create tooltips with HTML content.
|
||||
</sl-tooltip>
|
||||
```
|
||||
|
||||
### Hoisting
|
||||
|
||||
Tooltips will be clipped if they're inside a container that has `overflow: auto|hidden|scroll`. The `hoist` attribute forces the tooltip to use a fixed positioning strategy, allowing it to break out of the container. In this case, the tooltip will be positioned relative to its containing block, which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
|
||||
|
||||
```html preview
|
||||
<div class="tooltip-hoist">
|
||||
<sl-tooltip content="This is a tooltip">
|
||||
<sl-button>No Hoist</sl-button>
|
||||
</sl-tooltip>
|
||||
|
||||
<sl-tooltip content="This is a tooltip" hoist>
|
||||
<sl-button>Hoist</sl-button>
|
||||
</sl-tooltip>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.tooltip-hoist {
|
||||
border: solid 2px rgb(var(--sl-panel-border-color));
|
||||
overflow: hidden;
|
||||
padding: var(--sl-spacing-medium);
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
[component-metadata:sl-tooltip]
|
||||
|
||||
@@ -29,7 +29,7 @@ To customize a design token, simply override it in your stylesheet using a `:roo
|
||||
}
|
||||
```
|
||||
|
||||
Many design tokens are described further along in this documentation. For a complete list, refer to `src/themes/light.styles.ts` in the project's [source code](https://github.com/shoelace-style/shoelace/blob/current/src/themes/base.styles.ts).
|
||||
Many design tokens are described further along in this documentation. For a complete list, refer to `src/themes/light.styles.ts` in the project's [source code](https://github.com/shoelace-style/shoelace/blob/current/src/themes/light.styles.ts).
|
||||
|
||||
## Component Parts
|
||||
|
||||
@@ -46,7 +46,7 @@ Here's an example that modifies buttons with the `tomato-button` class.
|
||||
|
||||
<style>
|
||||
.tomato-button::part(base) {
|
||||
background: rgb(var(--sl-color-neutral-1000));
|
||||
background: rgb(var(--sl-color-neutral-0));
|
||||
border: solid 1px tomato;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,52 +1,75 @@
|
||||
# Installation
|
||||
|
||||
You can use Shoelace via CDN or by installing it locally.
|
||||
You can use Shoelace via CDN or by installing it locally. You can also [cherry pick](#cherry-picking) individual components for faster load times.
|
||||
|
||||
## CDN Installation (Recommended)
|
||||
|
||||
The easiest way to install Shoelace is with the CDN. Just add the following tags to your page.
|
||||
The easiest way to install Shoelace is with the CDN. Just add the following tags to your page to get all components and the default light theme.
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/themes/light.css">
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/shoelace.js"></script>
|
||||
```
|
||||
|
||||
### Dark Theme
|
||||
|
||||
If you prefer to use the dark theme instead, use this. Note the `sl-theme-dark` class on the `<html>` element. [Learn more about the Dark Theme.](/getting-started/themes#dark-theme)
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/themes/dark.css">
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/shoelace.js"></script>
|
||||
```
|
||||
|
||||
### Light & Dark Theme
|
||||
|
||||
If you want to load the light or dark theme based on the user's `prefers-color-scheme` setting, use this. The `media` attributes ensure that only the user's preferred theme stylesheet loads and the `onload` attribute sets the appropriate [theme class](/getting-started/themes) on the `<html>` element.
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" media="(prefers-color-scheme:light)" href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/themes/light.css">
|
||||
<link rel="stylesheet" media="(prefers-color-scheme:dark)"
|
||||
href="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/themes/dark.css"
|
||||
onload="document.documentElement.classList.add('sl-theme-dark');">
|
||||
<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/dist/shoelace.js"></script>
|
||||
```
|
||||
|
||||
Now you can [start using Shoelace!](/getting-started/usage)
|
||||
|
||||
## Local Installation
|
||||
|
||||
If you don't want to use the CDN, you can install Shoelace locally with the following command.
|
||||
If you don't want to use the CDN, you can install Shoelace locally with the following command.
|
||||
|
||||
```bash
|
||||
npm install @shoelace-style/shoelace
|
||||
```
|
||||
|
||||
It's up to you to make the source files available to your app. One way to do this is to create a route in your app called `/scripts/shoelace` that serves static files from `node_modules/@shoelace-style/shoelace`.
|
||||
It's up to you to make the source files available to your app. One way to do this is to create a route in your app called `/shoelace` that serves static files from `node_modules/@shoelace-style/shoelace`.
|
||||
|
||||
Once you've done that, add the following tags to your page. Make sure to update `href` and `src` so they point to the route you created.
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="/scripts/shoelace/dist/themes/light.css">
|
||||
<script type="module" src="/scripts/shoelace/dist/shoelace.js"></script>
|
||||
<link rel="stylesheet" href="/shoelace/dist/themes/light.css">
|
||||
<script type="module" src="/shoelace/dist/shoelace.js"></script>
|
||||
```
|
||||
|
||||
Alternatively, [you can use a bundler](#bundling).
|
||||
|
||||
?> For clarity, the docs will usually show imports from `@shoelace-style/shoelace`. If you're not using a module resolver or bundler, you'll need to adjust these paths to point to the folder Shoelace is in.
|
||||
|
||||
## Setting the Base Path
|
||||
|
||||
Some components rely on assets (icons, images, etc.) and Shoelace needs to know where they're located. For convenience, Shoelace will try to auto-detect the correct location based on the script you've loaded it from. This assumes assets are colocated with `shoelace.js` and will "just work" for most users.
|
||||
|
||||
However, if you're [cherry picking](#cherry-picking) or [bundling](#bundling) Shoelace, you'll need to set the base path. You can do this one of two ways. The following example assumes you're serving Shoelace's `dist` directory from `/scripts/shoelace`.
|
||||
However, if you're [cherry picking](#cherry-picking) or [bundling](#bundling) Shoelace, you'll need to set the base path. You can do this one of two ways.
|
||||
|
||||
```html
|
||||
<!-- Option 1: the data-shoelace attribute -->
|
||||
<script src="bundle.js" data-shoelace="/scripts/shoelace"></script>
|
||||
<script src="bundle.js" data-shoelace="/path/to/shoelace"></script>
|
||||
|
||||
<!-- Option 2: the setBasePath() method -->
|
||||
<script src="bundle.js"></script>
|
||||
<script type="module">
|
||||
import { setBasePath } from '/scripts/shoelace/dist/utilities/base-path.js';
|
||||
setBasePath('/scripts/shoelace');
|
||||
import { setBasePath } from '@shoelace-style/shoelace/dist/utilities/base-path.js';
|
||||
setBasePath('/path/to/shoelace');
|
||||
</script>
|
||||
```
|
||||
|
||||
@@ -56,22 +79,21 @@ However, if you're [cherry picking](#cherry-picking) or [bundling](#bundling) Sh
|
||||
|
||||
The previous approach is the _easiest_ way to load Shoelace, but easy isn't always efficient. You'll incur the full size of the library even if you only use a handful of components. This is convenient for prototyping, but may result in longer load times in production. To improve this, you can cherry pick the components you need.
|
||||
|
||||
Cherry picking can be done from your local install or [directly from the CDN](https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/). This will limit the number of files the browser has to download and reduce the amount of bytes being transferred. The disadvantage is that you need to load and register each component manually.
|
||||
Cherry picking can be done from your local install or [directly from the CDN](https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@%VERSION%/). This will limit the number of files the browser has to download and reduce the amount of bytes being transferred. The disadvantage is that you need to load component manually.
|
||||
|
||||
Here's an example that loads only the button component. Again, if you're not using a module resolver, you'll need to adjust the path to point to the folder Shoelace is in.
|
||||
|
||||
```html
|
||||
<!-- The base stylesheet is always required -->
|
||||
<link rel="stylesheet" href="@shoelace-style/shoelace/dist/themes/light.css">
|
||||
|
||||
<script type="module" data-shoelace="/scripts/shoelace">
|
||||
<script type="module" data-shoelace="/path/to/shoelace">
|
||||
import '@shoelace-style/shoelace/dist/components/button/button.js';
|
||||
|
||||
|
||||
// <sl-button> is ready to use!
|
||||
</script>
|
||||
```
|
||||
|
||||
Some components have dependencies that are automatically imported when you cherry pick. If a component has dependencies, they will be listed in the "Dependencies" section of the component's documentation.
|
||||
You can copy and paste the code to import a component from the "Importing" section of the component's documentation. Note that some components have dependencies that are automatically imported when you cherry pick. If a component has dependencies, they will be listed in the "Dependencies" section of its docs.
|
||||
|
||||
!> Never cherry pick components or utilities from `shoelace.js` as this will cause the browser to load the entire library. Instead, cherry pick from specific modules as shown above.
|
||||
|
||||
@@ -108,4 +130,4 @@ setBasePath('/dist/shoelace');
|
||||
// <sl-button>, <sl-icon>, <sl-input>, and <sl-rating> are ready to use!
|
||||
```
|
||||
|
||||
!> Component modules include side effects for registration purposes. Because of this, importing directly from `@shoelace-style/shoelace` may result in a larger bundle size than necessary. For optimal tree shaking, always cherry pick, i.e. import components and utilities from their respective files, as shown above.
|
||||
!> Component modules include side effects for registration purposes. Because of this, importing directly from `@shoelace-style/shoelace` may result in a larger bundle size than necessary. For optimal tree shaking, always cherry pick, i.e. import components and utilities from their respective files, as shown above.
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
<div class="splash-start">
|
||||
<img class="splash-logo" src="/assets/images/wordmark.svg" alt="Shoelace">
|
||||
|
||||
**A forward-thinking library of web components.**
|
||||
# <span hidden>Shoelace:</span> A forward-thinking library of web components.
|
||||
|
||||
- Works with all frameworks 🧩
|
||||
- Works with CDNs 🚛
|
||||
- Fully customizable with CSS 🎨
|
||||
- Includes an official dark theme 🌛
|
||||
- Includes a dark theme 🌛
|
||||
- Built with accessibility in mind ♿️
|
||||
- First-party [React wrappers](/getting-started/usage#react)
|
||||
- Open source 😸
|
||||
@@ -19,12 +19,12 @@ Designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska).
|
||||
</div>
|
||||
</div>
|
||||
|
||||
[](https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace)
|
||||
[](https://www.npmjs.com/package/@shoelace-style/shoelace)
|
||||
[](https://github.com/shoelace-style/shoelace/blob/next/LICENSE.md)<br>
|
||||
[](https://discord.gg/mg8f26C)
|
||||
[](https://twitter.com/shoelace_style)
|
||||
[](https://github.com/sponsors/claviska)
|
||||
[](https://www.jsdelivr.com/package/npm/@shoelace-style/shoelace)
|
||||
[](https://www.npmjs.com/package/@shoelace-style/shoelace)
|
||||
[](https://github.com/shoelace-style/shoelace/blob/next/LICENSE.md)<br>
|
||||
[](https://discord.gg/mg8f26C)
|
||||
[](https://twitter.com/shoelace_style)
|
||||
[](https://github.com/shoelace-style/shoelace)
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -93,9 +93,7 @@ If you need to support IE11 or pre-Chromium Edge, this library isn't for you. Al
|
||||
|
||||
Shoelace is designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska). It's available under the terms of the MIT license.
|
||||
|
||||
Designing, developing, and supporting this library requires a lot of time, effort, and skill. I'd like to keep it open source so everyone can use it, but that doesn't provide me with any income.
|
||||
|
||||
**Therefore, if you're using my software to make a profit,** I respectfully ask that you help [fund its development](https://github.com/sponsors/claviska) by becoming a sponsor. There are multiple tiers to choose from with benefits at every level, including prioritized support, bug fixes, feature requests, and advertising.
|
||||
Designing, developing, and supporting this library requires a lot of time, effort, and skill. If you're using this software to make a profit, I respectfully ask that you help [fund its development](https://github.com/sponsors/claviska) by becoming a sponsor.
|
||||
|
||||
👇 Your support is very much appreciated! 👇
|
||||
|
||||
@@ -125,4 +123,5 @@ Special thanks to the following projects and individuals that help make Shoelace
|
||||
- Positioning of menus, tooltips, et al is handled by [Popper.js](https://popper.js.org/)
|
||||
- Animations are courtesy of [animate.css](https://animate.style/)
|
||||
- QR codes are generated with [qr-creator](https://github.com/nimiq/qr-creator)
|
||||
- Search is powered by [Lunr](https://lunrjs.com/)
|
||||
- The Shoelace logo was designed with a single shoelace by [Adam K Olson](https://twitter.com/adamkolson)
|
||||
|
||||
@@ -108,7 +108,9 @@ You will, however, need to maintain your theme more carefully, as new versions o
|
||||
|
||||
## Dark Theme
|
||||
|
||||
The built-in dark theme uses an inverted + shifted color scale so, if you're using design tokens as intended, you'll get a decent dark mode for free. While this isn't the same as a professionally curated dark theme, it provides an excellent baseline for one and you're encouraged to customize it further depending on your needs.
|
||||
The built-in dark theme uses an inverted + shifted color scale so, if you're using design tokens as intended, you'll get a decent dark mode for free. While this isn't the same as a professionally curated dark theme, it provides an excellent baseline for one and you're encouraged to customize it depending on your needs.
|
||||
|
||||
This was achieved by taking the light theme's [color tokens](/tokens/color) and "flipping" the scale so 100 becomes 900, 200 becomes 800, 300 becomes 700, etc. Next, the luminance of each primitive was increased slightly to avoid true black, a color that is typically undesirable in dark themes. The result is a custom palette that complements the light theme well and makes it easy to offer light and dark variations with minimal effort.
|
||||
|
||||
To install the dark theme, add the following to the `<head>` section of your page.
|
||||
|
||||
|
||||
@@ -168,9 +168,14 @@ const MyComponent = (props) => {
|
||||
Vue [plays nice](https://custom-elements-everywhere.com/#vue) with custom elements. You just have to tell it to ignore Shoelace components. This is pretty easy because they all start with `sl-`.
|
||||
|
||||
```js
|
||||
Vue.config.ignoredElements = [/^sl-/];
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
|
||||
new Vue({ ... });
|
||||
const app = createApp(App);
|
||||
|
||||
app.config.compilerOptions.isCustomElement = tag => tag.startsWith('sl-');
|
||||
|
||||
app.mount('#app');
|
||||
```
|
||||
|
||||
### Binding Complex Data
|
||||
@@ -197,7 +202,7 @@ If that's too verbose, you can use a custom directive instead.
|
||||
|
||||
### Using a Custom Directive
|
||||
|
||||
You can use [this utility](https://www.npmjs.com/package/@shoelace-style/vue-sl-model) to add a custom directive to Vue that will work just like `v-model` but for Shoelace components. To install it, use this command.
|
||||
You can use [this utility](https://www.npmjs.com/package/@shoelace-style/vue-sl-model) to add a custom directive that will work just like `v-model` but for Shoelace components. To install it, use this command.
|
||||
|
||||
```bash
|
||||
npm install @shoelace-style/vue-sl-model
|
||||
@@ -207,12 +212,15 @@ Next, import the directive and enable it like this.
|
||||
|
||||
```js
|
||||
import ShoelaceModelDirective from '@shoelace-style/vue-sl-model';
|
||||
import { createApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
|
||||
Vue.config.ignoredElements = [/^sl-/];
|
||||
Vue.use(ShoelaceModelDirective);
|
||||
const app = createApp(App);
|
||||
app.use(ShoelaceModelDirective);
|
||||
|
||||
// Your init here
|
||||
new Vue({ ... });
|
||||
app.config.compilerOptions.isCustomElement = tag => tag.startsWith('sl-');
|
||||
|
||||
app.mount('#app');
|
||||
```
|
||||
|
||||
Now you can use the `v-sl-model` directive to keep your data in sync!
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify@4/themes/pure.css" />
|
||||
<link rel="stylesheet" href="/assets/styles/docs.css" />
|
||||
<link rel="stylesheet" href="/assets/plugins/code-block/code-block.css" />
|
||||
<link rel="stylesheet" href="/assets/plugins/search/search.css" />
|
||||
<link rel="stylesheet" href="/assets/plugins/theme-picker/theme-picker.css" />
|
||||
<link rel="icon" href="/assets/images/logo.svg" type="image/x-icon" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/images/touch-icon.png" />
|
||||
@@ -71,6 +72,7 @@
|
||||
maxLevel: 3,
|
||||
subMaxLevel: 2,
|
||||
name: 'Shoelace',
|
||||
nameLink: '/',
|
||||
notFoundPage: '404.md',
|
||||
pagination: {
|
||||
previousText: 'Previous',
|
||||
@@ -78,29 +80,21 @@
|
||||
crossChapter: true,
|
||||
crossChapterText: false
|
||||
},
|
||||
routerMode: location.port ? 'hash' : 'history',
|
||||
search: {
|
||||
maxAge: 86400000, // Expiration time, the default one day
|
||||
paths: 'auto',
|
||||
placeholder: 'Search',
|
||||
noData: 'No Results',
|
||||
depth: 3,
|
||||
namespace: 'shoelace-docs'
|
||||
},
|
||||
routerMode: 'history',
|
||||
themeColor: 'rgb(var(--sl-color-primary-500))'
|
||||
};
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify@4/lib/docsify.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify@4/lib/plugins/search.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify@4/lib/plugins/ga.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify-copy-code@2"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/docsify-pagination@2/dist/docsify-pagination.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.19.0/components/prism-bash.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@1.19.0/components/prism-jsx.min.js"></script>
|
||||
<script src="/assets/plugins/code-block/code-block.js"></script>
|
||||
<script src="/assets/plugins/scroll-position/scroll-position.js"></script>
|
||||
<script src="/assets/plugins/theme-picker/theme-picker.js"></script>
|
||||
<script src="/assets/plugins/metadata/metadata.js"></script>
|
||||
<script src="/assets/plugins/sidebar/sidebar.js"></script>
|
||||
<script src="/assets/plugins/scroll-position/scroll-position.js"></script>
|
||||
<script src="/assets/plugins/search/lunr.min.js"></script>
|
||||
<script src="/assets/plugins/search/search.js"></script>
|
||||
<script src="/assets/plugins/theme-picker/theme-picker.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,6 +6,136 @@ Components with the <sl-badge type="warning" pill>Experimental</sl-badge> badge
|
||||
|
||||
_During the beta period, these restrictions may be relaxed in the event of a mission-critical bug._ 🐛
|
||||
|
||||
## Next
|
||||
|
||||
- Added experimental `<sl-context-menu>` component
|
||||
- Added eye dropper to `<sl-color-picker>` when the browser supports the [EyeDropper API](https://wicg.github.io/eyedropper-api/)
|
||||
- Fixed a bug in `<sl-button-group>` where buttons groups with only one button would have an incorrect border radius
|
||||
- Improved the `<sl-color-picker>` trigger's border in dark mode
|
||||
- Refactored positioning logic in `<sl-dropdown>` so Popper is only active when the menu is open
|
||||
- Updated to Lit 2.0.2
|
||||
|
||||
## 2.0.0-beta.58
|
||||
|
||||
This version once again restores the bundled distribution because the unbundled + CDN approach is currently confusing and [not working properly](https://github.com/shoelace-style/shoelace/issues/559#issuecomment-949662331). Unbundling the few dependencies Shoelace has is still a goal of the project, but [this jsDelivr bug](https://github.com/jsdelivr/jsdelivr/issues/18337) needs to be resolved before we can achieve it.
|
||||
|
||||
I sincerely apologize for the instability of the last few beta releases as a result of this effort.
|
||||
|
||||
- Added experimental `<sl-animated-image>` component
|
||||
- Added `label` attribute to `<sl-progress-bar>` and `<sl-progress-ring>` to improve a11y
|
||||
- Fixed a bug where the tooltip would show briefly when clicking a disabled `<sl-range>`
|
||||
- Fixed a bug that caused a console error when `<sl-range>` was used
|
||||
- Fixed a bug where the `nav` part in `<sl-tab-group>` was on the incorrect element [#563](https://github.com/shoelace-style/shoelace/pull/563)
|
||||
- Fixed a bug where non-integer aspect ratios were calculated incorrectly in `<sl-responsive-media>`
|
||||
- Fixed a bug in `<sl-range>` where setting `value` wouldn't update the active and inactive portion of the track [#572](https://github.com/shoelace-style/shoelace/pull/572)
|
||||
- Reverted to publishing the bundled dist and removed `/+esm` links from the docs
|
||||
- Updated to Bootstrap Icons to 1.6.1
|
||||
|
||||
## 2.0.0-beta.57
|
||||
|
||||
- Fix CodePen links and CDN links
|
||||
|
||||
## 2.0.0-beta.56
|
||||
|
||||
This release is the second attempt at unbundling dependencies. This will be a breaking change only if your configuration _does not_ support bare module specifiers. CDN users and bundler users will be unaffected, but note the URLs for modules on the CDN must have the `/+esm` now.
|
||||
|
||||
- Added the `hoist` attribute to `<sl-tooltip>` [#564](https://github.com/shoelace-style/shoelace/issues/564)
|
||||
- Unbundled dependencies and configured external imports to be packaged with bare module specifiers
|
||||
|
||||
## 2.0.0-beta.55
|
||||
|
||||
- Revert unbundling due to issues with the CDN not handling bare module specifiers as expected
|
||||
|
||||
## 2.0.0-beta.54
|
||||
|
||||
Shoelace doesn't have a lot of dependencies, but this release unbundles most of them so you can potentially save some extra kilobytes. This will be a breaking change only if your configuration _does not_ support bare module specifiers. CDN users and bundler users will be unaffected.
|
||||
|
||||
- 🚨 BREAKING: renamed the `sl-clear` event to `sl-remove`, the `clear-button` part to `remove-button`, and the `clearable` property to `removable` in `<sl-tag>`
|
||||
- Added the `disabled` prop to `<sl-resize-observer>`
|
||||
- Fixed a bug in `<sl-mutation-observer>` where setting `disabled` initially didn't work
|
||||
- Unbundled dependencies and configured external imports to be packaged with bare module specifiers
|
||||
|
||||
## 2.0.0-beta.53
|
||||
|
||||
- 🚨 BREAKING: removed `<sl-menu-divider>` (use `<sl-divider>` instead)
|
||||
- 🚨 BREAKING: removed `percentage` attribute from `<sl-progress-bar>` and `<sl-progress-ring>` (use `value`) instead
|
||||
- 🚨 BREAKING: switched the default `type` of `<sl-tag>` from `primary` to `neutral`
|
||||
- Added the experimental `<sl-mutation-observer>` component
|
||||
- Added the `<sl-divider>` component
|
||||
- Added `--sl-surface-base` and `--sl-surface-base-alt` as early surface tokens to improve the appearance of alert, card, and panels in dark mode
|
||||
- Added the `--sl-panel-border-width` design token
|
||||
- Added missing background color to `<sl-details>`
|
||||
- Added the `--padding` custom property to `<sl-tab-panel>`
|
||||
- Added the `outline` variation to `<sl-button>` [#522](https://github.com/shoelace-style/shoelace/issues/522)
|
||||
- Added the `filled` variation to `<sl-input>`, `<sl-textarea>`, and `<sl-select>` and supporting design tokens
|
||||
- Added the `control` part to `<sl-select>` so you can target the main control with CSS [#538](https://github.com/shoelace-style/shoelace/issues/538)
|
||||
- Added a border to `<sl-badge>` to improve contrast when drawn on various background colors
|
||||
- Added `--track-color-active` and `--track-color-inactive` custom properties to `<sl-range>` [#550](https://github.com/shoelace-style/shoelace/issues/550)
|
||||
- Added the undocumented custom properties `--thumb-size`, `--tooltip-offset`, `--track-height` on `<sl-range>`
|
||||
- Changed the default `distance` in `<sl-dropdown>` from `2` to `0` [#538](https://github.com/shoelace-style/shoelace/issues/538)
|
||||
- Fixed a bug where `<sl-select>` would be larger than the viewport when it had lots of options [#544](https://github.com/shoelace-style/shoelace/issues/544)
|
||||
- Fixed a bug where `<sl-progress-ring>` wouldn't animate in Safari
|
||||
- Updated the default height of `<sl-progress-bar>` from `16px` to `1rem` and added a subtle shadow to indicate depth
|
||||
- Removed the `lit-html` dependency and moved corresponding imports to `lit` [#546](https://github.com/shoelace-style/shoelace/issues/546)
|
||||
|
||||
## 2.0.0-beta.52
|
||||
|
||||
- 🚨 BREAKING: changed the `--stroke-width` custom property of `<sl-spinner>` to `--track-width` for consistency
|
||||
- 🚨 BREAKING: removed the `size` and `stroke-width` attributes from `<sl-progress-ring>` so it's fully customizable with CSS (use the `--size` and `--track-width` custom properties instead)
|
||||
- Added the `--speed` custom property to `<sl-spinner>`
|
||||
- Added the `--size` and `--track-width` custom properties to `<sl-progress-ring>`
|
||||
- Added tests for `<sl-badge>` [#530](https://github.com/shoelace-style/shoelace/pull/530)
|
||||
- Fixed a bug where `<sl-tab>` wasn't using a border radius token [#523](https://github.com/shoelace-style/shoelace/issues/523)
|
||||
- Fixed a bug in the Remix Icons example where some icons would 404 [#528](https://github.com/shoelace-style/shoelace/issues/528)
|
||||
- Updated `<sl-progress-ring>` to use only CSS for styling
|
||||
- Updated `<sl-spinner>` to use an SVG and improved the indicator animation
|
||||
- Updated to Lit 2.0 and lit-html 2.0 🔥
|
||||
|
||||
## 2.0.0-beta.51
|
||||
|
||||
A number of users had trouble counting characters that repeat, so this release improves design token patterns so that "t-shirt sizes" are more accessible. For example, `--sl-font-size-xxx-large` has become `--sl-font-size-3x-large`. This change applies to all design tokens that use this scale.
|
||||
|
||||
- 🚨 BREAKING: all t-shirt size design tokens now use `2x`, `3x`, `4x` instead of `xx`, `xxx`, `xxxx`
|
||||
- Added missing `--sl-focus-ring-*` tokens to dark theme
|
||||
- Added an "Importing" section to all components with copy/paste code to make cherry picking easier
|
||||
- Improved the documentation search with a custom plugin powered by [Lunr](https://lunrjs.com/)
|
||||
- Improved the `--sl-shadow-x-small` elevation
|
||||
- Improved visibility of elevations and overlays in dark theme
|
||||
- Reduced the size of `<sl-color-picker>` slightly to better accommodate mobile devices
|
||||
- Removed `<sl-icon>` dependency from `<sl-color-picker>` and improved the copy animation
|
||||
|
||||
## 2.0.0-beta.50
|
||||
|
||||
- Added `<sl-breadcrumb>` and `<sl-breadcrumb-item>` components
|
||||
- Added `--sl-letter-spacing-denser`, `--sl-letter-spacing-looser`, `--sl-line-height-denser`, and `--sl-line-height-looser` design tokens
|
||||
- Fixed a bug where form controls would error out when the value was set to `undefined` [#513](https://github.com/shoelace-style/shoelace/pull/513)
|
||||
|
||||
## 2.0.0-beta.49
|
||||
|
||||
This release changes the way focus states are applied to elements. In browsers that support [`:focus-visible`](https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible), it will be used. In unsupportive browsers ([currently only Safari](https://caniuse.com/mdn-css_selectors_focus-visible)), `:focus` will be used instead. This means the browser will determine whether a focus ring should be shown based on how the user interacts with the page.
|
||||
|
||||
This release also fixes a critical bug in the color scale where `--sl-color-neutral-0` and `--sl-color-neutral-1000` were reversed.
|
||||
|
||||
- 🚨 BREAKING: fixed a bug where `--sl-color-neutral-0` and `--sl-color-neutral-1000` were inverted (swap them to update)
|
||||
- 🚨 BREAKING: removed the `no-fieldset` property from `<sl-radio-group>` (fieldsets are now hidden by default; use `fieldset` to show them)
|
||||
- 🚨 BREAKING: removed `--focus-ring` custom property from `<sl-input>`, `<sl-select>`, `<sl-tab>` for consistency with other form controls
|
||||
- Added `--swatch-size` custom property to `<sl-color-picker>`
|
||||
- Added `date` to `<sl-input>` as a supported `type`
|
||||
- Added the `--sl-focus-ring` design token for a more convenient way to apply focus ring styles
|
||||
- Adjusted elevation tokens to use neutral in light mode and black in dark mode
|
||||
- Adjusted `--sl-overlay-background-color` in dark theme to be black instead of gray
|
||||
- Fixed a bug in `<sl-color-picker>` where the opacity slider wasn't showing the current color
|
||||
- Fixed a bug where Edge in Windows would show the native password toggle next to the custom password toggle [#508](https://github.com/shoelace-style/shoelace/issues/508)
|
||||
- Fixed a bug where pressing up/down in `<sl-tab-group>` didn't select the next/previous tab in vertical placements
|
||||
- Improved size of `<sl-color-picker>`
|
||||
- Improved icon contrast in `<sl-input>`
|
||||
- Improved contrast of `<sl-switch>`
|
||||
- Improved `:focus-visible` behavior in many components
|
||||
- Removed elevation from `<sl-color-picker>` when rendered inline
|
||||
- Removed custom `:focus-visible` logic in favor of a directive that outputs `:focus-visible` or `:focus` depending on browser support
|
||||
- Updated to Lit 2.0.0-rc.3
|
||||
- Updated to lit-html 2.0.0-rc.4
|
||||
|
||||
## 2.0.0-beta.48
|
||||
|
||||
This release improves theming by offering both light and dark themes that can be used autonomously. It also improves contrast in most components, adds a variety of new color primitives, and changes the way color tokens are consumed.
|
||||
@@ -33,27 +163,27 @@ This change applies to all design tokens that implement a color. Refer to the [c
|
||||
- 🚨 BREAKING: all design tokens that implement colors have been converted to `R G B` and must be used with the `rgb()` function
|
||||
- 🚨 BREAKING: removed `--sl-color-black|white` color tokens (use `--sl-color-neutral-0|1000` instead)
|
||||
- 🚨 BREAKING: removed `--sl-color-primary|success|warning|info|danger-text` design tokens (use theme or primitive colors instead)
|
||||
- 🚨 BREAKING: removed `info` variant from `sl-alert`, `sl-badge`, `sl-button`, and `sl-tag` (use `neutral` instead)
|
||||
- 🚨 BREAKING: removed `info` variant from `<sl-alert>`, `<sl-badge>`, `<sl-button>`, and `<sl-tag>` (use `neutral` instead)
|
||||
- 🚨 BREAKING: removed `--sl-color-info-*` design token (use `--sl-color-neutral-*` instead)
|
||||
- 🚨 BREAKING: renamed `dist/themes/base.css` to `dist/themes/light.css`
|
||||
- 🚨 BREAKING: removed `--sl-focus-ring-color-primary` tokens (use color tokens and `--sl-focus-ring-width|alpha` instead)
|
||||
- 🚨 BREAKING: removed `--tabs-border-color` from `sl-tab-group` (use `--track-color` instead)
|
||||
- 🚨 BREAKING: changed the default value for `effect` to `none` (use `sheen` to restore the original behavior)
|
||||
- 🚨 BREAKING: removed `--tabs-border-color` from `<sl-tab-group>` (use `--track-color` instead)
|
||||
- 🚨 BREAKING: changed the default value for `effect` to `none` in `<sl-skeleton>` (use `sheen` to restore the original behavior)
|
||||
- Added new color primitives to the base set of design tokens
|
||||
- Added `--sl-color-*-950` swatches to all color palettes
|
||||
- Added a console error that appears when menu items have duplicate values in `sl-select`
|
||||
- Added a console error that appears when menu items have duplicate values in `<sl-select>`
|
||||
- Added CodePen link to code examples
|
||||
- Added `prefix` and `suffix` slots to `sl-select` [#501](https://github.com/shoelace-style/shoelace/pull/501)
|
||||
- Added `--indicator-color` custom property to `sl-tab-group`
|
||||
- Added `prefix` and `suffix` slots to `<sl-select>` [#501](https://github.com/shoelace-style/shoelace/pull/501)
|
||||
- Added `--indicator-color` custom property to `<sl-tab-group>`
|
||||
- Exposed base and dark stylesheets so they can be imported via JavaScript [#438](https://github.com/shoelace-style/shoelace/issues/438)
|
||||
- Fixed a bug in `sl-menu` where pressing <kbd>Enter</kbd> after using type to select would result in the wrong value
|
||||
- Fixed a bug in `sl-radio-group` where clicking a radio button would cause the wrong control to be focused
|
||||
- Fixed a bug in `sl-button` and `sl-icon-button` where an unintended `ref` attribute was present
|
||||
- Fixed a bug in `<sl-menu>` where pressing <kbd>Enter</kbd> after using type to select would result in the wrong value
|
||||
- Fixed a bug in `<sl-radio-group>` where clicking a radio button would cause the wrong control to be focused
|
||||
- Fixed a bug in `<sl-button>` and `<sl-icon-button>` where an unintended `ref` attribute was present
|
||||
- Fixed a bug in the focus-visible utility that failed to respond to mouseup events
|
||||
- Fixed a bug where clicking on a menu item would persist its hover/focus state
|
||||
- Fixed a bug in `sl-select` where it would erroneously intercept important keyboard shortcuts [#504](https://github.com/shoelace-style/shoelace/issues/504)
|
||||
- Fixed a bug in `<sl-select>` where it would erroneously intercept important keyboard shortcuts [#504](https://github.com/shoelace-style/shoelace/issues/504)
|
||||
- Improved contrast throughout all components [#128](https://github.com/shoelace-style/shoelace/issues/128)
|
||||
- Refactored thumb position logic in `sl-switch` [#490](https://github.com/shoelace-style/shoelace/pull/490)
|
||||
- Refactored thumb position logic in `<sl-switch>` [#490](https://github.com/shoelace-style/shoelace/pull/490)
|
||||
- Reworked the dark theme to use an inverted + shifted design token approach instead of component-specific selectors
|
||||
|
||||
## 2.0.0-beta.47
|
||||
@@ -62,11 +192,11 @@ This release improves how component dependencies are imported. If you've been ch
|
||||
|
||||
- Added "Reflects" column to the properties table
|
||||
- Dependencies are now automatically imported for all components
|
||||
- Fixed a bug where tabbing into `sl-radio-group` would not always focus the checked radio
|
||||
- Fixed a bug where tabbing into `<sl-radio-group>` would not always focus the checked radio
|
||||
- Fixed a bug in component styles that prevented the box sizing reset from being applied
|
||||
- Fixed a regression in `sl-color-picker` where dragging the grid handle wasn't smooth
|
||||
- Fixed a regression in `<sl-color-picker>` where dragging the grid handle wasn't smooth
|
||||
- Fixed a bug where slot detection could incorrecly match against slots of child elements [#481](https://github.com/shoelace-style/shoelace/pull/481)
|
||||
- Fixed a bug in `sl-input` where focus would move to the end of the input when typing in Safari [#480](https://github.com/shoelace-style/shoelace/issues/480)
|
||||
- Fixed a bug in `<sl-input>` where focus would move to the end of the input when typing in Safari [#480](https://github.com/shoelace-style/shoelace/issues/480)
|
||||
- Improved base path utility logic
|
||||
|
||||
## 2.0.0-beta.46
|
||||
@@ -77,13 +207,13 @@ This is a lot more intuitive and makes it easier to activate animations imperati
|
||||
|
||||
In addition, Shoelace no longer uses Sass. Component styles now use Lit's template literal styles and theme files use pure CSS.
|
||||
|
||||
- 🚨 BREAKING: removed the `pause` attribute from `sl-animation` (use `play` to start and stop the animation instead)
|
||||
- 🚨 BREAKING: removed `getCurrentTime()` and `setCurrentTime()` from `sl-animation` (use the `currentTime` property instead)
|
||||
- 🚨 BREAKING: removed the `close-on-select` attribute from `sl-dropdown` (use `stay-open-on-select` instead)
|
||||
- Added the `currentTime` property to `sl-animation` to control the current time without methods
|
||||
- Fixed a bug in `sl-range` where the tooltip wasn't showing in Safari [#477](https://github.com/shoelace-style/shoelace/issues/477)
|
||||
- Fixed a bug in `sl-menu` where pressing <kbd>Enter</kbd> in a menu didn't work with click handlers
|
||||
- Reworked `sl-menu` and `sl-menu-item` to use a roving tab index and improve keyboard accessibility
|
||||
- 🚨 BREAKING: removed the `pause` attribute from `<sl-animation>` (use `play` to start and stop the animation instead)
|
||||
- 🚨 BREAKING: removed `getCurrentTime()` and `setCurrentTime()` from `<sl-animation>` (use the `currentTime` property instead)
|
||||
- 🚨 BREAKING: removed the `close-on-select` attribute from `<sl-dropdown>` (use `stay-open-on-select` instead)
|
||||
- Added the `currentTime` property to `<sl-animation>` to control the current time without methods
|
||||
- Fixed a bug in `<sl-range>` where the tooltip wasn't showing in Safari [#477](https://github.com/shoelace-style/shoelace/issues/477)
|
||||
- Fixed a bug in `<sl-menu>` where pressing <kbd>Enter</kbd> in a menu didn't work with click handlers
|
||||
- Reworked `<sl-menu>` and `<sl-menu-item>` to use a roving tab index and improve keyboard accessibility
|
||||
- Reworked tabbable logic to be more performant [#466](https://github.com/shoelace-style/shoelace/issues/466)
|
||||
- Switched component stylesheets from Sass to Lit's template literal styles
|
||||
- Switched theme stylesheets from Sass to CSS
|
||||
@@ -96,13 +226,13 @@ Thanks to an amazing effort by [Pascal Schilp](https://twitter.com/passle_), the
|
||||
|
||||
The docs have been updated to use the new `custom-elements.json` file. If you're relying on the old `metadata.json` file for any purpose, this will be a breaking change for you.
|
||||
|
||||
- 🚨 BREAKING: removed the `sl-overlay-click` event from `sl-dialog` and `sl-drawer` (use `sl-request-close` instead) [#471](https://github.com/shoelace-style/shoelace/discussions/471)
|
||||
- 🚨 BREAKING: removed the `sl-overlay-click` event from `<sl-dialog>` and `<sl-drawer>` (use `sl-request-close` instead) [#471](https://github.com/shoelace-style/shoelace/discussions/471)
|
||||
- 🚨 BREAKING: removed `metadata.json` (use `custom-elements.json` instead)
|
||||
- Added `custom-elements.json` for component metadata
|
||||
- Added `sl-request-close` event to `sl-dialog` and `sl-drawer`
|
||||
- Added `sl-request-close` event to `<sl-dialog>` and `<sl-drawer>`
|
||||
- Added `dialog.denyClose` and `drawer.denyClose` animations
|
||||
- Fixed a bug in `sl-color-picker` where setting `value` immediately wouldn't trigger an update
|
||||
- Fixed a bug in `sl-dialog` and `sl-drawer` where setting `open` intially didn't set a focus trap
|
||||
- Fixed a bug in `<sl-color-picker>` where setting `value` immediately wouldn't trigger an update
|
||||
- Fixed a bug in `<sl-dialog>` and `<sl-drawer>` where setting `open` intially didn't set a focus trap
|
||||
- Fixed a bug that resulted in form controls having incorrect validity when `disabled` was initially set [#473](https://github.com/shoelace-style/shoelace/issues/473)
|
||||
- Fixed a bug in the docs that caused the metadata file to be requested twice
|
||||
- Fixed a bug where tabbing out of a modal would cause the browser to lag [#466](https://github.com/shoelace-style/shoelace/issues/466)
|
||||
@@ -113,24 +243,24 @@ The docs have been updated to use the new `custom-elements.json` file. If you're
|
||||
- 🚨 BREAKING: all `invalid` props on form controls now reflect validity before interaction [#455](https://github.com/shoelace-style/shoelace/issues/455)
|
||||
- Allow `null` to be passed to disable animations in `setDefaultAnimation()` and `setAnimation()`
|
||||
- Converted build scripts to ESM
|
||||
- Fixed a bug in `sl-checkbox` where `invalid` did not update properly
|
||||
- Fixed a bug in `sl-dropdown` where a `keydown` listener wasn't cleaned up properly
|
||||
- Fixed a bug in `sl-select` where `sl-blur` was emitted prematurely [#456](https://github.com/shoelace-style/shoelace/issues/456)
|
||||
- Fixed a bug in `sl-select` where no selection with `multiple` resulted in an incorrect value [#457](https://github.com/shoelace-style/shoelace/issues/457)
|
||||
- Fixed a bug in `sl-select` where `sl-change` was emitted immediately after connecting to the DOM [#458](https://github.com/shoelace-style/shoelace/issues/458)
|
||||
- Fixed a bug in `sl-select` where non-printable keys would cause the menu to open
|
||||
- Fixed a bug in `sl-select` where `invalid` was not always updated properly
|
||||
- Fixed a bug in `<sl-checkbox>` where `invalid` did not update properly
|
||||
- Fixed a bug in `<sl-dropdown>` where a `keydown` listener wasn't cleaned up properly
|
||||
- Fixed a bug in `<sl-select>` where `sl-blur` was emitted prematurely [#456](https://github.com/shoelace-style/shoelace/issues/456)
|
||||
- Fixed a bug in `<sl-select>` where no selection with `multiple` resulted in an incorrect value [#457](https://github.com/shoelace-style/shoelace/issues/457)
|
||||
- Fixed a bug in `<sl-select>` where `sl-change` was emitted immediately after connecting to the DOM [#458](https://github.com/shoelace-style/shoelace/issues/458)
|
||||
- Fixed a bug in `<sl-select>` where non-printable keys would cause the menu to open
|
||||
- Fixed a bug in `<sl-select>` where `invalid` was not always updated properly
|
||||
- Reworked the `@watch` decorator to use `update` instead of `updated` resulting in better performance and flexibility
|
||||
|
||||
## 2.0.0-beta.43
|
||||
|
||||
- Added `?` to optional arguments in methods tables in the docs
|
||||
- Added the `scrollPosition()` method to `sl-textarea` to get/set scroll position
|
||||
- Added intial tests for `sl-dialog`, `sl-drawer`, `sl-dropdown`, and `sl-tooltip`
|
||||
- Fixed a bug in `sl-tab-group` where scrollable tab icons were not displaying correctly
|
||||
- Fixed a bug in `sl-dialog` and `sl-drawer` where preventing clicks on the overlay no longer worked as described [#452](https://github.com/shoelace-style/shoelace/issues/452)
|
||||
- Fixed a bug in `sl-dialog` and `sl-drawer` where setting initial focus no longer worked as described [#453](https://github.com/shoelace-style/shoelace/issues/453)
|
||||
- Fixed a bug in `sl-card` where the `slotchange` listener wasn't attached correctly [#454](https://github.com/shoelace-style/shoelace/issues/454)
|
||||
- Added the `scrollPosition()` method to `<sl-textarea>` to get/set scroll position
|
||||
- Added intial tests for `<sl-dialog>`, `<sl-drawer>`, `<sl-dropdown>`, and `<sl-tooltip>`
|
||||
- Fixed a bug in `<sl-tab-group>` where scrollable tab icons were not displaying correctly
|
||||
- Fixed a bug in `<sl-dialog>` and `<sl-drawer>` where preventing clicks on the overlay no longer worked as described [#452](https://github.com/shoelace-style/shoelace/issues/452)
|
||||
- Fixed a bug in `<sl-dialog>` and `<sl-drawer>` where setting initial focus no longer worked as described [#453](https://github.com/shoelace-style/shoelace/issues/453)
|
||||
- Fixed a bug in `<sl-card>` where the `slotchange` listener wasn't attached correctly [#454](https://github.com/shoelace-style/shoelace/issues/454)
|
||||
- Fixed lifecycle bugs in a number of components [#451](https://github.com/shoelace-style/shoelace/issues/451)
|
||||
- Removed `fill: both` from internal animate utility so styles won't "stick" by default [#450](https://github.com/shoelace-style/shoelace/issues/450)
|
||||
|
||||
@@ -145,12 +275,12 @@ Technical reasons aside, canceling these events seldom led to a good user experi
|
||||
- 🚨 BREAKING: `sl-show` and `sl-hide` events are no longer cancelable
|
||||
- Added Iconoir example to the icon docs
|
||||
- Added Web Test Runner
|
||||
- Added intial tests for `sl-alert` and `sl-details`
|
||||
- Added intial tests for `<sl-alert>` and `<sl-details>`
|
||||
- Changed the `cancelable` default to `false` for the internal `@event` decorator
|
||||
- Fixed a bug where toggling `open` stopped working in `sl-alert`, `sl-dialog`, `sl-drawer`, `sl-dropdown`, and `sl-tooltip`
|
||||
- Fixed a bug in `sl-range` where setting a value outside the default `min` or `max` would clamp the value [#448](https://github.com/shoelace-style/shoelace/issues/448)
|
||||
- Fixed a bug in `sl-dropdown` where placement wouldn't adjust properly when shown [#447](https://github.com/shoelace-style/shoelace/issues/447)
|
||||
- Fixed a bug in the internal `shimKeyframesHeightAuto` utility that caused `sl-details` to measure heights incorrectly [#445](https://github.com/shoelace-style/shoelace/issues/445)
|
||||
- Fixed a bug where toggling `open` stopped working in `<sl-alert>`, `<sl-dialog>`, `<sl-drawer>`, `<sl-dropdown>`, and `<sl-tooltip>`
|
||||
- Fixed a bug in `<sl-range>` where setting a value outside the default `min` or `max` would clamp the value [#448](https://github.com/shoelace-style/shoelace/issues/448)
|
||||
- Fixed a bug in `<sl-dropdown>` where placement wouldn't adjust properly when shown [#447](https://github.com/shoelace-style/shoelace/issues/447)
|
||||
- Fixed a bug in the internal `shimKeyframesHeightAuto` utility that caused `<sl-details>` to measure heights incorrectly [#445](https://github.com/shoelace-style/shoelace/issues/445)
|
||||
- Fixed a number of imports that should have been type imports
|
||||
- Updated Lit to 2.0.0-rc.2
|
||||
- Updated esbuild to 0.12.4
|
||||
@@ -163,24 +293,24 @@ CSS animations, on the other hand, have a more reliable `animationend` event. Al
|
||||
|
||||
The most elegant solution I found was to use the [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API), which offers more control over animations at the expense of customizations being done in JavaScript. Fortunately, through the [Animation Registry](/getting-started/customizing#animations), you can customize animations globally and/or per component with a minimal amount of code.
|
||||
|
||||
- 🚨 BREAKING: changed `left` and `right` placements to `start` and `end` in `sl-drawer`
|
||||
- 🚨 BREAKING: changed `left` and `right` placements to `start` and `end` in `sl-tab-group`
|
||||
- 🚨 BREAKING: removed `--hide-duration`, `--hide-timing-function`, `--show-duration`, and `--show-timing-function` custom properties from `sl-tooltip` (use the Animation Registry instead)
|
||||
- 🚨 BREAKING: changed `left` and `right` placements to `start` and `end` in `<sl-drawer>`
|
||||
- 🚨 BREAKING: changed `left` and `right` placements to `start` and `end` in `<sl-tab-group>`
|
||||
- 🚨 BREAKING: removed `--hide-duration`, `--hide-timing-function`, `--show-duration`, and `--show-timing-function` custom properties from `<sl-tooltip>` (use the Animation Registry instead)
|
||||
- Added the Animation Registry
|
||||
- Fixed a bug where removing `sl-dropdown` from the DOM and adding it back destroyed the popover reference [#443](https://github.com/shoelace-style/shoelace/issues/443)
|
||||
- Updated animations for `sl-alert`, `sl-dialog`, `sl-drawer`, `sl-dropdown`, and `sl-tooltip` to use the Animation Registry instead of CSS transitions
|
||||
- Fixed a bug where removing `<sl-dropdown>` from the DOM and adding it back destroyed the popover reference [#443](https://github.com/shoelace-style/shoelace/issues/443)
|
||||
- Updated animations for `<sl-alert>`, `<sl-dialog>`, `<sl-drawer>`, `<sl-dropdown>`, and `<sl-tooltip>` to use the Animation Registry instead of CSS transitions
|
||||
- Improved a11y by respecting `prefers-reduced-motion` for all show/hide animations
|
||||
- Improved `--show-delay` and `--hide-delay` behavior in `sl-tooltip` so they only apply on hover
|
||||
- Improved `--show-delay` and `--hide-delay` behavior in `<sl-tooltip>` so they only apply on hover
|
||||
- Removed the internal popover utility
|
||||
|
||||
## 2.0.0-beta.40
|
||||
|
||||
- 🚨 BREAKING: renamed `sl-responsive-embed` to `sl-responsive-media` and added support for images and videos [#436](https://github.com/shoelace-style/shoelace/issues/436)
|
||||
- 🚨 BREAKING: renamed `<sl-responsive-embed>` to `<sl-responsive-media>` and added support for images and videos [#436](https://github.com/shoelace-style/shoelace/issues/436)
|
||||
- Fixed a bug where setting properties before an element was defined would render incorrectly [#425](https://github.com/shoelace-style/shoelace/issues/425)
|
||||
- Fixed a bug that caused all modules to be imported when cherry picking certain components [#439](https://github.com/shoelace-style/shoelace/issues/439)
|
||||
- Fixed a bug where the scrollbar would reposition `sl-dialog` on hide causing it to jump [#424](https://github.com/shoelace-style/shoelace/issues/424)
|
||||
- Fixed a bug where the scrollbar would reposition `<sl-dialog>` on hide causing it to jump [#424](https://github.com/shoelace-style/shoelace/issues/424)
|
||||
- Fixed a bug that prevented the project from being built in a Windows environment
|
||||
- Improved a11y in `sl-progress-ring`
|
||||
- Improved a11y in `<sl-progress-ring>`
|
||||
- Removed `src/utilities/index.ts` to prevent tree-shaking confusion (please import utilities directly from their respective modules)
|
||||
- Removed global `[hidden]` styles so they don't affect anything outside of components
|
||||
- Updated to Bootstrap Icons 1.5.0
|
||||
@@ -190,67 +320,67 @@ The most elegant solution I found was to use the [Web Animations API](https://de
|
||||
|
||||
## 2.0.0-beta.39
|
||||
|
||||
- Added experimental `sl-qr-code` component
|
||||
- Added experimental `<sl-qr-code>` component
|
||||
- Added `system` icon library and updated all components to use this instead of the default icon library [#420](https://github.com/shoelace-style/shoelace/issues/420)
|
||||
- Updated to esbuild 0.8.57
|
||||
- Updated to Lit 2.0.0-rc.1 and lit-html 2.0.0-rc.2
|
||||
|
||||
## 2.0.0-beta.38
|
||||
|
||||
- 🚨 BREAKING: `sl-radio` components must be located inside an `sl-radio-group` for proper accessibility [#218](https://github.com/shoelace-style/shoelace/issues/218)
|
||||
- Added `sl-radio-group` component [#218](https://github.com/shoelace-style/shoelace/issues/218)
|
||||
- Added `--header-spacing`, `--body-spacing`, and `--footer-spacing` custom properties to `sl-drawer` and `sl-dialog` [#409](https://github.com/shoelace-style/shoelace/issues/409)
|
||||
- Fixed a bug where `sl-menu-item` prefix and suffix slots wouldn't always receive the correct spacing
|
||||
- Fixed a bug where `sl-badge` used `--sl-color-white` instead of the correct design tokens [#407](https://github.com/shoelace-style/shoelace/issues/407)
|
||||
- Fixed a bug in `sl-dialog` and `sl-drawer` where the escape key would cause parent components to close
|
||||
- Fixed a race condition bug in `sl-icon` [#410](https://github.com/shoelace-style/shoelace/issues/410)
|
||||
- Improved focus trap behavior in `sl-dialog` and `sl-drawer`
|
||||
- Improved a11y in `sl-dialog` and `sl-drawer` by restoring focus to trigger on close
|
||||
- Improved a11y in `sl-radio` with Windows high contrast mode [#215](https://github.com/shoelace-style/shoelace/issues/215)
|
||||
- Improved a11y in `sl-select` by preventing the chevron icon from being announced
|
||||
- 🚨 BREAKING: `<sl-radio>` components must be located inside an `<sl-radio-group>` for proper accessibility [#218](https://github.com/shoelace-style/shoelace/issues/218)
|
||||
- Added `<sl-radio-group>` component [#218](https://github.com/shoelace-style/shoelace/issues/218)
|
||||
- Added `--header-spacing`, `--body-spacing`, and `--footer-spacing` custom properties to `<sl-drawer>` and `<sl-dialog>` [#409](https://github.com/shoelace-style/shoelace/issues/409)
|
||||
- Fixed a bug where `<sl-menu-item>` prefix and suffix slots wouldn't always receive the correct spacing
|
||||
- Fixed a bug where `<sl-badge>` used `--sl-color-white` instead of the correct design tokens [#407](https://github.com/shoelace-style/shoelace/issues/407)
|
||||
- Fixed a bug in `<sl-dialog>` and `<sl-drawer>` where the escape key would cause parent components to close
|
||||
- Fixed a race condition bug in `<sl-icon>` [#410](https://github.com/shoelace-style/shoelace/issues/410)
|
||||
- Improved focus trap behavior in `<sl-dialog>` and `<sl-drawer>`
|
||||
- Improved a11y in `<sl-dialog>` and `<sl-drawer>` by restoring focus to trigger on close
|
||||
- Improved a11y in `<sl-radio>` with Windows high contrast mode [#215](https://github.com/shoelace-style/shoelace/issues/215)
|
||||
- Improved a11y in `<sl-select>` by preventing the chevron icon from being announced
|
||||
- Internal: removed the `options` argument from the modal utility as focus trapping is now handled internally
|
||||
|
||||
## 2.0.0-beta.37
|
||||
|
||||
- Added `click()` method to `sl-checkbox`, `sl-radio`, and `sl-switch`
|
||||
- Added the `activation` attribute to `sl-tab-group` to allow for automatic and manual tab activation
|
||||
- Added `click()` method to `<sl-checkbox>`, `<sl-radio>`, and `<sl-switch>`
|
||||
- Added the `activation` attribute to `<sl-tab-group>` to allow for automatic and manual tab activation
|
||||
- Added `npm run create <tag>` script to scaffold new components faster
|
||||
- Fixed a bug in `sl-tooltip` where events weren't properly cleaned up on disconnect
|
||||
- Fixed a bug in `sl-tooltip` where they wouldn't display after toggling `disabled` off and on again [#391](https://github.com/shoelace-style/shoelace/issues/391)
|
||||
- Fixed a bug in `sl-details` where `show()` and `hide()` would toggle the control when disabled
|
||||
- Fixed a bug in `sl-color-picker` where setting `value` wouldn't update the control
|
||||
- Fixed a bug in `sl-tab-group` where tabs that are initially disabled wouldn't receive the indicator on activation [#403](https://github.com/shoelace-style/shoelace/issues/403)
|
||||
- Fixed incorrect event names for `sl-after-show` and `sl-after-hide` in `sl-details`
|
||||
- Fixed a bug in `<sl-tooltip>` where events weren't properly cleaned up on disconnect
|
||||
- Fixed a bug in `<sl-tooltip>` where they wouldn't display after toggling `disabled` off and on again [#391](https://github.com/shoelace-style/shoelace/issues/391)
|
||||
- Fixed a bug in `<sl-details>` where `show()` and `hide()` would toggle the control when disabled
|
||||
- Fixed a bug in `<sl-color-picker>` where setting `value` wouldn't update the control
|
||||
- Fixed a bug in `<sl-tab-group>` where tabs that are initially disabled wouldn't receive the indicator on activation [#403](https://github.com/shoelace-style/shoelace/issues/403)
|
||||
- Fixed incorrect event names for `sl-after-show` and `sl-after-hide` in `<sl-details>`
|
||||
- Improved a11y for disabled buttons that are rendered as links
|
||||
- Improved a11y for `sl-button-group` by adding the correct `role` attribute
|
||||
- Improved a11y for `sl-input`, `sl-range`, `sl-select`, and `sl-textarea` so labels and helper text are read properly by screen readers
|
||||
- Removed `sl-show`, `sl-hide`, `sl-after-show`, `sl-after-hide` events from `sl-color-picker` (the color picker's visibility cannot be controlled programmatically so these shouldn't have been exposed; the dropdown events now bubble up so you can listen for those instead)
|
||||
- Reworked `sl-button-group` so it doesn't require light DOM styles
|
||||
- Improved a11y for `<sl-button-group>` by adding the correct `role` attribute
|
||||
- Improved a11y for `<sl-input>`, `<sl-range>`, `<sl-select>`, and `<sl-textarea>` so labels and helper text are read properly by screen readers
|
||||
- Removed `sl-show`, `sl-hide`, `sl-after-show`, `sl-after-hide` events from `<sl-color-picker>` (the color picker's visibility cannot be controlled programmatically so these shouldn't have been exposed; the dropdown events now bubble up so you can listen for those instead)
|
||||
- Reworked `<sl-button-group>` so it doesn't require light DOM styles
|
||||
|
||||
## 2.0.0-beta.36
|
||||
|
||||
- 🚨 BREAKING: renamed `setFocus()` to `focus()` in button, checkbox, input, menu item, radio, range, rating, select, switch, and tab
|
||||
- 🚨 BREAKING: renamed `removeFocus()` to `blur()` in button, checkbox, input, menu item, radio, range, rating, select, switch, and tab
|
||||
- Added `click()` method to `sl-button`
|
||||
- Fixed a bug where toggling `open` on `sl-drawer` would skip the transition
|
||||
- Fixed a bug where `sl-color-picker` could be opened when disabled
|
||||
- Fixed a bug in `sl-color-picker` that caused erratic slider behaviors [#388](https://github.com/shoelace-style/shoelace/issues/388) [#389](https://github.com/shoelace-style/shoelace/issues/389)
|
||||
- Fixed a bug where `sl-details` wouldn't always render the correct height when open initially [#357](https://github.com/shoelace-style/shoelace/issues/357)
|
||||
- Added `click()` method to `<sl-button>`
|
||||
- Fixed a bug where toggling `open` on `<sl-drawer>` would skip the transition
|
||||
- Fixed a bug where `<sl-color-picker>` could be opened when disabled
|
||||
- Fixed a bug in `<sl-color-picker>` that caused erratic slider behaviors [#388](https://github.com/shoelace-style/shoelace/issues/388) [#389](https://github.com/shoelace-style/shoelace/issues/389)
|
||||
- Fixed a bug where `<sl-details>` wouldn't always render the correct height when open initially [#357](https://github.com/shoelace-style/shoelace/issues/357)
|
||||
- Renamed `components.json` to `metadata.json`
|
||||
- Updated to the prerelease versions of LitElement and lit-html
|
||||
- Updated to Bootstrap Icons 1.4.1
|
||||
|
||||
## 2.0.0-beta.35
|
||||
|
||||
- Fixed a bug in `sl-animation` where `sl-cancel` and `sl-finish` events would never fire
|
||||
- Fixed a bug where `sl-alert` wouldn't always transition properly
|
||||
- Fixed a bug where using `sl-menu` inside a shadow root would break keyboard selections [#382](https://github.com/shoelace-style/shoelace/issues/382)
|
||||
- Fixed a bug where toggling `multiple` in `sl-select` would lead to a stale display label
|
||||
- Fixed a bug in `sl-tab-group` where changing `placement` could result in the active tab indicator being drawn a few pixels off
|
||||
- Fixed a bug in `sl-button` where link buttons threw an error on focus, blur, and click
|
||||
- Fixed a bug in `<sl-animation>` where `sl-cancel` and `sl-finish` events would never fire
|
||||
- Fixed a bug where `<sl-alert>` wouldn't always transition properly
|
||||
- Fixed a bug where using `<sl-menu>` inside a shadow root would break keyboard selections [#382](https://github.com/shoelace-style/shoelace/issues/382)
|
||||
- Fixed a bug where toggling `multiple` in `<sl-select>` would lead to a stale display label
|
||||
- Fixed a bug in `<sl-tab-group>` where changing `placement` could result in the active tab indicator being drawn a few pixels off
|
||||
- Fixed a bug in `<sl-button>` where link buttons threw an error on focus, blur, and click
|
||||
- Improved `@watch` decorator to run after update instead of during
|
||||
- Updated `sl-menu-item` checked icon to `check` instead of `check2`
|
||||
- Upgraded the status of `sl-resize-observer` from experimental to stable
|
||||
- Updated `<sl-menu-item>` checked icon to `check` instead of `check2`
|
||||
- Upgraded the status of `<sl-resize-observer>` from experimental to stable
|
||||
|
||||
## 2.0.0-beta.34
|
||||
|
||||
@@ -260,35 +390,35 @@ From now on, importing a component will register it automatically. The caveat is
|
||||
|
||||
- 🚨 BREAKING: removed `all.shoelace.js` (use `shoelace.js` instead)
|
||||
- 🚨 BREAKING: component modules now have a side effect, so bundlers may not tree shake properly when importing from `@shoelace-style/shoelace` (see the [installation page](/getting-started/installation?id=bundling) for more details and how to update)
|
||||
- Added `sl-clear` event to `sl-select`
|
||||
- Fixed a bug where dynamically changing menu items in `sl-select` would cause the display label to be blank [#374](https://github.com/shoelace-style/shoelace/discussions/374)
|
||||
- Fixed a bug where setting the `value` attribute or property on `sl-input` and `sl-textarea` would trigger validation too soon
|
||||
- Fixed the margin in `sl-menu-label` to align with menu items
|
||||
- Fixed `autofocus` attributes in `sl-input` and `sl-textarea`
|
||||
- Improved types for `autocapitalize` in `sl-input` and `sl-textarea`
|
||||
- Added `sl-clear` event to `<sl-select>`
|
||||
- Fixed a bug where dynamically changing menu items in `<sl-select>` would cause the display label to be blank [#374](https://github.com/shoelace-style/shoelace/discussions/374)
|
||||
- Fixed a bug where setting the `value` attribute or property on `<sl-input>` and `<sl-textarea>` would trigger validation too soon
|
||||
- Fixed the margin in `<sl-menu-label>` to align with menu items
|
||||
- Fixed `autofocus` attributes in `<sl-input>` and `<sl-textarea>`
|
||||
- Improved types for `autocapitalize` in `<sl-input>` and `<sl-textarea>`
|
||||
- Reverted the custom `@tag` decorator in favor of `@customElement` to enable auto-registration
|
||||
|
||||
## 2.0.0-beta.33
|
||||
|
||||
- Fixed a bug where link buttons could have incorrect `target`, `download`, and `rel` props
|
||||
- Fixed `aria-label` and `aria-labelledby` props in `sl-dialog` and `sl-drawer`
|
||||
- Fixed `tabindex` attribute in `sl-menu`
|
||||
- Fixed a bug in `sl-select` where tags would always render as pills
|
||||
- Fixed a bug in `sl-button` where calling `setFocus()` would throw an error
|
||||
- Fixed `aria-label` and `aria-labelledby` props in `<sl-dialog>` and `<sl-drawer>`
|
||||
- Fixed `tabindex` attribute in `<sl-menu>`
|
||||
- Fixed a bug in `<sl-select>` where tags would always render as pills
|
||||
- Fixed a bug in `<sl-button>` where calling `setFocus()` would throw an error
|
||||
|
||||
## 2.0.0-beta.32
|
||||
|
||||
- Added tag name maps so TypeScript can identify Shoelace elements [#371](https://github.com/shoelace-style/shoelace/pull/371)
|
||||
- Fixed a bug where the active tab indicator wouldn't render properly on tabs styled with `flex-end` [#355](https://github.com/shoelace-style/shoelace/issues/355)
|
||||
- Fixed a bug where `sl-change` wasn't emitted by `sl-checkbox` or `sl-switch` [#370](https://github.com/shoelace-style/shoelace/issues/370)
|
||||
- Fixed a bug where some props weren't being watched correctly in `sl-alert` and `sl-color-picker`
|
||||
- Fixed a bug where `sl-change` wasn't emitted by `<sl-checkbox>` or `<sl-switch>` [#370](https://github.com/shoelace-style/shoelace/issues/370)
|
||||
- Fixed a bug where some props weren't being watched correctly in `<sl-alert>` and `<sl-color-picker>`
|
||||
- Improved `@watch` decorator so watch handlers don't run before the first render
|
||||
- Removed guards that were added due to previous watch handler behavior
|
||||
|
||||
## 2.0.0-beta.31
|
||||
|
||||
- Add touch support to `sl-rating` [#362](https://github.com/shoelace-style/shoelace/pull/362)
|
||||
- Fixed a bug where the `open` attribute on `sl-details` would prevent it from opening [#357](https://github.com/shoelace-style/shoelace/issues/357)
|
||||
- Add touch support to `<sl-rating>` [#362](https://github.com/shoelace-style/shoelace/pull/362)
|
||||
- Fixed a bug where the `open` attribute on `<sl-details>` would prevent it from opening [#357](https://github.com/shoelace-style/shoelace/issues/357)
|
||||
- Fixed event detail type parsing so component class names are shown instead of `default`
|
||||
|
||||
## 2.0.0-beta.30
|
||||
@@ -300,11 +430,11 @@ From now on, importing a component will register it automatically. The caveat is
|
||||
|
||||
**This release migrates component implementations from Shoemaker to LitElement.** Due to feedback from the community, Shoelace will rely on a more heavily tested library for component implementations. This gives you a more solid foundation and reduces my maintenance burden. Thank you for all your comments, concerns, and encouragement! Aside from that, everything else from beta.28 still applies plus the following.
|
||||
|
||||
- 🚨 BREAKING: removed the `symbol` property from `sl-rating` and reverted to `getSymbol` for optimal flexibility
|
||||
- 🚨 BREAKING: removed the `symbol` property from `<sl-rating>` and reverted to `getSymbol` for optimal flexibility
|
||||
- Added `vscode.html-custom-data.json` to the build to support IntelliSense (see [the usage section](/getting-started/usage#code-completion) for details)
|
||||
- Added a base style to prevent FOUC before components are defined
|
||||
- Fixed bug where TypeScript types weren't being generated [#364](https://github.com/shoelace-style/shoelace/pull/364)
|
||||
- Improved vertical padding in `sl-tooltip`
|
||||
- Improved vertical padding in `<sl-tooltip>`
|
||||
- Moved chunk files into a separate folder
|
||||
- Reverted menu item active styles
|
||||
- Updated esbuild to 0.8.54
|
||||
@@ -320,16 +450,16 @@ This change in tooling addresses a number of longstanding bugs and limitations.
|
||||
The component API remains the same except for the changes noted below. Thanks for your patience as I work diligently to make Shoelace more stable and future-proof. 🙌
|
||||
|
||||
- 🚨 BREAKING: removed the custom elements bundle (you can import ES modules directly)
|
||||
- 🚨 BREAKING: removed `getAnimationNames()` and `getEasingNames()` methods from `sl-animation` (you can import them from `utilities/animation.js` instead)
|
||||
- 🚨 BREAKING: removed the `sl-icon-library` component since it required imperative initialization (you can import the `registerIconLibrary()` function from `utilities/icon-library.js` instead)
|
||||
- 🚨 BREAKING: removed the experimental `sl-theme` component due to limitations (you should set the `sl-theme-{name}` class on the `<body>` instead)
|
||||
- 🚨 BREAKING: removed `getAnimationNames()` and `getEasingNames()` methods from `<sl-animation>` (you can import them from `utilities/animation.js` instead)
|
||||
- 🚨 BREAKING: removed the `<sl-icon-library>` component since it required imperative initialization (you can import the `registerIconLibrary()` function from `utilities/icon-library.js` instead)
|
||||
- 🚨 BREAKING: removed the experimental `<sl-theme>` component due to technical limitations (you should set the `sl-theme-{name}` class on the `<body>` instead)
|
||||
- 🚨 BREAKING: moved the base stylesheet from `dist/shoelace.css` to `dist/themes/base.css`
|
||||
- 🚨 BREAKING: moved `icons` into `assets/icons` to make future assets easier to colocate
|
||||
- 🚨 BREAKING: changed `getSymbol` property in `sl-rating` to `symbol` (it now accepts a string or a function that returns an icon name)
|
||||
- 🚨 BREAKING: changed `getSymbol` property in `<sl-rating>` to `symbol` (it now accepts a string or a function that returns an icon name)
|
||||
- 🚨 BREAKING: renamed `setAssetPath()` to `setBasePath()` and added the ability to set the library's base path with a `data-shoelace` attribute (`setBasePath()` is exported from `utilities/base-path.js`)
|
||||
- Fixed `min` and `max` types in `sl-input` to allow numbers and strings [#330](https://github.com/shoelace-style/shoelace/issues/330)
|
||||
- Fixed a bug where `sl-checkbox`, `sl-radio`, and `sl-switch` controls would shrink with long labels [#325](https://github.com/shoelace-style/shoelace/issues/325)
|
||||
- Fixed a bug in `sl-select` where the dropdown menu wouldn't reposition when the box resized [#340](https://github.com/shoelace-style/shoelace/issues/340)
|
||||
- Fixed `min` and `max` types in `<sl-input>` to allow numbers and strings [#330](https://github.com/shoelace-style/shoelace/issues/330)
|
||||
- Fixed a bug where `<sl-checkbox>`, `<sl-radio>`, and `<sl-switch>` controls would shrink with long labels [#325](https://github.com/shoelace-style/shoelace/issues/325)
|
||||
- Fixed a bug in `<sl-select>` where the dropdown menu wouldn't reposition when the box resized [#340](https://github.com/shoelace-style/shoelace/issues/340)
|
||||
- Fixed a bug where ignoring clicks and clicking the overlay would prevent the escape key from closing the dialog/drawer [#344](https://github.com/shoelace-style/shoelace/pull/344)
|
||||
- Removed the lazy loading dist (importing `shoelace.js` will load and register all components now)
|
||||
- Switched from Stencil to Shoemaker
|
||||
@@ -338,17 +468,17 @@ The component API remains the same except for the changes noted below. Thanks fo
|
||||
|
||||
## 2.0.0-beta.27
|
||||
|
||||
- Added `handle-icon` slot to `sl-image-comparer` [#311](https://github.com/shoelace-style/shoelace/issues/311)
|
||||
- Added `label` and `helpText` props and slots to `sl-range` [#318](https://github.com/shoelace-style/shoelace/issues/318)
|
||||
- Added `handle-icon` slot to `<sl-image-comparer>` [#311](https://github.com/shoelace-style/shoelace/issues/311)
|
||||
- Added `label` and `helpText` props and slots to `<sl-range>` [#318](https://github.com/shoelace-style/shoelace/issues/318)
|
||||
- Added "Integrating with NextJS" tutorial to the docs, courtesy of [crutchcorn](https://github.com/crutchcorn)
|
||||
- Added `content` slot to `sl-tooltip` [#322](https://github.com/shoelace-style/shoelace/pull/322)
|
||||
- Fixed a bug in `sl-select` where removing a tag would toggle the dropdown
|
||||
- Fixed a bug in `sl-input` and `sl-textarea` where the input might not exist when the value watcher is called [#313](https://github.com/shoelace-style/shoelace/issues/313)
|
||||
- Fixed a bug in `sl-details` where hidden elements would receive focus when tabbing [#323](https://github.com/shoelace-style/shoelace/issues/323)
|
||||
- Fixed a bug in `sl-icon` where `sl-error` would only be emitted for network failures [#326](https://github.com/shoelace-style/shoelace/pull/326)
|
||||
- Reduced the default line-height for `sl-tooltip`
|
||||
- Updated `sl-menu-item` focus styles
|
||||
- Updated `sl-select` so tags will wrap when `multiple` is true
|
||||
- Added `content` slot to `<sl-tooltip>` [#322](https://github.com/shoelace-style/shoelace/pull/322)
|
||||
- Fixed a bug in `<sl-select>` where removing a tag would toggle the dropdown
|
||||
- Fixed a bug in `<sl-input>` and `<sl-textarea>` where the input might not exist when the value watcher is called [#313](https://github.com/shoelace-style/shoelace/issues/313)
|
||||
- Fixed a bug in `<sl-details>` where hidden elements would receive focus when tabbing [#323](https://github.com/shoelace-style/shoelace/issues/323)
|
||||
- Fixed a bug in `<sl-icon>` where `sl-error` would only be emitted for network failures [#326](https://github.com/shoelace-style/shoelace/pull/326)
|
||||
- Reduced the default line-height for `<sl-tooltip>`
|
||||
- Updated `<sl-menu-item>` focus styles
|
||||
- Updated `<sl-select>` so tags will wrap when `multiple` is true
|
||||
- Updated to Stencil 2.4.0
|
||||
|
||||
## 2.0.0-beta.26
|
||||
@@ -359,16 +489,16 @@ The component API remains the same except for the changes noted below. Thanks fo
|
||||
- Animation and easing names are now camelcase (e.g. `easeInOut` instead of `ease-in-out`)
|
||||
- Added initial E2E tests [#169](https://github.com/shoelace-style/shoelace/pull/169)
|
||||
- Added the `FocusOptions` argument to all components that have a `setFocus()` method
|
||||
- Added `sl-initial-focus` event to `sl-dialog` and `sl-drawer` so focus can be customized to a specific element
|
||||
- Added `close-button` part to `sl-tab` so the close button can be customized
|
||||
- Added `scroll-button` part to `sl-tab-group` so the scroll buttons can be customized
|
||||
- Added `sl-initial-focus` event to `<sl-dialog>` and `<sl-drawer>` so focus can be customized to a specific element
|
||||
- Added `close-button` part to `<sl-tab>` so the close button can be customized
|
||||
- Added `scroll-button` part to `<sl-tab-group>` so the scroll buttons can be customized
|
||||
- Fixed a bug where `sl-hide` would be emitted twice when closing an alert with `hide()`
|
||||
- Fixed a bug in `sl-color-picker` where the toggle button was smaller than the preview button in Safari
|
||||
- Fixed a bug in `sl-tab-group` where activating a nested tab group didn't work properly [#299](https://github.com/shoelace-style/shoelace/issues/299)
|
||||
- Fixed a bug in `sl-tab-group` where removing tabs would throw an error
|
||||
- Fixed a bug in `sl-alert`, `sl-dialog`, `sl-drawer`, `sl-select`, and `sl-tag` where the close button's base wasn't exported so it couldn't be styled
|
||||
- Removed `text` type from `sl-badge` as it was erroneously copied and never had styles
|
||||
- Updated `sl-tab-group` so the `active` property is reflected to its attribute
|
||||
- Fixed a bug in `<sl-color-picker>` where the toggle button was smaller than the preview button in Safari
|
||||
- Fixed a bug in `<sl-tab-group>` where activating a nested tab group didn't work properly [#299](https://github.com/shoelace-style/shoelace/issues/299)
|
||||
- Fixed a bug in `<sl-tab-group>` where removing tabs would throw an error
|
||||
- Fixed a bug in `<sl-alert>`, `<sl-dialog>`, `<sl-drawer>`, `<sl-select>`, and `<sl-tag>` where the close button's base wasn't exported so it couldn't be styled
|
||||
- Removed `text` type from `<sl-badge>` as it was erroneously copied and never had styles
|
||||
- Updated `<sl-tab-group>` so the `active` property is reflected to its attribute
|
||||
- Updated the docs to show dependencies instead of dependents which is much more useful when working with the custom elements bundle
|
||||
- Updated to Bootstrap Icons 1.3.0
|
||||
|
||||
@@ -381,103 +511,103 @@ The component API remains the same except for the changes noted below. Thanks fo
|
||||
- All component styles were adapted to use the new color tokens, but visual changes are subtle
|
||||
- The dark theme was adapted use the new color tokens
|
||||
- HSL is no longer used because it is not perceptually uniform (this may be revisited when all browsers support [LCH colors](https://lea.verou.me/2020/04/lch-colors-in-css-what-why-and-how/))
|
||||
- 🚨 BREAKING: Refactored `sl-select` to improve accessibility [#216](https://github.com/shoelace-style/shoelace/issues/216)
|
||||
- Removed the internal `sl-input` because it was causing problems with a11y and virtual keyboards
|
||||
- 🚨 BREAKING: Refactored `<sl-select>` to improve accessibility [#216](https://github.com/shoelace-style/shoelace/issues/216)
|
||||
- Removed the internal `<sl-input>` because it was causing problems with a11y and virtual keyboards
|
||||
- Removed `input`, `prefix` and `suffix` parts
|
||||
- 🚨 BREAKING: Removed `copy-button` part from `sl-color-picker` since copying is now done by clicking the preview
|
||||
- Added `getFormattedValue()` method to `sl-color-picker` so you can retrieve the current value in any format
|
||||
- Added visual separators between solid buttons in `sl-button-group`
|
||||
- Added `help-text` attribute to `sl-input`, `sl-textarea`, and `sl-select`
|
||||
- Fixed a bug where moving the mouse while `sl-dropdown` is closing would remove focus from the trigger
|
||||
- Fixed a bug where `sl-menu-item` didn't set a default color in the dark theme
|
||||
- Fixed a bug where `sl-color-picker` preview wouldn't update in Safari
|
||||
- 🚨 BREAKING: Removed `copy-button` part from `<sl-color-picker>` since copying is now done by clicking the preview
|
||||
- Added `getFormattedValue()` method to `<sl-color-picker>` so you can retrieve the current value in any format
|
||||
- Added visual separators between solid buttons in `<sl-button-group>`
|
||||
- Added `help-text` attribute to `<sl-input>`, `<sl-textarea>`, and `<sl-select>`
|
||||
- Fixed a bug where moving the mouse while `<sl-dropdown>` is closing would remove focus from the trigger
|
||||
- Fixed a bug where `<sl-menu-item>` didn't set a default color in the dark theme
|
||||
- Fixed a bug where `<sl-color-picker>` preview wouldn't update in Safari
|
||||
- Fixed a bug where removing an icon's `name` or `src` wouldn't remove the previously rendered SVG [#285](https://github.com/shoelace-style/shoelace/issues/285)
|
||||
- Fixed a bug where disabled link buttons didn't appear disabled
|
||||
- Improved button spacings and added split button example
|
||||
- Improved elevation tokens in dark theme
|
||||
- Improved accessibility in `sl-tooltip` by allowing escape to dismiss it [#219](https://github.com/shoelace-style/shoelace/issues/219)
|
||||
- Improved slot detection in `sl-card`, `sl-dialog`, and `sl-drawer`
|
||||
- Improved accessibility in `<sl-tooltip>` by allowing escape to dismiss it [#219](https://github.com/shoelace-style/shoelace/issues/219)
|
||||
- Improved slot detection in `<sl-card>`, `<sl-dialog>`, and `<sl-drawer>`
|
||||
- Made `@types/resize-observer-browser` a dependency so users don't have to install it manually
|
||||
- Refactored internal label + help text logic into a functional component used by `sl-input`, `sl-textarea`, and `sl-select`
|
||||
- Removed `sl-blur` and `sl-focus` events from `sl-menu` since menus can't have focus as of 2.0.0-beta.22
|
||||
- Updated `sl-spinner` so the indicator is more obvious
|
||||
- Refactored internal label + help text logic into a functional component used by `<sl-input>`, `<sl-textarea>`, and `<sl-select>`
|
||||
- Removed `sl-blur` and `sl-focus` events from `<sl-menu>` since menus can't have focus as of 2.0.0-beta.22
|
||||
- Updated `<sl-spinner>` so the indicator is more obvious
|
||||
- Updated to Bootstrap Icons 1.2.2
|
||||
|
||||
## 2.0.0-beta.24
|
||||
|
||||
- Added `sl-format-date` component
|
||||
- Added `indeterminate` state to `sl-progress-bar` [#274](https://github.com/shoelace-style/shoelace/issues/274)
|
||||
- Added `--track-color`, `--indicator-color`, and `--label-color` to `sl-progress-bar` [#276](https://github.com/shoelace-style/shoelace/issues/276)
|
||||
- Added `allow-scripts` attribute to `sl-include` [#280](https://github.com/shoelace-style/shoelace/issues/280)
|
||||
- Fixed a bug where `sl-menu-item` color variable was incorrect [#272](https://github.com/shoelace-style/shoelace/issues/272)
|
||||
- Fixed a bug where `sl-dialog` and `sl-drawer` would emit the `sl-hide` event twice [#275](https://github.com/shoelace-style/shoelace/issues/275)
|
||||
- Fixed a bug where calling `event.preventDefault()` on certain form elements wouldn't prevent `sl-form` from submitting [#277](https://github.com/shoelace-style/shoelace/issues/277)
|
||||
- Fixed drag handle orientation in `sl-image-comparer`
|
||||
- Restyled `sl-spinner` so the track is visible and the indicator is smaller.
|
||||
- Added `<sl-format-date>` component
|
||||
- Added `indeterminate` state to `<sl-progress-bar>` [#274](https://github.com/shoelace-style/shoelace/issues/274)
|
||||
- Added `--track-color`, `--indicator-color`, and `--label-color` to `<sl-progress-bar>` [#276](https://github.com/shoelace-style/shoelace/issues/276)
|
||||
- Added `allow-scripts` attribute to `<sl-include>` [#280](https://github.com/shoelace-style/shoelace/issues/280)
|
||||
- Fixed a bug where `<sl-menu-item>` color variable was incorrect [#272](https://github.com/shoelace-style/shoelace/issues/272)
|
||||
- Fixed a bug where `<sl-dialog>` and `<sl-drawer>` would emit the `sl-hide` event twice [#275](https://github.com/shoelace-style/shoelace/issues/275)
|
||||
- Fixed a bug where calling `event.preventDefault()` on certain form elements wouldn't prevent `<sl-form>` from submitting [#277](https://github.com/shoelace-style/shoelace/issues/277)
|
||||
- Fixed drag handle orientation in `<sl-image-comparer>`
|
||||
- Restyled `<sl-spinner>` so the track is visible and the indicator is smaller.
|
||||
- Removed `resize-observer-polyfill` in favor of `@types/resize-observer-browser` since all target browsers support `ResizeObserver`
|
||||
- Upgraded the status of `sl-form`, `sl-image-comparer`, and `sl-include` from experimental to stable
|
||||
- Upgraded the status of `<sl-form>`, `<sl-image-comparer>`, and `<sl-include>` from experimental to stable
|
||||
|
||||
## 2.0.0-beta.23
|
||||
|
||||
- Added `sl-format-number` component
|
||||
- Added `sl-relative-time` component
|
||||
- Added `closable` attribute to `sl-tab`
|
||||
- Added experimental `sl-resize-observer` utility
|
||||
- Added experimental `sl-theme` utility and updated theming documentation
|
||||
- Fixed a bug where `sl-menu-item` wouldn't render properly in the dark theme
|
||||
- Fixed a bug where `sl-select` would show an autocomplete menu
|
||||
- Added `<sl-format-number>` component
|
||||
- Added `<sl-relative-time>` component
|
||||
- Added `closable` attribute to `<sl-tab>`
|
||||
- Added experimental `<sl-resize-observer>` utility
|
||||
- Added experimental `<sl-theme>` utility and updated theming documentation
|
||||
- Fixed a bug where `<sl-menu-item>` wouldn't render properly in the dark theme
|
||||
- Fixed a bug where `<sl-select>` would show an autocomplete menu
|
||||
- Improved placeholder contrast in dark theme
|
||||
- Updated to Boostrap Icons 1.1.0
|
||||
- Updated to Stencil 2.3.0
|
||||
|
||||
## 2.0.0-beta.22
|
||||
|
||||
- 🚨 BREAKING: Refactored `sl-menu` and `sl-menu-item` to improve accessibility by using proper focus states [#217](https://github.com/shoelace-style/shoelace/issues/217)
|
||||
- Moved `tabindex` from `sl-menu` to `sl-menu-item`
|
||||
- Removed the `active` attribute from `sl-menu-item` because synthetic focus states are bad for accessibility
|
||||
- Removed the `sl-activate` and `sl-deactivate` events from `sl-menu-item` (listen for `focus` and `blur` instead)
|
||||
- Updated `sl-select` so keyboard navigation still works
|
||||
- Added `no-scroll-controls` attribute to `sl-tab-group` [#253](https://github.com/shoelace-style/shoelace/issues/253)
|
||||
- Fixed a bug where setting `open` initially wouldn't show `sl-dialog` or `sl-drawer` [#255](https://github.com/shoelace-style/shoelace/issues/255)
|
||||
- 🚨 BREAKING: Refactored `<sl-menu>` and `<sl-menu-item>` to improve accessibility by using proper focus states [#217](https://github.com/shoelace-style/shoelace/issues/217)
|
||||
- Moved `tabindex` from `<sl-menu>` to `<sl-menu-item>`
|
||||
- Removed the `active` attribute from `<sl-menu-item>` because synthetic focus states are bad for accessibility
|
||||
- Removed the `sl-activate` and `sl-deactivate` events from `<sl-menu-item>` (listen for `focus` and `blur` instead)
|
||||
- Updated `<sl-select>` so keyboard navigation still works
|
||||
- Added `no-scroll-controls` attribute to `<sl-tab-group>` [#253](https://github.com/shoelace-style/shoelace/issues/253)
|
||||
- Fixed a bug where setting `open` initially wouldn't show `<sl-dialog>` or `<sl-drawer>` [#255](https://github.com/shoelace-style/shoelace/issues/255)
|
||||
- Fixed a bug where `disabled` could be set when buttons are rendered as links
|
||||
- Fixed a bug where hoisted dropdowns would render in the wrong position when placed inside `sl-dialog` [#252](https://github.com/shoelace-style/shoelace/issues/252)
|
||||
- Fixed a bug where hoisted dropdowns would render in the wrong position when placed inside `<sl-dialog>` [#252](https://github.com/shoelace-style/shoelace/issues/252)
|
||||
- Fixed a bug where boolean aria attributes didn't explicitly set `true|false` string values in the DOM
|
||||
- Fixed a bug where `aria-describedby` was never set on tooltip targets in `sl-tooltip`
|
||||
- Fixed a bug where setting `position` on `sl-image-comparer` wouldn't update the divider's position
|
||||
- Fixed a bug where the check icon was announced to screen readers in `sl-menu-item`
|
||||
- Improved `sl-icon-button` accessibility by encouraging proper use of `label` and hiding the internal icon from screen readers [#220](https://github.com/shoelace-style/shoelace/issues/220)
|
||||
- Improved `sl-dropdown` accessibility by attaching `aria-haspopup` and `aria-expanded` to the slotted trigger
|
||||
- Refactored position logic to remove an unnecessary state variable in `sl-image-comparer`
|
||||
- Fixed a bug where `aria-describedby` was never set on tooltip targets in `<sl-tooltip>`
|
||||
- Fixed a bug where setting `position` on `<sl-image-comparer>` wouldn't update the divider's position
|
||||
- Fixed a bug where the check icon was announced to screen readers in `<sl-menu-item>`
|
||||
- Improved `<sl-icon-button>` accessibility by encouraging proper use of `label` and hiding the internal icon from screen readers [#220](https://github.com/shoelace-style/shoelace/issues/220)
|
||||
- Improved `<sl-dropdown>` accessibility by attaching `aria-haspopup` and `aria-expanded` to the slotted trigger
|
||||
- Refactored position logic to remove an unnecessary state variable in `<sl-image-comparer>`
|
||||
- Refactored design tokens to use `rem` instead of `px` for input height and spacing [#221](https://github.com/shoelace-style/shoelace/issues/221)
|
||||
- Removed `console.log` from modal utility
|
||||
- Updated to Stencil 2.2.0
|
||||
|
||||
## 2.0.0-beta.21
|
||||
|
||||
- Added `label` slot to `sl-input`, `sl-select`, and `sl-textarea` [#248](https://github.com/shoelace-style/shoelace/issues/248)
|
||||
- Added `label` slot to `sl-dialog` and `sl-drawer`
|
||||
- Added experimental `sl-include` component
|
||||
- Added status code to the `sl-error` event in `sl-icon`
|
||||
- Fixed a bug where initial transitions didn't show in `sl-dialog` and `sl-drawer` [#247](https://github.com/shoelace-style/shoelace/issues/247)
|
||||
- Added `label` slot to `<sl-input>`, `<sl-select>`, and `<sl-textarea>` [#248](https://github.com/shoelace-style/shoelace/issues/248)
|
||||
- Added `label` slot to `<sl-dialog>` and `<sl-drawer>`
|
||||
- Added experimental `<sl-include>` component
|
||||
- Added status code to the `sl-error` event in `<sl-icon>`
|
||||
- Fixed a bug where initial transitions didn't show in `<sl-dialog>` and `<sl-drawer>` [#247](https://github.com/shoelace-style/shoelace/issues/247)
|
||||
- Fixed a bug where indeterminate checkboxes would maintain the indeterminate state when toggled
|
||||
- Fixed a bug where concurrent active modals (i.e. dialog, drawer) would try to steal focus from each other
|
||||
- Improved `sl-color-picker` grid and slider handles [#246](https://github.com/shoelace-style/shoelace/issues/246)
|
||||
- Refactored `sl-icon` request logic and removed unused cache map
|
||||
- Reworked show/hide logic in `sl-alert`, `sl-dialog`, and `sl-drawer` to not use reflow hacks and the `hidden` attribute
|
||||
- Reworked slot logic in `sl-card`, `sl-dialog`, and `sl-drawer`
|
||||
- Improved `<sl-color-picker>` grid and slider handles [#246](https://github.com/shoelace-style/shoelace/issues/246)
|
||||
- Refactored `<sl-icon>` request logic and removed unused cache map
|
||||
- Reworked show/hide logic in `<sl-alert>`, `<sl-dialog>`, and `<sl-drawer>` to not use reflow hacks and the `hidden` attribute
|
||||
- Reworked slot logic in `<sl-card>`, `<sl-dialog>`, and `<sl-drawer>`
|
||||
- Updated to Popper 2.5.3 to address a fixed position bug in Firefox
|
||||
|
||||
## 2.0.0-beta.20
|
||||
|
||||
- 🚨 BREAKING: Transformed all Shoelace events to lowercase ([details](#why-did-event-names-change))
|
||||
- Added support for dropdowns and non-icon elements to `sl-input`
|
||||
- Added `spellcheck` attribute to `sl-input`
|
||||
- Added `sl-icon-library` to allow custom icon library registration
|
||||
- Added `library` attribute to `sl-icon` and `sl-icon-button`
|
||||
- Added support for dropdowns and non-icon elements to `<sl-input>`
|
||||
- Added `spellcheck` attribute to `<sl-input>`
|
||||
- Added `<sl-icon-library>` to allow custom icon library registration
|
||||
- Added `library` attribute to `<sl-icon>` and `<sl-icon-button>`
|
||||
- Added "Integrating with Rails" tutorial to the docs, courtesy of [ParamagicDev](https://github.com/ParamagicDev)
|
||||
- Fixed a bug where `sl-progress-ring` rendered incorrectly when zoomed in Safari [#227](https://github.com/shoelace-style/shoelace/issues/227)
|
||||
- Fixed a bug where tabbing into slotted elements closes `sl-dropdown` when used in a shadow root [#223](https://github.com/shoelace-style/shoelace/issues/223)
|
||||
- Fixed a bug where scroll anchoring caused undesirable scrolling when `sl-details` are grouped
|
||||
- Fixed a bug where `<sl-progress-ring>` rendered incorrectly when zoomed in Safari [#227](https://github.com/shoelace-style/shoelace/issues/227>)
|
||||
- Fixed a bug where tabbing into slotted elements closes `<sl-dropdown>` when used in a shadow root [#223](https://github.com/shoelace-style/shoelace/issues/223)
|
||||
- Fixed a bug where scroll anchoring caused undesirable scrolling when `<sl-details>` are grouped
|
||||
|
||||
### Why did event names change?
|
||||
|
||||
@@ -494,40 +624,40 @@ The following pages demonstrate why this change was necessary.
|
||||
|
||||
## 2.0.0-beta.19
|
||||
|
||||
- Added `input`, `label`, `prefix`, `clear-button`, `suffix`, `help-text` exported parts to `sl-select` to make the input customizable
|
||||
- Added toast notifications through the `toast()` method on `sl-alert`
|
||||
- Fixed a bug where mouse events would bubble up when `sl-button` was disabled, causing tooltips to erroneously appear
|
||||
- Fixed a bug where pressing space would open and immediately close `sl-dropdown` panels in Firefox
|
||||
- Fixed a bug where `sl-tooltip` would throw an error on init
|
||||
- Added `input`, `label`, `prefix`, `clear-button`, `suffix`, `help-text` exported parts to `<sl-select>` to make the input customizable
|
||||
- Added toast notifications through the `toast()` method on `<sl-alert>`
|
||||
- Fixed a bug where mouse events would bubble up when `<sl-button>` was disabled, causing tooltips to erroneously appear
|
||||
- Fixed a bug where pressing space would open and immediately close `<sl-dropdown>` panels in Firefox
|
||||
- Fixed a bug where `<sl-tooltip>` would throw an error on init
|
||||
- Fixed a bug in custom keyframes animation example
|
||||
- Refactored clear logic in `sl-input`
|
||||
- Refactored clear logic in `<sl-input>`
|
||||
|
||||
## 2.0.0-beta.18
|
||||
|
||||
- Added `name` and `invalid` attribute to `sl-color-picker`
|
||||
- Added support for form submission and validation to `sl-color-picker`
|
||||
- Added `name` and `invalid` attribute to `<sl-color-picker>`
|
||||
- Added support for form submission and validation to `<sl-color-picker>`
|
||||
- Added touch support to demo resizers in the docs
|
||||
- Added `sl-responsive-embed` component
|
||||
- Fixed a bug where swapping an animated element wouldn't restart the animation in `sl-animation`
|
||||
- Fixed a bug where the cursor was incorrect when `sl-select` was disabled
|
||||
- Fixed a bug where `slblur` and `slfocus` were emitted twice in `sl-select`
|
||||
- Fixed a bug where clicking on `sl-menu` wouldn't focus it
|
||||
- Added `<sl-responsive-embed>` component
|
||||
- Fixed a bug where swapping an animated element wouldn't restart the animation in `<sl-animation>`
|
||||
- Fixed a bug where the cursor was incorrect when `<sl-select>` was disabled
|
||||
- Fixed a bug where `slblur` and `slfocus` were emitted twice in `<sl-select>`
|
||||
- Fixed a bug where clicking on `<sl-menu>` wouldn't focus it
|
||||
- Fixed a bug in the popover utility where `onAfterShow` would fire too soon
|
||||
- Fixed a bug where `bottom` and `right` placements didn't render properly in `sl-tab-group`
|
||||
- Improved keyboard logic in `sl-dropdown`, `sl-menu`, and `sl-select`
|
||||
- Updated `sl-animation` to stable
|
||||
- Fixed a bug where `bottom` and `right` placements didn't render properly in `<sl-tab-group>`
|
||||
- Improved keyboard logic in `<sl-dropdown>`, `<sl-menu>`, and `<sl-select>`
|
||||
- Updated `<sl-animation>` to stable
|
||||
- Updated to Stencil 2.0 (you may need to purge `node_modules` and run `npm install` after pulling)
|
||||
- Updated entry points in `package.json` to reflect new filenames generated by Stencil 2
|
||||
|
||||
## 2.0.0-beta.17
|
||||
|
||||
- Added `minlength` and `spellcheck` attributes to `sl-textarea`
|
||||
- Fixed a bug where clicking a tag in `sl-select` wouldn't toggle the menu
|
||||
- Fixed a bug where options where `sl-select` options weren't always visible or scrollable
|
||||
- Fixed a bug where setting `null` on `sl-input`, `sl-textarea`, or `sl-select` would throw an error
|
||||
- Fixed a bug where `role` was on the wrong element and aria attribute weren't explicit in `sl-checkbox`, `sl-switch`, and `sl-radio`
|
||||
- Fixed a bug where dynamically adding/removing a slot wouldn't work as expected in `sl-card`, `sl-dialog`, and `sl-drawer`
|
||||
- Fixed a bug where the value wasn't updated and events weren't emitted when using `setRangeText` in `sl-input` and `sl-textarea`
|
||||
- Added `minlength` and `spellcheck` attributes to `<sl-textarea>`
|
||||
- Fixed a bug where clicking a tag in `<sl-select>` wouldn't toggle the menu
|
||||
- Fixed a bug where options where `<sl-select>` options weren't always visible or scrollable
|
||||
- Fixed a bug where setting `null` on `<sl-input>`, `<sl-textarea>`, or `<sl-select>` would throw an error
|
||||
- Fixed a bug where `role` was on the wrong element and aria attribute weren't explicit in `<sl-checkbox>`, `<sl-switch>`, and `<sl-radio>`
|
||||
- Fixed a bug where dynamically adding/removing a slot wouldn't work as expected in `<sl-card>`, `<sl-dialog>`, and `<sl-drawer>`
|
||||
- Fixed a bug where the value wasn't updated and events weren't emitted when using `setRangeText` in `<sl-input>` and `<sl-textarea>`
|
||||
- Optimized `hasSlot` utility by using a simpler selector
|
||||
- Updated Bootstrap Icons to 1.0.0 with many icons redrawn and improved
|
||||
- Updated contribution guidelines
|
||||
@@ -535,65 +665,65 @@ The following pages demonstrate why this change was necessary.
|
||||
**Form validation has been reworked and is much more powerful now!**
|
||||
|
||||
- The `invalid` attribute now reflects the control's validity as determined by the browser's constraint validation API
|
||||
- Added `required` to `sl-checkbox`, `sl-select`, and `sl-switch`
|
||||
- Added `required` to `<sl-checkbox>`, `<sl-select>`, and `<sl-switch>`
|
||||
- Added `reportValidity()` and `setCustomValidity()` methods to all form controls
|
||||
- Added validation checking for custom and native form controls to `sl-form`
|
||||
- Added `novalidate` attribute to `sl-form` to disable validation
|
||||
- Added validation checking for custom and native form controls to `<sl-form>`
|
||||
- Added `novalidate` attribute to `<sl-form>` to disable validation
|
||||
- Removed the `valid` attribute from all form controls
|
||||
- Removed valid and invalid design tokens and related styles (you can use your own custom styles to achieve this)
|
||||
|
||||
## 2.0.0-beta.16
|
||||
|
||||
- Added `hoist` attribute to `sl-color-picker`, `sl-dropdown`, and `sl-select` to work around panel clipping
|
||||
- Added `sl-format-bytes` utility component
|
||||
- Added `clearable` and `required` props to `sl-select`
|
||||
- Added `slclear` event to `sl-input`
|
||||
- Added `hoist` attribute to `<sl-color-picker>`, `<sl-dropdown>`, and `<sl-select>` to work around panel clipping
|
||||
- Added `<sl-format-bytes>` utility component
|
||||
- Added `clearable` and `required` props to `<sl-select>`
|
||||
- Added `slclear` event to `<sl-input>`
|
||||
- Added keyboard support to the preview resizer in the docs
|
||||
- Fixed a bug where the `aria-selected` state was incorrect in `sl-menu-item`
|
||||
- Fixed a bug where custom properties applied to `sl-tooltip` didn't affect show/hide transitions
|
||||
- Fixed a bug where `--sl-input-color-*` custom properties had no effect on `sl-input` and `sl-textarea`
|
||||
- Refactored `sl-dropdown` and `sl-tooltip` to use positioner elements so panels/tooltips can be customized easier
|
||||
- Fixed a bug where the `aria-selected` state was incorrect in `<sl-menu-item>`
|
||||
- Fixed a bug where custom properties applied to `<sl-tooltip>` didn't affect show/hide transitions
|
||||
- Fixed a bug where `--sl-input-color-*` custom properties had no effect on `<sl-input>` and `<sl-textarea>`
|
||||
- Refactored `<sl-dropdown>` and `<sl-tooltip>` to use positioner elements so panels/tooltips can be customized easier
|
||||
|
||||
## 2.0.0-beta.15
|
||||
|
||||
- Added `image-comparer` component
|
||||
- Added `--width`, `--height`, and `--thumb-size` custom props to `sl-switch`
|
||||
- Added `--width`, `--height`, and `--thumb-size` custom props to `<sl-switch>`
|
||||
- Fixed an `aria-labelledby` attribute typo in a number of components
|
||||
- Fixed a bug where the `change` event wasn't updating the value in `sl-input`
|
||||
- Fixed a bug where `sl-color-picker` had the wrong border color in the dark theme
|
||||
- Fixed a bug where `sl-menu-item` had the wrong color in dark mode when disabled
|
||||
- Fixed a bug where the `change` event wasn't updating the value in `<sl-input>`
|
||||
- Fixed a bug where `<sl-color-picker>` had the wrong border color in the dark theme
|
||||
- Fixed a bug where `<sl-menu-item>` had the wrong color in dark mode when disabled
|
||||
- Fixed a bug where WebKit's autocomplete styles made inputs looks broken
|
||||
- Fixed a bug where aria labels were wrong in `sl-select`
|
||||
- Fixed a bug where clicking the label wouldn't focus the control in `sl-select`
|
||||
- Fixed a bug where aria labels were wrong in `<sl-select>`
|
||||
- Fixed a bug where clicking the label wouldn't focus the control in `<sl-select>`
|
||||
|
||||
## 2.0.0-beta.14
|
||||
|
||||
- Added dark theme
|
||||
- Added `--sl-panel-background-color` and `--sl-panel-border-color` tokens
|
||||
- Added `--tabs-border-color` custom property to `sl-tab-group`
|
||||
- Added `--track-color` custom property to `sl-range`
|
||||
- Added `tag` part to `sl-select`
|
||||
- Added `--tabs-border-color` custom property to `<sl-tab-group>`
|
||||
- Added `--track-color` custom property to `<sl-range>`
|
||||
- Added `tag` part to `<sl-select>`
|
||||
- Updated `package.json` so custom elements imports can be consumed from the root
|
||||
- Fixed a bug where scrolling dialogs didn't resize properly in Safari
|
||||
- Fixed a bug where `slshow` and `slhide` would be emitted twice in some components
|
||||
- Fixed a bug where `custom-elements/index.d.ts` was broken due to an unclosed comment (fixed in Stencil 1.17.3)
|
||||
- Fixed bug where inputs were not using border radius tokens
|
||||
- Fixed a bug where the text color was being erroneously set in `sl-progress-ring`
|
||||
- Fixed a bug where `sl-progress-bar` used the wrong part name internally for `indicator`
|
||||
- Removed background color from `sl-menu`
|
||||
- Fixed a bug where the text color was being erroneously set in `<sl-progress-ring>`
|
||||
- Fixed a bug where `<sl-progress-bar>` used the wrong part name internally for `indicator`
|
||||
- Removed background color from `<sl-menu>`
|
||||
- Updated to Stencil 1.17.3
|
||||
|
||||
## 2.0.0-beta.13
|
||||
|
||||
- Added `slactivate` and `sldeactivate` events to `sl-menu-item`
|
||||
- Added experimental `sl-animation` component
|
||||
- Added `slactivate` and `sldeactivate` events to `<sl-menu-item>`
|
||||
- Added experimental `<sl-animation>` component
|
||||
- Added shields to documentation
|
||||
- Fixed a bug where link buttons would have `type="button"`
|
||||
- Fixed a bug where button groups with tooltips experienced an odd spacing issue in Safari
|
||||
- Fixed a bug where scrolling in dropdowns/selects didn't work properly on Windows (special thanks to [Trendy](http://github.com/trendy) for helping troubleshoot!)
|
||||
- Fixed a bug where selecting a menu item in a dropdown would cause Safari to scroll
|
||||
- Fixed a bug where type to select wouldn't accept symbols
|
||||
- Moved scrolling logic from `sl-menu` to `sl-dropdown`
|
||||
- Moved scrolling logic from `<sl-menu>` to `<sl-dropdown>`
|
||||
|
||||
## 2.0.0-beta.12
|
||||
|
||||
@@ -605,7 +735,7 @@ The following pages demonstrate why this change was necessary.
|
||||
|
||||
- Added button group component
|
||||
- Fixed icon button alignment
|
||||
- Fixed a bug where focus visible observer wasn't removed from `sl-details`
|
||||
- Fixed a bug where focus visible observer wasn't removed from `<sl-details>`
|
||||
- Replaced the deprecated `componentDidUnload` lifecycle method with `disconnectedCallback` to prevent issues with frameworks
|
||||
|
||||
## 2.0.0-beta.10
|
||||
@@ -626,10 +756,10 @@ The following pages demonstrate why this change was necessary.
|
||||
- Fixed a bug where closing dropdowns wouldn't give focus back to the trigger
|
||||
- Fixed a bug where type-to-select wasn't working after the first letter
|
||||
- Fixed a bug where clicking on menu items and dividers would steal focus from the menu
|
||||
- Fix a bug where the color picker wouldn't parse uppercase values
|
||||
- Fixed a bug where the color picker wouldn't parse uppercase values
|
||||
- Removed the `no-footer` attribute from dialog and drawer (slot detection is automatic, so the attribute is not required)
|
||||
- Removed `close-icon` slot from alert
|
||||
- Replaced make-shift icon buttons with `sl-icon-button` in alert, dialog, drawer, and tag
|
||||
- Replaced make-shift icon buttons with `<sl-icon-button>` in alert, dialog, drawer, and tag
|
||||
- Updated Stencil to 1.17.1
|
||||
- Switched to jsDelivr for better CDN performance
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Community
|
||||
|
||||
Shoelace has a budding community of designers and developers that are building amazing things with web components. We'd love for you to become a part of it!
|
||||
Shoelace has a growing community of designers and developers that are building amazing things with web components. We'd love for you to become a part of it!
|
||||
|
||||
Please be respectful of other users and remember that Shoelace is an open source project. We'll try to help when we can, but there's no guarantee we'll be able solve your problem. Please manage your expectations and don't forget to contribute back to the conversation when you can!
|
||||
|
||||
@@ -14,6 +14,7 @@ The [discussion forum](https://github.com/shoelace-style/shoelace/discussions) i
|
||||
- Learn more about the project, its values, and its roadmap
|
||||
|
||||
<sl-button type="primary" href="https://github.com/shoelace-style/shoelace/discussions" target="_blank">
|
||||
<sl-icon name="github" slot="prefix"></sl-icon>
|
||||
Join the Discussion
|
||||
</sl-button>
|
||||
|
||||
@@ -27,9 +28,19 @@ The [community chat](https://discord.gg/mg8f26C) is open to the public and power
|
||||
- Chat live with other designers, developers, and Shoelace fans
|
||||
|
||||
<sl-button type="primary" href="https://discord.gg/mg8f26C" target="_blank">
|
||||
<sl-icon name="discord" slot="prefix"></sl-icon>
|
||||
Join the Chat
|
||||
</sl-button>
|
||||
|
||||
## Stack Overflow
|
||||
|
||||
You can post questions on Stack Overflow using [the "shoelace" tag](https://stackoverflow.com/questions/tagged/shoelace). This is a public forum where talented developers answer questions. It's a great way to get help, but it is not maintained or actively monitored by the Shoelace author.
|
||||
|
||||
<sl-button type="primary" href="https://stackoverflow.com/questions/ask?tags=shoelace" target="_blank">
|
||||
<sl-icon name="stack-overflow" slot="prefix"></sl-icon>
|
||||
Ask for Help
|
||||
</sl-button>
|
||||
|
||||
## Twitter
|
||||
|
||||
Follow [@shoelace_style](https://twitter.com/shoelace_style) on Twitter for general updates and announcements about Shoelace. This is a great place to say "hi" or to share something you're working on. You're also welcome to follow [@claviska](https://twitter.com/claviska), the creator, for tweets about web components, web development, and life.
|
||||
@@ -37,5 +48,6 @@ Follow [@shoelace_style](https://twitter.com/shoelace_style) on Twitter for gene
|
||||
**Please avoid using Twitter for support questions.** The [discussion forum](https://github.com/shoelace-style/shoelace/discussions) is a much better place to share code snippets, screenshots, and other troubleshooting info. You'll have much better luck there, as more users will have a chance to help you.
|
||||
|
||||
<sl-button type="primary" href="https://twitter.com/shoelace_style" target="_blank">
|
||||
<sl-icon name="twitter" slot="prefix"></sl-icon>
|
||||
Follow on Twitter
|
||||
</sl-button>
|
||||
|
||||
@@ -129,10 +129,13 @@ Theme tokens give you a semantic way to reference colors in your app. The primar
|
||||
Black & White<br>
|
||||
<code>--sl-color-neutral-<em>{n}</em></code>
|
||||
</div>
|
||||
<div class="color-palette__example"><div class="color-palette__swatch" style="background-color: rgb(var(--sl-color-neutral-0));"></div>0</div>
|
||||
<div class="color-palette__example"><div class="color-palette__swatch color-palette__swatch--border" style="background-color: rgb(var(--sl-color-neutral-1000));"></div>1000</div>
|
||||
<div class="color-palette__example"><div class="color-palette__swatch color-palette__swatch--border" style="background-color: rgb(var(--sl-color-neutral-0));"></div>0</div>
|
||||
<div class="color-palette__example"><div class="color-palette__swatch " style="background-color: rgb(var(--sl-color-neutral-1000));"></div>1000</div>
|
||||
</div>
|
||||
|
||||
?> Looking for an easy way to customize your theme? [Try the color token generator!](https://codepen.io/claviska/full/QWveRgL)
|
||||
|
||||
|
||||
## Primitives
|
||||
|
||||
Additional palettes are provided in the form of color primitives. Use these when you need arbitrary colors that don't have semantic meaning. Color primitives are derived from the fantastic [Tailwind color palette](https://tailwindcss.com/docs/customizing-colors).
|
||||
|
||||
@@ -4,13 +4,13 @@ Spacing tokens are used to provide consistent spacing between components and con
|
||||
|
||||
| Token | Value | Example |
|
||||
| ------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--sl-spacing-xxx-small` | 0.125rem (2px) | <div class="spacing-demo" style="width: var(--sl-spacing-xxx-small); height: var(--sl-spacing-xxx-small);"></div> |
|
||||
| `--sl-spacing-xx-small` | 0.25rem (4px) | <div class="spacing-demo" style="width: var(--sl-spacing-xx-small); height: var(--sl-spacing-xx-small);"></div> |
|
||||
| `--sl-spacing-3x-small` | 0.125rem (2px) | <div class="spacing-demo" style="width: var(--sl-spacing-3x-small); height: var(--sl-spacing-3x-small);"></div> |
|
||||
| `--sl-spacing-2x-small` | 0.25rem (4px) | <div class="spacing-demo" style="width: var(--sl-spacing-2x-small); height: var(--sl-spacing-2x-small);"></div> |
|
||||
| `--sl-spacing-x-small` | 0.5rem (8px) | <div class="spacing-demo" style="width: var(--sl-spacing-x-small); height: var(--sl-spacing-x-small);"></div> |
|
||||
| `--sl-spacing-small` | 0.75rem (12px) | <div class="spacing-demo" style="width: var(--sl-spacing-small); height: var(--sl-spacing-small);"></div> |
|
||||
| `--sl-spacing-medium` | 1rem (16px) | <div class="spacing-demo" style="width: var(--sl-spacing-medium); height: var(--sl-spacing-medium);"></div> |
|
||||
| `--sl-spacing-large` | 1.25rem (20px) | <div class="spacing-demo" style="width: var(--sl-spacing-large); height: var(--sl-spacing-large);"></div> |
|
||||
| `--sl-spacing-x-large` | 1.75rem (28px) | <div class="spacing-demo" style="width: var(--sl-spacing-x-large); height: var(--sl-spacing-x-large);"></div> |
|
||||
| `--sl-spacing-xx-large` | 2.25rem (36px) | <div class="spacing-demo" style="width: var(--sl-spacing-xx-large); height: var(--sl-spacing-xx-large);"></div> |
|
||||
| `--sl-spacing-xxx-large` | 3rem (48px) | <div class="spacing-demo" style="width: var(--sl-spacing-xxx-large); height: var(--sl-spacing-xxx-large);"></div> |
|
||||
| `--sl-spacing-xxxx-large` | 4.5rem (72px) | <div class="spacing-demo" style="width: var(--sl-spacing-xxxx-large); height: var(--sl-spacing-xxxx-large);"></div> |
|
||||
| `--sl-spacing-2x-large` | 2.25rem (36px) | <div class="spacing-demo" style="width: var(--sl-spacing-2x-large); height: var(--sl-spacing-2x-large);"></div> |
|
||||
| `--sl-spacing-3x-large` | 3rem (48px) | <div class="spacing-demo" style="width: var(--sl-spacing-3x-large); height: var(--sl-spacing-3x-large);"></div> |
|
||||
| `--sl-spacing-4x-large` | 4.5rem (72px) | <div class="spacing-demo" style="width: var(--sl-spacing-4x-large); height: var(--sl-spacing-4x-large);"></div> |
|
||||
|
||||
@@ -18,15 +18,15 @@ Font sizes use `rem` units so they scale with the base font size. The pixel valu
|
||||
|
||||
| Token | Value | Example |
|
||||
| --------------------------- | --------------- | ----------------------------------------------------------------- |
|
||||
| `--sl-font-size-xx-small` | 0.625rem (10px) | <span style="font-size: var(--sl-font-size-xx-small)">Aa</span> |
|
||||
| `--sl-font-size-2x-small` | 0.625rem (10px) | <span style="font-size: var(--sl-font-size-2x-small)">Aa</span> |
|
||||
| `--sl-font-size-x-small` | 0.75rem (12px) | <span style="font-size: var(--sl-font-size-x-small)">Aa</span> |
|
||||
| `--sl-font-size-small` | 0.875rem (14px) | <span style="font-size: var(--sl-font-size-small)">Aa</span> |
|
||||
| `--sl-font-size-medium` | 1rem (16px) | <span style="font-size: var(--sl-font-size-medium)">Aa</span> |
|
||||
| `--sl-font-size-large` | 1.25rem (20px) | <span style="font-size: var(--sl-font-size-large)">Aa</span> |
|
||||
| `--sl-font-size-x-large` | 1.5rem (24px) | <span style="font-size: var(--sl-font-size-x-large)">Aa</span> |
|
||||
| `--sl-font-size-xx-large` | 2.25rem (36px) | <span style="font-size: var(--sl-font-size-xx-large)">Aa</span> |
|
||||
| `--sl-font-size-xxx-large` | 3rem (48px) | <span style="font-size: var(--sl-font-size-xxx-large)">Aa</span> |
|
||||
| `--sl-font-size-xxxx-large` | 4.5rem (72px) | <span style="font-size: var(--sl-font-size-xxxx-large)">Aa</span> |
|
||||
| `--sl-font-size-2x-large` | 2.25rem (36px) | <span style="font-size: var(--sl-font-size-2x-large)">Aa</span> |
|
||||
| `--sl-font-size-3x-large` | 3rem (48px) | <span style="font-size: var(--sl-font-size-3x-large)">Aa</span> |
|
||||
| `--sl-font-size-4x-large` | 4.5rem (72px) | <span style="font-size: var(--sl-font-size-4x-large)">Aa</span> |
|
||||
|
||||
## Font Weight
|
||||
|
||||
@@ -39,16 +39,20 @@ Font sizes use `rem` units so they scale with the base font size. The pixel valu
|
||||
|
||||
## Letter Spacing
|
||||
|
||||
| Token | Value | Example |
|
||||
| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--sl-letter-spacing-dense` | -0.015em | <span style="letter-spacing: var(--sl-letter-spacing-dense);">The quick brown fox jumped over the lazy dog.</span> |
|
||||
| `--sl-letter-spacing-normal` | normal | <span style="letter-spacing: var(--sl-letter-spacing-normal);">The quick brown fox jumped over the lazy dog.</span> |
|
||||
| `--sl-letter-spacing-loose` | 0.075em | <span style="letter-spacing: var(--sl-letter-spacing-loose);">The quick brown fox jumped over the lazy dog.</span> |
|
||||
| Token | Value | Example |
|
||||
| ---------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--sl-letter-spacing-denser` | ? | <span style="letter-spacing: var(--sl-letter-spacing-denser);">The quick brown fox jumped over the lazy dog.</span> |
|
||||
| `--sl-letter-spacing-dense` | -0.015em | <span style="letter-spacing: var(--sl-letter-spacing-dense);">The quick brown fox jumped over the lazy dog.</span> |
|
||||
| `--sl-letter-spacing-normal` | normal | <span style="letter-spacing: var(--sl-letter-spacing-normal);">The quick brown fox jumped over the lazy dog.</span> |
|
||||
| `--sl-letter-spacing-loose` | 0.075em | <span style="letter-spacing: var(--sl-letter-spacing-loose);">The quick brown fox jumped over the lazy dog.</span> |
|
||||
| `--sl-letter-spacing-looser` | ? | <span style="letter-spacing: var(--sl-letter-spacing-looser);">The quick brown fox jumped over the lazy dog.</span> |
|
||||
|
||||
## Line Height
|
||||
|
||||
| Token | Value | Example |
|
||||
| ------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--sl-line-height-dense` | 1.4 | <div style="line-height: var(--sl-line-height-dense);">The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.</div> |
|
||||
| `--sl-line-height-normal` | 1.8 | <div style="line-height: var(--sl-line-height-normal);">The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.</div> |
|
||||
| `--sl-line-height-loose` | 2.2 | <div style="line-height: var(--sl-line-height-loose);">The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.</div> |
|
||||
| Token | Value | Example |
|
||||
| ------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `--sl-line-height-denser` | ? | <div style="line-height: var(--sl-line-height-denser);">The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.</div> |
|
||||
| `--sl-line-height-dense` | 1.4 | <div style="line-height: var(--sl-line-height-dense);">The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.</div> |
|
||||
| `--sl-line-height-normal` | 1.8 | <div style="line-height: var(--sl-line-height-normal);">The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.</div> |
|
||||
| `--sl-line-height-loose` | 2.2 | <div style="line-height: var(--sl-line-height-loose);">The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.</div> |
|
||||
| `--sl-line-height-looser` | ? | <div style="line-height: var(--sl-line-height-looser);">The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.<br>The quick brown fox jumped over the lazy dog.</div> |
|
||||
|
||||
114
docs/tutorials/integrating-with-laravel.md
Normal file
114
docs/tutorials/integrating-with-laravel.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Integrating with Laravel
|
||||
|
||||
This page explains how to integrate Shoelace with a [Laravel](https://laravel.com) app using a local Webpack bundle. This is a community-maintained document. For questions about this integration, please [ask the community](/resources/community).
|
||||
|
||||
## Requirements
|
||||
|
||||
This integration has been tested with the following:
|
||||
|
||||
- Laravel >= 8
|
||||
- Node >= 14
|
||||
- Laravel Mix >= 6
|
||||
|
||||
## Instructions
|
||||
|
||||
These instructions assume an out-of-the-box [Laravel 8+ install](https://laravel.com/docs/8.x/installation) that uses [Laravel Mix](https://laravel.com/docs/8.x/mix) to compile assets.
|
||||
Be sure to run `npm install` to install the default Laravel front-end dependencies before installing Shoelace.
|
||||
|
||||
### Install the Shoelace package
|
||||
|
||||
```bash
|
||||
npm install @shoelace-style/shoelace
|
||||
```
|
||||
|
||||
### Import the Default Theme
|
||||
|
||||
Import Shoelace's default theme (stylesheet) in `/resources/css/app.css`:
|
||||
|
||||
```css
|
||||
@import "/node_modules/@shoelace-style/shoelace/dist/themes/light.css";
|
||||
```
|
||||
|
||||
### Import Your Shoelace Components
|
||||
|
||||
Import each Shoelace component you plan to use in `/resources/js/boostrap.js`. Since [Laravel Mix](https://laravel.com/docs/8.x/mix) uses Webpack, use the full path to each component -- as outlined in the [Cherry Picking instructions](https://shoelace.style/getting-started/installation?id=cherry-picking). You can find the full import statement for a component in the *Importing* section of the component's documentation (use the *Bundler* import). Your imports should look similar to:
|
||||
|
||||
```js
|
||||
import "@shoelace-style/shoelace/dist/components/button/button.js";
|
||||
import "@shoelace-style/shoelace/dist/components/dialog/dialog.js";
|
||||
import "@shoelace-style/shoelace/dist/components/drawer/drawer.js";
|
||||
import "@shoelace-style/shoelace/dist/components/menu/menu.js";
|
||||
import "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js";
|
||||
```
|
||||
|
||||
### Set the Base Path
|
||||
|
||||
Add the base path to your Shoelace assets (icons, images, etc.) in `/resources/js/boostrap.js`. The path must point to the same folder where you copy assets to in the next step.
|
||||
|
||||
```js
|
||||
import { setBasePath } from "@shoelace-style/shoelace/dist/utilities/base-path.js";
|
||||
setBasePath("/");
|
||||
```
|
||||
|
||||
Here's an example `/resources/js/boostrap.js` file, after importing and setting the base path and components.
|
||||
|
||||
```js
|
||||
import { setBasePath } from "@shoelace-style/shoelace/dist/utilities/base-path.js";
|
||||
setBasePath("/assets");
|
||||
|
||||
import "@shoelace-style/shoelace/dist/components/button/button.js";
|
||||
import "@shoelace-style/shoelace/dist/components/dialog/dialog.js";
|
||||
import "@shoelace-style/shoelace/dist/components/drawer/drawer.js";
|
||||
import "@shoelace-style/shoelace/dist/components/menu/menu.js";
|
||||
import "@shoelace-style/shoelace/dist/components/menu-item/menu-item.js";
|
||||
```
|
||||
|
||||
|
||||
### Configure Laravel Mix
|
||||
|
||||
[Laravel Mix](https://laravel.com/docs/8.x/mix) is a wrapper around Webpack that simplifies configuration. Mix is used by default for compiling front-end assets in Laravel.
|
||||
|
||||
Modify `webpack.mix.js` to add Shoelace's assets to Webpack's build process:
|
||||
```js
|
||||
mix.js("resources/js/app.js", "public/js")
|
||||
.postCss("resources/css/app.css", "public/css", [])
|
||||
.copy("node_modules/@shoelace-style/shoelace/dist/assets", "public/assets")
|
||||
```
|
||||
|
||||
Consider [extracting vendor libraries](https://laravel.com/docs/8.x/mix#vendor-extraction) to a separate file. This splits frequently updated vendor libraries (like Shoelace) from your front-end application code -- for better long-term caching.
|
||||
Here's an example `webpack.mix.js` file that compiles and splits your JS into `app.js` and `vendor.js` files, and builds an optimized CSS bundle using PostCSS.
|
||||
|
||||
```js
|
||||
mix.js("resources/js/app.js", "public/js")
|
||||
.postCss("resources/css/app.css", "public/css", [])
|
||||
.copy("node_modules/@shoelace-style/shoelace/dist/assets", "public/assets")
|
||||
.extract(); // extracts libraries in node_modules to vendor.js
|
||||
```
|
||||
|
||||
### Compile Front-End Assets
|
||||
|
||||
Run the [Laravel Mix](https://laravel.com/docs/8.x/mix) npm scripts to build your application's CSS and JavaScript code.
|
||||
|
||||
```bash
|
||||
## build a development bundle
|
||||
npm run dev
|
||||
|
||||
## build a production bundle
|
||||
npm run prod
|
||||
```
|
||||
|
||||
### Include Front-End Assets in Your Layout File
|
||||
|
||||
Most full-stack Laravel applications use [layouts](https://laravel.com/docs/8.x/blade#building-layouts) to define the basic structure of a page.
|
||||
After compiling your front-end assets (above), include them in your top-level layouts/templates. The following example uses the [Laravel asset helper](https://laravel.com/docs/8.x/helpers#method-asset) to generate a full URL.
|
||||
|
||||
```html
|
||||
<script defer src="{{ asset('js/manifest.js') }}"></script>
|
||||
<script defer src="{{ asset('js/vendor.js') }}"></script>
|
||||
<script defer src="{{ asset('/js/app.js') }}"></script>
|
||||
|
||||
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
|
||||
```
|
||||
|
||||
Have fun using Shoelace components in your Laravel app!
|
||||
|
||||
@@ -23,9 +23,12 @@ yarn add @shoelace-style/shoelace copy-webpack-plugin
|
||||
The next step is to import Shoelace's default theme (stylesheet) in `app/javascript/stylesheets/application.scss`.
|
||||
|
||||
```css
|
||||
@import '~@shoelace-style/shoelace/dist/themes/base';
|
||||
@import '~@shoelace-style/shoelace/dist/themes/light';
|
||||
@import '~@shoelace-style/shoelace/dist/themes/dark'; // Optional dark theme
|
||||
```
|
||||
|
||||
Fore more details about themes, please refer to [Theme Basics](/getting-started/themes?id=theme-basics).
|
||||
|
||||
### Importing Required Scripts
|
||||
|
||||
After importing the theme, you'll need to import the JavaScript files for Shoelace. Add the following code to `app/javascript/packs/application.js`.
|
||||
|
||||
220
package-lock.json
generated
220
package-lock.json
generated
@@ -1,20 +1,17 @@
|
||||
{
|
||||
"name": "@shoelace-style/shoelace",
|
||||
"version": "2.0.0-beta.48",
|
||||
"version": "2.0.0-beta.58",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@shoelace-style/shoelace",
|
||||
"version": "2.0.0-beta.48",
|
||||
"version": "2.0.0-beta.58",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@popperjs/core": "^2.7.0",
|
||||
"@shoelace-style/animations": "^1.1.0",
|
||||
"color": "^3.1.3",
|
||||
"globby": "^11.0.3",
|
||||
"lit": "^2.0.0-rc.2",
|
||||
"lit-html": "^2.0.0-rc.2",
|
||||
"qr-creator": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -25,10 +22,10 @@
|
||||
"@web/test-runner": "^0.13.5",
|
||||
"@web/test-runner-puppeteer": "^0.10.0",
|
||||
"bluebird": "^3.7.2",
|
||||
"bootstrap-icons": "^1.4.1",
|
||||
"bootstrap-icons": "^1.6.1",
|
||||
"browser-sync": "^2.26.14",
|
||||
"chalk": "^4.1.0",
|
||||
"command-line-args": "^5.1.1",
|
||||
"command-line-args": "^5.2.0",
|
||||
"comment-parser": "^1.1.5",
|
||||
"concurrently": "^5.3.0",
|
||||
"del": "^6.0.0",
|
||||
@@ -36,7 +33,10 @@
|
||||
"esbuild": "^0.12.4",
|
||||
"front-matter": "^4.0.2",
|
||||
"get-port": "^5.1.1",
|
||||
"globby": "^11.0.4",
|
||||
"husky": "^4.3.8",
|
||||
"lit": "^2.0.2",
|
||||
"lunr": "^2.3.9",
|
||||
"mkdirp": "^0.5.5",
|
||||
"plop": "^2.7.4",
|
||||
"prettier": "^2.2.1",
|
||||
@@ -174,9 +174,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@lit/reactive-element": {
|
||||
"version": "1.0.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.0.0-rc.2.tgz",
|
||||
"integrity": "sha512-cujeIl5Ei8FC7UHf4/4Q3bRJOtdTe1vpJV/JEBYCggedmQ+2P8A2oz7eE+Vxi6OJ4nc0X+KZxXnBoH4QrEbmEQ=="
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.0.0.tgz",
|
||||
"integrity": "sha512-Kpgenb8UNFsKCsFhggiVvUkCbcFQSd6N8hffYEEGjz27/4rw3cTSsmP9t3q1EHOAsdum60Wo64HvuZDFpEwexA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@mdn/browser-compat-data": {
|
||||
"version": "3.3.5",
|
||||
@@ -188,6 +189,7 @@
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
|
||||
"integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "2.0.4",
|
||||
"run-parallel": "^1.1.9"
|
||||
@@ -200,6 +202,7 @@
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
|
||||
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
@@ -208,6 +211,7 @@
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
|
||||
"integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.scandir": "2.1.4",
|
||||
"fastq": "^1.6.0"
|
||||
@@ -796,9 +800,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/trusted-types": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz",
|
||||
"integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw=="
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
|
||||
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/uuid": {
|
||||
"version": "8.3.0",
|
||||
@@ -1440,6 +1445,7 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -1659,9 +1665,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/bootstrap-icons": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.5.0.tgz",
|
||||
"integrity": "sha512-44feMc7DE1Ccpsas/1wioN8ewFJNquvi5FewA06wLnqct7CwMdGDVy41ieHaacogzDqLfG8nADIvMNp9e4bfbA==",
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.6.1.tgz",
|
||||
"integrity": "sha512-MNpF89+njCdVJePDRbCd2DrUusqIyNsPlBrdKqBEXAvFZpwb+Gc8k2VlyF2ueiDQn1PoeTSg9UqQNgx8tGqHAA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
@@ -1681,6 +1687,7 @@
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
},
|
||||
@@ -2420,12 +2427,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/command-line-args": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz",
|
||||
"integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz",
|
||||
"integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"array-back": "^3.0.1",
|
||||
"array-back": "^3.1.0",
|
||||
"find-replace": "^3.0.0",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"typical": "^4.0.0"
|
||||
@@ -3378,6 +3385,7 @@
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"path-type": "^4.0.0"
|
||||
},
|
||||
@@ -4066,6 +4074,7 @@
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
|
||||
"integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
@@ -4082,6 +4091,7 @@
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
|
||||
"integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
@@ -4146,6 +4156,7 @@
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
@@ -4615,6 +4626,7 @@
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
@@ -4656,6 +4668,7 @@
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
|
||||
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
@@ -5087,6 +5100,7 @@
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
@@ -5429,6 +5443,7 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -5458,6 +5473,7 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
@@ -5502,6 +5518,7 @@
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
@@ -6129,30 +6146,33 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/lit": {
|
||||
"version": "2.0.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/lit/-/lit-2.0.0-rc.2.tgz",
|
||||
"integrity": "sha512-BOCuoJR04WaTV8UqTKk09cNcQA10Aq2LCcBOiHuF7TzWH5RNDsbCBP5QM9sLBSotGTXbDug/gFO08jq6TbyEtw==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lit/-/lit-2.0.2.tgz",
|
||||
"integrity": "sha512-hKA/1YaSB+P+DvKWuR2q1Xzy/iayhNrJ3aveD0OQ9CKn6wUjsdnF/7LavDOJsKP/K5jzW/kXsuduPgRvTFrFJw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@lit/reactive-element": "^1.0.0-rc.2",
|
||||
"lit-element": "^3.0.0-rc.2",
|
||||
"lit-html": "^2.0.0-rc.3"
|
||||
"@lit/reactive-element": "^1.0.0",
|
||||
"lit-element": "^3.0.0",
|
||||
"lit-html": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lit-element": {
|
||||
"version": "3.0.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.0.0-rc.2.tgz",
|
||||
"integrity": "sha512-2Z7DabJ3b5K+p5073vFjMODoaWqy5PIaI4y6ADKm+fCGc8OnX9fU9dMoUEBZjFpd/bEFR9PBp050tUtBnT9XTQ==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.0.0.tgz",
|
||||
"integrity": "sha512-oPqRhhBBhs+AlI62QLwtWQNU/bNK/h2L1jI3IDroqZubo6XVAkyNy2dW3CRfjij8mrNlY7wULOfyyKKOnfEePA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@lit/reactive-element": "^1.0.0-rc.2",
|
||||
"lit-html": "^2.0.0-rc.3"
|
||||
"@lit/reactive-element": "^1.0.0",
|
||||
"lit-html": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lit-html": {
|
||||
"version": "2.0.0-rc.3",
|
||||
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.0.0-rc.3.tgz",
|
||||
"integrity": "sha512-Y6P8LlAyQuqvzq6l/Nc4z5/P5M/rVLYKQIRxcNwSuGajK0g4kbcBFQqZmgvqKG+ak+dHZjfm2HUw9TF5N/pkCw==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.0.0.tgz",
|
||||
"integrity": "sha512-tJsCapCmc0vtLj6harqd6HfCxnlt/RSkgowtz4SC9dFE3nSL38Tb33I5HMDiyJsRjQZRTgpVsahrnDrR9wg27w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/trusted-types": "^1.0.1"
|
||||
"@types/trusted-types": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/localtunnel": {
|
||||
@@ -6414,6 +6434,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lunr": {
|
||||
"version": "2.3.9",
|
||||
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
||||
@@ -6515,6 +6541,7 @@
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
@@ -6523,6 +6550,7 @@
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
|
||||
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"braces": "^3.0.1",
|
||||
"picomatch": "^2.0.5"
|
||||
@@ -7855,6 +7883,7 @@
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -7878,6 +7907,7 @@
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
|
||||
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
}
|
||||
@@ -8305,7 +8335,8 @@
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz",
|
||||
"integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg=="
|
||||
"integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
@@ -8706,6 +8737,7 @@
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"iojs": ">=1.0.0",
|
||||
"node": ">=0.10.0"
|
||||
@@ -8751,6 +8783,7 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
@@ -9114,6 +9147,7 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -10074,6 +10108,7 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
@@ -11259,9 +11294,10 @@
|
||||
}
|
||||
},
|
||||
"@lit/reactive-element": {
|
||||
"version": "1.0.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.0.0-rc.2.tgz",
|
||||
"integrity": "sha512-cujeIl5Ei8FC7UHf4/4Q3bRJOtdTe1vpJV/JEBYCggedmQ+2P8A2oz7eE+Vxi6OJ4nc0X+KZxXnBoH4QrEbmEQ=="
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.0.0.tgz",
|
||||
"integrity": "sha512-Kpgenb8UNFsKCsFhggiVvUkCbcFQSd6N8hffYEEGjz27/4rw3cTSsmP9t3q1EHOAsdum60Wo64HvuZDFpEwexA==",
|
||||
"dev": true
|
||||
},
|
||||
"@mdn/browser-compat-data": {
|
||||
"version": "3.3.5",
|
||||
@@ -11273,6 +11309,7 @@
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
|
||||
"integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "2.0.4",
|
||||
"run-parallel": "^1.1.9"
|
||||
@@ -11281,12 +11318,14 @@
|
||||
"@nodelib/fs.stat": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
|
||||
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q=="
|
||||
"integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@nodelib/fs.walk": {
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
|
||||
"integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.scandir": "2.1.4",
|
||||
"fastq": "^1.6.0"
|
||||
@@ -11864,9 +11903,10 @@
|
||||
}
|
||||
},
|
||||
"@types/trusted-types": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-1.0.6.tgz",
|
||||
"integrity": "sha512-230RC8sFeHoT6sSUlRO6a8cAnclO06eeiq1QDfiv2FGCLWFvvERWgwIQD4FWqD9A69BN7Lzee4OXwoMVnnsWDw=="
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
|
||||
"integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "8.3.0",
|
||||
@@ -12364,7 +12404,8 @@
|
||||
"array-union": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="
|
||||
"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
|
||||
"dev": true
|
||||
},
|
||||
"array-uniq": {
|
||||
"version": "1.0.3",
|
||||
@@ -12538,9 +12579,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"bootstrap-icons": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.5.0.tgz",
|
||||
"integrity": "sha512-44feMc7DE1Ccpsas/1wioN8ewFJNquvi5FewA06wLnqct7CwMdGDVy41ieHaacogzDqLfG8nADIvMNp9e4bfbA==",
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.6.1.tgz",
|
||||
"integrity": "sha512-MNpF89+njCdVJePDRbCd2DrUusqIyNsPlBrdKqBEXAvFZpwb+Gc8k2VlyF2ueiDQn1PoeTSg9UqQNgx8tGqHAA==",
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
@@ -12557,6 +12598,7 @@
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
@@ -13174,12 +13216,12 @@
|
||||
}
|
||||
},
|
||||
"command-line-args": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.1.1.tgz",
|
||||
"integrity": "sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.0.tgz",
|
||||
"integrity": "sha512-4zqtU1hYsSJzcJBOcNZIbW5Fbk9BkjCp1pZVhQKoRaWL5J7N4XphDLwo8aWwdQpTugxwu+jf9u2ZhkXiqp5Z6A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-back": "^3.0.1",
|
||||
"array-back": "^3.1.0",
|
||||
"find-replace": "^3.0.0",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"typical": "^4.0.0"
|
||||
@@ -13949,6 +13991,7 @@
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-type": "^4.0.0"
|
||||
}
|
||||
@@ -14513,6 +14556,7 @@
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
|
||||
"integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
@@ -14526,6 +14570,7 @@
|
||||
"version": "1.11.0",
|
||||
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
|
||||
"integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
@@ -14575,6 +14620,7 @@
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
@@ -14952,6 +14998,7 @@
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
@@ -14984,6 +15031,7 @@
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
|
||||
"integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "^2.1.0",
|
||||
"dir-glob": "^3.0.1",
|
||||
@@ -15323,7 +15371,8 @@
|
||||
"ignore": {
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw=="
|
||||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"immutable": {
|
||||
"version": "3.8.2",
|
||||
@@ -15569,7 +15618,8 @@
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
@@ -15587,6 +15637,7 @@
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
}
|
||||
@@ -15621,7 +15672,8 @@
|
||||
"is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true
|
||||
},
|
||||
"is-number-like": {
|
||||
"version": "1.0.8",
|
||||
@@ -16121,30 +16173,33 @@
|
||||
"dev": true
|
||||
},
|
||||
"lit": {
|
||||
"version": "2.0.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/lit/-/lit-2.0.0-rc.2.tgz",
|
||||
"integrity": "sha512-BOCuoJR04WaTV8UqTKk09cNcQA10Aq2LCcBOiHuF7TzWH5RNDsbCBP5QM9sLBSotGTXbDug/gFO08jq6TbyEtw==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/lit/-/lit-2.0.2.tgz",
|
||||
"integrity": "sha512-hKA/1YaSB+P+DvKWuR2q1Xzy/iayhNrJ3aveD0OQ9CKn6wUjsdnF/7LavDOJsKP/K5jzW/kXsuduPgRvTFrFJw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@lit/reactive-element": "^1.0.0-rc.2",
|
||||
"lit-element": "^3.0.0-rc.2",
|
||||
"lit-html": "^2.0.0-rc.3"
|
||||
"@lit/reactive-element": "^1.0.0",
|
||||
"lit-element": "^3.0.0",
|
||||
"lit-html": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"lit-element": {
|
||||
"version": "3.0.0-rc.2",
|
||||
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.0.0-rc.2.tgz",
|
||||
"integrity": "sha512-2Z7DabJ3b5K+p5073vFjMODoaWqy5PIaI4y6ADKm+fCGc8OnX9fU9dMoUEBZjFpd/bEFR9PBp050tUtBnT9XTQ==",
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.0.0.tgz",
|
||||
"integrity": "sha512-oPqRhhBBhs+AlI62QLwtWQNU/bNK/h2L1jI3IDroqZubo6XVAkyNy2dW3CRfjij8mrNlY7wULOfyyKKOnfEePA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@lit/reactive-element": "^1.0.0-rc.2",
|
||||
"lit-html": "^2.0.0-rc.3"
|
||||
"@lit/reactive-element": "^1.0.0",
|
||||
"lit-html": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"lit-html": {
|
||||
"version": "2.0.0-rc.3",
|
||||
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.0.0-rc.3.tgz",
|
||||
"integrity": "sha512-Y6P8LlAyQuqvzq6l/Nc4z5/P5M/rVLYKQIRxcNwSuGajK0g4kbcBFQqZmgvqKG+ak+dHZjfm2HUw9TF5N/pkCw==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.0.0.tgz",
|
||||
"integrity": "sha512-tJsCapCmc0vtLj6harqd6HfCxnlt/RSkgowtz4SC9dFE3nSL38Tb33I5HMDiyJsRjQZRTgpVsahrnDrR9wg27w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/trusted-types": "^1.0.1"
|
||||
"@types/trusted-types": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"localtunnel": {
|
||||
@@ -16355,6 +16410,12 @@
|
||||
"integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
|
||||
"dev": true
|
||||
},
|
||||
"lunr": {
|
||||
"version": "2.3.9",
|
||||
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
|
||||
"integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
|
||||
"dev": true
|
||||
},
|
||||
"make-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
||||
@@ -16435,12 +16496,14 @@
|
||||
"merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
|
||||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
|
||||
"dev": true
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
|
||||
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"braces": "^3.0.1",
|
||||
"picomatch": "^2.0.5"
|
||||
@@ -17506,7 +17569,8 @@
|
||||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
},
|
||||
"pathval": {
|
||||
"version": "1.1.1",
|
||||
@@ -17523,7 +17587,8 @@
|
||||
"picomatch": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
|
||||
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
|
||||
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
|
||||
"dev": true
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
@@ -17865,7 +17930,8 @@
|
||||
"queue-microtask": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz",
|
||||
"integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg=="
|
||||
"integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg==",
|
||||
"dev": true
|
||||
},
|
||||
"range-parser": {
|
||||
"version": "1.2.1",
|
||||
@@ -18197,7 +18263,8 @@
|
||||
"reusify": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
|
||||
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
|
||||
"dev": true
|
||||
},
|
||||
"rimraf": {
|
||||
"version": "3.0.2",
|
||||
@@ -18227,6 +18294,7 @@
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
@@ -18541,7 +18609,8 @@
|
||||
"slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"dev": true
|
||||
},
|
||||
"slice-ansi": {
|
||||
"version": "4.0.0",
|
||||
@@ -19355,6 +19424,7 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
|
||||
16
package.json
16
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@shoelace-style/shoelace",
|
||||
"description": "A forward-thinking library of web components.",
|
||||
"version": "2.0.0-beta.48",
|
||||
"version": "2.0.0-beta.58",
|
||||
"homepage": "https://github.com/shoelace-style/shoelace",
|
||||
"author": "Cory LaViska",
|
||||
"license": "MIT",
|
||||
@@ -30,8 +30,8 @@
|
||||
"url": "https://github.com/sponsors/claviska"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node scripts/build.js --dev",
|
||||
"build": "node scripts/build.js",
|
||||
"start": "node scripts/build.js --bundle --serve",
|
||||
"build": "node scripts/build.js --bundle --types --copydir \"docs/dist\"",
|
||||
"prepublishOnly": "npm run build && npm run test",
|
||||
"prettier": "prettier --write --loglevel warn .",
|
||||
"create": "plop --plopfile scripts/plop/plopfile.cjs",
|
||||
@@ -42,9 +42,6 @@
|
||||
"@popperjs/core": "^2.7.0",
|
||||
"@shoelace-style/animations": "^1.1.0",
|
||||
"color": "^3.1.3",
|
||||
"globby": "^11.0.3",
|
||||
"lit": "^2.0.0-rc.2",
|
||||
"lit-html": "^2.0.0-rc.2",
|
||||
"qr-creator": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -55,10 +52,10 @@
|
||||
"@web/test-runner": "^0.13.5",
|
||||
"@web/test-runner-puppeteer": "^0.10.0",
|
||||
"bluebird": "^3.7.2",
|
||||
"bootstrap-icons": "^1.4.1",
|
||||
"bootstrap-icons": "^1.6.1",
|
||||
"browser-sync": "^2.26.14",
|
||||
"chalk": "^4.1.0",
|
||||
"command-line-args": "^5.1.1",
|
||||
"command-line-args": "^5.2.0",
|
||||
"comment-parser": "^1.1.5",
|
||||
"concurrently": "^5.3.0",
|
||||
"del": "^6.0.0",
|
||||
@@ -66,7 +63,10 @@
|
||||
"esbuild": "^0.12.4",
|
||||
"front-matter": "^4.0.2",
|
||||
"get-port": "^5.1.1",
|
||||
"globby": "^11.0.4",
|
||||
"husky": "^4.3.8",
|
||||
"lit": "^2.0.2",
|
||||
"lunr": "^2.3.9",
|
||||
"mkdirp": "^0.5.5",
|
||||
"plop": "^2.7.4",
|
||||
"prettier": "^2.2.1",
|
||||
|
||||
107
scripts/build.js
107
scripts/build.js
@@ -1,6 +1,3 @@
|
||||
//
|
||||
// Builds the project. To spin up a dev server, pass the --serve flag.
|
||||
//
|
||||
import browserSync from 'browser-sync';
|
||||
import chalk from 'chalk';
|
||||
import commandLineArgs from 'command-line-args';
|
||||
@@ -10,51 +7,67 @@ import esbuild from 'esbuild';
|
||||
import fs from 'fs';
|
||||
import getPort from 'get-port';
|
||||
import glob from 'globby';
|
||||
import mkdirp from 'mkdirp';
|
||||
import path from 'path';
|
||||
import { URL } from 'url';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const build = esbuild.build;
|
||||
const bs = browserSync.create();
|
||||
const { dev } = commandLineArgs({ name: 'dev', type: Boolean });
|
||||
|
||||
del.sync('./dist');
|
||||
const { bundle, copydir, dir, serve, types } = commandLineArgs([
|
||||
{ name: 'bundle', type: Boolean },
|
||||
{ name: 'copydir', type: String },
|
||||
{ name: 'dir', type: String, defaultValue: 'dist' },
|
||||
{ name: 'serve', type: Boolean },
|
||||
{ name: 'types', type: Boolean }
|
||||
]);
|
||||
|
||||
try {
|
||||
if (!dev) execSync('tsc', { stdio: 'inherit' }); // for type declarations
|
||||
execSync('node scripts/make-metadata.js', { stdio: 'inherit' });
|
||||
execSync('node scripts/make-vscode-data.js', { stdio: 'inherit' });
|
||||
execSync('node scripts/make-css.js', { stdio: 'inherit' });
|
||||
execSync('node scripts/make-icons.js', { stdio: 'inherit' });
|
||||
} catch (err) {
|
||||
console.error(chalk.red(err));
|
||||
process.exit(1);
|
||||
}
|
||||
const outdir = dir;
|
||||
|
||||
del.sync(outdir);
|
||||
mkdirp.sync(outdir);
|
||||
|
||||
(async () => {
|
||||
const entryPoints = [
|
||||
// The whole shebang dist
|
||||
'./src/shoelace.ts',
|
||||
// Components
|
||||
...(await glob('./src/components/**/!(*.(style|test)).ts')),
|
||||
// Public utilities
|
||||
...(await glob('./src/utilities/**/!(*.(style|test)).ts')),
|
||||
// Theme stylesheets
|
||||
...(await glob('./src/themes/**/!(*.test).ts'))
|
||||
];
|
||||
try {
|
||||
if (types) execSync(`tsc --project . --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
execSync(`node scripts/make-metadata.js --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
execSync(`node scripts/make-search.js --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
execSync(`node scripts/make-vscode-data.js --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
execSync(`node scripts/make-css.js --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
execSync(`node scripts/make-icons.js --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
} catch (err) {
|
||||
console.error(chalk.red(err));
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const buildResult = await esbuild
|
||||
.build({
|
||||
format: 'esm',
|
||||
target: 'es2017',
|
||||
entryPoints,
|
||||
outdir: './dist',
|
||||
entryPoints: [
|
||||
// The whole shebang
|
||||
'./src/shoelace.ts',
|
||||
// Components
|
||||
...(await glob('./src/components/**/!(*.(style|test)).ts')),
|
||||
// Public utilities
|
||||
...(await glob('./src/utilities/**/!(*.(style|test)).ts')),
|
||||
// Theme stylesheets
|
||||
...(await glob('./src/themes/**/!(*.test).ts'))
|
||||
],
|
||||
outdir,
|
||||
chunkNames: 'chunks/[name].[hash]',
|
||||
incremental: dev,
|
||||
incremental: serve,
|
||||
define: {
|
||||
// Popper.js expects this to be set
|
||||
'process.env.NODE_ENV': '"production"'
|
||||
},
|
||||
bundle: true,
|
||||
//
|
||||
// We don't bundle certain dependencies in the unbundled build. This ensures we ship bare module specifiers,
|
||||
// allowing end users to better optimize when using a bundler. (Only packages that ship ESM can be external.)
|
||||
//
|
||||
external: bundle ? undefined : ['@popperjs/core', '@shoelace-style/animations', 'lit', 'qr-creator'],
|
||||
splitting: true,
|
||||
plugins: []
|
||||
})
|
||||
@@ -63,20 +76,23 @@ try {
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Create the docs distribution by copying dist into the docs folder. This is what powers the website. It doesn't need
|
||||
// to exist in dev because Browser Sync routes it virtually.
|
||||
await del('./docs/dist');
|
||||
if (!dev) {
|
||||
await Promise.all([copy('./dist', './docs/dist')]);
|
||||
// Copy the build output to an additional directory
|
||||
if (copydir) {
|
||||
del.sync(copydir);
|
||||
copy(outdir, copydir);
|
||||
}
|
||||
|
||||
console.log(chalk.green('The build has finished! 📦\n'));
|
||||
console.log(chalk.green(`The build has been generated at ${outdir} 📦\n`));
|
||||
|
||||
if (dev) {
|
||||
// Dev server
|
||||
if (serve) {
|
||||
const port = await getPort({
|
||||
port: getPort.makeRange(4000, 4999)
|
||||
});
|
||||
|
||||
// Make sure docs/dist is empty since we're serving it virtually
|
||||
del.sync('docs/dist');
|
||||
|
||||
console.log(chalk.cyan(`Launching the Shoelace dev server at http://localhost:${port}! 🥾\n`));
|
||||
|
||||
// Launch browser sync
|
||||
@@ -87,6 +103,8 @@ try {
|
||||
logPrefix: '[shoelace]',
|
||||
logFileChanges: true,
|
||||
notify: false,
|
||||
single: true,
|
||||
ghostMode: false,
|
||||
server: {
|
||||
baseDir: 'docs',
|
||||
routes: {
|
||||
@@ -101,10 +119,10 @@ try {
|
||||
buildResult
|
||||
// Rebuild and reload
|
||||
.rebuild()
|
||||
.then(async () => {
|
||||
.then(() => {
|
||||
// Rebuild stylesheets when a theme file changes
|
||||
if (/^src\/themes/.test(filename)) {
|
||||
execSync('node scripts/make-css.js', { stdio: 'inherit' });
|
||||
execSync(`node scripts/make-css.js --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
@@ -113,19 +131,22 @@ try {
|
||||
return;
|
||||
}
|
||||
|
||||
execSync('node scripts/make-metadata.js', { stdio: 'inherit' });
|
||||
execSync(`node scripts/make-metadata.js --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
})
|
||||
.then(() => {
|
||||
bs.reload();
|
||||
})
|
||||
.then(() => bs.reload())
|
||||
.catch(err => console.error(chalk.red(err)));
|
||||
});
|
||||
|
||||
// Reload without rebuilding when the docs change
|
||||
bs.watch(['docs/**/*']).on('change', filename => {
|
||||
bs.watch(['docs/**/*.md']).on('change', filename => {
|
||||
console.log(`Docs file changed - ${filename}`);
|
||||
execSync(`node scripts/make-search.js --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
bs.reload();
|
||||
});
|
||||
|
||||
// Cleanup on exit
|
||||
process.on('SIGTERM', () => buildResult.rebuild.dispose());
|
||||
}
|
||||
|
||||
// Cleanup on exit
|
||||
process.on('SIGTERM', () => buildResult.rebuild.dispose());
|
||||
})();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// This script generates stylesheets from all *.styles.ts files in src/themes
|
||||
//
|
||||
import chalk from 'chalk';
|
||||
import commandLineArgs from 'command-line-args';
|
||||
import esbuild from 'esbuild';
|
||||
import fs from 'fs/promises';
|
||||
import glob from 'globby';
|
||||
@@ -10,10 +11,13 @@ import path from 'path';
|
||||
import prettier from 'prettier';
|
||||
import stripComments from 'strip-css-comments';
|
||||
|
||||
const { outdir } = commandLineArgs({ name: 'outdir', type: String });
|
||||
const files = glob.sync('./src/themes/**/*.styles.ts');
|
||||
const outdir = './dist/themes';
|
||||
const themesDir = path.join(outdir, 'themes');
|
||||
|
||||
mkdirp.sync(outdir);
|
||||
console.log('Generating stylesheets');
|
||||
|
||||
mkdirp.sync(themesDir);
|
||||
|
||||
try {
|
||||
files.map(async file => {
|
||||
@@ -30,11 +34,9 @@ try {
|
||||
|
||||
const formattedStyles = prettier.format(stripComments(css), { parser: 'css' });
|
||||
const filename = path.basename(file).replace('.styles.ts', '.css');
|
||||
const outfile = path.join(outdir, filename);
|
||||
const outfile = path.join(themesDir, filename);
|
||||
await fs.writeFile(outfile, formattedStyles, 'utf8');
|
||||
});
|
||||
|
||||
console.log(chalk.cyan(`Successfully generated stylesheets 🎨\n`));
|
||||
} catch (err) {
|
||||
console.error(chalk.red('Error generating styleseheets!'));
|
||||
console.error(err);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
//
|
||||
import Promise from 'bluebird';
|
||||
import chalk from 'chalk';
|
||||
import commandLineArgs from 'command-line-args';
|
||||
import copy from 'recursive-copy';
|
||||
import del from 'del';
|
||||
import download from 'download';
|
||||
@@ -13,7 +14,9 @@ import { stat, readFile, writeFile } from 'fs/promises';
|
||||
import glob from 'globby';
|
||||
import path from 'path';
|
||||
|
||||
const iconDir = './dist/assets/icons';
|
||||
const { outdir } = commandLineArgs({ name: 'outdir', type: String });
|
||||
const iconDir = path.join(outdir, '/assets/icons');
|
||||
|
||||
const iconPackageData = JSON.parse(readFileSync('./node_modules/bootstrap-icons/package.json', 'utf8'));
|
||||
let numIcons = 0;
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
// This script runs the Custom Elements Manifest analyzer to generate custom-elements.json
|
||||
//
|
||||
import chalk from 'chalk';
|
||||
import mkdirp from 'mkdirp';
|
||||
import commandLineArgs from 'command-line-args';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
mkdirp.sync('./dist');
|
||||
const { outdir } = commandLineArgs({ name: 'outdir', type: String });
|
||||
|
||||
// Run the analyzer
|
||||
console.log('Generating component metadata');
|
||||
execSync('cem analyze --litelement --outdir dist', { stdio: 'inherit' });
|
||||
console.log(chalk.cyan(`Successfully generated metadata 🏷\n`));
|
||||
execSync(`cem analyze --litelement --outdir "${outdir}"`, { stdio: 'inherit' });
|
||||
|
||||
100
scripts/make-search.js
Normal file
100
scripts/make-search.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import commandLineArgs from 'command-line-args';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import glob from 'globby';
|
||||
import lunr from 'lunr';
|
||||
import { getAllComponents } from './shared.js';
|
||||
|
||||
const { outdir } = commandLineArgs({ name: 'outdir', type: String });
|
||||
const metadata = JSON.parse(fs.readFileSync(path.join(outdir, 'custom-elements.json'), 'utf8'));
|
||||
|
||||
console.log('Generating search index for documentation');
|
||||
|
||||
(async () => {
|
||||
function getHeadings(markdown, maxLevel = 6) {
|
||||
const headings = [];
|
||||
const lines = markdown.split('\n');
|
||||
|
||||
lines.map(line => {
|
||||
if (line.startsWith('#')) {
|
||||
const level = line.match(/^(#+)/)[0].length;
|
||||
const content = line.replace(/^#+/, '');
|
||||
|
||||
if (level <= maxLevel) {
|
||||
headings.push({ level, content });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return headings;
|
||||
}
|
||||
|
||||
function getMembers(markdown) {
|
||||
const members = [];
|
||||
const headers = markdown.match(/\[component-header:([a-z-]+)\]/g);
|
||||
|
||||
if (!headers) {
|
||||
return '';
|
||||
}
|
||||
|
||||
headers.map(header => {
|
||||
const tagName = header.match(/\[component-header:([a-z-]+)\]/)[1];
|
||||
const component = getAllComponents(metadata).find(component => component.tagName === tagName);
|
||||
|
||||
if (component) {
|
||||
const fields = ['members', 'cssProperties', 'cssParts', 'slots', 'events'];
|
||||
|
||||
fields.map(field => {
|
||||
if (component[field]) {
|
||||
component[field].map(entry => {
|
||||
if (entry.name) members.push(entry.name);
|
||||
if (entry.description) members.push(entry.description);
|
||||
if (entry.attribute) members.push(entry.attribute);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return members.join(' ');
|
||||
}
|
||||
|
||||
const files = await glob('./docs/**/*.md');
|
||||
const map = {};
|
||||
const searchIndex = lunr(function () {
|
||||
// The search index uses these field names extensively, so shortening them can save some serious bytes. The initial
|
||||
// index file went from 468 KB => 401 KB by using single-character names!
|
||||
this.ref('id'); // id
|
||||
this.field('t', { boost: 10 }); // title
|
||||
this.field('h', { boost: 5 }); // headings
|
||||
this.field('m', { boost: 2 }); // members (props, methods, events, etc.)
|
||||
this.field('c'); // content
|
||||
|
||||
files.map((file, index) => {
|
||||
const relativePath = path.relative('./docs', file).replace(/\\/g, '/');
|
||||
const relativePathNoExtension = relativePath.split('.').slice(0, -1).join('.');
|
||||
const url = relativePath.replace(/\.md$/, '');
|
||||
const filename = path.basename(file);
|
||||
// Ignore certain directories and files
|
||||
if (relativePath.startsWith('assets/') || relativePath.startsWith('dist/') || filename === '_sidebar.md') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(file, 'utf8');
|
||||
const allHeadings = getHeadings(content, 4);
|
||||
const title = allHeadings.find(heading => heading.level === 1)?.content || '';
|
||||
const headings = allHeadings
|
||||
.filter(heading => heading.level > 1)
|
||||
.map(heading => heading.content)
|
||||
.concat([relativePathNoExtension])
|
||||
.join(' ');
|
||||
const members = getMembers(content);
|
||||
|
||||
this.add({ id: index, t: title, h: headings, m: members, c: content });
|
||||
|
||||
map[index] = { title, url };
|
||||
});
|
||||
});
|
||||
|
||||
fs.writeFileSync('./docs/search.json', JSON.stringify({ searchIndex, map }), 'utf8');
|
||||
})();
|
||||
@@ -4,31 +4,17 @@
|
||||
// You must generate dist/custom-elements.json before running this script.
|
||||
//
|
||||
import chalk from 'chalk';
|
||||
import commandLineArgs from 'command-line-args';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { getAllComponents } from './shared.js';
|
||||
|
||||
const metadata = JSON.parse(fs.readFileSync('./dist/custom-elements.json', 'utf8'));
|
||||
|
||||
function getAllComponents() {
|
||||
const allComponents = [];
|
||||
|
||||
metadata.modules.map(module => {
|
||||
module.declarations?.map(declaration => {
|
||||
if (declaration.customElement) {
|
||||
const component = declaration;
|
||||
|
||||
if (component) {
|
||||
allComponents.push(component);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return allComponents;
|
||||
}
|
||||
const { outdir } = commandLineArgs({ name: 'outdir', type: String });
|
||||
const metadata = JSON.parse(fs.readFileSync(path.join(outdir, 'custom-elements.json'), 'utf8'));
|
||||
|
||||
console.log('Generating custom data for VS Code');
|
||||
|
||||
const components = getAllComponents();
|
||||
const components = getAllComponents(metadata);
|
||||
const vscode = { tags: [] };
|
||||
|
||||
components.map(component => {
|
||||
@@ -70,6 +56,4 @@ components.map(component => {
|
||||
vscode.tags.push({ name, attributes });
|
||||
});
|
||||
|
||||
fs.writeFileSync('./dist/vscode.html-custom-data.json', JSON.stringify(vscode, null, 2), 'utf8');
|
||||
|
||||
console.log(chalk.cyan(`Successfully generated custom data for VS Code 🔮\n`));
|
||||
fs.writeFileSync(path.join(outdir, 'vscode.html-custom-data.json'), JSON.stringify(vscode, null, 2), 'utf8');
|
||||
|
||||
17
scripts/shared.js
Normal file
17
scripts/shared.js
Normal file
@@ -0,0 +1,17 @@
|
||||
export function getAllComponents(metadata) {
|
||||
const allComponents = [];
|
||||
|
||||
metadata.modules.map(module => {
|
||||
module.declarations?.map(declaration => {
|
||||
if (declaration.customElement) {
|
||||
const component = declaration;
|
||||
|
||||
if (component) {
|
||||
allComponents.push(component);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return allComponents;
|
||||
}
|
||||
@@ -15,9 +15,9 @@ export default css`
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
background-color: rgb(var(--sl-color-neutral-1000));
|
||||
border: solid 1px rgb(var(--sl-color-neutral-200));
|
||||
border-top-width: 3px;
|
||||
background-color: rgb(var(--sl-surface-base-alt));
|
||||
border: solid var(--sl-panel-border-width) rgb(var(--sl-panel-border-color));
|
||||
border-top-width: calc(var(--sl-panel-border-width) * 3);
|
||||
border-radius: var(--sl-border-radius-medium);
|
||||
box-shadow: var(--box-shadow);
|
||||
font-family: var(--sl-font-sans);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, property, query } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit-html/directives/class-map';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { animateTo, stopAnimations } from '../../internal/animate';
|
||||
import { emit } from '../../internal/event';
|
||||
import { watch } from '../../internal/watch';
|
||||
@@ -22,9 +22,9 @@ const toastStack = Object.assign(document.createElement('div'), { className: 'sl
|
||||
* @slot icon - An icon to show in the alert.
|
||||
*
|
||||
* @event sl-show - Emitted when the alert opens.
|
||||
* @event sl-after-show - Emitted after the alert opens and all transitions are complete.
|
||||
* @event sl-after-show - Emitted after the alert opens and all animations are complete.
|
||||
* @event sl-hide - Emitted when the alert closes.
|
||||
* @event sl-after-hide - Emitted after the alert closes and all transitions are complete.
|
||||
* @event sl-after-hide - Emitted after the alert closes and all animations are complete.
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart icon - The container that wraps the alert icon.
|
||||
|
||||
52
src/components/animated-image/animated-image.styles.ts
Normal file
52
src/components/animated-image/animated-image.styles.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { css } from 'lit';
|
||||
import componentStyles from '../../styles/component.styles';
|
||||
|
||||
export default css`
|
||||
${componentStyles}
|
||||
|
||||
:host {
|
||||
--control-box-size: 2.5rem;
|
||||
--icon-size: calc(var(--control-box-size) * 0.625);
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
img[aria-hidden='true'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.animated-image__control-box {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
top: calc(50% - var(--control-box-size) / 2);
|
||||
right: calc(50% - var(--control-box-size) / 2);
|
||||
width: var(--control-box-size);
|
||||
height: var(--control-box-size);
|
||||
font-size: var(--icon-size);
|
||||
background: none;
|
||||
border: none;
|
||||
background-color: rgb(var(--sl-color-neutral-1000) / 50%);
|
||||
border-radius: var(--sl-border-radius-circle);
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
pointer-events: none;
|
||||
transition: var(--sl-transition-fast) opacity;
|
||||
}
|
||||
|
||||
:host([play]:hover) .animated-image__control-box {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
:host([play]:not(:hover)) .animated-image__control-box {
|
||||
opacity: 0;
|
||||
}
|
||||
`;
|
||||
13
src/components/animated-image/animated-image.test.ts
Normal file
13
src/components/animated-image/animated-image.test.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { expect, fixture, html, waitUntil } from '@open-wc/testing';
|
||||
// import sinon from 'sinon';
|
||||
|
||||
import '../../../dist/shoelace.js';
|
||||
import type SlAnimatedImage from './animated-image';
|
||||
|
||||
describe('<sl-animated-image>', () => {
|
||||
it('should render a component', async () => {
|
||||
const el = await fixture(html` <sl-animated-image></sl-animated-image> `);
|
||||
|
||||
expect(el).to.exist;
|
||||
});
|
||||
});
|
||||
120
src/components/animated-image/animated-image.ts
Normal file
120
src/components/animated-image/animated-image.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, property, query, state } from 'lit/decorators.js';
|
||||
import { watch } from '../../internal/watch';
|
||||
import { emit } from '../../internal/event';
|
||||
import styles from './animated-image.styles';
|
||||
|
||||
import '../icon/icon';
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
* @status experimental
|
||||
*
|
||||
* @dependency sl-icon
|
||||
*
|
||||
* @event sl-load - Emitted when the image loads successfully.
|
||||
* @event sl-error - Emitted when the image fails to load.
|
||||
*
|
||||
* @part - control-box - The container that surrounds the pause/play icons and provides their background.
|
||||
* @part - play-icon - The icon to use for the play button.
|
||||
* @part - pause-icon - The icon to use for the pause button.
|
||||
*
|
||||
* @cssproperty --control-box-size - The size of the icon box.
|
||||
* @cssproperty --icon-size - The size of the play/pause icons.
|
||||
*/
|
||||
@customElement('sl-animated-image')
|
||||
export default class SlAnimatedImage extends LitElement {
|
||||
static styles = styles;
|
||||
|
||||
@state() frozenFrame: string;
|
||||
@state() isLoaded = false;
|
||||
|
||||
@query('.animated-image__animated') animatedImage: HTMLImageElement;
|
||||
|
||||
/** The image's src attribute. */
|
||||
@property() src: string;
|
||||
|
||||
/** The image's alt attribute. */
|
||||
@property() alt: string;
|
||||
|
||||
/** When set, the image will animate. Otherwise, it will be paused. */
|
||||
@property({ type: Boolean, reflect: true }) play: boolean;
|
||||
|
||||
handleClick() {
|
||||
this.play = !this.play;
|
||||
}
|
||||
|
||||
handleLoad() {
|
||||
const canvas = document.createElement('canvas');
|
||||
const { width, height } = this.animatedImage;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
canvas.getContext('2d')!.drawImage(this.animatedImage, 0, 0, width, height);
|
||||
this.frozenFrame = canvas.toDataURL('image/gif');
|
||||
|
||||
if (!this.isLoaded) {
|
||||
emit(this, 'sl-load');
|
||||
this.isLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
handleError() {
|
||||
emit(this, 'sl-error');
|
||||
}
|
||||
|
||||
@watch('play')
|
||||
async handlePlayChange() {
|
||||
// When the animation starts playing, reset the src so it plays from the beginning. Since the src is cached, this
|
||||
// won't trigger another request.
|
||||
if (this.play) {
|
||||
this.animatedImage.src = '';
|
||||
this.animatedImage.src = this.src;
|
||||
}
|
||||
}
|
||||
|
||||
@watch('src')
|
||||
handleSrcChange() {
|
||||
this.isLoaded = false;
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="animated-image">
|
||||
<img
|
||||
class="animated-image__animated"
|
||||
src=${this.src}
|
||||
alt=${this.alt}
|
||||
crossorigin="anonymous"
|
||||
aria-hidden=${this.play ? 'false' : 'true'}
|
||||
@click=${this.handleClick}
|
||||
@load=${this.handleLoad}
|
||||
@error=${this.handleError}
|
||||
/>
|
||||
|
||||
${this.isLoaded
|
||||
? html`
|
||||
<img
|
||||
class="animated-image__frozen"
|
||||
src=${this.frozenFrame}
|
||||
alt=${this.alt}
|
||||
aria-hidden=${this.play ? 'true' : 'false'}
|
||||
@click=${this.handleClick}
|
||||
/>
|
||||
|
||||
<div part="control-box" class="animated-image__control-box">
|
||||
${this.play
|
||||
? html`<sl-icon part="pause-icon" name="pause-fill" library="system"></sl-icon>`
|
||||
: html`<sl-icon part="play-icon" name="play-fill" library="system"></sl-icon>`}
|
||||
</div>
|
||||
`
|
||||
: ''}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'sl-animated-image': SlAnimatedImage;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ export default css`
|
||||
font-family: var(--sl-font-sans);
|
||||
font-size: calc(var(--size) * 0.5);
|
||||
font-weight: var(--sl-font-weight-normal);
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
vertical-align: middle;
|
||||
|
||||
126
src/components/avatar/avatar.test.ts
Normal file
126
src/components/avatar/avatar.test.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
|
||||
import '../../../dist/shoelace.js';
|
||||
import type SlAvatar from './avatar';
|
||||
|
||||
describe('<sl-avatar>', () => {
|
||||
let el: SlAvatar;
|
||||
|
||||
describe('when provided no parameters', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlAvatar>(html` <sl-avatar></sl-avatar> `);
|
||||
});
|
||||
|
||||
it('passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should default to circle styling', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
expect(el.getAttribute('shape')).to.eq('circle');
|
||||
expect(part.classList.value.trim()).to.eq('avatar avatar--circle');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an image and alt parameter', async () => {
|
||||
const image =
|
||||
'https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80';
|
||||
const alt = 'Gray tabby kitten looking down';
|
||||
before(async () => {
|
||||
el = await fixture<SlAvatar>(html`<sl-avatar image="${image}" alt="${alt}"></sl-avatar>`);
|
||||
});
|
||||
|
||||
it('passes accessibility test', async () => {
|
||||
/**
|
||||
* The image element itself is ancillary, because it's parent container contains the
|
||||
* aria-label which dictates what "sl-avatar" is. This also implies that alt text will
|
||||
* resolve to "" when not provided and ignored by readers. This is why we use alt="" on
|
||||
* the image element to pass accessibility.
|
||||
* https://html.spec.whatwg.org/multipage/images.html#ancillary-images
|
||||
*/
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('renders "image" part, with src and a role of presentation', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="image"]') as HTMLImageElement;
|
||||
|
||||
expect(part.getAttribute('src')).to.eq(image);
|
||||
});
|
||||
|
||||
it('renders the alt attribute in the "base" part', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
|
||||
expect(part.getAttribute('aria-label')).to.eq(alt);
|
||||
});
|
||||
|
||||
describe('when an error occurs when attempting to load the image', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlAvatar>(
|
||||
html`<sl-avatar image="data:text/plain;not-an-image-url" alt="${alt}"></sl-avatar>`
|
||||
);
|
||||
});
|
||||
|
||||
it('does not render the "image" part', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="image"]') as HTMLImageElement;
|
||||
|
||||
expect(part).not.to.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided initials parameter', async () => {
|
||||
const initials = 'SL';
|
||||
before(async () => {
|
||||
el = await fixture<SlAvatar>(html`<sl-avatar initials="${initials}"></sl-avatar>`);
|
||||
});
|
||||
|
||||
it('passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('renders "initials" part, with initials as the text node', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="initials"]') as HTMLImageElement;
|
||||
|
||||
expect(part.innerText).to.eq(initials);
|
||||
});
|
||||
});
|
||||
|
||||
['square', 'rounded', 'circle'].forEach(shape => {
|
||||
describe(`when passed a shape attribute ${shape}`, () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlAvatar>(html`<sl-avatar shape="${shape}"></sl-avatar>`);
|
||||
});
|
||||
|
||||
it('passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('appends the appropriate class on the "base" part', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
|
||||
expect(el.getAttribute('shape')).to.eq(shape);
|
||||
expect(part.classList.value.trim()).to.eq(`avatar avatar--${shape}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when passed a <span>, on slot "icon"', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlAvatar>(html`<sl-avatar><span slot="icon">random content</span></sl-avatar>`);
|
||||
});
|
||||
|
||||
it('passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should accept as an assigned child in the shadow root', async () => {
|
||||
const slot = <HTMLSlotElement>el.shadowRoot.querySelector('slot[name=icon]');
|
||||
const childNodes = slot.assignedNodes({ flatten: true });
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
|
||||
const span = <HTMLElement>childNodes[0];
|
||||
expect(span.innerHTML).to.eq('random content');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit-html/directives/class-map';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import styles from './avatar.styles';
|
||||
|
||||
import '../icon/icon';
|
||||
@@ -61,7 +61,13 @@ export default class SlAvatar extends LitElement {
|
||||
`}
|
||||
${this.image && !this.hasError
|
||||
? html`
|
||||
<img part="image" class="avatar__image" src="${this.image}" @error="${() => (this.hasError = true)}" />
|
||||
<img
|
||||
part="image"
|
||||
class="avatar__image"
|
||||
src="${this.image}"
|
||||
alt=""
|
||||
@error="${() => (this.hasError = true)}"
|
||||
/>
|
||||
`
|
||||
: ''}
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,7 @@ export default css`
|
||||
letter-spacing: var(--sl-letter-spacing-normal);
|
||||
line-height: 1;
|
||||
border-radius: var(--sl-border-radius-small);
|
||||
border: solid 1px rgb(var(--sl-color-neutral-0));
|
||||
white-space: nowrap;
|
||||
padding: 3px 6px;
|
||||
user-select: none;
|
||||
@@ -26,27 +27,27 @@ export default css`
|
||||
/* Type modifiers */
|
||||
.badge--primary {
|
||||
background-color: rgb(var(--sl-color-primary-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.badge--success {
|
||||
background-color: rgb(var(--sl-color-success-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.badge--neutral {
|
||||
background-color: rgb(var(--sl-color-neutral-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.badge--warning {
|
||||
background-color: rgb(var(--sl-color-warning-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.badge--danger {
|
||||
background-color: rgb(var(--sl-color-danger-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Pill modifier */
|
||||
|
||||
77
src/components/badge/badge.test.ts
Normal file
77
src/components/badge/badge.test.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
|
||||
import '../../../dist/shoelace.js';
|
||||
import type SlBadge from './badge';
|
||||
|
||||
describe('<sl-badge>', () => {
|
||||
let el: SlBadge;
|
||||
|
||||
describe('when provided no parameters', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBadge>(html` <sl-badge>Badge</sl-badge> `);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test, with a role of status on the base part.', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
expect(part.getAttribute('role')).to.eq('status');
|
||||
});
|
||||
|
||||
it('should render the child content provided', async () => {
|
||||
expect(el.innerText).to.eq('Badge');
|
||||
});
|
||||
|
||||
it('should default to square styling, with the primary color', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
expect(part.classList.value.trim()).to.eq('badge badge--primary');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided a pill parameter', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBadge>(html` <sl-badge pill>Badge</sl-badge> `);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should append the pill class to the classlist to render a pill', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
expect(part.classList.value.trim()).to.eq('badge badge--primary badge--pill');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided a pulse parameter', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBadge>(html` <sl-badge pulse>Badge</sl-badge> `);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should append the pulse class to the classlist to render a pulse', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
expect(part.classList.value.trim()).to.eq('badge badge--primary badge--pulse');
|
||||
});
|
||||
});
|
||||
|
||||
['primary', 'success', 'neutral', 'warning', 'danger'].forEach(type => {
|
||||
describe(`when passed a type attribute ${type}`, () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBadge>(html`<sl-badge type="${type as any}">Badge</sl-badge>`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should default to square styling, with the primary color', async () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
expect(part.classList.value.trim()).to.eq(`badge badge--${type}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit-html/directives/class-map';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import styles from './badge.styles';
|
||||
|
||||
/**
|
||||
|
||||
85
src/components/breadcrumb-item/breadcrumb-item.styles.ts
Normal file
85
src/components/breadcrumb-item/breadcrumb-item.styles.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import { css } from 'lit';
|
||||
import componentStyles from '../../styles/component.styles';
|
||||
import { focusVisibleSelector } from '../../internal/focus-visible';
|
||||
|
||||
export default css`
|
||||
${componentStyles}
|
||||
|
||||
:host {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.breadcrumb-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-family: var(--sl-font-sans);
|
||||
font-size: var(--sl-font-size-small);
|
||||
font-weight: var(--sl-font-weight-semibold);
|
||||
color: rgb(var(--sl-color-neutral-600));
|
||||
line-height: var(--sl-line-height-normal);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.breadcrumb-item__label {
|
||||
display: inline-block;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
line-height: inherit;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
background: none;
|
||||
border: none;
|
||||
border-radius: var(--sl-border-radius-medium);
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
transition: var(--sl-transition-fast) --color;
|
||||
}
|
||||
|
||||
:host(:not(:last-of-type)) .breadcrumb-item__label {
|
||||
color: rgb(var(--sl-color-primary-600));
|
||||
}
|
||||
|
||||
:host(:not(:last-of-type)) .breadcrumb-item__label:hover {
|
||||
color: rgb(var(--sl-color-primary-500));
|
||||
}
|
||||
|
||||
:host(:not(:last-of-type)) .breadcrumb-item__label:active {
|
||||
color: rgb(var(--sl-color-primary-600));
|
||||
}
|
||||
|
||||
.breadcrumb-item__label${focusVisibleSelector} {
|
||||
outline: none;
|
||||
box-shadow: var(--sl-focus-ring);
|
||||
}
|
||||
|
||||
.breadcrumb-item__prefix,
|
||||
.breadcrumb-item__suffix {
|
||||
display: none;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.breadcrumb-item--has-prefix .breadcrumb-item__prefix {
|
||||
display: inline-flex;
|
||||
margin-right: var(--sl-spacing-x-small);
|
||||
}
|
||||
|
||||
.breadcrumb-item--has-suffix .breadcrumb-item__suffix {
|
||||
display: inline-flex;
|
||||
margin-left: var(--sl-spacing-x-small);
|
||||
}
|
||||
|
||||
:host(:last-of-type) .breadcrumb-item__separator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.breadcrumb-item__separator {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin: 0 var(--sl-spacing-x-small);
|
||||
user-select: none;
|
||||
}
|
||||
`;
|
||||
160
src/components/breadcrumb-item/breadcrumb-item.test.ts
Normal file
160
src/components/breadcrumb-item/breadcrumb-item.test.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
|
||||
import '../../../dist/shoelace.js';
|
||||
import type SlBreadcrumbItem from './breadcrumb-item';
|
||||
|
||||
describe('<sl-breadcrumb-item>', () => {
|
||||
let el: SlBreadcrumbItem;
|
||||
|
||||
describe('when not provided a href attribute', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumbItem>(html` <sl-breadcrumb-item>Home</sl-breadcrumb-item> `);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should hide the seperator from screen readers', async () => {
|
||||
const separator: HTMLSpanElement = el.shadowRoot.querySelector('[part="separator"]');
|
||||
expect(separator).attribute('aria-hidden', 'true');
|
||||
});
|
||||
|
||||
it('should render a HTMLButtonElement as the part "label", with a set type "button"', () => {
|
||||
const button: HTMLButtonElement = el.shadowRoot.querySelector('[part="label"]');
|
||||
expect(button).to.exist;
|
||||
expect(button).attribute('type', 'button');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided a href attribute', async () => {
|
||||
describe('and no target', () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumbItem>(html`
|
||||
<sl-breadcrumb-item href="https://jsonplaceholder.typicode.com/">Home</sl-breadcrumb-item>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should render a HTMLAnchorElement as the part "label", with the supplied href value', () => {
|
||||
const hyperlink: HTMLAnchorElement = el.shadowRoot.querySelector('[part="label"]');
|
||||
expect(hyperlink).attribute('href', 'https://jsonplaceholder.typicode.com/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('and target, without rel', () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumbItem>(html`
|
||||
<sl-breadcrumb-item href="https://jsonplaceholder.typicode.com/" target="_blank">Help</sl-breadcrumb-item>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
describe('should render a HTMLAnchorElement as the part "label"', () => {
|
||||
let hyperlink: HTMLAnchorElement;
|
||||
|
||||
before(() => {
|
||||
hyperlink = el.shadowRoot.querySelector('[part="label"]');
|
||||
});
|
||||
|
||||
it('should use the supplied href value, as the href attribute value', () => {
|
||||
expect(hyperlink).attribute('href', 'https://jsonplaceholder.typicode.com/');
|
||||
});
|
||||
|
||||
it('should default rel attribute to "noreferrer noopener"', () => {
|
||||
expect(hyperlink).attribute('rel', 'noreferrer noopener');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('and target, with rel', () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumbItem>(html`
|
||||
<sl-breadcrumb-item href="https://jsonplaceholder.typicode.com/" target="_blank" rel="alternate"
|
||||
>Help</sl-breadcrumb-item
|
||||
>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
describe('should render a HTMLAnchorElement', () => {
|
||||
let hyperlink: HTMLAnchorElement;
|
||||
|
||||
before(() => {
|
||||
hyperlink = el.shadowRoot.querySelector('a');
|
||||
});
|
||||
|
||||
it('should use the supplied href value, as the href attribute value', () => {
|
||||
expect(hyperlink).attribute('href', 'https://jsonplaceholder.typicode.com/');
|
||||
});
|
||||
|
||||
it('should use the supplied rel value, as the rel attribute value', () => {
|
||||
expect(hyperlink).attribute('rel', 'alternate');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an element in the slot "prefix" to support prefix icons', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumbItem>(html`
|
||||
<sl-breadcrumb-item>
|
||||
<span class="prefix-example" slot="prefix">/</span>
|
||||
Home
|
||||
</sl-breadcrumb-item>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should accept as an assigned child in the shadow root', () => {
|
||||
const slot = <HTMLSlotElement>el.shadowRoot.querySelector('slot[name=prefix]');
|
||||
const childNodes = slot.assignedNodes({ flatten: true });
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should append class "breadcrumb-item--has-prefix" to "base" part', () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
expect(part.classList.value).to.equal('breadcrumb-item breadcrumb-item--has-prefix');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an element in the slot "suffix" to support suffix icons', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumbItem>(html`
|
||||
<sl-breadcrumb-item>
|
||||
<span class="prefix-example" slot="suffix">/</span>
|
||||
Security
|
||||
</sl-breadcrumb-item>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should accept as an assigned child in the shadow root', () => {
|
||||
const slot = <HTMLSlotElement>el.shadowRoot.querySelector('slot[name=suffix]');
|
||||
const childNodes = slot.assignedNodes({ flatten: true });
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should append class "breadcrumb-item--has-suffix" to "base" part', () => {
|
||||
const part = el.shadowRoot?.querySelector('[part="base"]') as HTMLElement;
|
||||
expect(part.classList.value).to.equal('breadcrumb-item breadcrumb-item--has-suffix');
|
||||
});
|
||||
});
|
||||
});
|
||||
98
src/components/breadcrumb-item/breadcrumb-item.ts
Normal file
98
src/components/breadcrumb-item/breadcrumb-item.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { hasSlot } from '../../internal/slot';
|
||||
import styles from './breadcrumb-item.styles';
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
* @status stable
|
||||
*
|
||||
* @slot - The breadcrumb item's label.
|
||||
* @slot prefix - An optional prefix, usually an icon or icon button.
|
||||
* @slot suffix - An optional suffix, usually an icon or icon button.
|
||||
* @slot separator - The separator to use for the breadcrumb item. This will only change the separator for this item. If
|
||||
* you want to change it for all items in the group, set the separator on `<sl-breadcrumb>` instead.
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
* @csspart label - The breadcrumb item's label.
|
||||
* @csspart prefix - The container that wraps the prefix slot.
|
||||
* @csspart suffix - The container that wraps the suffix slot.
|
||||
* @csspart separator - The container that wraps the separator slot.
|
||||
*/
|
||||
@customElement('sl-breadcrumb-item')
|
||||
export default class SlBreadcrumbItem extends LitElement {
|
||||
static styles = styles;
|
||||
|
||||
@state() hasPrefix = false;
|
||||
@state() hasSuffix = false;
|
||||
|
||||
/**
|
||||
* Optional URL to direct the user to when the breadcrumb item is activated. When set, a link will be rendered
|
||||
* internally. When unset, a button will be rendered instead.
|
||||
*/
|
||||
@property() href: string;
|
||||
|
||||
/** Tells the browser where to open the link. Only used when `href` is set. */
|
||||
@property() target: '_blank' | '_parent' | '_self' | '_top';
|
||||
|
||||
/** The `rel` attribute to use on the link. Only used when `href` is set. */
|
||||
@property() rel: string = 'noreferrer noopener';
|
||||
|
||||
handleSlotChange() {
|
||||
this.hasPrefix = hasSlot(this, 'prefix');
|
||||
this.hasSuffix = hasSlot(this, 'suffix');
|
||||
}
|
||||
|
||||
render() {
|
||||
const isLink = this.href ? true : false;
|
||||
|
||||
return html`
|
||||
<div
|
||||
part="base"
|
||||
class=${classMap({
|
||||
'breadcrumb-item': true,
|
||||
'breadcrumb-item--has-prefix': this.hasPrefix,
|
||||
'breadcrumb-item--has-suffix': this.hasSuffix
|
||||
})}
|
||||
>
|
||||
<span part="prefix" class="breadcrumb-item__prefix">
|
||||
<slot name="prefix" @slotchange=${this.handleSlotChange}></slot>
|
||||
</span>
|
||||
|
||||
${isLink
|
||||
? html`
|
||||
<a
|
||||
part="label"
|
||||
class="breadcrumb-item__label breadcrumb-item__label--link"
|
||||
href="${this.href}"
|
||||
target="${this.target}"
|
||||
rel=${ifDefined(this.target ? this.rel : undefined)}
|
||||
>
|
||||
<slot></slot>
|
||||
</a>
|
||||
`
|
||||
: html`
|
||||
<button part="label" type="button" class="breadcrumb-item__label breadcrumb-item__label--button">
|
||||
<slot></slot>
|
||||
</button>
|
||||
`}
|
||||
|
||||
<span part="suffix" class="breadcrumb-item__suffix">
|
||||
<slot name="suffix" @slotchange=${this.handleSlotChange}></slot>
|
||||
</span>
|
||||
|
||||
<span part="separator" class="breadcrumb-item__separator" aria-hidden="true">
|
||||
<slot name="separator"></slot>
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'sl-breadcrumb-item': SlBreadcrumbItem;
|
||||
}
|
||||
}
|
||||
12
src/components/breadcrumb/breadcrumb.styles.ts
Normal file
12
src/components/breadcrumb/breadcrumb.styles.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { css } from 'lit';
|
||||
import componentStyles from '../../styles/component.styles';
|
||||
|
||||
export default css`
|
||||
${componentStyles}
|
||||
|
||||
.breadcrumb {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
`;
|
||||
104
src/components/breadcrumb/breadcrumb.test.ts
Normal file
104
src/components/breadcrumb/breadcrumb.test.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
|
||||
import '../../../dist/shoelace.js';
|
||||
import type SlBreadcrumb from './breadcrumb';
|
||||
|
||||
describe('<sl-breadcrumb>', () => {
|
||||
let el: SlBreadcrumb;
|
||||
|
||||
describe('when provided a standard list of el-breadcrumb-item children and no parameters', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumb>(html`
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item>Catalog</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Clothing</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Women's</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Shirts & Tops</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should render sl-icon as separator', async () => {
|
||||
expect(el.querySelectorAll('sl-icon').length).to.eq(4);
|
||||
});
|
||||
|
||||
it('should attach aria-current "page" on the last breadcrumb item.', async () => {
|
||||
const breadcrumbItems = el.querySelectorAll('sl-breadcrumb-item');
|
||||
const lastNode = breadcrumbItems[3];
|
||||
expect(lastNode).attribute('aria-current', 'page');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided a standard list of el-breadcrumb-item children and an element in the slot "seperator" to support Custom Separators', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumb>(html`
|
||||
<sl-breadcrumb>
|
||||
<span class="replacement-separator" slot="separator">/</span>
|
||||
<sl-breadcrumb-item>First</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Second</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Third</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should accept "separator" as an assigned child in the shadow root', async () => {
|
||||
const slot = <HTMLSlotElement>el.shadowRoot.querySelector('slot[name=separator]');
|
||||
const childNodes = slot.assignedNodes({ flatten: true });
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should replace the sl-icon separator with the provided separator', async () => {
|
||||
expect(el.querySelectorAll('.replacement-separator').length).to.eq(4);
|
||||
expect(el.querySelectorAll('sl-icon').length).to.eq(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided a standard list of el-breadcrumb-item children and an element in the slot "prefix" to support prefix icons', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumb>(html`
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item>
|
||||
<span class="prefix-example" slot="prefix">/</span>
|
||||
Home
|
||||
</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>First</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Second</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Third</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided a standard list of el-breadcrumb-item children and an element in the slot "suffix" to support suffix icons', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlBreadcrumb>(html`
|
||||
<sl-breadcrumb>
|
||||
<sl-breadcrumb-item>First</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Second</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>Third</sl-breadcrumb-item>
|
||||
<sl-breadcrumb-item>
|
||||
<span class="prefix-example" slot="suffix">/</span>
|
||||
Security
|
||||
</sl-breadcrumb-item>
|
||||
</sl-breadcrumb>
|
||||
`);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
});
|
||||
});
|
||||
82
src/components/breadcrumb/breadcrumb.ts
Normal file
82
src/components/breadcrumb/breadcrumb.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, property, query } from 'lit/decorators.js';
|
||||
import styles from './breadcrumb.styles';
|
||||
import type SlBreadcrumbItem from '../breadcrumb-item/breadcrumb-item';
|
||||
|
||||
import '../icon/icon';
|
||||
|
||||
/**
|
||||
* @since 2.0
|
||||
* @status stable
|
||||
*
|
||||
* @slot - One or more breadcrumb items to display.
|
||||
* @slot separator - The separator to use between breadcrumb items.
|
||||
*
|
||||
* @dependency sl-icon
|
||||
*
|
||||
* @csspart base - The component's base wrapper.
|
||||
*/
|
||||
@customElement('sl-breadcrumb')
|
||||
export default class SlBreadcrumb extends LitElement {
|
||||
static styles = styles;
|
||||
|
||||
@query('slot') defaultSlot: HTMLSlotElement;
|
||||
@query('slot[name="separator"]') separatorSlot: HTMLSlotElement;
|
||||
|
||||
/**
|
||||
* The label to use for the breadcrumb control. This will not be shown, but it will be announced by screen readers and
|
||||
* other assistive devices.
|
||||
*/
|
||||
@property() label = 'Breadcrumb';
|
||||
|
||||
// Generates a clone of the separator element to use for each breadcrumb item
|
||||
private getSeparator() {
|
||||
const separator = this.separatorSlot.assignedElements({ flatten: true })[0] as HTMLElement;
|
||||
|
||||
// Clone it, remove ids, and slot it
|
||||
const clone = separator.cloneNode(true) as HTMLElement;
|
||||
[clone, ...clone.querySelectorAll('[id]')].map(el => el.removeAttribute('id'));
|
||||
clone.slot = 'separator';
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
handleSlotChange() {
|
||||
const items = [...this.defaultSlot.assignedElements({ flatten: true })].filter(
|
||||
item => item.tagName.toLowerCase() === 'sl-breadcrumb-item'
|
||||
) as SlBreadcrumbItem[];
|
||||
|
||||
items.map((item, index) => {
|
||||
// Append separators to each item if they don't already have one
|
||||
const separator = item.querySelector('[slot="separator"]') as HTMLElement;
|
||||
if (!separator) {
|
||||
item.append(this.getSeparator());
|
||||
}
|
||||
|
||||
// The last breadcrumb item is the "current page"
|
||||
if (index === items.length - 1) {
|
||||
item.setAttribute('aria-current', 'page');
|
||||
} else {
|
||||
item.removeAttribute('aria-current');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<nav part="base" class="breadcrumb" aria-label=${this.label}>
|
||||
<slot @slotchange=${this.handleSlotChange}></slot>
|
||||
</nav>
|
||||
|
||||
<slot name="separator" hidden aria-hidden="true">
|
||||
<sl-icon name="chevron-right" library="system"></sl-icon>
|
||||
</slot>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'sl-breadcrumb': SlBreadcrumb;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { css } from 'lit';
|
||||
import componentStyles from '../../styles/component.styles';
|
||||
import { focusVisibleSelector } from '../../internal/focus-visible';
|
||||
|
||||
export default css`
|
||||
${componentStyles}
|
||||
@@ -37,13 +38,13 @@ export default css`
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.button.button--disabled {
|
||||
.button--disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* When disabled, prevent mouse events from bubbling up */
|
||||
.button.button--disabled * {
|
||||
.button--disabled * {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -68,158 +69,300 @@ export default css`
|
||||
*/
|
||||
|
||||
/* Default */
|
||||
.button.button--default {
|
||||
background-color: rgb(var(--sl-color-neutral-1000));
|
||||
.button--standard.button--default {
|
||||
background-color: rgb(var(--sl-color-neutral-0));
|
||||
border-color: rgb(var(--sl-color-neutral-300));
|
||||
color: rgb(var(--sl-color-neutral-700));
|
||||
}
|
||||
|
||||
.button.button--default:hover:not(.button--disabled) {
|
||||
.button--standard.button--default:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-primary-50));
|
||||
border-color: rgb(var(--sl-color-primary-500));
|
||||
border-color: rgb(var(--sl-color-primary-300));
|
||||
color: rgb(var(--sl-color-primary-700));
|
||||
}
|
||||
|
||||
.button.button--default:focus:not(.button--disabled) {
|
||||
.button--standard.button--default${focusVisibleSelector}:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-primary-50));
|
||||
border-color: rgb(var(--sl-color-primary-500));
|
||||
border-color: rgb(var(--sl-color-primary-400));
|
||||
color: rgb(var(--sl-color-primary-700));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button.button--default:active:not(.button--disabled) {
|
||||
.button--standard.button--default:active:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-primary-100));
|
||||
border-color: rgb(var(--sl-color-primary-500));
|
||||
border-color: rgb(var(--sl-color-primary-400));
|
||||
color: rgb(var(--sl-color-primary-700));
|
||||
}
|
||||
|
||||
/* Primary */
|
||||
.button.button--primary {
|
||||
.button--standard.button--primary {
|
||||
background-color: rgb(var(--sl-color-primary-600));
|
||||
border-color: rgb(var(--sl-color-primary-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--primary:hover:not(.button--disabled) {
|
||||
.button--standard.button--primary:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-primary-500));
|
||||
border-color: rgb(var(--sl-color-primary-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--primary:focus:not(.button--disabled) {
|
||||
.button--standard.button--primary${focusVisibleSelector}:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-primary-500));
|
||||
border-color: rgb(var(--sl-color-primary-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button.button--primary:active:not(.button--disabled) {
|
||||
.button--standard.button--primary:active:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-primary-600));
|
||||
border-color: rgb(var(--sl-color-primary-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Success */
|
||||
.button.button--success {
|
||||
.button--standard.button--success {
|
||||
background-color: rgb(var(--sl-color-success-600));
|
||||
border-color: rgb(var(--sl-color-success-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--success:hover:not(.button--disabled) {
|
||||
.button--standard.button--success:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-success-500));
|
||||
border-color: rgb(var(--sl-color-success-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--success:focus:not(.button--disabled) {
|
||||
.button--standard.button--success${focusVisibleSelector}:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-success-600));
|
||||
border-color: rgb(var(--sl-color-success-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-success-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button.button--success:active:not(.button--disabled) {
|
||||
.button--standard.button--success:active:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-success-600));
|
||||
border-color: rgb(var(--sl-color-success-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Neutral */
|
||||
.button.button--neutral {
|
||||
.button--standard.button--neutral {
|
||||
background-color: rgb(var(--sl-color-neutral-600));
|
||||
border-color: rgb(var(--sl-color-neutral-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--neutral:hover:not(.button--disabled) {
|
||||
.button--standard.button--neutral:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-neutral-500));
|
||||
border-color: rgb(var(--sl-color-neutral-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--neutral:focus:not(.button--disabled) {
|
||||
.button--standard.button--neutral${focusVisibleSelector}:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-neutral-500));
|
||||
border-color: rgb(var(--sl-color-neutral-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-neutral-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button.button--neutral:active:not(.button--disabled) {
|
||||
.button--standard.button--neutral:active:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-neutral-600));
|
||||
border-color: rgb(var(--sl-color-neutral-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Warning */
|
||||
.button.button--warning {
|
||||
.button--standard.button--warning {
|
||||
background-color: rgb(var(--sl-color-warning-600));
|
||||
border-color: rgb(var(--sl-color-warning-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
.button.button--warning:hover:not(.button--disabled) {
|
||||
.button--standard.button--warning:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-warning-500));
|
||||
border-color: rgb(var(--sl-color-warning-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--warning:focus:not(.button--disabled) {
|
||||
.button--standard.button--warning${focusVisibleSelector}:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-warning-500));
|
||||
border-color: rgb(var(--sl-color-warning-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-warning-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button.button--warning:active:not(.button--disabled) {
|
||||
.button--standard.button--warning:active:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-warning-600));
|
||||
border-color: rgb(var(--sl-color-warning-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Danger */
|
||||
.button.button--danger {
|
||||
.button--standard.button--danger {
|
||||
background-color: rgb(var(--sl-color-danger-600));
|
||||
border-color: rgb(var(--sl-color-danger-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--danger:hover:not(.button--disabled) {
|
||||
.button--standard.button--danger:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-danger-500));
|
||||
border-color: rgb(var(--sl-color-danger-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button.button--danger:focus:not(.button--disabled) {
|
||||
.button--standard.button--danger${focusVisibleSelector}:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-danger-500));
|
||||
border-color: rgb(var(--sl-color-danger-500));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-danger-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button.button--danger:active:not(.button--disabled) {
|
||||
.button--standard.button--danger:active:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-danger-600));
|
||||
border-color: rgb(var(--sl-color-danger-600));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Outline buttons
|
||||
*/
|
||||
|
||||
.button--outline {
|
||||
background: none;
|
||||
border: solid 1px;
|
||||
}
|
||||
|
||||
/* Default */
|
||||
.button--outline.button--default {
|
||||
border-color: rgb(var(--sl-color-neutral-300));
|
||||
color: rgb(var(--sl-color-neutral-700));
|
||||
}
|
||||
|
||||
.button--outline.button--default:hover:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-primary-600));
|
||||
background-color: rgb(var(--sl-color-primary-600));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button--outline.button--default${focusVisibleSelector}:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-primary-500));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button--outline.button--default:active:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-primary-700));
|
||||
background-color: rgb(var(--sl-color-primary-700));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Primary */
|
||||
.button--outline.button--primary {
|
||||
border-color: rgb(var(--sl-color-primary-600));
|
||||
color: rgb(var(--sl-color-primary-600));
|
||||
}
|
||||
|
||||
.button--outline.button--primary:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-primary-600));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button--outline.button--primary${focusVisibleSelector}:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-primary-500));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button--outline.button--primary:active:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-primary-700));
|
||||
background-color: rgb(var(--sl-color-primary-700));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Success */
|
||||
.button--outline.button--success {
|
||||
border-color: rgb(var(--sl-color-success-600));
|
||||
color: rgb(var(--sl-color-success-600));
|
||||
}
|
||||
|
||||
.button--outline.button--success:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-success-600));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button--outline.button--success${focusVisibleSelector}:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-success-500));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-success-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button--outline.button--success:active:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-success-700));
|
||||
background-color: rgb(var(--sl-color-success-700));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Neutral */
|
||||
.button--outline.button--neutral {
|
||||
border-color: rgb(var(--sl-color-neutral-600));
|
||||
color: rgb(var(--sl-color-neutral-600));
|
||||
}
|
||||
|
||||
.button--outline.button--neutral:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-neutral-600));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button--outline.button--neutral${focusVisibleSelector}:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-neutral-500));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-neutral-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button--outline.button--neutral:active:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-neutral-700));
|
||||
background-color: rgb(var(--sl-color-neutral-700));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Warning */
|
||||
.button--outline.button--warning {
|
||||
border-color: rgb(var(--sl-color-warning-600));
|
||||
color: rgb(var(--sl-color-warning-600));
|
||||
}
|
||||
|
||||
.button--outline.button--warning:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-warning-600));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button--outline.button--warning${focusVisibleSelector}:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-warning-500));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-warning-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button--outline.button--warning:active:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-warning-700));
|
||||
background-color: rgb(var(--sl-color-warning-700));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/* Danger */
|
||||
.button--outline.button--danger {
|
||||
border-color: rgb(var(--sl-color-danger-600));
|
||||
color: rgb(var(--sl-color-danger-600));
|
||||
}
|
||||
|
||||
.button--outline.button--danger:hover:not(.button--disabled) {
|
||||
background-color: rgb(var(--sl-color-danger-600));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
.button--outline.button--danger${focusVisibleSelector}:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-danger-500));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-danger-500) / var(--sl-focus-ring-alpha));
|
||||
}
|
||||
|
||||
.button--outline.button--danger:active:not(.button--disabled) {
|
||||
border-color: rgb(var(--sl-color-danger-700));
|
||||
background-color: rgb(var(--sl-color-danger-700));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -238,7 +381,7 @@ export default css`
|
||||
color: rgb(var(--sl-color-primary-500));
|
||||
}
|
||||
|
||||
.button--text:focus:not(.button--disabled) {
|
||||
.button--text${focusVisibleSelector}:not(.button--disabled) {
|
||||
background-color: transparent;
|
||||
border-color: transparent;
|
||||
color: rgb(var(--sl-color-primary-500));
|
||||
@@ -455,7 +598,7 @@ export default css`
|
||||
* buttons and we style them here instead.
|
||||
*/
|
||||
|
||||
:host(.sl-button-group__button--first) .button {
|
||||
:host(.sl-button-group__button--first:not(.sl-button-group__button--last)) .button {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
@@ -464,7 +607,7 @@ export default css`
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
:host(.sl-button-group__button--last) .button {
|
||||
:host(.sl-button-group__button--last:not(.sl-button-group__button--first)) .button {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
@@ -482,7 +625,7 @@ export default css`
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
border-left: solid 1px rgb(var(--sl-color-neutral-1000) / 20%);
|
||||
border-left: solid 1px rgb(var(--sl-color-neutral-0) / 20%);
|
||||
}
|
||||
|
||||
/* Bump focused buttons up so their focus ring isn't clipped */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, property, query, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit-html/directives/class-map';
|
||||
import { ifDefined } from 'lit-html/directives/if-defined';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { emit } from '../../internal/event';
|
||||
import { hasSlot } from '../../internal/slot';
|
||||
import styles from './button.styles';
|
||||
@@ -54,6 +54,9 @@ export default class SlButton extends LitElement {
|
||||
/** Draws the button in a loading state. */
|
||||
@property({ type: Boolean, reflect: true }) loading = false;
|
||||
|
||||
/** Draws an outlined button. */
|
||||
@property({ type: Boolean, reflect: true }) outline = false;
|
||||
|
||||
/** Draws a pill-style button with rounded edges. */
|
||||
@property({ type: Boolean, reflect: true }) pill = false;
|
||||
|
||||
@@ -174,6 +177,8 @@ export default class SlButton extends LitElement {
|
||||
'button--disabled': this.disabled,
|
||||
'button--focused': this.hasFocus,
|
||||
'button--loading': this.loading,
|
||||
'button--standard': !this.outline,
|
||||
'button--outline': this.outline,
|
||||
'button--pill': this.pill,
|
||||
'button--has-label': this.hasLabel,
|
||||
'button--has-prefix': this.hasPrefix,
|
||||
@@ -213,6 +218,8 @@ export default class SlButton extends LitElement {
|
||||
'button--disabled': this.disabled,
|
||||
'button--focused': this.hasFocus,
|
||||
'button--loading': this.loading,
|
||||
'button--standard': !this.outline,
|
||||
'button--outline': this.outline,
|
||||
'button--pill': this.pill,
|
||||
'button--has-label': this.hasLabel,
|
||||
'button--has-prefix': this.hasPrefix,
|
||||
|
||||
@@ -16,7 +16,7 @@ export default css`
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: rgb(var(--sl-color-neutral-1000));
|
||||
background-color: rgb(var(--sl-surface-base-alt));
|
||||
box-shadow: var(--sl-shadow-x-small);
|
||||
border: solid var(--border-width) var(--border-color);
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
139
src/components/card/card.test.ts
Normal file
139
src/components/card/card.test.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { expect, fixture, html } from '@open-wc/testing';
|
||||
|
||||
import '../../../dist/shoelace.js';
|
||||
import type SlCard from './card';
|
||||
|
||||
describe('<sl-card>', () => {
|
||||
let el: SlCard;
|
||||
|
||||
describe('when provided no parameters', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlCard>(
|
||||
html` <sl-card>This is just a basic card. No image, no header, and no footer. Just your content.</sl-card> `
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test.', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should render the child content provided.', async () => {
|
||||
expect(el.innerText).to.eq('This is just a basic card. No image, no header, and no footer. Just your content.');
|
||||
});
|
||||
|
||||
it('should contain the class card.', async () => {
|
||||
const card = el.shadowRoot.querySelector('.card') as HTMLElement;
|
||||
expect(card.classList.value.trim()).to.eq('card');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an element in the slot "header" to render a header', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlCard>(
|
||||
html`<sl-card>
|
||||
<div slot="header">Header Title</div>
|
||||
This card has a header. You can put all sorts of things in it!
|
||||
</sl-card>`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test.', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should render the child content provided.', async () => {
|
||||
expect(el.innerText).to.contain('This card has a header. You can put all sorts of things in it!');
|
||||
});
|
||||
|
||||
it('render the header content provided.', async () => {
|
||||
const header = <HTMLDivElement>el.querySelector('div[slot=header]');
|
||||
expect(header.innerText).eq('Header Title');
|
||||
});
|
||||
|
||||
it('accept "header" as an assigned child in the shadow root.', async () => {
|
||||
const slot = <HTMLSlotElement>el.shadowRoot.querySelector('slot[name=header]');
|
||||
const childNodes = slot.assignedNodes({ flatten: true });
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should contain the class card--has-header.', async () => {
|
||||
const card = el.shadowRoot.querySelector('.card') as HTMLElement;
|
||||
expect(card.classList.value.trim()).to.eq('card card--has-header');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an element in the slot "footer" to render a footer', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlCard>(
|
||||
html`<sl-card>
|
||||
This card has a footer. You can put all sorts of things in it!
|
||||
|
||||
<div slot="footer">Footer Content</div>
|
||||
</sl-card>`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test.', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should render the child content provided.', async () => {
|
||||
expect(el.innerText).to.contain('This card has a footer. You can put all sorts of things in it!');
|
||||
});
|
||||
|
||||
it('render the footer content provided.', async () => {
|
||||
const footer = <HTMLDivElement>el.querySelector('div[slot=footer]');
|
||||
expect(footer.innerText).eq('Footer Content');
|
||||
});
|
||||
|
||||
it('accept "footer" as an assigned child in the shadow root.', async () => {
|
||||
const slot = <HTMLSlotElement>el.shadowRoot.querySelector('slot[name=footer]');
|
||||
const childNodes = slot.assignedNodes({ flatten: true });
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should contain the class card--has-footer.', async () => {
|
||||
const card = el.shadowRoot.querySelector('.card') as HTMLElement;
|
||||
expect(card.classList.value.trim()).to.eq('card card--has-footer');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when provided an element in the slot "image" to render a image', async () => {
|
||||
before(async () => {
|
||||
el = await fixture<SlCard>(
|
||||
html`<sl-card>
|
||||
<img
|
||||
slot="image"
|
||||
src="https://images.unsplash.com/photo-1547191783-94d5f8f6d8b1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=80"
|
||||
alt="A kitten walks towards camera on top of pallet."
|
||||
/>
|
||||
This is a kitten, but not just any kitten. This kitten likes walking along pallets.
|
||||
</sl-card>`
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a component that passes accessibility test.', async () => {
|
||||
await expect(el).to.be.accessible();
|
||||
});
|
||||
|
||||
it('should render the child content provided.', async () => {
|
||||
expect(el.innerText).to.contain(
|
||||
'This is a kitten, but not just any kitten. This kitten likes walking along pallets.'
|
||||
);
|
||||
});
|
||||
|
||||
it('accept "image" as an assigned child in the shadow root.', async () => {
|
||||
const slot = <HTMLSlotElement>el.shadowRoot.querySelector('slot[name=image]');
|
||||
const childNodes = slot.assignedNodes({ flatten: true });
|
||||
|
||||
expect(childNodes.length).to.eq(1);
|
||||
});
|
||||
|
||||
it('should contain the class card--has-image.', async () => {
|
||||
const card = el.shadowRoot.querySelector('.card') as HTMLElement;
|
||||
expect(card.classList.value.trim()).to.eq('card card--has-image');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit-html/directives/class-map';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { hasSlot } from '../../internal/slot';
|
||||
import styles from './card.styles';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { css } from 'lit';
|
||||
import componentStyles from '../../styles/component.styles';
|
||||
import { focusVisibleSelector } from '../../internal/focus-visible';
|
||||
|
||||
export default css`
|
||||
${componentStyles}
|
||||
@@ -30,12 +31,12 @@ export default css`
|
||||
border: solid var(--sl-input-border-width) rgb(var(--sl-input-border-color));
|
||||
border-radius: 2px;
|
||||
background-color: rgb(var(--sl-input-background-color));
|
||||
color: rgb(var(--sl-color-neutral-1000));
|
||||
color: rgb(var(--sl-color-neutral-0));
|
||||
transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color,
|
||||
var(--sl-transition-fast) color, var(--sl-transition-fast) box-shadow;
|
||||
}
|
||||
|
||||
.checkbox__control input[type='checkbox'] {
|
||||
.checkbox__input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
padding: 0;
|
||||
@@ -61,10 +62,12 @@ export default css`
|
||||
}
|
||||
|
||||
/* Focus */
|
||||
.checkbox.checkbox--focused:not(.checkbox--checked):not(.checkbox--disabled) .checkbox__control {
|
||||
.checkbox:not(.checkbox--checked):not(.checkbox--disabled)
|
||||
.checkbox__input${focusVisibleSelector}
|
||||
~ .checkbox__control {
|
||||
border-color: rgb(var(--sl-input-border-color-focus));
|
||||
background-color: rgb(var(--sl-input-background-color-focus));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
box-shadow: var(--sl-focus-ring);
|
||||
}
|
||||
|
||||
/* Checked/indeterminate */
|
||||
@@ -82,11 +85,13 @@ export default css`
|
||||
}
|
||||
|
||||
/* Checked/indeterminate + focus */
|
||||
.checkbox.checkbox--checked:not(.checkbox--disabled).checkbox--focused .checkbox__control,
|
||||
.checkbox.checkbox--indeterminate:not(.checkbox--disabled).checkbox--focused .checkbox__control {
|
||||
.checkbox.checkbox--checked:not(.checkbox--disabled) .checkbox__input${focusVisibleSelector} ~ .checkbox__control,
|
||||
.checkbox.checkbox--indeterminate:not(.checkbox--disabled)
|
||||
.checkbox__input${focusVisibleSelector}
|
||||
~ .checkbox__control {
|
||||
border-color: rgb(var(--sl-color-primary-500));
|
||||
background-color: rgb(var(--sl-color-primary-500));
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) rgb(var(--sl-color-primary-500) / var(--sl-focus-ring-alpha));
|
||||
box-shadow: var(--sl-focus-ring);
|
||||
}
|
||||
|
||||
/* Disabled */
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { LitElement, html } from 'lit';
|
||||
import { customElement, property, query, state } from 'lit/decorators.js';
|
||||
import { classMap } from 'lit-html/directives/class-map';
|
||||
import { ifDefined } from 'lit-html/directives/if-defined';
|
||||
import { live } from 'lit-html/directives/live';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import { ifDefined } from 'lit/directives/if-defined.js';
|
||||
import { live } from 'lit/directives/live.js';
|
||||
import { emit } from '../../internal/event';
|
||||
import { watch } from '../../internal/watch';
|
||||
import styles from './checkbox.styles';
|
||||
@@ -112,12 +112,6 @@ export default class SlCheckbox extends LitElement {
|
||||
emit(this, 'sl-focus');
|
||||
}
|
||||
|
||||
handleLabelMouseDown(event: MouseEvent) {
|
||||
// Prevent clicks on the label from briefly blurring the input
|
||||
event.preventDefault();
|
||||
this.input.focus();
|
||||
}
|
||||
|
||||
@watch('checked', { waitUntilFirstUpdate: true })
|
||||
@watch('indeterminate', { waitUntilFirstUpdate: true })
|
||||
handleStateChange() {
|
||||
@@ -136,8 +130,25 @@ export default class SlCheckbox extends LitElement {
|
||||
'checkbox--indeterminate': this.indeterminate
|
||||
})}
|
||||
for=${this.inputId}
|
||||
@mousedown=${this.handleLabelMouseDown}
|
||||
>
|
||||
<input
|
||||
id=${this.inputId}
|
||||
class="checkbox__input"
|
||||
type="checkbox"
|
||||
name=${ifDefined(this.name)}
|
||||
value=${ifDefined(this.value)}
|
||||
.indeterminate=${live(this.indeterminate)}
|
||||
.checked=${live(this.checked)}
|
||||
.disabled=${this.disabled}
|
||||
.required=${this.required}
|
||||
role="checkbox"
|
||||
aria-checked=${this.checked ? 'true' : 'false'}
|
||||
aria-labelledby=${this.labelId}
|
||||
@click=${this.handleClick}
|
||||
@blur=${this.handleBlur}
|
||||
@focus=${this.handleFocus}
|
||||
/>
|
||||
|
||||
<span part="control" class="checkbox__control">
|
||||
${this.checked
|
||||
? html`
|
||||
@@ -170,23 +181,6 @@ export default class SlCheckbox extends LitElement {
|
||||
</span>
|
||||
`
|
||||
: ''}
|
||||
|
||||
<input
|
||||
id=${this.inputId}
|
||||
type="checkbox"
|
||||
name=${ifDefined(this.name)}
|
||||
value=${ifDefined(this.value)}
|
||||
.indeterminate=${live(this.indeterminate)}
|
||||
.checked=${live(this.checked)}
|
||||
.disabled=${this.disabled}
|
||||
.required=${this.required}
|
||||
role="checkbox"
|
||||
aria-checked=${this.checked ? 'true' : 'false'}
|
||||
aria-labelledby=${this.labelId}
|
||||
@click=${this.handleClick}
|
||||
@blur=${this.handleBlur}
|
||||
@focus=${this.handleFocus}
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span part="label" id=${this.labelId} class="checkbox__label">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user