pull/105/head
Cory LaViska 2020-07-15 17:30:37 -04:00
commit 0b86753038
161 zmienionych plików z 23958 dodań i 0 usunięć

15
.editorconfig 100644
Wyświetl plik

@ -0,0 +1,15 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

39
.eslintrc.json 100644
Wyświetl plik

@ -0,0 +1,39 @@
{
"parserOptions": {
"project": "./tsconfig.json"
},
"extends": ["plugin:@stencil/recommended"],
"rules": {
"@stencil/async-methods": "error",
"@stencil/ban-prefix": ["error", ["stencil", "stnl", "st"]],
"@stencil/decorators-context": "error",
"@stencil/decorators-style": [
"error",
{
"prop": "inline",
"state": "inline",
"element": "inline",
"event": "inline",
"method": "multiline",
"watch": "multiline",
"listen": "multiline"
}
],
"@stencil/element-type": "error",
"@stencil/host-data-deprecated": "error",
"@stencil/methods-must-be-public": "error",
"@stencil/no-unused-watch": "error",
"@stencil/own-methods-must-be-private": "off",
"@stencil/own-props-must-be-private": "off",
"@stencil/prefer-vdom-listener": "error",
"@stencil/props-must-be-public": "off",
"@stencil/props-must-be-readonly": "off",
"@stencil/render-returns-host": "error",
"@stencil/required-jsdoc": "error",
"@stencil/reserved-member-names": "error",
"@stencil/single-export": "error",
"@stencil/strict-boolean-conditions": "off",
"@stencil/strict-mutable": "off",
"react/jsx-no-bind": "off"
}
}

44
.github/CODE_OF_CONDUCT.md vendored 100644
Wyświetl plik

@ -0,0 +1,44 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at cory@abeautifulsite.net. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4.

1
.github/FUNDING.yml vendored 100644
Wyświetl plik

@ -0,0 +1 @@
github: [claviska]

Wyświetl plik

@ -0,0 +1,38 @@
---
name: Bug Report
about: Create a report to help us improve.
title: ''
labels: bug
assignees: claviska
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**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]
**Additional context**
Add any other context about the problem here.

Wyświetl plik

@ -0,0 +1,4 @@
contact_links:
- name: Personal Support
url: https://github.com/sponsors/claviska
about: Support for issues outside the scope of the library can be obtained via sponsorship.

Wyświetl plik

@ -0,0 +1,20 @@
---
name: Feature Request
about: Suggest an idea for this project.
title: ''
labels: feature
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 [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**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.

7
.github/SECURITY.md vendored 100644
Wyświetl plik

@ -0,0 +1,7 @@
# Reporting Security Issues
We take security issues in Shoelace very seriously and appreciate your efforts to disclose your findings responsibly.
To report a security issue, email [cory@abeautifulsite.net](mailto:cory@abeautifulsite.net) and include "SHOELACE SECURITY" in the subject line.
Well respond as soon as possible and keep you updated throughout the process.

33
.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,33 @@
src/components/*/readme.md
src/components/icon/icons
docs/assets/data/custom.json
docs/assets/icons/sprite.svg
dist/
docs/dist/
loader/
temp/
www/
*~
*.sw[mnpcod]
*.log
*.lock
*.tmp
*.tmp.*
log.txt
*.sublime-project
*.sublime-workspace
.stencil/
.idea/
.vscode/
.sass-cache/
.versions/
node_modules/
$RECYCLE.BIN/
.DS_Store
Thumbs.db
UserInterfaceState.xcuserstate
.env

11
.prettierignore 100644
Wyświetl plik

@ -0,0 +1,11 @@
.github
.stencil
dist
docs/assets
docs/**/*.md
loader
node_modules
src/components/**/readme.md
src/components.d.ts
www
package-lock.json

16
CHANGELOG.md 100644
Wyświetl plik

@ -0,0 +1,16 @@
# Changelog
## 2.0.0-beta.3
- Fix version in docs
- Remove custom elements bundle
## 2.0.0-beta.2
- Fix quick start and installation URLs
- Switch Docsify theme
- Update line heights tokens
## 2.0.0-beta.1
- Initial release

111
CONTRIBUTING.md 100644
Wyświetl plik

@ -0,0 +1,111 @@
# Contributing to Shoelace
Shoelace is an open source project, meaning everyone can use it and contribute to its development. Please take a moment to review these guidelines to make the contribution process as easy as possible for both you and the project's maintainers.
## Using the Issue Tracker
The [issue tracker](https://github.com/shoelace-style/shoelace/issues) is for bug reports, feature requests, and pull requests.
- Please **do not** use the issue tracker for personal support requests. Please [ask your question](https://stackoverflow.com/questions/ask) on StackOverflow instead.
- Please **do not** derail, hijack, or troll issues. Keep the discussion on topic and be respectful of others.
- Please **do not** post comments with "+1" or "👍". Use [reactions](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) instead.
- Please **do** use the issue tracker for feature requests, bug reports, and pull requests.
Issues that do not follow these guidelines are subject to closure. There simply aren't enough resources for the author and contributors to troubleshoot personal support requests.
### Feature Requests
Feature requests can be added using the issue tracker.
- Please **do** search for an existing request before suggesting a new feature.
- Please **do** use the "👍" reaction to vote for a feature.
- Please **do** share substantial use cases and perspective that support new features if they haven't already been mentioned.
- Please **do not** bump, spam, or ping contributors to prioritize your own feature.
If you would like your feature prioritized, please consider [sponsoring the project](https://github.com/sponsors/claviska).
### Bug Reports
A bug is _a demonstrable problem_ caused by code in the library. Bug reports are an important contribution to the quality of the project. When submitting a bug report, there are a few steps you can take to make sure your issues gets attention quickly.
- Please **do not** paste in large blocks of irrelevant code
- Please **do** search for an existing issue before creating a new one
- Please **do** explain the bug clearly
- Please **do** provide a minimal test case that demonstrates the bug (e.g. [jsfiddle.net](https://jsfiddle.net/) or [CodePen](https://codepen.io/))
- Please **do** provide additional information, when necessary, to replicate the bug
**A minimal test case is critical to a successful bug report.** It demonstrates that the bug exists in the library and not in surrounding code. Contributors should be able to understand the bug without studying your code, otherwise they'll probably move on to another bug.
If you would like your bug prioritized, please consider [sponsoring the project](https://github.com/sponsors/claviska).
### Pull Requests
To keep the project on track, please consider the following guidelines before submitting a PR.
- Please **do not** submit a PR without opening an issue first, especially for non-trivial changes. This may prevent you from doing work that won't be accepted for various reasons (e.g. someone is already working on it, it's not a good fit for the project, it needs additional planning, etc.)
- Please **do** make sure your PR clearly defines what you're changing. Even if you feel your changes are obvious, please explain them so other contributors can more easily review your works. PRs without detailed descriptions are subject to closure pending more details.
- Please **do not** edit anything in `dist/`. These files are generated automatically, so you need to edit the source files instead.
The author reserves the right to reject any PR that's outside the scope of the project or doesn't meet code quality standards.
## Conventions
This section aims to describe some of the design decisions and code conventions that support the project. All contributors are expected to follow conventions and best practices, even those not explicitly defined in this document. When in doubt, refer to existing source code and execute your best judgment.
In order to keep the project in a maintainable state, code that doesn't follow conventions and best practices will need to be refactored before it will be accepted. This isn't a knock on your code or your style — it's something the author considers necessary to operate a successful open source project.
### Semantic Versioning
This project follows [Semantic Versioning](https://semver.org/). Breaking changes in stable components will not be accepted until the next major version. As such, all contributions must consider the project's roadmap and take this into consideration. Features that are deemed no longer necessary in future versions will be deprecated instead.
**Components marked "experimental" should not be used in production,** as changes to them will not be subject to this rule.
### Code Formatting & Linting
The majority of code formatting is handled automatically by [Prettier](https://prettier.io/) at build time. However, for the best experience, you should [install it in your editor](https://prettier.io/docs/en/editors.html) and enable format on save.
Linting is run automatically at build time. By design, the project will not build if the linter is unhappy. Contributors are strongly encouraged to install an ESLint plugin for your editor for the best developer experience.
### BEM Class Names
All components use a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM), so styles are completely encapsulated from the rest of the document. As a result, class names _inside_ a component won't conflict with class names _outside_ the component, so we're free to name them whatever we want.
Internally, each component uses the [BEM methodology](http://getbem.com/) for its class names. There is no technical requirement to do this — it's purely the preference of the author. However, all contributions are expected to follow this practice for the sake of consistency.
## Developer Tips
### Documentation is the key to success
Nobody likes writing documentation, but not having good docs is frustrating to users and makes the project less appealing. Fortunately, writing documentation for Shoelace is really easy!
A lot of the documentation is generated automatically based on JSDoc comments in each component's source code. If you have ESLint enabled, your editor will tell you when a comment is missing. This may feel a bit naggy, but it's a very good thing. Every property, method, event, etc. is documented this way. By adding comments as you code, the docs are more easily kept up to date.
The documentation pages are served up by [Docsify](https://docsify.now.sh/). Check out `docs/_sidebar.md` and `docs/components/` to get an idea of how pages are created and formatted. If you're creating a new component, it may help to use an existing component's markdown file as a template.
If you need help with documentation, feel free to reach out!
### Choose composability when possible
When designed right, web components are highly composable, meaning you can easily reuse them in other components. This reduces the overall size of the library, expedites feature development, and maintains a consistent user experience throughout.
The select component, for example, makes use of the dropdown, input, and menu components. Because it's offloading most of its functionality and styles to these lower-level components, the select component remains very lightweight and its appearance and behavior is consistent with other form controls and menus.
### When to use a standard property vs. a CSS custom property
When designing a component's API, standard properties ("props") are generally used to change the _behavior_ of a component, whereas CSS custom properties ("CSS variables") are used to change the _appearance_ of a component. Remember that props can't respond to media queries, but CSS variables can.
There are some exceptions to this (e.g. when it significantly improves developer experience), but a good rule of thumbs is "will this need to change based on screen size?" If so, you probably want to use a CSS variable.
### Boolean Props
Boolean props should _always_ default to `false`, otherwise there's no way for the user to unset it without JavaScript. To keep the API as friendly and consistent as possible, use a name like `noHeader` with a default value of `false` instead of `header` with a default value of `true`.
### A Note About Sass
The Shoelace _source_ is developed using Sass for the convenience of nested selectors, imports, and tedious things such as color palette generation. By design, Sass variables, color functions, and other preprocessor-specific feaures are not used in the source and will not be accepted in a PR.
Consumers of the library should never need to worry about preprocessing the library.
### Positioning Popovers
Shoelace uses an internal popover utility for dropdowns, tooltips, etc. This is a light abstraction of Popper.js designed to make positioning and transitioning things easy and consistent throughout the library. When possible, use this utility instead of relying on Popper directly. See `src/utilities/popover.ts` for details.

7
LICENSE.md 100644
Wyświetl plik

@ -0,0 +1,7 @@
Copyright (c) 2020 A Beautiful Site, LLC
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

86
README.md 100644
Wyświetl plik

@ -0,0 +1,86 @@
# Shoelace
A forward-thinking library of web components.
- Works with all frameworks 🧩
- Works with CDNs 🚛
- Fully customizable with CSS 🎨
- Open source 😸
Designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska).
---
Documentation: [shoelace.style](https://shoelace.style)
Source: [github.com/shoelace-style/shoelace](https://github.com/shoelace-style/shoelace)
Twitter: [@shoelace_style](https://twitter.com/shoelace_style)
---
## Shoemakers 🥾
Shoemakers, or "developers," can use this documentation to learn how to build Shoelace from source.
**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.
If that's not what you're trying to do, the [documentation website](https://shoelace.style) is where you want to be.
### What are you using to build Shoelace?
Components are built with [Stencil](https://stenciljs.com/), a compiler that generates standards-based web components. The source code is a combination of TypeScript + JSX (TSX). Stylesheets are written in SCSS.
The build is done through a combination of Stencil's CLI and a handful of custom scripts.
### Forking the Repo
Start by [forking the repo](https://github.com/shoelace-style/shoelace/fork) on GitHub, then clone it locally and install dependencies.
```sh
git clone https://github.com/YOUR_GITHUB_USERNAME/shoelace
cd shoelace
npm install
```
### Developing
Once you've cloned the repo, run the following command.
```sh
npm run start
```
This will spin up the Shoelace dev server. Note that the dev server requires ports 4000, 4001, and 4002 to be available.
After the initial build, a browser will open at `http://localhost:4000`.
Hot module reloading (HMR) is enabled for components, so changes will instantly reflect in the browser as you work. The documentation is powered by Docsify, which uses raw markdown files to generate pages. As such, no static files are built for the docs. Unfortunately, changes to _documentation pages_ will trigger a page refresh (no HMR).
### Building
To generate a production build, run the following command.
```sh
npm run build
```
### Contributing
Shoelace is an open source project and contributions are encouraged! If you're interesting in contributing, please review the [contribution guidelines](CONTRIBUTING.md) first.
## License
Shoelace is designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska). Its available under the terms of the MIT license.
Designing, developing, and supporting this library requires a lot of time, effort, and skill. Id like to keep it open source so everyone can use it, but that doesnt provide me with any income.
**Therefore, if youre 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.
👇 Your support is very much appreciated! 👇
- [Become a sponsor](https://github.com/sponsors/claviska)
- [Star on GitHub](https://github.com/shoelace-style/shoelace/stargazers)
- [Follow on Twitter](https://twitter.com/shoelace_style)
Whether you're building Shoelace or building something _with_ Shoelace — have fun creating! 🥾

76
dev-server.js 100644
Wyświetl plik

@ -0,0 +1,76 @@
//
// The Shoelace dev server! 🥾
//
// This is an Express + Browsersync script that:
//
// - Proxies Stencil's dev server (for HMR of components)
// - Serves dist/ and docs/ from https://localhost:3000/
// - Launches the docs site and reloads the page when pages are modified
//
// Usage:
//
// 1. Run Stencil: `stencil build --dev --docs --watch --serve --no-open`
//
// 2. Run this script at the same time as Stencil
//
const bs = require('browser-sync').create();
const chalk = require('chalk');
const express = require('express');
const fs = require('fs').promises;
const path = require('path');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
const browserPort = 4000;
const stencilPort = 4001;
const proxyPort = 4002;
// Proxy Stencil's dev server
app.use(
'/~dev-server',
createProxyMiddleware({
target: `http://localhost:${stencilPort}`,
changeOrigin: true,
ws: true
})
);
// Inject Stencil's dev server iframe into the main entry point
app.use(/^\/$/, async (req, res, next) => {
let index = await fs.readFile('./docs/index.html', 'utf8');
index = index
.replace('<head>', '<head><script>window.ShoelaceDevServer = true;</script>')
.replace(
'</body>',
'<iframe src="/~dev-server" style="display: block; width: 0; height: 0; border: 0;"></iframe></body>'
);
res.type('html').send(index);
});
app.use('/dist', express.static('./dist'));
app.use('/', express.static('./docs'));
app.listen(proxyPort);
// Give Stencil's dev server a few seconds to spin up, then launch the browser
setTimeout(() => {
console.log(chalk.cyan(`\nLaunching the Shoelace dev server at http://localhost:${browserPort}! 🥾\n`));
bs.init({
startPath: '/',
port: browserPort,
proxy: {
target: `http://localhost:${proxyPort}`,
ws: true
},
logLevel: 'silent',
notify: false,
snippetOptions: {
ignorePaths: '/~dev-server'
}
});
// Reload when docs change
bs.watch('docs/**/*').on('change', async () => {
bs.reload();
});
}, 5000);

0
docs/.nojekyll 100644
Wyświetl plik

3
docs/404.md 100644
Wyświetl plik

@ -0,0 +1,3 @@
# Not Found
Sorry, I couldn't find that page.

49
docs/_sidebar.md 100644
Wyświetl plik

@ -0,0 +1,49 @@
- Getting Started
- [Overview](/)
- [Installation](/getting-started/installation.md)
- [Usage](/getting-started/usage.md)
- [Customizing](/getting-started/customizing.md)
- [Roadmap](/getting-started/roadmap.md)
- Components
- [Alert](/components/alert.md)
- [Avatar](/components/avatar.md)
- [Badge](/components/badge.md)
- [Button](/components/button.md)
- [Checkbox](/components/checkbox.md)
- [Color Picker](/components/color-picker.md)
- [Details](/components/details.md)
- [Dialog](/components/dialog.md)
- [Drawer](/components/drawer.md)
- [Dropdown](/components/dropdown.md)
- [Form](/components/form.md)
- [Icon](/components/icon.md)
- [Input](/components/input.md)
- [Menu](/components/menu.md)
- [Menu Divider](/components/menu-divider.md)
- [Menu Item](/components/menu-item.md)
- [Menu Label](/components/menu-label.md)
- [Progress Bar](/components/progress-bar.md)
- [Progress Ring](/components/progress-ring.md)
- [Radio](/components/radio.md)
- [Range](/components/range.md)
- [Select](/components/select.md)
- [Spinner](/components/spinner.md)
- [Switch](/components/switch.md)
- [Tab Group](/components/tab-group.md)
- [Tab](/components/tab.md)
- [Tab Panel](/components/tab-panel.md)
- [Tag](/components/tag.md)
- [Textarea](/components/textarea.md)
- [Tooltip](/components/tooltip.md)
- Design Tokens
- [Typography](/tokens/typography.md)
- [Color](/tokens/color.md)
- [Spacing](/tokens/spacing.md)
- [Elevation](/tokens/elevation.md)
- [Border Radius](/tokens/border-radius.md)
- [Transition](/tokens/transition.md)
- [Z-index](/tokens/z-index.md)

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 12 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 11 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 15 KiB

Wyświetl plik

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub icon</title><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 848 B

Wyświetl plik

@ -0,0 +1,7 @@
<svg viewBox="0 0 127 141" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g fill-rule="nonzero" fill="#409eff">
<path d="M102.375,90.85 C102.979,90.557 103.57,90.215 104.15,89.826 L106.425,88.501 C106.848,88.19 107.64,87.573 108.8,86.65 L108.95,86.501 C109.883,85.567 110.916,85.117 112.05,85.15 C112.55,85.15 113.133,85.284 113.8,85.55 L122.3,78 C122.533,77.8 122.767,77.633 123,77.5 L123.05,77.5 C123.95,76.967 124.7,77 125.3,77.6 C126.367,78.166 126.45,79.133 125.55,80.5 L116.65,88.399 C116.717,88.533 116.75,88.666 116.75,88.799 C116.883,89.399 116.833,89.999 116.6,90.599 C116.4,90.999 116.117,91.382 115.75,91.749 C115.379,92.145 114.996,92.528 114.6,92.898 L109.45,96.648 C108.99,96.97 108.523,97.27 108.05,97.548 C107.46,97.906 106.86,98.232 106.25,98.523 C105.985,98.644 105.718,98.76 105.45,98.874 C103.841,99.559 102.174,100.017 100.45,100.249 C99.65,106.982 97.35,113.183 93.55,118.849 C88.75,125.915 82.183,131.299 73.85,134.999 C65.55,138.699 56.567,140.549 46.9,140.549 C33.567,140.415 22.75,137.415 14.45,131.549 C4.817,124.75 0,115.7 0,104.399 L0,102.849 C0.333,95.149 2.6,87.849 6.8,80.95 C10.933,74.116 16.983,69.5 24.95,67.1 C29.05,65.9 33.166,65.3 37.3,65.3 C41.567,65.3 45.967,66.083 50.5,67.65 C55.033,69.216 60.15,71.916 65.85,75.75 L80.7,85.7 C84.833,88.399 88.6,90.233 92,91.2 C91.3,84.3 88.8,78.399 84.5,73.5 C80.2,68.533 74.717,64.9 68.05,62.6 L61.65,60.4 C55.783,58.333 51.417,56.3 48.55,54.3 C40.817,49.067 36.517,41.883 35.65,32.75 L35.5,30.05 C35.5,21.25 39.067,13.883 46.2,7.95 C52.567,2.65 60.133,0 68.9,0 C75.5,0 81.417,1.9 86.65,5.7 C91.917,9.533 94.9,14.967 95.6,22 L95.75,24.75 C95.75,29.85 94.433,34.216 91.8,37.85 C89.1,41.483 86.717,43.3 84.65,43.3 C84.21,43.269 83.802,43.21 83.425,43.125 L74.1,51.9 C72.6,52.733 71.583,52.583 71.05,51.45 C70.517,50.85 70.567,50.1 71.2,49.2 L71.25,49.15 C71.383,48.95 71.567,48.733 71.8,48.5 L80.475,40.275 C80.376,39.872 80.318,39.431 80.3,38.95 C80.3,37.817 80.75,36.867 81.65,36.1 C85.45,32.7 87.35,28.784 87.35,24.35 C87.35,19.95 85.683,16.25 82.35,13.25 C79.017,10.25 74.467,8.716 68.7,8.65 C61.5,8.65 55.583,10.817 50.95,15.15 C46.317,19.483 44,24.683 44,30.75 C44,35.65 45.883,40.066 49.65,44 C53.383,47.9 59.15,50.966 66.95,53.2 C77.883,56.367 86.233,61.7 92,69.2 C97.133,75.833 100,83.283 100.6,91.55 C101.199,91.365 101.791,91.132 102.375,90.85 Z M71.95,49.05 C71.95,49.35 72.117,49.5 72.45,49.5 C72.483,49.5 75.117,47.066 80.35,42.2 C80.35,41.533 78.95,42.45 76.15,44.95 C73.35,47.483 71.95,48.85 71.95,49.05 Z M74.15,50.8 C74.15,50.533 74.017,50.4 73.75,50.4 C73.45,50.4 73.183,50.55 72.95,50.85 C72.416,50.817 72.033,50.884 71.8,51.05 C71.7,51.117 71.65,51.183 71.65,51.25 C71.65,51.45 71.783,51.6 72.05,51.7 L72.95,51.7 C73.75,51.4 74.15,51.1 74.15,50.8 Z M80.35,45.35 C80.35,44.583 79.9,44.583 79,45.35 C78.567,45.75 78.017,46.317 77.35,47.05 C77.117,47.217 76.633,47.667 75.9,48.4 C75.133,49.2 74.75,49.683 74.75,49.85 L74.8,50.2 C75,50.267 75.133,50.3 75.2,50.3 C75.233,50.3 76.1,49.5 77.8,47.9 C79.5,46.3 80.35,45.45 80.35,45.35 Z M124.2,78.3 L115.8,85.7 C116.3,85.967 116.667,86.349 116.9,86.849 L125.2,79.45 C125.266,79.116 125.217,78.849 125.05,78.649 C124.883,78.517 124.6,78.399 124.2,78.3 Z M123.75,78.05 L123.55,77.85 L116.15,83.85 L116.6,84.4 L123.75,78.05 Z M91.85,99.899 C89.65,99.333 87.617,98.649 85.75,97.849 C81.55,96.149 76.333,93.183 70.1,88.95 L59.85,82 C55.517,79.233 51.567,77.166 48,75.8 C44.4,74.467 40.867,73.8 37.4,73.8 L35.9,73.8 C27.067,74.267 20.2,77.583 15.3,83.75 C10.734,89.45 8.45,96.184 8.45,103.95 C8.45,112.683 11.95,119.516 18.95,124.45 C25.916,129.416 35.467,131.899 47.6,131.899 C57.133,131.899 65.166,130.2 71.7,126.799 C78.2,123.399 83.25,118.899 86.85,113.299 C89.55,109.033 91.217,104.566 91.85,99.899 Z"></path>
</g>
</g>
</svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.8 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 5.6 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 24 KiB

Wyświetl plik

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg4301" viewBox="0 0 307.58 261.84" version="1.0" inkscape:version="0.48.4 r9939" sodipodi:docname="chaussures.svg">
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1366" inkscape:window-height="719" id="namedview90" showgrid="false" inkscape:zoom="0.90131378" inkscape:cx="560.67485" inkscape:cy="151.01783" inkscape:window-x="0" inkscape:window-y="25" inkscape:window-maximized="1" inkscape:current-layer="svg4301"/>
<defs id="defs4303">
<linearGradient id="linearGradient3321" y2="156.59" gradientUnits="userSpaceOnUse" x2="319.39" gradientTransform="translate(71.83 210.51)" y1="249.49" x1="327.13">
<stop id="stop2445" style="stop-color:#4e4e4e;stop-opacity:1;" offset="0"/>
<stop id="stop2447" style="stop-color:#cdcdcd;stop-opacity:1;" offset="1"/>
</linearGradient>
<radialGradient id="radialGradient3323" gradientUnits="userSpaceOnUse" cy="305.17" cx="161.26" gradientTransform="matrix(.6108 0 0 .6108 215.8 352.93)" r="37.761">
<stop id="stop2460" style="stop-color:#cdcdcd;stop-opacity:1;" offset="0"/>
<stop id="stop2462" style="stop-color:#cfcfcf;stop-opacity:1;" offset="0.2703"/>
<stop id="stop2464" style="stop-color:#d3d3d3;stop-opacity:1;" offset="0.4603"/>
<stop id="stop2466" style="stop-color:#dcdcdc;stop-opacity:1;" offset="0.62559998"/>
<stop id="stop2468" style="stop-color:#e7e7e7;stop-opacity:1;" offset="0.77679998"/>
<stop id="stop2470" style="stop-color:#f7f7f7;stop-opacity:1;" offset="0.91720003"/>
<stop id="stop2472" style="stop-color:#ffffff;stop-opacity:1;" offset="1"/>
</radialGradient>
<linearGradient id="linearGradient3325" y2="315.57" gradientUnits="userSpaceOnUse" x2="185.59" gradientTransform="translate(71.83 210.51)" y1="315.57" x1="163.05">
<stop id="stop2477" style="stop-color:#cdcdcd;stop-opacity:1;" offset="0"/>
<stop id="stop2479" style="stop-color:#ffffff" offset="1"/>
</linearGradient>
<linearGradient id="linearGradient3327" y2="149.16" gradientUnits="userSpaceOnUse" x2="312.09" y1="239.51" x1="303.03">
<stop id="stop2651" style="stop-color:#cdcdcd;stop-opacity:1;" offset="0"/>
<stop id="stop2653" style="stop-color:#ffffff" offset="1"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#radialGradient3323" id="radialGradient3846" cx="-252.96408" cy="92.035866" fx="-252.96408" fy="92.035866" r="45.934406" gradientTransform="matrix(1.1352297,-1.0627683,0.60088776,0.64185731,-21.094963,-239.15678)" gradientUnits="userSpaceOnUse"/>
</defs>
<g id="layer1" transform="translate(-218.26 -395.26)">
<g id="g4403" transform="translate(-5.0956 59.533)">
<path id="path3529_2_" style="fill:#ffffff" d="m299.45 339.2c-6.14 0.41-24.15 2.87-31.52 5.33s-13.51 5.27-12.28 8.14 3.82 2.87 3.82 2.87-5.07 56.14-8.75 64.74c-3.69 8.6-11.65 20.2-17.2 33.16-7.45 17.41-6.79 33.96-5.97 42.15 0.81 8.19 1.91 16.16 8.46 16.98l0.02 0.02-0.46 16.79s6.22 4.84 20.16 9.61c16.34 5.6 22.04 5.44 40.35 5.27 5.46-0.05 12.41-0.63 17.55 0.23l22.11 13.43c19.39 13.91 27.21 16.49 49.43 25.37 10.71 4.22 12.66 2.1 15.61 1.8 1.32 0.8 5.16 8.65 20.52 4.81 8.99 5.08 17.69 4.99 24.86 2.04 13.42 4.08 21.92 2.52 27.61-2.53 11.48 3.49 23.78 1.9 29.18-5.52 10.23-0.47 12.79-1.88 17.89-9.24 5.13-1.92 7.69-4.44 7.69-10.2-0.33-7.94-1.93-15.12-3.85-22.11 0 0-2.41-6.72-7.21-6.72 0 0 3.32-25.54-36.98-42.73-2-0.85-6.73-1-8.66-1.84-29.72-12.92-38.96-24.28-38.96-24.28l-20.65-15.85c-7.07-7.85-13.09-12.1-16.93-42.18-3.71-29.08 6.88-58.01 6.88-58.01s-1.71-2.51-5.39-2.51c-3.69 0-4.49 1.22-4.49 1.22s-28.65 1.25-33.86-1.64c-3.9-2.16-5.15-7.37-18.02-8.6-13.61-1.09-27.33-0.71-40.96 0z"/>
<path id="path2415" style="fill:#409EFE;fill-opacity:1" d="m325.11 347.4c-27.5-0.28-67.53 7.38-67.53 7.38l0.25 14.75-5.28 39.12-6.94 21.32-5.34 8.4-1.47 3.35-9.03 14.87-1.31 8.94-1.97 4.53v8.94l-1.19 8.12h1.19v9.03l5.97 14.54 8.18 3.34 25.72 7.84 21.63 0.38 18.28-1.5 5.22 2.25 15.28 5.97 26.09 14.53 36.16 16.78 10.81 2.22 1.5-1.85 2.25-20.5 6.69-17.53 14.56-16.78 20.5-11.56 22.38-4.09-7.85-5.97-4.28-1.63-10.59-5.94-33.44-26.21-12.62-26.1-5.04-32.5s5.5-32.67 5.5-34.84-13.31-1.38-18.56-1.38c-5.24 0-15.74 1.86-36.72-5.75-4.59-1.66-11.29-2.39-19-2.47z"/>
<path id="path2449" style="fill:url(#linearGradient3321)" d="m359.61 351.33l7.99 64.43s4.74 26.72 11.98 37.96c7.25 11.23 13.99 17.58 28.72 25.72 14.74 8.14 18.98 8.14 18.98 8.14s6.62-4.02 2.5-8.14-19.73-14.48-22.23-16.98-15.48-18.98-16.48-22.73c-1-3.74-6.51-16.34-6.51-41.55s5.36-39.37 5.36-39.37l2.15-6.73-32.46-0.75z"/>
<path id="path2451" style="fill:#2e3436" d="m358.47 351.47l7.99 64.43c0.2 1.16 4.88 27.14 12.16 38.44 7.58 11.77 14.66 18.11 29.13 26.1 14.57 8.06 19.07 8.29 19.53 8.29h0.32l0.28-0.17c0.4-0.25 3.98-2.5 4.36-5.71 0.13-1.04-0.06-2.63-1.65-4.22-2.38-2.38-8.35-6.69-13.61-10.48-3.9-2.82-7.59-5.47-8.62-6.51-2.78-2.78-15.3-18.9-16.18-22.2l-0.69-2.22c-1.73-5.27-5.78-17.61-5.78-39.04 0-24.67 5.24-38.83 5.29-38.97l2.63-8.25-35.33-0.81 0.17 1.32zm50.39 126.97c-14.09-7.78-20.97-13.94-28.31-25.34-7.04-10.92-11.78-37.28-11.82-37.54 0 0-7.51-60.52-7.82-63.05 2.32 0.05 26.94 0.62 29.6 0.68-0.57 1.79-1.68 5.27-1.68 5.27-0.2 0.52-5.42 14.59-5.42 39.72 0 21.8 4.13 34.38 5.9 39.76l0.65 2.09c1.12 4.18 14.4 20.86 16.78 23.24 1.16 1.16 4.74 3.74 8.9 6.74 5.19 3.75 11.07 7.99 13.33 10.24 0.68 0.68 1.01 1.36 1.01 2.06 0 0.09 0 0.18-0.02 0.27-0.19 1.62-2.02 3.15-2.98 3.81-1.21-0.19-6.14-1.33-18.12-7.95z"/>
<path id="path2457" style="fill:#d3d7cf" d="m489.55 505.94s18.34 2.45 22.79 27.53c0.57 10.4-4.36 6.85-4.36 4.1-1.05-4.16-4.18-21.14-18.43-31.63z"/>
<path id="path2474" style="fill:url(#radialGradient3323)" d="m287.17 522.78l1.21 23.54 25.12-0.46 18.64 11.59 9.27-20.03-33.28-16.22-20.96 1.58z"/>
<path id="path2481" style="fill:url(#linearGradient3325)" d="m236.58 510.93l20.52 8.72 0.32 21.58-22.54-10.21 1.7-20.09z"/>
<path id="path2483" style="fill:#d3d7cf" d="m516.48 536.36l9.06 11.87 0.86 21.35-5.39 3.02s0.75-20.49-5.29-36.23"/>
<path id="path2485" style="fill:#d3d7cf" d="m506.25 543.91l7.55 0.65 5.39 31.27-6.9 5.82s1.72-29.11-6.04-37.74z"/>
<path id="path2487" style="fill:#d3d7cf" d="m490.07 550.6l8.85 3.67 3.37 29.89-8.33 5.26s3.23-36.23-3.89-38.82"/>
<path id="path2489" style="fill:#d3d7cf" d="m466.45 555.56l6.04 4.96-1.08 30.41-7.98 2.15s8.2-9.27 3.02-37.52"/>
<path id="path2491" style="fill:#d3d7cf" d="m439.18 556.73l7.76 4.53s-2.37 12.08-2.37 12.73c0 0.64 0.43 14.88 0.43 14.88l-8.84 4.1s8.84-10.57 3.02-36.24z"/>
<path id="path2493" style="fill:#d3d7cf" d="m396.48 567.2l3.23 1.51v16.18l-4.74 0.22s4.09-5.61 1.51-17.91"/>
<path id="path2497" style="fill:#d3d7cf" d="m419.12 558.36l3.67 3.24-2.65 5.6-0.57 21.89-7.56 0.11s3.45-0.65 7.11-30.84z"/>
<path id="path2580" style="fill:#2e3436" d="m298.63 336.41h-0.04c-6.05 0.41-24.52 2.9-32.29 5.49-8.67 2.89-12.75 5.27-14.07 8.21-0.31 0.68-0.46 1.38-0.46 2.09 0 0.66 0.14 1.32 0.4 1.94 0.82 1.91 2.09 3.1 3.37 3.81-2.07 22.42-5.82 55.62-8.3 61.39-1.58 3.71-4.11 8.19-6.78 12.94-3.42 6.06-7.28 12.92-10.41 20.23-4.43 10.34-6.7 21.92-6.7 33.95 0 3.21 0.16 6.44 0.49 9.7 0.7 6.98 1.64 16.24 8.41 18.99-0.1 3.51-0.44 15.96-0.44 15.96l1.22 0.96c0.27 0.21 6.79 5.2 21.05 10.08 16.55 5.67 22.56 5.61 40.43 5.44l0.94-0.01 4.54-0.11c4.21-0.13 8.52-0.25 11.97 0.25 1.08 0.66 21.26 12.92 21.44 13.03 18.09 12.96 26.52 16.31 44.95 23.65l5.02 2c8.76 3.45 12.45 3.05 15.73 2.27 2.37 2.53 8.01 7.64 21.17 4.71 8.26 4.31 17.17 5.04 25.35 2.03 12.19 3.51 21.45 2.74 28.2-2.38 12.31 3.27 23.95 0.95 29.96-5.91 9.66-0.59 13.21-2.48 18.36-9.71 4.49-1.83 8.79-4.9 8.79-12.7v-0.06-0.07c-0.37-8.77-2.21-16.44-3.96-22.79l-0.03-0.1-0.04-0.11c-0.92-2.58-3.3-6.53-6.97-8.08-0.27-7.49-4.28-28.39-38.9-43.16-1.36-0.58-3.18-0.85-5.11-1.13-1.24-0.19-2.94-0.44-3.53-0.7-28.45-12.37-37.73-23.31-37.82-23.42l-0.22-0.26-0.28-0.22s-20.02-15.36-20.43-15.69c-0.32-0.34-1.52-1.65-1.52-1.65-6.18-6.69-11.05-11.97-14.46-38.65-0.53-4.17-0.76-8.34-0.76-12.43 0-23.35 7.4-43.91 7.48-44.15l0.54-1.47-0.88-1.3c-0.27-0.39-2.77-3.84-7.92-3.84-2.76 0-4.48 0.59-5.56 1.25-13.17 0.53-28.62 0.2-31.31-1.29-0.72-0.4-1.4-1.04-2.26-1.85-2.75-2.58-6.52-6.12-16.95-7.12-14.5-1.16-29.07-0.65-41.41-0.01zm40.88 6.11c8.29 0.79 10.95 3.29 13.3 5.49 1.02 0.96 2.09 1.96 3.48 2.73 5.53 3.07 28.55 2.33 35.47 2.02l1.28-0.05s0.38-0.44 0.72-0.82c0.07-0.05 0.68-0.34 2.36-0.34 0.79 0 1.36 0.2 1.82 0.43-1.92 5.87-7.17 23.7-7.17 44.02 0 4.38 0.25 8.88 0.82 13.39 3.66 28.63 9.39 34.84 16.03 42.03l1.85 2.02 0.23 0.18s19.92 15.29 20.4 15.66c1.7 1.93 12.03 12.75 39.84 24.84 1.34 0.58 3.16 0.85 5.08 1.14 1.32 0.19 2.97 0.44 3.61 0.71 32.9 14.03 35.2 33.23 35.2 38.3 0 0.7-0.04 1.13-0.06 1.25l-0.39 3.41 3.43 0.02c1.94 0 3.7 3.06 4.29 4.62 1.65 5.97 3.36 13.14 3.71 21.21-0.02 3.98-1.3 5.62-5.7 7.27l-0.9 0.34-0.55 0.78c-4.38 6.32-5.92 7.48-15.51 7.93l-1.47 0.07-0.87 1.19c-4.29 5.9-14.91 7.71-25.81 4.39l-1.64-0.49-1.28 1.13c-5.31 4.71-13.38 5.33-24.69 1.89l-1.05-0.31-1 0.41c-4.99 2.05-12.89 3.39-22.19-1.88l-1.07-0.6-1.18 0.3c-11.29 2.82-14.96-1.19-16.72-3.13l-2.6-2.34-0.77 0.59-2.1 0.39c-1.95 0.47-4.38 1.04-12.09-1.99 0.02 0-5.01-2-5.01-2-18.53-7.38-26.2-10.43-43.75-23.02l-0.1-0.06-22.7-13.8-0.58-0.1c-4.12-0.69-9.2-0.53-13.69-0.38l-4.4 0.11-0.95 0.01c-17.53 0.16-22.83 0.21-38.38-5.12-9.82-3.36-15.68-6.76-18.05-8.29 0.07-2.7 0.49-17.9 0.49-17.9l-2.77-0.37c-3.73-0.46-4.92-5.36-5.8-14.24-0.31-3.06-0.46-6.1-0.46-9.11 0-11.19 2.1-21.95 6.2-31.53 3-7 6.78-13.72 10.12-19.64 2.75-4.89 5.36-9.52 7.08-13.53 3.76-8.79 8.46-59.87 8.99-65.66l0.29-3.24s-2.99-0.09-3.21-0.1c-0.16-0.01-0.5-0.1-0.81-0.47 0.72-0.68 2.99-2.21 10.1-4.58 6.78-2.26 24.22-4.74 30.75-5.18 12.13-0.63 26.44-1.13 40.53 0z"/>
<path style="fill:#2e3436" d="M 13.40625 174.5 L 12.21875 176.46875 C 32.228749 188.40875 51.296251 189.33125 83.90625 186.78125 C 94.56625 189.67125 104.36375 195.21375 113.84375 200.59375 C 118.76375 203.39375 123.87 206.28 129 208.75 C 157.51142 222.9319 163.05796 225.54474 177.5625 227.96875 C 176.97616 228.96111 176.47871 230.05592 176.0625 231.25 L 176.03125 231.34375 L 176 231.40625 C 175.12232 230.74911 173.9157 230.06765 172.21875 229.6875 L 172.15625 229.6875 L 172.09375 229.6875 C 165.49375 228.9475 160.72625 231.2125 158.65625 236.0625 L 158.625 236.125 L 158.59375 236.21875 C 157.68375 239.78875 157.6725 243.64375 158.5625 248.34375 L 160.84375 247.90625 C 160.42375 245.71625 160.21875 243.74625 160.21875 241.90625 C 160.21875 240.11625 160.4125 238.455 160.8125 236.875 C 162.4725 233.055 166.24 231.36875 171.75 231.96875 C 173.98435 232.47884 175.10023 233.5158 175.5625 234.09375 C 174.874 239.05235 175.01123 244.43196 176 250.8125 L 178.28125 250.46875 C 177.71125 246.82875 177.4375 243.5175 177.4375 240.4375 C 177.4375 237.4175 177.7 234.6175 178.25 231.9375 C 180.55 225.3975 185.74125 222.49 193.28125 223.5 C 196.92386 224.5123 198.39914 226.72513 198.84375 227.5625 C 198.02304 228.93811 197.33544 230.47205 196.78125 232.1875 L 196.75 232.28125 L 196.75 232.34375 C 195.4 239.38375 195.4 247.00375 196.75 256.34375 L 199 256 C 198.34 251.45 198 247.34 198 243.5 C 198 239.71 198.36 236.20375 199 232.84375 C 201.7 224.58375 207.74125 220.88625 216.53125 222.15625 C 220.35647 223.30308 222.21461 225.77974 222.9375 227.0625 C 222.37942 228.19593 221.91063 229.42222 221.5 230.75 L 221.46875 230.8125 L 221.46875 230.90625 C 220.10875 238.25625 220.0875 246.20875 221.4375 255.96875 L 223.71875 255.65625 C 223.05875 250.89625 222.71875 246.5825 222.71875 242.5625 C 222.71875 238.5925 223.0475 234.895 223.6875 231.375 C 226.3875 222.715 232.47 218.8675 241.25 220.1875 C 246.2917 221.77506 248.40986 226.12107 248.59375 226.5 C 248.55888 226.60813 248.50259 226.70306 248.46875 226.8125 L 248.4375 226.96875 L 248.40625 227.125 C 248.12625 232.795 248.2225 238.3925 248.3125 243.8125 L 248.40625 251.875 L 250.71875 251.875 L 250.625 243.78125 C 250.585 241.06125 250.53125 238.32125 250.53125 235.53125 C 250.53125 232.84125 250.58875 230.095 250.71875 227.375 C 253.42875 218.755 259.49 214.89875 268.25 216.21875 C 272.80875 217.645 274.44139 220.00773 274.84375 220.6875 C 274.92127 221.41844 275.01239 222.20846 275.125 223.1875 C 275.605 227.3775 276.43375 234.40875 277.34375 246.96875 L 279.625 246.8125 C 278.705 234.2025 277.89625 227.1575 277.40625 222.9375 C 277.09625 220.3175 276.9375 218.7875 276.9375 217.6875 C 276.9375 217.1375 276.9625 216.70125 277.0625 216.28125 C 278.2625 213.09125 280.08875 210.9925 282.46875 210.0625 C 285.34651 208.92711 288.41554 209.72238 289.96875 210.28125 C 290.80024 215.92606 292.44227 226.28561 292.53125 226.84375 L 294.34375 238.1875 L 296.625 237.8125 L 294.8125 226.46875 C 294.7925 226.29875 292.14125 209.71 291.78125 206.75 C 291.47125 204.16 292.605 202.02 292.625 202 L 290.625 200.90625 C 290.565 201.01625 289.1 203.69125 289.5 207.03125 C 289.51583 207.16362 289.56984 207.60059 289.59375 207.78125 C 287.57406 207.21222 284.57689 206.75501 281.625 207.90625 C 278.585 209.09625 276.315 211.6825 274.875 215.5625 L 274.875 215.625 L 274.84375 215.6875 C 274.73609 216.14297 274.6814 216.62015 274.65625 217.125 C 273.37099 216.02782 271.51706 214.8302 268.8125 214 L 268.75 214 L 268.65625 213.96875 C 259.77355 212.59945 253.1278 216.05741 249.625 223.75 C 248.33814 221.8835 245.88727 219.17921 241.84375 217.9375 L 241.75 217.9375 L 241.6875 217.90625 C 233.98912 216.71832 227.9672 219.18454 224.21875 224.875 C 223.02733 223.20051 220.87545 221.03333 217.125 219.9375 L 217.03125 219.90625 L 216.96875 219.90625 C 209.76924 218.8458 204.02926 220.81365 200.25 225.53125 C 199.23637 224.13241 197.29552 222.19139 193.84375 221.25 L 193.75 221.21875 L 193.6875 221.21875 C 186.99056 220.30273 181.74959 222.2084 178.46875 226.625 L 178.59375 225.84375 C 164.31375 223.50375 159.7 221.4675 130 206.6875 C 124.92 204.2475 119.89 201.37375 115 198.59375 C 105.35 193.11375 95.35375 187.46 84.34375 184.5 L 84.15625 184.4375 L 83.9375 184.46875 C 51.697501 187.00875 32.926249 186.14 13.40625 174.5 z " transform="translate(223.3556,335.727)" id="path2582"/>
<path id="path2598" style="fill:#2e3436" d="m419.3 506.98c-10.88 9.7-23.31 27.27-20.82 55.92l6.09-0.53c-2.27-26.12 8.97-42.06 18.8-50.82 15.94-14.22 38.54-19.04 51.7-16.36l1.22-5.99c-14.99-3.06-39.38 2.07-56.99 17.78z"/>
<path id="path2600" style="fill:#2e3436" d="m232.82 519.57c-0.93 1.44-0.51 3.35 0.94 4.28 20.61 13.17 45.09 17.69 79.24 14.62 4.6 2.5 7.81 4.51 11.14 6.62 4.93 3.11 10.52 6.64 21.91 12.57 1.52 0.79 3.39 0.2 4.18-1.32s0.2-3.39-1.32-4.18c-11.16-5.81-16.63-9.26-21.46-12.31-3.63-2.29-7.06-4.46-12.3-7.28-0.54-0.29-1.15-0.41-1.76-0.35-33.19 3.11-56.73-1.08-76.3-13.59-1.44-0.93-3.35-0.51-4.27 0.94z"/>
<path id="path2731_2_" style="fill:#8cc2d7" d="m356.17 362.56c0 2.93-2.14 5.3-4.77 5.3-2.64 0-4.77-2.37-4.77-5.3 0-2.92 2.13-5.29 4.77-5.29 2.63 0 4.77 2.37 4.77 5.29z"/>
<path id="path2603" style="fill:#2e3436" d="m345.52 362.56c0 3.53 2.64 6.4 5.88 6.4s5.87-2.87 5.87-6.4c0-3.52-2.63-6.39-5.87-6.39s-5.88 2.87-5.88 6.39zm2.21 0c0-2.31 1.64-4.19 3.67-4.19 2.02 0 3.66 1.88 3.66 4.19s-1.64 4.19-3.66 4.19-3.67-1.88-3.67-4.19z"/>
<path id="path3503_2_" style="fill:#babdb6" d="m360.14 395.34c0 2.93-2.14 5.3-4.77 5.3-2.64 0-4.78-2.37-4.78-5.3 0-2.92 2.14-5.29 4.78-5.29 2.63 0 4.77 2.37 4.77 5.29z"/>
<path id="path2606" style="fill:#2e3436" d="m349.49 395.34c0 3.53 2.63 6.4 5.87 6.4s5.88-2.87 5.88-6.4c0-3.52-2.64-6.39-5.88-6.39s-5.87 2.87-5.87 6.39zm2.2 0c0-2.31 1.65-4.19 3.67-4.19 2.03 0 3.67 1.88 3.67 4.19s-1.64 4.19-3.67 4.19c-2.02 0-3.67-1.88-3.67-4.19z"/>
<path id="path3505_2_" style="fill:#babdb6" d="m364.57 429.35c0 2.92-2.14 5.29-4.78 5.29-2.63 0-4.77-2.37-4.77-5.29s2.14-5.29 4.77-5.29c2.64 0 4.78 2.37 4.78 5.29z"/>
<path id="path2609" style="fill:#2e3436" d="m353.92 429.35c0 3.53 2.64 6.4 5.87 6.4 3.24 0 5.88-2.87 5.88-6.4s-2.64-6.4-5.88-6.4c-3.23 0-5.87 2.87-5.87 6.4zm2.21 0c0-2.31 1.64-4.19 3.66-4.19 2.03 0 3.67 1.88 3.67 4.19s-1.64 4.19-3.67 4.19c-2.02 0-3.66-1.88-3.66-4.19z"/>
<path id="path3507_2_" style="fill:#babdb6" d="m376.58 463.6c0 2.93-2.14 5.29-4.77 5.29-2.64 0-4.77-2.36-4.77-5.29 0-2.92 2.13-5.29 4.77-5.29 2.63 0 4.77 2.37 4.77 5.29z"/>
<path id="path2612" style="fill:#2e3436" d="m365.93 463.6c0 3.53 2.64 6.4 5.88 6.4s5.88-2.87 5.88-6.4c0-3.52-2.64-6.39-5.88-6.39s-5.88 2.87-5.88 6.39zm2.21 0c0-2.31 1.65-4.19 3.67-4.19s3.67 1.88 3.67 4.19-1.65 4.19-3.67 4.19-3.67-1.88-3.67-4.19z"/>
<path id="path3509_2_" style="fill:#babdb6" d="m403.97 487.08c0 2.92-2.14 5.29-4.77 5.29-2.64 0-4.78-2.37-4.78-5.29 0-2.93 2.14-5.3 4.78-5.3 2.63 0 4.77 2.37 4.77 5.3z"/>
<path id="path2615" style="fill:#2e3436" d="m393.32 487.08c0 3.52 2.63 6.39 5.87 6.39s5.88-2.87 5.88-6.39c0-3.53-2.64-6.4-5.88-6.4s-5.87 2.87-5.87 6.4zm2.21 0c0-2.31 1.64-4.19 3.66-4.19 2.03 0 3.67 1.88 3.67 4.19s-1.64 4.19-3.67 4.19c-2.02 0-3.66-1.88-3.66-4.19z"/>
<path id="path3511_2_" style="fill:#eeeeec" d="m401.44 361.21l-1.37 9.15c2.52 5.76 4.4 13.74 4.21 19.56-0.68 21.52 0.92 38.64 2.23 45.24 1.83 9.31 2.77 9.36 3.76 10.2l5.05 5.4s-2.57-3.54-5.27-24.11c-2.69-20.57 1.64-30.07-2.84-50.28-1.65-7.41-3.75-12.15-5.77-15.16z"/>
<path id="path2618" style="fill:#2e3436" d="m401.05 361.15l-1.39 9.26 0.04 0.11c2.68 6.12 4.36 13.91 4.19 19.39-0.74 23.2 1.13 39.8 2.23 45.33 1.71 8.7 2.66 9.45 3.66 10.24l0.23 0.18 5.02 5.37 0.61-0.51c-0.02-0.03-2.57-3.85-5.19-23.92-1.2-9.14-1-16.07-0.81-22.78 0.23-8.37 0.45-16.29-2.04-27.53-1.46-6.56-3.42-11.71-5.83-15.3l-0.57-0.86-0.15 1.02zm0.62 1.24c2.09 3.46 3.83 8.14 5.15 14.07 1.75 7.92 2.15 14.18 2.15 20.12 0 2.43-0.06 4.81-0.13 7.22-0.07 2.5-0.14 5.03-0.14 7.7 0 4.51 0.2 9.41 0.96 15.2 1.7 13.04 3.36 19.25 4.36 22.09-1.49-1.59-3.46-3.7-3.46-3.7-0.04-0.03-0.28-0.23-0.28-0.23-0.81-0.64-1.72-1.36-3.38-9.77-0.92-4.64-2.39-17.1-2.39-34.74 0-3.3 0.05-6.78 0.17-10.42 0.01-0.26 0.01-0.53 0.01-0.81 0-5.49-1.65-12.9-4.21-18.81 0.03-0.18 0.93-6.21 1.19-7.92z"/>
<path id="path3518_2_" style="fill:#2e3436" d="m273.51 560.51l-0.26 3.04-15.56-1.4c-2.43-0.22-1.81-3.68 0.26-3.44l15.56 1.8z"/>
<path id="path2624" style="fill:#2e3436" d="m256.17 559.12c-0.48 0.65-0.59 1.56-0.27 2.27 0.31 0.67 0.93 1.08 1.76 1.15l15.95 1.44 0.33-3.83-15.94-1.84c-0.73-0.08-1.4 0.21-1.83 0.81zm1.56 2.63c-0.54-0.05-0.92-0.29-1.1-0.69-0.08-0.17-0.11-0.36-0.11-0.55 0-0.33 0.1-0.66 0.29-0.92 0.15-0.21 0.5-0.55 1.1-0.48 0 0 14.44 1.66 15.17 1.75-0.04 0.5-0.15 1.74-0.19 2.26-0.76-0.07-15.16-1.37-15.16-1.37z"/>
<path id="path3528_2_" style="fill:#ffffff" d="m384.63 383.23l-0.13 10.48-20.62-15.69-1.95-11.69 22.7 16.9z"/>
<path id="path2627" style="fill:#2e3436" d="m361.54 366.4l1.97 11.84 21.37 16.26 0.15-11.47-23.65-17.61 0.16 0.98zm0.95 0.84c1.46 1.09 21.43 15.96 21.74 16.19 0 0.36-0.1 8.16-0.12 9.48-1.18-0.9-19.62-14.93-19.86-15.11-0.05-0.28-1.49-8.95-1.76-10.56z"/>
<path id="path3530_2_" style="fill:#dcecf3" d="m385.34 415.37l-19.39-14.93 1.29 9.57 19.49 14.81-1.39-9.45z"/>
<path id="path2630" style="fill:#2e3436" d="m365.56 400.49l1.31 9.74 20.4 15.5-1.55-10.57-20.29-15.63 0.13 0.96zm0.91 0.85c1.41 1.09 18.26 14.06 18.5 14.25 0.04 0.28 1 6.8 1.23 8.32-1.43-1.08-18.34-13.92-18.59-14.11-0.04-0.29-0.93-6.93-1.14-8.46z"/>
<path id="path3532_2_" style="fill:#babdb6" d="m393.26 445.42l-21.08-12.13 2.16 8.12 26.83 14.77-7.91-10.76z"/>
<path id="path2633" style="fill:#2e3436" d="m371.8 433.39l2.2 8.28 26.98 14.86 0.51-0.59-7.96-10.83-21.98-12.65 0.25 0.93zm1.01 0.72c1.53 0.88 20.04 11.53 20.18 11.61 0.08 0.12 5.2 7.07 6.79 9.23-2.79-1.53-24.82-13.66-25.1-13.81-0.07-0.28-1.49-5.61-1.87-7.03z"/>
<path id="path3534_2_" style="fill:#babdb6" d="m413.5 467.82l-28.37-6.06 7.56 7.4 28.28 4.67-7.47-6.01z"/>
<path id="path2636" style="fill:#2e3436" d="m384.85 462.05l7.65 7.48 29.9 4.94-8.72-7.02-29.81-6.36 0.98 0.96zm1.54 0.39c2.43 0.52 26.76 5.71 26.94 5.75 0.12 0.09 4.56 3.67 6.21 5-2.67-0.44-26.43-4.37-26.66-4.4-0.15-0.15-5.02-4.91-6.49-6.35z"/>
<path id="path3546_2_" style="fill:#ffffff" d="m397.83 483.74c9.2-8.52 19.96-13.21 38.83-16.79 2.36 0.89 5.66 3.26 4.87 6.21-8.45 3.04-22.7 5.05-40.02 17.06-2.79-1.45-4.23-3.06-3.68-6.48z"/>
<path id="path2639" style="fill:#2e3436" d="m436.59 466.56c-18.81 3.56-29.76 8.3-39.03 16.89l-0.1 0.09-0.03 0.14c-0.59 3.74 1.13 5.46 3.9 6.89l0.21 0.11 0.2-0.13c13.31-9.23 24.82-12.54 33.23-14.95 2.55-0.74 4.75-1.37 6.69-2.07l0.2-0.07 0.05-0.2c0.92-3.41-2.94-5.86-5.11-6.68l-0.1-0.04-0.11 0.02zm0.03 0.8c2.01 0.79 4.63 2.64 4.63 4.91 0 0.19-0.04 0.39-0.08 0.59-1.87 0.66-3.97 1.27-6.42 1.97-8.41 2.42-19.92 5.73-33.25 14.92-2.1-1.13-3.39-2.34-3.39-4.67 0-0.35 0.04-0.74 0.1-1.14 9.11-8.39 19.91-13.05 38.41-16.58z"/>
<g id="layer1_3_" transform="translate(71.83 210.51)">
<path id="path2600_2_" style="fill:url(#linearGradient3327)" d="m318.35 147.12c-9.02-0.46-11.89 6.38-14.26 14.03-4.86 23.71-1.7 47.64 0 71.51 0.46 5.52 5.75 11.73 5.75 11.73l-0.69-9.89c-1.1-24.04-3.82-48.14 0.92-71.97 0.75-3.39 3.91-9.2 5.29-9.2s2.3-5.97 2.99-6.21z"/>
<path id="path2656" style="fill:#2e3436" d="m303.71 161.03c-4.14 20.18-2.48 40.77-0.87 60.69l0.86 10.97c0.46 5.59 5.62 11.7 5.84 11.96l0.78 0.92-0.77-11.1-0.69-12.9c-1.12-19.39-2.28-39.45 1.6-58.96 0.77-3.48 3.91-8.88 4.9-8.88 1.04 0 1.63-1.66 2.41-4.19 0.25-0.8 0.59-1.9 0.77-2.07l1.26-0.67-1.43-0.07c-9.29-0.48-12.23 6.49-14.66 14.3zm0.78 71.6l-0.85-10.97c-0.86-10.62-1.73-21.43-1.73-32.24 0-9.43 0.66-18.86 2.57-28.19 2.25-7.25 4.98-13.78 13.14-13.73-0.17 0.41-0.36 0.98-0.61 1.8-0.33 1.09-1.12 3.63-1.65 3.63-1.74 0-4.94 6.19-5.68 9.51-2.04 10.28-2.7 20.68-2.7 31.05 0 9.44 0.54 18.86 1.08 28.12l0.69 12.91s0.47 6.65 0.6 8.6c-1.47-1.95-4.52-6.44-4.86-10.49z"/>
</g>
<path id="path3540_2_" style="fill:#ffffff" d="m355.48 391.38c12.41-2.3 25.67-3.52 41.51-1.47 1.66 1.89 1.76 6.53-0.32 8.77-8.89-1.27-20.12-1.8-41.05 0.71-1.79-2.59-2.22-5.24-0.14-8.01z"/>
<path id="path2659" style="fill:#2e3436" d="m355.41 390.99l-0.15 0.02-0.1 0.13c-2.01 2.68-1.97 5.45 0.13 8.48l0.14 0.2 0.23-0.03c21.97-2.64 33.03-1.84 40.96-0.72l0.2 0.03 0.14-0.15c2.25-2.43 2.09-7.3 0.33-9.3l-0.1-0.12-0.15-0.02c-13.71-1.77-26.55-1.32-41.63 1.48zm41.36-0.7c0.69 0.85 1.07 2.26 1.07 3.73 0 1.55-0.43 3.15-1.35 4.23-7.92-1.11-18.98-1.87-40.65 0.72-0.88-1.34-1.36-2.59-1.36-3.8 0-1.17 0.44-2.3 1.25-3.43 14.85-2.74 27.53-3.18 41.04-1.45z"/>
<path id="path3542_2_" style="fill:#ffffff" d="m359.69 425.5c12.16-3.35 25.27-5.7 41.22-5.02 1.47 1.53 2.32 6.35 0.44 8.76-8.97-0.49-20.21-0.06-40.84 4.24-2.01-2.43-2.66-5.04-0.82-7.98z"/>
<path id="path2662" style="fill:#2e3436" d="m359.58 425.12l-0.15 0.04-0.08 0.13c-1.77 2.85-1.5 5.61 0.85 8.44l0.15 0.19 0.24-0.05c21.66-4.52 32.75-4.67 40.74-4.23l0.21 0.01 0.12-0.16c2.02-2.59 1.14-7.62-0.46-9.29l-0.11-0.11-0.16-0.01c-13.82-0.59-26.57 0.96-41.35 5.04zm41.13-4.25c0.77 0.89 1.32 2.74 1.32 4.58 0 1.26-0.28 2.49-0.9 3.38-7.98-0.43-19.07-0.23-40.45 4.21-1.11-1.4-1.68-2.75-1.68-4.1 0-1.02 0.33-2.05 0.96-3.1 14.56-4 27.14-5.53 40.75-4.97z"/>
<path id="path3544_2_" style="fill:#ffffff" d="m371.37 459.04c12.19-5.33 25.55-9.82 42.47-11.79 4.61-0.1 7.63 4.18 6.1 6.87-9.54 0.99-25.31 4.99-46.24 12.65-2.56-2.06-3.98-2.9-2.33-7.73z"/>
<path id="path2665" style="fill:#2e3436" d="m413.83 446.85c-14.69 1.71-27.82 5.35-42.62 11.82l-0.16 0.07-0.06 0.17c-1.67 4.87-0.24 6.01 2.12 7.89l0.52 0.42 0.21-0.08c19.24-7.04 35.62-11.53 46.14-12.63l0.21-0.02 0.1-0.18c0.68-1.19 0.58-2.76-0.26-4.18-0.97-1.63-3.11-3.34-6.2-3.28zm0.05 0.79c2.23-0.04 4.39 1.1 5.46 2.9 0.4 0.68 0.61 1.37 0.61 2.01 0 0.43-0.13 0.83-0.32 1.2-10.54 1.15-26.8 5.6-45.85 12.57l-0.18-0.14c-1.56-1.25-2.55-2.04-2.55-3.78 0-0.78 0.22-1.78 0.65-3.07 14.65-6.39 27.67-10 42.18-11.69z"/>
<path id="path4266" style="fill-rule:evenodd;fill:#2e3436" d="m327.18 345.75c-2.97-0.01-6.77 0.04-10.88 0.15-8.21 0.23-17.54 0.69-23.47 1.35-11.83 1.31-33.78 5.97-33.78 5.97l0.59 2.93s22.07-4.63 33.54-5.9c5.72-0.64 15.02-1.12 23.18-1.35 4.09-0.11 7.89-0.16 10.82-0.15 1.46 0 2.71 0.03 3.65 0.06 0.95 0.03 1.69 0.11 1.75 0.13h0.03 0.03c6.78 0.97 14.56 4.48 21.04 6.43h0.06l0.06 0.03c1.15 0.24 2.12 0.25 3-0.09 0.89-0.34 1.5-1.03 1.88-1.66 0.74-1.24 1.01-2.34 1.96-3.37l-2.21-2.03c-1.46 1.57-1.93 3.2-2.32 3.84-0.19 0.32-0.24 0.36-0.37 0.41s-0.53 0.12-1.31-0.03c-0.01-0.01-0.03 0-0.04 0-6.1-1.86-13.85-5.39-21.21-6.47v-0.03c-0.03-0.01-0.07 0-0.1 0-0.56-0.11-1.17-0.13-2.12-0.16-1-0.03-2.3-0.06-3.78-0.06z"/>
<path id="path4268" style="fill-rule:evenodd;fill:#2e3436" d="m335.93 350.9h2l-0.04-4h-2l0.04 4zm0.06 4.04l0.03 1.5v0.03l0.06 2.47 2-0.07-0.06-2.47-0.03-1.5-2 0.04zm0.19 8v0.21l0.12 3.79 2-0.07-0.12-3.78v-0.22l-2 0.07zm0.28 8v0.21l0.15 3.79 2-0.1-0.15-3.75v-0.03l-0.03-0.19-1.97 0.07zm0.34 8l0.06 1.25v0.03l0.16 2.72 2-0.1-0.16-2.75-0.06-1.25-2 0.1zm0.44 8l0.19 3.06v0.03l0.06 0.91 2-0.13-0.1-0.91v-0.03l-0.15-3.03-2 0.1zm0.53 8l0.28 4 2-0.16-0.28-4-2 0.16zm0.62 8l0.22 2.65v0.03l0.13 1.32 2-0.22-0.13-1.28-0.25-2.69-1.97 0.19zm0.72 7.96l0.44 4 1.97-0.21-0.41-3.97-2 0.18zm0.91 7.97l0.28 2.57 0.22 1.43 1.97-0.28-0.19-1.4v-0.04l-0.31-2.5-1.97 0.22zm1.03 7.97l0.59 3.97 1.97-0.31-0.59-3.97-1.97 0.31zm1.25 7.91l0.31 1.81v0.03l0.41 2.13 1.97-0.38-0.41-2.12-0.31-1.78-1.97 0.31zm1.53 7.9l0.69 3.19v0.03h0.03l0.16 0.72 1.93-0.5-0.15-0.65v-0.04l-0.72-3.18-1.94 0.43zm1.88 7.85l1.06 3.69h0.03v0.03l0.06 0.15 1.88-0.62-0.03-0.13-0.03-0.06-1.04-3.62-1.93 0.56zm2.47 7.72l0.53 1.43h0.03v0.04l0.69 1.62v0.03l0.31 0.63 1.81-0.85-0.28-0.59-0.03-0.03-0.66-1.56v-0.04l-0.56-1.4-1.84 0.72zm3.43 7.37l0.07 0.1v0.03h0.03l0.78 1.22v0.03l0.03 0.03 0.78 1.09 0.03 0.03 0.03 0.03 0.69 0.82 1.53-1.28-0.65-0.75-0.04-0.07-0.75-1-0.03-0.06-0.72-1.12-0.03-0.04-0.03-0.06-1.72 1zm5.25 6.35l1 1 1.88 1.78 1.37-1.44-1.84-1.75-0.03-0.03-0.97-0.97-1.41 1.41zm5.91 5.5l1.22 1.06h0.03l1.81 1.53 1.28-1.53-1.81-1.53-1.22-1.07-1.31 1.54zm6.22 5.09l1.72 1.34 0.03 0.03 1.44 1.07 1.21-1.6-1.46-1.09v0.03l-1.69-1.34-1.25 1.56zm6.44 4.84l3.25 2.32 1.15-1.66-3.25-2.28-1.15 1.62zm6.59 4.6l2.66 1.78 0.68 0.44 1.07-1.69-0.66-0.44v0.03l-2.66-1.81-1.09 1.69zm6.69 4.37l0.47 0.31 2.93 1.85 1.07-1.72-2.91-1.81h-0.03l-0.44-0.28-1.09 1.65zm6.81 4.25l1.94 1.16h0.03l1.5 0.87 1-1.72-1.5-0.87-1.91-1.16-1.06 1.72zm6.94 4.06l1.78 1.04 1.69 0.93 1-1.75-1.69-0.9-0.03-0.03-1.75-1.04-1 1.75zm7 3.91l1 0.56 2.53 1.35 0.94-1.78-2.54-1.35-1-0.53-0.93 1.75zm7.06 3.78l2.97 1.6 0.94-1.79-2.97-1.59-0.94 1.78z"/>
<path id="path3516_2_" style="fill:#ffffff" d="m351.81 359.95c2.9 0.24 3.25 3.63 3.54 6.16 1.41 12.17-3.45 28.98-13.5 42.7-9.52 13-12.08 23.88-9.66 34.57 3.02 13.36 10.03 23.53 11.86 34.38 1.84 10.89-0.44 27.15-2.32 33.54-1.94 6.62-10.11 60.87-38.8 58.48-23.75-2-27.17-5.02-27.17-5.02l-2.62-1.21 0.16-3.05s6.87-1.24 8.98-0.38 19.07 4.43 22.52 4.26c4.25-0.2 7.36-0.45 12.6-5.84s9.97-15.61 9.97-15.61c6.82-21.87 13.25-39.24 10.11-66.82-2.86-15.15-18.12-29.3-10.36-54.2 4.44-12.26 14.52-23.19 18.86-35.47 2.38-6.75 3.39-11.65 2.61-17.9-0.2-1.59-0.76-2-0.55-5.61 0.13-2.14 1.83-3.14 3.77-2.98z"/>
<path id="path2621" style="fill:#2e3436" d="m348.79 360.43c-0.69 0.6-1.09 1.46-1.15 2.48-0.15 2.6 0.1 3.61 0.32 4.51l0.23 1.17c0.8 6.42-0.34 11.36-2.59 17.72-2.17 6.16-5.87 12.09-9.45 17.83-3.54 5.67-7.19 11.52-9.41 17.63-5.36 17.22 0.19 29.38 5.09 40.12 2.24 4.92 4.37 9.57 5.26 14.29 2.89 25.44-2.44 42.32-8.61 61.87l-1.5 4.76c-0.02 0.06-4.73 10.18-9.86 15.45-5.23 5.38-8.37 5.53-12.34 5.73-3.49 0.17-20.42-3.45-22.35-4.24-2.19-0.89-8.92 0.31-9.2 0.36l-0.31 0.06-0.19 3.63s2.74 1.27 2.82 1.31c0.5 0.38 4.89 3.18 27.35 5.07 25.75 2.15 35.19-40.72 38.29-54.81l0.93-3.96c1.72-5.86 4.26-22.3 2.33-33.71-0.94-5.54-3.2-10.88-5.6-16.54-2.35-5.56-4.79-11.3-6.27-17.87-2.5-11.02 0.55-21.9 9.59-34.24 9.73-13.29 15.06-30.16 13.58-42.98l-0.02-0.12c-0.3-2.59-0.7-6.14-3.89-6.4-1.2-0.09-2.28 0.22-3.05 0.88zm-43.97 204.35c4.15-0.2 7.42-0.36 12.87-5.96 5.22-5.37 9.99-15.62 10.04-15.72 0.02-0.05 1.51-4.81 1.51-4.81 6.2-19.63 11.55-36.59 8.64-62.23-0.92-4.85-3.06-9.54-5.33-14.5-4.83-10.61-10.32-22.62-5.05-39.53 2.18-6.02 5.81-11.84 9.32-17.47 3.61-5.77 7.33-11.75 9.53-17.98 2.29-6.47 3.45-11.51 2.63-18.09l-0.25-1.26c-0.21-0.88-0.44-1.79-0.29-4.27 0.05-0.82 0.34-1.46 0.87-1.92 0.6-0.53 1.48-0.77 2.47-0.69 2.53 0.2 2.88 3.25 3.16 5.69l0.02 0.12c0.16 1.4 0.24 2.85 0.24 4.34 0 11.94-5.12 26.4-13.67 38.08-7.13 9.73-10.59 18.59-10.59 27.33 0 2.52 0.29 5.04 0.86 7.56 1.5 6.63 3.95 12.41 6.32 18 2.37 5.61 4.62 10.92 5.54 16.36 0.48 2.87 0.68 6.05 0.68 9.31 0 9.56-1.72 19.71-2.99 24.04l-0.94 4.02c-3.06 13.92-12.39 56.27-37.44 54.19-23.11-1.95-26.92-4.9-26.96-4.93l-0.04-0.03-0.05-0.03s-1.97-0.91-2.37-1.1c0.02-0.39 0.11-1.99 0.13-2.46 2.06-0.35 6.88-0.99 8.45-0.35 2.16 0.88 19.1 4.47 22.69 4.29z"/>
<path id="path4270" style="fill-rule:evenodd;fill:#2e3436" d="m233.24 455.06l0.34 0.09 1.13 0.38 0.03 0.03 1.69 0.69v0.03h0.06l0.03 0.03 0.81-1.66-0.09-0.03-0.03-0.03h-0.03l-1.79-0.75h-0.03l-1.15-0.4-0.03-0.04-0.41-0.12-0.53 1.78zm6.5 2.88l0.28 0.15 0.03 0.03 1.34 0.82h0.04l1.37 0.9 1-1.53-1.41-0.91v-0.03h-0.03l-1.4-0.84-0.03-0.03-0.29-0.16-0.9 1.6zm5.97 4.03l0.31 0.22 0.03 0.03 1.63 1.34 0.03 0.03 0.75 0.69 1.25-1.38-0.82-0.71h-0.03l-1.65-1.41h-0.03v-0.03l-0.35-0.25-1.12 1.47zm5.34 4.78l1.69 1.84 0.03 0.03 0.69 0.85 1.4-1.19-0.72-0.88-0.03-0.03-1.72-1.84-1.34 1.22zm4.69 5.56l0.34 0.47 0.03 0.03 1.6 2.34 0.03 0.04 0.03 0.06 1.56-0.97-0.06-0.09v-0.04l-1.66-2.4-0.03-0.03v-0.03l-0.4-0.5-1.44 1.12zm3.9 6.03l1.19 2.13 0.03 0.03 0.5 1.03 1.66-0.81-0.53-1.07v-0.03h-0.03l-1.19-2.18-1.63 0.9zm3.25 6.47l0.79 1.81v0.03l0.59 1.54 1.72-0.66-0.6-1.56v-0.03h-0.03l-0.78-1.85-1.69 0.72zm2.57 6.78l0.65 2.03v0.07l0.38 1.37 1.78-0.47-0.38-1.44v-0.03h-0.03l-0.65-2.09-1.75 0.56zm1.93 7l0.69 3h-0.03l0.13 0.53 1.78-0.31-0.1-0.53v-0.03l-0.68-3.06-1.79 0.4zm1.38 7.13l0.06 0.25 0.31 2.25v0.03l0.13 1.06 1.81-0.19-0.12-1.12-0.32-2.31-0.06-0.25-1.81 0.28zm0.87 7.25l0.19 2.47 0.06 1.15 1.85-0.12-0.06-1.16-0.19-2.5v-0.03l-1.85 0.19zm0.41 7.25v0.37l1.84-0.06v-0.38l-1.84 0.07z"/>
<path id="path4293" style="fill:#ffffff" d="m303.98 661.1c0 15.3-9.7 27.71-21.67 27.71s-21.68-12.41-21.67-27.71c-0.01-15.29 9.7-27.7 21.67-27.7s21.67 12.41 21.67 27.7z" transform="matrix(1.003 0 0 .87191 -4.7828 -148.61)"/>
<path id="path4272" style="fill:#2e3436" d="m277.34 402.92l-1.1 0.08h-0.06l-1.1 0.16h-0.06l-1.07 0.22-0.06 0.03h-0.09l-0.66 0.54 0.09 0.79 0.79 0.38 0.34-0.02h0.03l0.06-0.03 0.94-0.19h0.07l0.97-0.16v0.02l1.03-0.11h0.07 0.28l0.81-0.38 0.13-0.76-0.66-0.55-0.34-0.05h-0.35l-0.06 0.03zm3.48 0.43l-0.28 0.74 0.5 0.65 0.31 0.08 0.28 0.06h0.06l0.95 0.19 0.06 0.03 0.94 0.21 0.06 0.03 0.91 0.27v0.03h0.06l0.07 0.03 0.87-0.06 0.5-0.65-0.31-0.74-0.28-0.16-0.1-0.03-0.06-0.02-1.03-0.33h-0.07l-1.03-0.27-0.06-0.03-1.07-0.22h-0.06l-0.35-0.05-0.87 0.24zm-10.69 1.28l-0.47 0.22-0.06 0.03-0.98 0.49-0.03 0.03-0.94 0.54-0.06 0.03-0.75 0.49-0.44 0.68 0.41 0.71 0.87 0.13 0.32-0.13 0.75-0.46 0.03-0.03 0.85-0.49 0.06-0.03 0.85-0.41 0.06-0.03 0.44-0.19 0.53-0.62-0.25-0.77-0.85-0.27-0.34 0.08zm17.33 1.5l0.16 0.76 0.25 0.22 0.44 0.25 0.06 0.03 0.82 0.51 0.03 0.03 0.81 0.57 0.03 0.03 0.63 0.52 0.88 0.22 0.72-0.5-0.03-0.76-0.22-0.24-0.66-0.55-0.03-0.03-0.88-0.62-0.06-0.03-0.91-0.57-0.03-0.03-0.47-0.27-0.91-0.11-0.63 0.57zm-23.29 2.45l-0.28 0.17-0.69 0.68-0.03 0.03-0.75 0.81-0.03 0.03-0.72 0.85-0.04 0.02-0.18 0.22-0.1 0.79 0.63 0.55 0.91-0.14 0.22-0.22 0.15-0.19 0.04-0.03 0.65-0.79 0.04-0.02 0.69-0.74 0.03-0.03 0.69-0.65 0.22-0.74-0.54-0.62-0.91 0.02zm28.9 1.72l-0.12 0.79 0.15 0.25 0.04 0.02 0.68 0.79v0.03l0.66 0.82v0.03l0.6 0.84 0.03 0.03 0.03 0.02 0.72 0.44 0.88-0.24 0.25-0.74-0.09-0.3-0.07-0.05v-0.03l-0.65-0.93-0.04-0.03-0.65-0.87-0.04-0.02-0.72-0.85-0.03-0.03-0.03-0.02-0.81-0.33-0.79 0.38zm-33.38 3.73l-0.22 0.25-0.41 0.71v0.02l-0.53 1.01-0.03 0.03-0.47 1.04v0.05l-0.13 0.24 0.13 0.77 0.78 0.38 0.82-0.3 0.19-0.27 0.09-0.22v-0.03l0.44-0.98 0.03-0.03 0.47-0.95 0.03-0.03 0.38-0.65v-0.79l-0.72-0.46-0.85 0.21zm37.36 1.69l-0.37 0.71 0.06 0.3 0.47 0.98v0.03l0.41 1.01 0.37 1.01 0.6 0.54 0.91-0.08 0.44-0.68-0.03-0.3-0.38-1.01v-0.03l-0.44-1.06v-0.05l-0.47-0.99-0.69-0.51-0.88 0.13zm-40.12 4.58l-0.12 0.3-0.28 1.06v0.03l-0.25 1.17v0.03l-0.16 0.98 0.28 0.74 0.85 0.24 0.75-0.44 0.09-0.29 0.16-0.93v-0.06l0.25-1.11h-0.03l0.28-1.04-0.22-0.76-0.81-0.3-0.79 0.38zm41.85 2.21v0.32l0.06 0.3 0.22 1.18h-0.03l0.15 1.17v0.02l0.04 0.47 0.43 0.65 0.91 0.11 0.6-0.57 0.06-0.3-0.03-0.49v-0.03l-0.16-1.22v-0.03l-0.18-1.2v-0.03l-0.1-0.35-0.53-0.63h-0.91l-0.53 0.63zm-42.88 4.41l-0.06 0.3-0.04 0.66v0.02l0.04 1.26v0.02l0.09 1.23v0.03l0.03 0.16 0.47 0.65 0.91 0.06 0.56-0.6 0.04-0.3v-0.11-0.03l-0.1-1.17v-0.03l-0.03-1.17v-0.02l0.03-0.63-0.37-0.68-0.91-0.17-0.66 0.52zm43.44 0.66l-0.06 0.3-0.03 1.19v0.03l-0.07 1.17v0.03l-0.09 0.76 0.31 0.71 0.88 0.22 0.72-0.46 0.1-0.3 0.09-0.79v-0.03l0.06-1.23v-0.02l0.03-1.26-0.37-0.71-0.88-0.16-0.69 0.55zm-42.85 5.99v0.33l0.04 0.16v0.05l0.28 1.15 0.03 0.03 0.34 1.11v0.03l0.25 0.71 0.63 0.57 0.88-0.11 0.44-0.65-0.03-0.33-0.25-0.65v-0.06l-0.32-1.03v-0.03l-0.31-1.09h0.03l-0.03-0.19-0.57-0.63h-0.87l-0.54 0.63zm42.16 0.33l-0.12 0.27-0.19 0.68v0.03l-0.32 1.03-0.03 0.06-0.34 1.01-0.03 0.05-0.07 0.19 0.1 0.76 0.78 0.39 0.82-0.3 0.19-0.28 0.09-0.21v-0.03l0.41-1.12v-0.03l0.34-1.11v-0.03l0.19-0.71-0.22-0.76-0.81-0.3-0.79 0.41zm-39.59 5.36l-0.34 0.74 0.09 0.3 0.25 0.46v0.03l0.57 0.98 0.03 0.03 0.6 0.95 0.03 0.03 0.34 0.49 0.75 0.41 0.85-0.27 0.25-0.77-0.16-0.3-0.31-0.43-0.03-0.03-0.56-0.9v-0.03l-0.54-0.9-0.03-0.05-0.22-0.44-0.69-0.49-0.88 0.19zm37.33 0.63l-0.21 0.25-0.47 0.81-0.04 0.03-0.56 0.9-0.03 0.03-0.6 0.84v0.03l-0.09 0.08-0.1 0.79 0.63 0.55 0.91-0.14 0.22-0.22 0.09-0.11 0.04-0.02 0.65-0.93v-0.03l0.63-0.95v-0.03l0.5-0.87v-0.76l-0.72-0.49-0.85 0.24zm-33.56 5.07l-0.1 0.79 0.16 0.27 0.28 0.27 0.03 0.06 0.79 0.73 0.03 0.06 0.81 0.71 0.06 0.02 0.73 0.58 0.84 0.21 0.72-0.49v-0.76l-0.22-0.24-0.69-0.55-0.03-0.03-0.75-0.65-0.03-0.05-0.75-0.69-0.03-0.02-0.22-0.28-0.85-0.32-0.78 0.38zm29.68 0.22l-0.28 0.19-0.57 0.52-0.03 0.05-0.75 0.65-0.03 0.03-0.79 0.6-0.03 0.03-0.41 0.3-0.34 0.71 0.44 0.68 0.88 0.11 0.31-0.17 0.44-0.3 0.03-0.02 0.85-0.69 0.03-0.02 0.84-0.71 0.04-0.06 0.56-0.54 0.25-0.76-0.56-0.63-0.88 0.03zm-24.2 4.33l0.22 0.76 0.25 0.22 0.82 0.38 0.06 0.03 0.97 0.43 0.06 0.03 1.01 0.38 0.06 0.03 0.56 0.16 0.91-0.08 0.44-0.68-0.34-0.71-0.32-0.16-0.53-0.16-0.03-0.03-0.91-0.33-0.06-0.03-0.88-0.38-0.06-0.02-0.76-0.39-0.87-0.02-0.6 0.57zm18.37-0.22l-0.13 0.06-0.03 0.02-0.91 0.38-0.03 0.03-0.91 0.33-0.06 0.03-0.97 0.3-0.19 0.05-0.66 0.55 0.1 0.76 0.78 0.41 0.34-0.03 0.25-0.08h0.07l1.03-0.33 0.06-0.03 1.01-0.38 0.06-0.03 0.97-0.43 0.06-0.03 0.16-0.08 0.5-0.63-0.31-0.73-0.88-0.25-0.31 0.11zm-10.25 1.77l-0.82 0.22-0.28 0.74 0.5 0.65 0.32 0.08h0.03l0.06 0.03 1.1 0.08h0.06l1.13 0.03h0.06l1.13-0.03h0.06l0.38-0.03 0.75-0.41 0.1-0.79-0.69-0.51-0.35-0.03-0.34 0.03h-0.07l-0.97 0.02h-0.03-0.03l-1-0.02h-0.07l-0.97-0.08h-0.06v0.02z"/>
</g>
</g>
<metadata id="metadata88">
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/>
<dc:publisher>
<cc:Agent rdf:about="http://openclipart.org/">
<dc:title>Openclipart</dc:title>
</cc:Agent>
</dc:publisher>
<dc:title>blue boot</dc:title>
<dc:date>2009-06-18T11:16:58</dc:date>
<dc:description>A draw of a boot</dc:description>
<dc:source>https://openclipart.org/detail/26707/blue-boot-by-badaman</dc:source>
<dc:creator>
<cc:Agent>
<dc:title>badaman</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>azul</rdf:li>
<rdf:li>blue</rdf:li>
<rdf:li>boot</rdf:li>
<rdf:li>bota</rdf:li>
<rdf:li>deporte</rdf:li>
<rdf:li>inkscape</rdf:li>
<rdf:li>line art</rdf:li>
<rdf:li>monochrome</rdf:li>
<rdf:li>sport</rdf:li>
<rdf:li>vectorial</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 36 KiB

Wyświetl plik

@ -0,0 +1 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter icon</title><path fill="currentColor" d="M23.954 4.569c-.885.389-1.83.654-2.825.775 1.014-.611 1.794-1.574 2.163-2.723-.951.555-2.005.959-3.127 1.184-.896-.959-2.173-1.559-3.591-1.559-2.717 0-4.92 2.203-4.92 4.917 0 .39.045.765.127 1.124C7.691 8.094 4.066 6.13 1.64 3.161c-.427.722-.666 1.561-.666 2.475 0 1.71.87 3.213 2.188 4.096-.807-.026-1.566-.248-2.228-.616v.061c0 2.385 1.693 4.374 3.946 4.827-.413.111-.849.171-1.296.171-.314 0-.615-.03-.916-.086.631 1.953 2.445 3.377 4.604 3.417-1.68 1.319-3.809 2.105-6.102 2.105-.39 0-.779-.023-1.17-.067 2.189 1.394 4.768 2.209 7.557 2.209 9.054 0 13.999-7.496 13.999-13.986 0-.209 0-.42-.015-.63.961-.689 1.8-1.56 2.46-2.548l-.047-.02z"/></svg>

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 778 B

File diff suppressed because one or more lines are too long

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 21 KiB

Wyświetl plik

@ -0,0 +1,108 @@
.code-block {
position: relative;
border-radius: 3px;
background: hsl(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 97%);
margin-bottom: 1.5rem;
}
.code-block__preview {
position: relative;
border: solid 1px var(--sl-color-gray-90);
border-bottom: none;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
background-color: white;
min-width: 20rem;
max-width: 100%;
padding: 1.5rem 3rem 1.5rem 1.5rem;
}
.code-block__resizer {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 1.75rem;
font-size: 20px;
color: var(--sl-color-gray-50);
background-color: white;
border-left: solid 1px var(--sl-color-gray-90);
border-top-right-radius: 3px;
cursor: ew-resize;
transition: 250ms background-color;
}
@media screen and (max-width: 600px) {
.code-block__preview {
padding-right: 1.5rem;
}
.code-block__resizer {
display: none;
}
}
.code-block__source {
border: solid 1px var(--sl-color-gray-90);
border-bottom: none;
border-radius: 0 !important;
margin: 0 !important;
display: none;
}
.code-block__source .docsify-copy-code-button {
border-top-right-radius: 0;
}
.code-block--expanded .code-block__source {
display: block;
}
.code-block__toggle {
position: relative;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 2.5rem;
border: solid 1px var(--sl-color-gray-90);
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
background: var(--sl-color-white);
font: inherit;
font-size: 0.875rem;
color: var(--sl-color-gray-40);
cursor: pointer;
transition: 250ms background-color;
-webkit-appearance: none;
}
.code-block__toggle:hover,
.code-block__toggle:active {
border-color: var(--sl-color-primary-80);
background-color: var(--sl-color-primary-95);
color: var(--sl-color-primary-50);
}
.code-block__toggle:focus {
outline: none;
border-color: var(--sl-color-primary-50);
background-color: var(--sl-color-primary-95);
color: var(--sl-color-primary-50);
box-shadow: var(--sl-focus-ring-box-shadow);
}
.code-block__toggle svg {
width: 1em;
height: 1em;
margin-left: 0.25rem;
transition: 250ms transform;
}
.code-block--expanded .code-block__toggle svg {
transform: rotate(180deg);
}

Wyświetl plik

@ -0,0 +1,133 @@
(() => {
let count = 1;
if (!window.$docsify) {
throw new Error('Docsify must be loaded before installing this plugin.');
}
function runScript(script) {
const newScript = document.createElement('script');
newScript.appendChild(
document.createTextNode(`
(() => {
${script.innerHTML}
})();
`)
);
script.parentNode.replaceChild(newScript, script);
}
function wrap(el, wrapper) {
el.parentNode.insertBefore(wrapper, el);
wrapper.appendChild(el);
}
window.$docsify.plugins.push((hook, vm) => {
// Convert code blocks to previews
hook.afterEach(function (html, next) {
const domParser = new DOMParser();
const doc = domParser.parseFromString(html, 'text/html');
[...doc.querySelectorAll('code[class^="lang-"]')].map(code => {
if (code.classList.contains('preview')) {
const codeBlock = document.createElement('div');
const preview = document.createElement('div');
const pre = code.closest('pre');
const preId = `code-block-preview-${count}`;
const toggle = document.createElement('button');
const toggleId = `code-block-toggle-${count}`;
wrap(pre, codeBlock);
codeBlock.classList.add('code-block');
preview.classList.add('code-block__preview');
preview.innerHTML = code.textContent;
preview.innerHTML += `
<div class="code-block__resizer">
<sl-icon name="grip-horizontal"></sl-icon>
</div>
`;
pre.id = preId;
pre.classList.add('code-block__source');
pre.setAttribute('data-lang', pre.getAttribute('data-lang').replace(/ preview$/, ''));
pre.setAttribute('aria-labeledby', toggleId);
toggle.id = toggleId;
toggle.type = 'button';
toggle.classList.add('code-block__toggle');
toggle.setAttribute('aria-expanded', 'false');
toggle.setAttribute('aria-controls', preId);
toggle.innerHTML = `
Source
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
`;
codeBlock.prepend(preview);
codeBlock.append(toggle);
count++;
}
});
next(doc.body.innerHTML);
});
// After the page is done loading, force scripts in previews to execute
hook.doneEach(() => {
[...document.querySelectorAll('.code-block__preview script')].map(script => runScript(script));
});
// Horizontal resizing
hook.doneEach(() => {
[...document.querySelectorAll('.code-block__preview')].map(resizeElement => {
let startX;
let startY;
let startWidth;
let startHeight;
const initDrag = event => {
startX = event.clientX;
startY = event.clientY;
startWidth = parseInt(document.defaultView.getComputedStyle(resizeElement).width, 10);
startHeight = parseInt(document.defaultView.getComputedStyle(resizeElement).height, 10);
document.documentElement.addEventListener('mousemove', doDrag, false);
document.documentElement.addEventListener('mouseup', stopDrag, false);
event.preventDefault();
};
const doDrag = event => {
resizeElement.style.width = startWidth + event.clientX - startX + 'px';
};
const stopDrag = event => {
document.documentElement.removeEventListener('mousemove', doDrag, false);
document.documentElement.removeEventListener('mouseup', stopDrag, false);
};
resizeElement.querySelector('.code-block__resizer').addEventListener('mousedown', initDrag);
}, false);
});
});
// Expand and collapse code blocks
document.addEventListener('click', event => {
const toggle = event.target.closest('.code-block__toggle');
if (toggle) {
const codeBlock = event.target.closest('.code-block');
codeBlock.classList.toggle('code-block--expanded');
event.target.setAttribute('aria-expanded', codeBlock.classList.contains('code-block--expanded'));
}
});
})();

Wyświetl plik

@ -0,0 +1,371 @@
(() => {
let metadataStore;
function createPropsTable(props) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Property</th>
<th>Attribute</th>
<th>Description</th>
<th>Type</th>
<th>Default</th>
</tr>
</thead>
<tbody>
${props
.map(
prop => `
<tr>
<td><code>${escapeHtml(prop.name)}</code></td>
<td><code style="white-space: nowrap;">${escapeHtml(prop.attr)}</code></td>
<td>${escapeHtml(prop.docs)}</td>
<td><code>${escapeHtml(prop.type)}</code></td>
<td><code>${escapeHtml(prop.default)}</code></td>
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createEventsTable(events) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Event</th>
<th>Description</th>
<th>Type</th>
</tr>
</thead>
<tbody>
${events
.map(
event => `
<tr>
<td><code>${escapeHtml(event.event)}</code></td>
<td>${escapeHtml(event.docs)}</td>
<td><code>CustomEvent&lt;${escapeHtml(event.detail)}&gt;</code></td>
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createMethodsTable(methods) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Method</th>
<th>Description</th>
<th>Returns</th>
</tr>
</thead>
<tbody>
${methods
.map(
method => `
<tr>
<td><code>${escapeHtml(method.name)}</code></td>
<td>${escapeHtml(method.docs)}</td>
<td><code>${escapeHtml(method.returns.type)}</code></td>
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createSlotsTable(slots) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Slot</th>
<th>Description</th>
</tr>
</thead>
<tbody>
${slots
.map(
slot => `
<tr>
<td><code>${slot.name ? escapeHtml(slot.name) : '(default)'}</code></td>
<td>${escapeHtml(slot.docs)}</td>
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createCustomPropertiesTable(styles) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
${styles
.map(
style => `
<tr>
<td><code style="white-space: nowrap;">${escapeHtml(style.name)}</code></td>
<td>${escapeHtml(style.docs)}</td>
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createPartsTable(parts) {
const table = document.createElement('table');
table.innerHTML = `
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
${parts
.map(
part => `
<tr>
<td><code>${escapeHtml(part.name)}</code></td>
<td>${escapeHtml(part.docs)}</td>
</tr>
`
)
.join('')}
</tbody>
`;
return table.outerHTML;
}
function createDependentsList(dependents) {
const ul = document.createElement('ul');
ul.innerHTML = `
${dependents
.map(
dependent => `
<li><code>${escapeHtml(dependent)}</code></li>
`
)
.join('')}
`;
return ul.outerHTML;
}
function escapeHtml(html) {
return (html + '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
.replace(/`(.*?)`/g, '<code>$1</code>');
}
function getMetadata() {
return new Promise((resolve, reject) => {
// Simple caching to prevent multiple XHR requests
if (metadataStore) {
return resolve(metadataStore);
}
fetch('/dist/components.json')
.then(res => res.json())
.then(data => {
metadataStore = data;
resolve(metadataStore);
})
.catch(err => console.error(err));
});
}
function getDocsTagsObject(docsTags) {
let tags = {};
for (const tag of docsTags) {
tags[tag.name] = tag.text;
}
return tags;
}
if (!window.$docsify) {
throw new Error('Docsify must be loaded before installing this plugin.');
}
window.$docsify.plugins.push((hook, vm) => {
hook.mounted(function () {
getMetadata().then(metadata => {
const target = document.querySelector('.app-name');
// Add version
const version = document.createElement('div');
version.classList.add('sidebar-version');
version.textContent = metadata.version;
target.appendChild(version);
// Add repo buttons
const buttons = document.createElement('div');
buttons.classList.add('sidebar-buttons');
buttons.innerHTML = `
<a class="repo-button repo-button--small repo-button--sponsor" href="https://github.com/sponsors/claviska" rel="noopener" target="_blank">
<sl-icon name="heart"></sl-icon> Sponsor
</a>
<a class="repo-button repo-button--small repo-button--github" href="https://github.com/shoelace-style/shoelace/stargazers" rel="noopener" target="_blank">
<sl-icon src="/assets/images/github.svg"></sl-icon> Star
</a>
<a class="repo-button repo-button--small repo-button--twitter" href="https://twitter.com/shoelace_style" rel="noopener" target="_blank">
<sl-icon src="/assets/images/twitter.svg"></sl-icon> Follow
</a>
`;
target.appendChild(buttons);
});
});
hook.beforeEach(async function (content, next) {
const metadata = await getMetadata();
// Replace %VERSION% placeholders
content = content.replace(/%VERSION%/g, metadata.version);
// Handle [component-header] tags
content = content.replace(/\[component-header:([a-z-]+)\]/g, (match, tag) => {
const data = metadata.components.filter(data => data.tag === tag)[0];
let result = '';
if (!data) {
console.error('Component not found in metadata: ' + tag);
next(content);
}
const tags = getDocsTagsObject(data.docsTags);
if (tags && tags.status) {
let badgeType = 'info';
if (tags.status === 'stable') badgeType = 'primary';
if (tags.status === 'experimental') badgeType = 'warning';
if (tags.status === 'planned') badgeType = 'info';
if (tags.status === 'deprecated') badgeType = 'danger';
result += `
<div class="component-header">
<div class="component-header__tag">
<code>&lt;${tag}&gt;</code>
</div>
<div class="component-header__info">
<sl-badge type="info">
Since ${tags.since || '?'}
</sl-badge>
<sl-badge type="${badgeType}" style="text-transform: capitalize;">
${tags.status}
</sl-badge>
</div>
</div>
`;
}
return result.replace(/^ +| +$/gm, '');
});
// Handle [component-metadata] tags
content = content.replace(/\[component-metadata:([a-z-]+)\]/g, (match, tag) => {
const data = metadata.components.filter(data => data.tag === tag)[0];
let result = '';
if (!data) {
console.error('Component not found in metadata: ' + tag);
next(content);
}
if (data.props.length) {
result += `
## Properties
${createPropsTable(data.props)}
`;
}
if (data.events.length) {
result += `
## Events
${createEventsTable(data.events)}
`;
}
if (data.methods.length) {
result += `
## Methods
${createMethodsTable(data.methods)}
`;
}
if (data.slots.length) {
result += `
## Slots
${createSlotsTable(data.slots)}
`;
}
if (data.styles.length) {
result += `
## CSS Custom Properties
${createCustomPropertiesTable(data.styles)}
`;
}
if (data.parts.length) {
result += `
## CSS Parts
${createPartsTable(data.parts)}
`;
}
if (data.dependents.length) {
result += `
## Dependents
The following components make use of this component.
${createDependentsList(data.dependents)}
`;
}
// Strip whitespace so markdown doesn't process things as code blocks
return result.replace(/^ +| +$/gm, '');
});
next(content);
});
});
})();

Wyświetl plik

@ -0,0 +1,14 @@
(() => {
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);
});
});
})();

Wyświetl plik

@ -0,0 +1,52 @@
/* Color demo */
.color-demo {
width: 4rem;
height: 2rem;
border-radius: var(--sl-border-radius-small);
box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.33);
}
/* Border radius demo */
.border-radius-demo {
width: 3rem;
height: 3rem;
background: var(--sl-color-primary-50);
}
/* Transition demo */
.transition-demo {
position: relative;
background: var(--sl-color-gray-90);
width: 8rem;
height: 2rem;
}
.transition-demo::after {
content: '';
position: absolute;
background-color: var(--sl-color-primary-50);
top: 0;
left: 0;
width: 0;
height: 100%;
transition-duration: inherit;
transition-property: width;
}
.transition-demo:hover::after {
width: 100%;
}
/* Spacing demo */
.spacing-demo {
width: 100px;
background: var(--sl-color-primary-50);
}
/* Elevation dmeo */
.elevation-demo {
background: var(--sl-color-white);
border-radius: 3px;
width: 4rem;
height: 4rem;
}

Wyświetl plik

@ -0,0 +1,503 @@
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
font-family: var(--sl-font-sans);
font-size: var(--sl-font-size-medium);
font-weight: var(--sl-font-weight-normal);
letter-spacing: var(--sl-letter-spacing-normal);
color: var(--sl-color-gray-25);
line-height: var(--sl-line-height-normal);
}
a {
color: var(--sl-color-primary-50);
}
/* Sidebar */
.sidebar {
background: var(--sl-color-white);
border-right: solid 1px var(--sl-color-gray-95);
}
.sidebar .app-name {
padding: 0 1.5rem;
margin-top: 1.5rem;
}
.sidebar-version {
font-size: var(--sl-font-size-x-small);
font-weight: var(--sl-font-weight-normal);
color: var(--sl-color-gray-60);
text-align: right;
padding: 0 var(--sl-spacing-small);
margin: -1.25rem 0 .6rem 0;
}
.sidebar-buttons {
text-align: center;
margin-top: 0;
}
/* Search */
.sidebar .search {
position: relative;
border: none;
}
.sidebar .search input[type='search'] {
border: solid 1px var(--sl-input-border-color);
border-radius: var(--sl-border-radius-pill);
padding-left: 1rem;
padding-right: 2rem;
margin: 0 1.25rem;
transition: var(--sl-transition-fast) box-shadow;
}
.sidebar .search input[type='search']:focus {
box-shadow: var(--sl-focus-ring-box-shadow);
border-color: var(--sl-input-border-color-focus);
outline: none;
}
.sidebar .input-wrap {
position: relative;
width: 100%;
padding: 0 .25rem;
}
.sidebar .clear-button {
position: absolute;
right: 30px;
top: 7px;
width: 22px !important;
height: 22px !important;
}
.sidebar .clear-button svg {
transform: scale(.75) !important;
}
.sidebar .clear-button:focus {
outline: none;
}
.search .results-panel {
margin-top: 1rem;
}
.search .matching-post {
border-bottom: solid 1px var(--sl-color-gray-95) !important;
padding: .25rem 1.5rem;
}
.search .matching-post a {
display: block;
border-radius: inherit
padding: .5rem;
}
.search .matching-post h2 {
margin-bottom: 0;
}
.search .matching-post p {
margin-top: 0;
}
/* Sidebar toggle */
.sidebar-toggle {
top: .25rem;
left: .25rem;
width: 2rem;
height: 2rem;
border-radius: var(--sl-border-radius-medium);
padding: .5rem;
}
@media screen and (max-width: 768px) {
body.close .sidebar-toggle {
padding: .5rem;
}
}
/* Sidebar nav */
.sidebar-nav {
padding: 0 1rem;
}
.sidebar-nav a {
color: inherit;
text-decoration: none;
}
.sidebar-nav li.collapse > a,
.sidebar-nav li.active > a {
color: var(--sl-color-primary-50);
}
.sidebar li > p {
font-weight: var(--sl-font-weight-bold);
border-bottom: solid 1px var(--sl-color-gray-90);
margin: 0 .75rem .5rem 0;
}
.sidebar ul li ul {
padding-left: .5rem;
margin: 0 .75rem 1.5rem 0;
}
.sidebar ul ul ul {
padding: 0;
margin: 0 0 0 .5rem;
}
.sidebar ul ul ul li {
list-style: disc;
margin-left: 1.5rem;
}
/* Content */
.content {
padding-top: 0;
}
.markdown-section {
max-width: 860px;
}
.markdown-section .logo {
max-width: 24rem;
}
.markdown-section ul {
padding: 0 0 0 1.5rem;
margin: 0;
}
.markdown-section .anchor {
color: var(--sl-color-primary-50);
}
.markdown-section h1,
.markdown-section h2,
.markdown-section h3,
.markdown-section h4,
.markdown-section h5,
.markdown-section h6 {
font-weight: var(--sl-font-weight-normal);
margin: 0 0 1em 0;
}
.markdown-section h1 {
font-size: var(--sl-font-size-xx-large);
}
.markdown-section h2 {
font-size: var(--sl-font-size-x-large);
border-bottom: solid 1px var(--sl-color-gray-90);
margin-top: 2rem;
}
.markdown-section h3 {
font-size: var(--sl-font-size-large);
}
.markdown-section h4 {
font-size: var(--sl-font-size-medium);
}
.markdown-section h5 {
font-size: var(--sl-font-size-small);
}
.markdown-section h6 {
font-size: var(--sl-font-size-x-small);
}
.markdown-section pre {
font-family: var(--sl-font-mono);
}
.markdown-section h1:first-of-type {
margin-bottom: 0;
}
.markdown-section code {
font-family: var(--sl-font-mono);
font-size: 87.5%;
background: hsla(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 50%, .05);
border-radius: var(--sl-border-radius-small);
padding: 2px 4px;
}
.markdown-section table code:not([class*="lang-"]):not([class*="language-"]) {
white-space: normal;
}
/* Code blocks */
.markdown-section pre {
position: relative;
background: hsl(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 97%);
border-radius: var(--sl-border-radius-medium);
}
.markdown-section pre > code {
display: block;
background: none;
color: var(--sl-color-gray-30);
padding: var(--sl-spacing-medium);
overflow: auto;
hyphens: none;
tab-size: 2;
}
.markdown-section pre .token.comment {
color: var(--sl-color-gray-70);
}
.markdown-section pre .token.prolog,
.markdown-section pre .token.doctype,
.markdown-section pre .token.cdata,
.markdown-section pre .token.operator {
color: var(--sl-color-gray-40);
}
.markdown-section pre .token.punctuation {
color: var(--sl-color-gray-50);
}
.namespace {
opacity: .7;
}
.markdown-section pre .token.property,
.markdown-section pre .token.keyword,
.markdown-section pre .token.tag,
.markdown-section pre .token.url {
color: var(--sl-color-primary-45);
}
.markdown-section pre .token.class-name {
color: #f8e71c;
text-decoration: underline;
}
.markdown-section pre .token.symbol,
.markdown-section pre .token.deleted {
color: #f92672;
}
.markdown-section pre .token.boolean,
.markdown-section pre .token.constant,
.markdown-section pre .token.selector,
.markdown-section pre .token.attr-name,
.markdown-section pre .token.string,
.markdown-section pre .token.char,
.markdown-section pre .token.builtin,
.markdown-section pre .token.inserted {
color: var(--sl-color-success-40);
}
.markdown-section pre .token.atrule,
.markdown-section pre .token.attr-value,
.markdown-section pre .token.number,
.markdown-section pre .token.variable {
color: #9013fe;
}
.markdown-section pre .token.function {
color: #eb9200;
}
.markdown-section pre .token.regex {
color: #f5a623;
}
.markdown-section pre .token.important {
color: #d0021b;
}
.markdown-section pre .token.important,
.markdown-section pre .token.bold {
font-weight: bold;
}
.markdown-section pre .token.italic {
font-style: italic;
}
/* Tables */
.markdown-section table {
margin-bottom: 1.5rem;
}
.markdown-section tr {
border: none;
}
.markdown-section tr:nth-child(2n) {
background: hsl(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 97%);
}
.markdown-section th {
border: none;
font-weight: inherit;
text-align: left;
}
.markdown-section td {
border-top: solid 1px var(--sl-color-gray-90);
border-bottom: solid 1px var(--sl-color-gray-90);
border-left: none;
border-right: none;
}
/* Tips & Warnings */
.markdown-section p.tip,
.markdown-section p.warn {
position: relative;
background: hsl(var(--sl-color-gray-hue), var(--sl-color-gray-saturation), 97%);
border-left: solid 4px transparent;
border-radius: var(--sl-border-radius-medium);
padding-left: 1.5rem;
}
.markdown-section p.tip:before,
.markdown-section p.warn:before {
content: '!';
border-radius: 100%;
color: var(--sl-color-white);
font-size: 14px;
font-weight: bold;
left: -12px;
line-height: 20px;
position: absolute;
height: 20px;
width: 20px;
text-align: center;
top: calc(50% - 10px);
}
.markdown-section p.warn {
border-left-color: var(--sl-color-primary-50);
}
.markdown-section p.warn:before {
background-color: var(--sl-color-primary-50);
}
.markdown-section p.tip {
border-left-color: var(--sl-color-danger-50);
}
.markdown-section p.tip:before {
background-color: var(--sl-color-danger-50);
}
/* Component headers */
.component-header {
border-bottom: solid 1px var(--sl-color-gray-90);
padding-bottom: 2rem;
margin-top: -1rem;
margin-bottom: 2rem;
}
.component-header__tag {
border-bottom: none;
padding: 0;
margin: 0.75rem 0 0.25rem 0;
}
.component-header__tag code {
background: none;
color: var(--sl-color-gray-50);
font-size: var(--sl-font-size-large);
padding: 0;
margin: 0;
}
.component-header__info {
margin-bottom: 0.5rem;
}
/* Lead sentences that occur immediately after the header */
.component-header + p {
font-size: var(--sl-font-size-large);
line-height: 1.6;
}
/* Copy button */
.docsify-copy-code-button {
font-size: var(--sl-font-size-small) !important;
border-top-right-radius: var(--sl-border-radius-medium) !important;
border-bottom-left-radius: var(--sl-border-radius-medium) !important;
}
/* Repo buttons */
html .repo-button {
display: inline-block;
vertical-align: middle;
background-color: var(--sl-color-white);
border: solid 1px var(--sl-color-gray-85);
border-radius: var(--sl-border-radius-medium);
box-shadow: var(--sl-shadow-x-small);
font-size: var(--sl-font-size-small);
font-weight: var(--sl-font-weight-semibold);
text-decoration: none;
color: var(--sl-color-gray-30);
padding: var(--sl-spacing-xx-small) var(--sl-spacing-small);
margin-bottom: var(--sl-spacing-xx-small);
transition: 0.25s all;
}
html .repo-button:hover {
text-decoration: none;
background-color: var(--sl-color-gray-95);
border: solid 1px var(--sl-color-gray-80);
}
html .repo-button:focus {
outline: none;
border-color: var(--sl-color-primary-50);
box-shadow: var(--sl-focus-ring-box-shadow);
}
html .repo-button:not(:last-of-type) {
margin-right: .125rem;
}
html .repo-button sl-icon {
position: relative;
top: -1px;
vertical-align: middle;
margin-right: 0.125rem;
}
html .repo-button--small {
font-size: var(--sl-font-size-x-small);
padding: var(--sl-spacing-xxx-small) var(--sl-spacing-x-small);
}
html .repo-button--sponsor sl-icon {
color: #ea4aaa;
}
html .repo-button--github sl-icon {
color: #242a2e;
}
html .repo-button--twitter sl-icon {
color: #1ea0f2;
}
body[data-page^="tokens/"] .table-wrapper td:first-child,
body[data-page^="tokens/"] .table-wrapper td:first-child code {
white-space: nowrap;
}

Wyświetl plik

@ -0,0 +1,90 @@
# Alert
[component-header:sl-alert]
Alerts are used to display important messages.
Alerts are designed to be shown dynamically, so you need to include the `open` attribute to display them.
```html preview
<sl-alert open>
<sl-icon slot="icon" name="info-circle"></sl-icon>
This is a standard alert. You can customize its content and even the icon.
</sl-alert>
```
## Examples
### Types
Set the `type` attribute to change the alert's type.
```html preview
<sl-alert type="primary" open>
<sl-icon slot="icon" name="info-circle"></sl-icon>
<strong>This is super informative</strong><br>
You can tell by how pretty the alert is.
</sl-alert>
<br>
<sl-alert type="success" open>
<sl-icon slot="icon" name="check2-circle"></sl-icon>
<strong>Your changes have been saved</strong><br>
You can safely exit the app now.
</sl-alert>
<br>
<sl-alert type="info" open>
<sl-icon slot="icon" name="gear"></sl-icon>
<strong>Your settings have been updated</strong><br>
Some settings will take affect the next time you log in.
</sl-alert>
<br>
<sl-alert type="warning" open>
<sl-icon slot="icon" name="exclamation-triangle"></sl-icon>
<strong>This will end your session</strong><br>
You will be logged out until you log in again.
</sl-alert>
<br>
<sl-alert type="danger" open>
<sl-icon slot="icon" name="exclamation-octagon"></sl-icon>
<strong>Delete this file?</strong><br>
This is permanent, which means forever!
</sl-alert>
```
### Closable
Add the `closable` attribute to show a close button that will hide the alert.
```html preview
<sl-alert type="primary" open closable class="alert-closable">
<sl-icon slot="icon" name="info-circle"></sl-icon>
You can close this alert any time!
</sl-alert>
<script>
const alert = document.querySelector('.alert-closable');
alert.addEventListener('slAfterHide', () => {
setTimeout(() => alert.open = true, 2000);
});
</script>
```
### Without Icons
Icons are optional. Simply omit the `icon` slot if you don't want them.
```html preview
<sl-alert type="primary" open>
Nothing fancy here, just a simple alert.
</sl-alert>
```
[component-metadata:sl-alert]

Wyświetl plik

@ -0,0 +1,62 @@
# Avatar
[component-header:sl-avatar]
Avatars are used to represent a person or object.
```html preview
<sl-avatar></sl-avatar>
```
## Examples
### Images
To use an image for the avatar, set the `image` and `alt` attributes. This will take priority and be shown over initials and icons.
```html preview
<sl-avatar
image="https://images.unsplash.com/photo-1529778873920-4da4926a72c2?ixlib=rb-1.2.1&auto=format&fit=crop&w=300&q=80"
alt="Gray tabby kitten looking down"
></sl-avatar>
```
### Initials
When you don't have an image to use, you can set the `initials` attribute to show something more personalized than an icon.
```html preview
<sl-avatar initials="SL"></sl-avatar>
```
### Custom Icons
When no image or initials are set, an icon will be shown. The default avatar shows a generic "user" icon, but you can customize this with the `icon` slot.
```html preview
<sl-avatar>
<sl-icon slot="icon" name="image"></sl-icon>
</sl-avatar>
<sl-avatar>
<sl-icon slot="icon" name="archive"></sl-icon>
</sl-avatar>
<sl-avatar>
<sl-icon slot="icon" name="briefcase"></sl-icon>
</sl-avatar>
```
### Shapes
Avatars can be shaped using the `shape` attribute.
```html preview
<sl-avatar shape="square"></sl-avatar>
<sl-avatar shape="rounded"></sl-avatar>
<sl-avatar shape="circle"></sl-avatar>
```
[component-metadata:sl-avatar]

Wyświetl plik

@ -0,0 +1,60 @@
# Badge
[component-header:sl-badge]
Badges are used to draw attention and display statuses or counts.
```html preview
<sl-badge>Badge</sl-icon></sl-badge>
```
## Examples
### Types
Set the `type` attribute to change the badge's type.
```html preview
<sl-badge type="primary">Primary</sl-icon></sl-badge>
<sl-badge type="success">Success</sl-badge>
<sl-badge type="info">Info</sl-badge>
<sl-badge type="warning">Warning</sl-badge>
<sl-badge type="danger">Danger</sl-badge>
```
### With Buttons
One of the most common use cases for badges is attaching them to buttons. To make this easier, badges will be automatically positioned at the top-right when they're a child of a button.
```html preview
<sl-button>
Requests
<sl-badge>30</sl-badge>
</sl-button>
<sl-button style="margin-left: 1rem;">
Warnings
<sl-badge type="warning">8</sl-badge>
</sl-button>
<sl-button style="margin-left: 1rem;">
Errors
<sl-badge type="danger">6</sl-badge>
</sl-button>
```
### With Menu Items
When including badges in menu items, use the `suffix` slot to make sure they're aligned correctly.
```html preview
<sl-menu
style="max-width: 240px; border: solid 1px var(--sl-color-gray-90); border-radius: var(--sl-border-radius-medium);"
>
<sl-menu-label>Messages</sl-menu-label>
<sl-menu-item>Comments <sl-badge slot="suffix">4</sl-badge></sl-menu-item>
<sl-menu-item>Replies <sl-badge slot="suffix">12</sl-badge></sl-menu-item>
</sl-menu>
```
[component-metadata:sl-badge]

Wyświetl plik

@ -0,0 +1,134 @@
# Button
[component-header:sl-button]
Buttons represent actions that are available to the user.
```html preview
<sl-button>Button</sl-button>
```
## Examples
### Types
Use the `type` attribute to set the button's type.
```html preview
<sl-button type="default">Default</sl-button>
<sl-button type="primary">Primary</sl-button>
<sl-button type="success">Success</sl-button>
<sl-button type="info">Info</sl-button>
<sl-button type="warning">Warning</sl-button>
<sl-button type="danger">Danger</sl-button>
```
### Sizes
Use the `size` prop to change a button's size.
```html preview
<sl-button size="small">Small</sl-button>
<sl-button size="medium">Medium</sl-button>
<sl-button size="large">Large</sl-button>
```
### Pill Buttons
Use the `pill` prop to give buttons rounded edges.
```html preview
<sl-button size="small" pill>Small</sl-button>
<sl-button size="medium" pill>Medium</sl-button>
<sl-button size="large" pill>Large</sl-button>
```
### Circle Buttons
Use the `circle` prop to create circular icon buttons.
```html preview
<sl-button type="default" size="small" circle><sl-icon name="gear"></sl-icon></sl-button>
<sl-button type="default" size="medium" circle><sl-icon name="gear"></sl-icon></sl-button>
<sl-button type="default" size="large" circle><sl-icon name="gear"></sl-icon></sl-button>
```
### Text Buttons
Use the `text` type to create text buttons that share the same size as regular buttons but don't have backgrounds or borders.
```html preview
<sl-button type="text" size="small">Text</sl-button>
<sl-button type="text" size="medium">Text</sl-button>
<sl-button type="text" size="large">Text</sl-button>
```
### Setting a Custom Width
As expected, buttons can be given a custom width by setting its `width`. This is useful for making buttons span the full width of their container on smaller screens.
```html preview
<sl-button type="default" size="small" style="width: 100%; margin-bottom: 1rem;">Small</sl-button>
<sl-button type="default" size="medium" style="width: 100%; margin-bottom: 1rem;">Medium</sl-button>
<sl-button type="default" size="large" style="width: 100%;">Large</sl-button>
```
### Prefix and Suffix Icons
Use the `prefix` and `suffix` slots to add icons.
```html preview
<sl-button type="default">
<sl-icon slot="prefix" name="gear"></sl-icon>
Settings
</sl-button>
<sl-button type="default">
<sl-icon slot="suffix" name="arrow-counterclockwise"></sl-icon>
Refresh
</sl-button>
<sl-button type="default">
<sl-icon slot="prefix" name="link-45deg"></sl-icon>
<sl-icon slot="suffix" name="box-arrow-up-right"></sl-icon>
Open
</sl-button>
```
### Caret
Use the `caret` prop to add a dropdown indicator when a button will trigger a dropdown, menu, or popover.
```html preview
<sl-button size="small" caret>Small</sl-button>
<sl-button size="medium" caret>Medium</sl-button>
<sl-button size="large" caret>Large</sl-button>
```
### Loading
Use the `loading` prop to make a button busy. The width will remain the same as before, preventing adjacent elements from moving around. Clicks will be suppressed until the loading state is removed.
```html preview
<sl-button type="default" loading>Default</sl-button>
<sl-button type="primary" loading>Primary</sl-button>
<sl-button type="success" loading>Success</sl-button>
<sl-button type="info" loading>Info</sl-button>
<sl-button type="warning" loading>Warning</sl-button>
<sl-button type="danger" loading>Danger</sl-button>
```
### Disabled
Use the `disabled` prop to disable a button. Clicks will be suppressed until the disabled state is removed.
```html preview
<sl-button type="default" disabled>Default</sl-button>
<sl-button type="primary" disabled>Primary</sl-button>
<sl-button type="success" disabled>Success</sl-button>
<sl-button type="info" disabled>Info</sl-button>
<sl-button type="warning" disabled>Warning</sl-button>
<sl-button type="danger" disabled>Danger</sl-button>
```
[component-metadata:sl-button]

Wyświetl plik

@ -0,0 +1,39 @@
# Checkbox
[component-header:sl-checkbox]
Checkboxes allow the user to toggle an option on or off.
```html preview
<sl-checkbox>Checkbox</sl-checkbox>
```
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form.md) instead.
## Examples
### Checked
Use the `checked` attribute to activate the checkbox.
```html preview
<sl-checkbox checked>Checked</sl-checkbox>
```
### Indeterminate
Use the `indeterminate` attribute to make the checkbox indeterminate.
```html preview
<sl-checkbox indeterminate>Indeterminate</sl-checkbox>
```
### Disabled
Use the `disabled` attribute to disable the checkbox.
```html preview
<sl-checkbox disabled>Disabled</sl-checkbox>
```
[component-metadata:sl-checkbox]

Wyświetl plik

@ -0,0 +1,39 @@
# Color Picker
[component-header:sl-color-picker]
Color pickers allow the user to select a color.
```html preview
<sl-color-picker></sl-color-picker>
```
## Examples
### Opacity
Use the `opacity` attribute to enable the opacity slider. When this is enabled, the value will be displayed as HEXA, RGBA, or HSLA based on `format`.
```html preview
<sl-color-picker opacity format="hsl"></sl-color-picker>
```
### Formats
Set the color picker's format with the `format` attribute. Valid options include `hex`, `rgb`, and `hsl`. Note that the color picker will accept any parsable format (including CSS color names) regardless of this option.
```html preview
<sl-color-picker format="hex" value="#4a90e2"></sl-color-picker>
<sl-color-picker format="rgb" value="rgb(80, 227, 194)"></sl-color-picker>
<sl-color-picker format="hsl" value="hsl(290, 87%, 47%)"></sl-color-picker>
```
### Inline
The color picker can be rendered inline instead of in a dropdown using the `inline` attribute.
```html preview
<sl-color-picker inline></sl-color-picker>
```
[component-metadata:sl-color-picker]

Wyświetl plik

@ -0,0 +1,65 @@
# Details
[component-header:sl-details]
Details show a brief summary and expand to show additional content.
```html preview
<sl-details summary="Toggle Me">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
```
## Examples
### Disabled
Use the `disable` attribute to prevent the details from expanding.
```html preview
<sl-details summary="Disabled" disabled>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
```
### Grouping Details
Details are designed to function independently, but you can simulate a group or "accordion" where only one is shown at a time by listening for the `slShow` event.
```html preview
<div class="details-group-example">
<sl-details summary="First" open>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
<sl-details summary="Second">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
<sl-details summary="Third">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
</div>
<script>
const container = document.querySelector('.details-group-example');
// Close all other details when one is shown
container.addEventListener('slShow', event => {
[...container.querySelectorAll('sl-details')].map(details => (details.open = event.target === details));
});
</script>
<style>
.details-group-example sl-details:not(:last-of-type) {
margin-bottom: var(--sl-spacing-xx-small);
}
</style>
```
[component-metadata:sl-details]

Wyświetl plik

@ -0,0 +1,111 @@
# Dialog
[component-header:sl-dialog]
Dialogs appear above the page and require the user's immediate attention.
```html preview
<sl-dialog label="Dialog" class="dialog-overview">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-dialog>
<sl-button>Open Dialog</sl-button>
<script>
(() => {
const dialog = document.querySelector('.dialog-overview');
const openButton = dialog.nextElementSibling;
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
openButton.addEventListener('click', () => dialog.show());
closeButton.addEventListener('click', () => dialog.hide());
})();
</script>
```
## UX Tips
- Use a dialog when you immediately require the user's attention, e.g. confirming a destructive action.
- Always provide an obvious way for the user to dismiss the dialog.
- Don't nest dialogs. It almost always leads to a poor experience for the user.
## Examples
### Custom Width
Use the `--width` custom property to set the dialog's width.
```html preview
<sl-dialog label="Dialog" class="dialog-width" style="--width: 50vw;">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-dialog>
<sl-button>Open Dialog</sl-button>
<script>
(() => {
const dialog = document.querySelector('.dialog-width');
const openButton = dialog.nextElementSibling;
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
openButton.addEventListener('click', () => dialog.show());
closeButton.addEventListener('click', () => dialog.hide());
})();
</script>
```
### Scrolling
By design, a dialog's height will never exceed that of the viewport. As such, dialogs will not scroll with the page ensuring the header and footer are always accessible to the user.
```html preview
<sl-dialog label="Dialog" class="dialog-scrolling">
<div style="height: 150vh; border: dashed 2px var(--sl-color-gray-80); padding: 0 1rem;">
<p>Scroll down and give it a try! 👇</p>
</div>
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-dialog>
<sl-button>Open Dialog</sl-button>
<script>
(() => {
const dialog = document.querySelector('.dialog-scrolling');
const openButton = dialog.nextElementSibling;
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
openButton.addEventListener('click', () => dialog.show());
closeButton.addEventListener('click', () => dialog.hide());
})();
</script>
```
### Ignoring Clicks on the Overlay
By default, dialogs are closed when the user clicks or taps on the overlay. To prevent this behavior, cancel the `slOverlayDismiss` event.
```html preview
<sl-dialog label="Dialog" class="dialog-no-overlay-dismiss">
This dialog will not be closed when you click outside of it.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-dialog>
<sl-button>Open Dialog</sl-button>
<script>
(() => {
const dialog = document.querySelector('.dialog-no-overlay-dismiss');
const openButton = dialog.nextElementSibling;
const closeButton = dialog.querySelector('sl-button[slot="footer"]');
openButton.addEventListener('click', () => dialog.show());
closeButton.addEventListener('click', () => dialog.hide());
dialog.addEventListener('slOverlayDismiss', event => event.preventDefault());
})();
</script>
```
[component-metadata:sl-dialog]

Wyświetl plik

@ -0,0 +1,207 @@
# Drawer
[component-header:sl-drawer]
Drawers slide in from a container to expose additional options and information.
```html preview
<sl-drawer label="Drawer" class="drawer-overview">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
(() => {
const drawer = document.querySelector('.drawer-overview');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
})();
</script>
```
## Examples
### Slide in From Left
To make the drawer slide in from the left, set the `placement` attribute to `left`.
```html preview
<sl-drawer label="Drawer" placement="left" class="drawer-placement-left">
This drawer slides in from the left.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
(() => {
const drawer = document.querySelector('.drawer-placement-left');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
})();
</script>
```
### Slide in From Top
To make the drawer slide in from the top, set the `placement` attribute to `top`.
```html preview
<sl-drawer label="Drawer" placement="top" class="drawer-placement-top">
This drawer slides in from the top.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
(() => {
const drawer = document.querySelector('.drawer-placement-top');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
})();
</script>
```
### Slide in From Bottom
To make the drawer slide in from the bottom, set the `placement` attribute to `bottom`.
```html preview
<sl-drawer label="Drawer" placement="bottom" class="drawer-placement-bottom">
This drawer slides in from the bottom.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
(() => {
const drawer = document.querySelector('.drawer-placement-bottom');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
})();
</script>
```
### Contained to an Element
By default, the drawer slides out of its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport. To make the drawer slide out of its parent element, set this prop and add `position: relative` to the parent.
```html preview
<div
style="position: relative; border: solid 2px var(--sl-color-gray-80); height: 300px; padding: 1rem; margin-bottom: 1rem;"
>
The drawer will be contained to this box. This content won't shift or be affected in any way when the drawer opens.
<sl-drawer label="Drawer" contained class="drawer-contained" style="--size: 50%;">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-drawer>
</div>
<sl-button>Open Drawer</sl-button>
<script>
(() => {
const drawer = document.querySelector('.drawer-contained');
const openButton = drawer.parentElement.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
})();
</script>
```
### Custom Size
Use the `--size` custom property to set the drawer's size. This will be applied to the drawer's width or height depending on its `placement`.
```html preview
<sl-drawer label="Drawer" class="drawer-custom-size" style="--size: 50vw;">
This drawer is always 50% of the viewport.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
(() => {
const drawer = document.querySelector('.drawer-custom-size');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
})();
</script>
```
### Scrolling
By design, a drawer's height will never exceed 100% of its container. As such, drawers will not scroll with the page to ensure the header and footer are always accessible to the user.
```html preview
<sl-drawer label="Drawer" class="drawer-scrolling">
<div style="height: 150vh; border: dashed 2px var(--sl-color-gray-80); padding: 0 1rem;">
<p>Scroll down and give it a try! 👇</p>
</div>
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
(() => {
const drawer = document.querySelector('.drawer-scrolling');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
})();
</script>
```
### Ignoring Clicks on the Overlay
By default, drawers are closed when the user clicks or taps on the overlay. To prevent this behavior, cancel the `slOverlayDismiss` event.
```html preview
<sl-drawer label="Drawer" class="drawer-no-overlay-dismiss">
This drawer will not be closed when you click outside of it.
<sl-button slot="footer" type="primary">Close</sl-button>
</sl-drawer>
<sl-button>Open Drawer</sl-button>
<script>
(() => {
const drawer = document.querySelector('.drawer-no-overlay-dismiss');
const openButton = drawer.nextElementSibling;
const closeButton = drawer.querySelector('sl-button[type="primary"]');
openButton.addEventListener('click', () => drawer.show());
closeButton.addEventListener('click', () => drawer.hide());
drawer.addEventListener('slOverlayDismiss', event => event.preventDefault());
})();
</script>
```
[component-metadata:sl-drawer]

Wyświetl plik

@ -0,0 +1,90 @@
# Dropdown
[component-header:sl-dropdown]
Dropdowns expose additional content that "drops down" in a panel.
Dropdowns consist of a trigger and a panel. By default, activating the trigger will expose the panel and interacting outside of the panel will close it.
Dropdowns are designed to work well with [menus](/components/menu.md) to provide a list of options the user can select from. However, dropdowns can also be used in lower-level applications (e.g. [color picker](/components/color-picker.md) and [select](/components/select.md)). The API gives you complete control over showing, hiding, and positioning the panel.
```html preview
<sl-dropdown>
<sl-button slot="trigger" caret>Dropdown</sl-button>
<sl-menu>
<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-menu-item checked>Checked</sl-menu-item>
<sl-menu-item disabled>Disabled</sl-menu-item>
<sl-menu-divider></sl-menu-divider>
<sl-menu-item>
Prefix
<sl-icon slot="prefix" name="gift"></sl-icon>
</sl-menu-item>
<sl-menu-item>
Suffix Icon
<sl-icon slot="suffix" name="heart"></sl-icon>
</sl-menu-item>
</sl-menu>
</sl-dropdown>
```
## Examples
### 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.
```html preview
<sl-dropdown placement="top-start">
<sl-button slot="trigger" caret>Edit</sl-button>
<sl-menu>
<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-menu-item>Find</sl-menu-item>
<sl-menu-item>Replace</sl-menu-item>
</sl-menu>
</sl-dropdown>
```
### Distance
The distance from the panel to the trigger can be customized using the `distance` attribute. This value is specified in pixels.
```html preview
<sl-dropdown distance="30">
<sl-button slot="trigger" caret>Edit</sl-button>
<sl-menu>
<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-menu-item>Find</sl-menu-item>
<sl-menu-item>Replace</sl-menu-item>
</sl-menu>
</sl-dropdown>
```
### Skidding
The offset of the panel along the trigger can be customized using the `skidding` attribute. This value is specified in pixels.
```html preview
<sl-dropdown skidding="30">
<sl-button slot="trigger" caret>Edit</sl-button>
<sl-menu>
<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-menu-item>Find</sl-menu-item>
<sl-menu-item>Replace</sl-menu-item>
</sl-menu>
</sl-dropdown>
```
[component-metadata:sl-dropdown]

Wyświetl plik

@ -0,0 +1,69 @@
# Form
[component-header:sl-form]
Forms collect data that can easily be processed and sent to a server.
All of Shoelace's components make use of the [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to encapsulate markup, style, and behavior. One caveat of this approach is that native `<form>` elements don't recognize Shoelace form controls.
This component solves that problem by serializing _both_ Shoelace form controls and native form controls. The resulting form data is exposed in the `slSubmit` event in a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object.
```html preview
<sl-form class="form-overview">
<sl-input name="name" type="text" label="Name"></sl-input>
<br>
<sl-select name="favorite" label="Select your favorite">
<sl-menu-item value="birds">Birds</sl-menu-item>
<sl-menu-item value="cats">Cats</sl-menu-item>
<sl-menu-item value="dogs">Dogs</sl-menu-item>
</sl-select>
<br>
<sl-checkbox name="agree" value="yes">
I totally agree
</sl-checkbox>
<br><br>
<sl-button submit>Submit</sl-button>
</sl-form>
<script>
const form = document.querySelector('.form-overview');
form.addEventListener('slSubmit', event => {
const formData = event.detail.formData;
let output = '';
//
// Example 1: Post data to a server and wait for a JSON response
//
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(result => {
console.log('Success:', result);
})
.catch(error => {
console.error('Error:', error);
});
//
// Example 2: Output all form control names + values
//
for (const entry of formData.entries()) {
output += `${entry[0]}: ${entry[1]}\n`;
}
alert(output);
//
// Example 3: Get all form controls that were serialized as
// an array of HTML elements
//
console.log(event.detail.formControls);
});
</script>
```
?> Shoelace forms don't make use of `action` and `method` attributes and they don't submit automatically like native forms. To handle submission, you need to listen for the `slSubmit` event as shown in the example above.
[component-metadata:sl-form]

Wyświetl plik

@ -0,0 +1,223 @@
# Icon
[component-header:sl-icon]
Icons are symbols that can be used to represent or provide context to various options and actions within an application.
Shoelace comes bundled with over 1,000 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. Click or tap on an icon below to copy the name and use it like this.
```html
<sl-icon name="icon-name-here" hidden></sl-icon>
```
<div class="icon-search">
<div class="icon-search-controls">
<sl-input placeholder="Search Icons" clearable>
<sl-icon slot="prefix" name="search"></sl-icon>
</sl-input>
<sl-select value="outline">
<sl-menu-item value="outline">Outlined</sl-menu-item>
<sl-menu-item value="fill">Filled</sl-menu-item>
<sl-menu-item value="all">All icons</sl-menu-item>
</sl-select>
</div>
<div class="icon-list"></div>
<input type="text" class="icon-copy-input">
</div>
## Examples
### Icon Sizes
Icons are sized relative to the current font size. To change their size, set the `font-size` property on the icon itself or on a parent element as shown below.
```html preview
<div style="font-size: 32px;">
<sl-icon name="exclamation-triangle"></sl-icon>
<sl-icon name="archive"></sl-icon>
<sl-icon name="battery-charging"></sl-icon>
<sl-icon name="bell"></sl-icon>
<sl-icon name="clock"></sl-icon>
<sl-icon name="download"></sl-icon>
<sl-icon name="file-earmark"></sl-icon>
<sl-icon name="flag"></sl-icon>
<sl-icon name="heart"></sl-icon>
<sl-icon name="image"></sl-icon>
<sl-icon name="lightning"></sl-icon>
<sl-icon name="mic"></sl-icon>
<sl-icon name="search"></sl-icon>
<sl-icon name="star"></sl-icon>
<sl-icon name="trash"></sl-icon>
<sl-icon name="x-circle"></sl-icon>
</div>
```
### Custom Icons
Custom icons can be loaded by setting the `src` attribute. Only SVG images are supported
```html preview
<sl-icon src="/assets/images/shoe.svg" style="font-size: 8rem;"></sl-icon>
```
<script>
fetch('/dist/shoelace/icons/icons.json')
.then(res => res.json())
.then(icons => {
const container = document.querySelector('.icon-search');
const input = container.querySelector('sl-input');
const select = container.querySelector('sl-select');
const copyInput = container.querySelector('.icon-copy-input');
const loader = container.querySelector('.icon-loader');
const list = container.querySelector('.icon-list');
const queue = [];
// Generate icons
icons.map(i => {
const item = document.createElement('div');
item.classList.add('icon-list-item');
item.setAttribute('data-name', i.name);
item.setAttribute('data-terms', [i.name, i.title, ...(i.tags || []), ...(i.categories || [])].join(' '));
item.innerHTML = `
<svg width="1em" height="1em">
<use xlink:href="/assets/icons/sprite.svg#${i.name}"></use>
</svg>
`;
const tooltip = document.createElement('sl-tooltip');
tooltip.content = i.name;
tooltip.appendChild(item);
list.appendChild(tooltip);
item.addEventListener('click', () => {
copyInput.value = i.name;
copyInput.select();
document.execCommand('copy');
tooltip.content = 'Copied!';
setTimeout(() => tooltip.content = i.name, 1000);
});
});
// Filter as the user types
input.addEventListener('slInput', () => {
[...list.querySelectorAll('.icon-list-item')].map(item => {
const filter = input.value.toLowerCase();
if (filter === '') {
item.hidden = false;
} else {
const terms = item.getAttribute('data-terms').toLowerCase();
item.hidden = terms.indexOf(filter) < 0;
}
});
});
// Sort by type and remember preference
const iconType = localStorage.getItem('sl-icon:type') || 'outline';
select.value = iconType;
list.setAttribute('data-type', select.value);
select.addEventListener('slChange', () => {
list.setAttribute('data-type', select.value);
localStorage.setItem('sl-icon:type', select.value);
});
});
</script>
<style>
.icon-search {
border: solid 1px var(--sl-color-gray-90);
border-radius: var(--sl-border-radius-medium);
padding: var(--sl-spacing-medium);
}
.icon-search-controls {
display: flex;
}
.icon-search-controls sl-input {
flex: 1 1 auto;
}
.icon-search-controls sl-select {
flex: 0 0 auto;
margin-left: 1rem;
}
.icon-loader {
display: flex;
align-items: center;
justify-content: center;
min-height: 30vh;
}
.icon-list {
display: grid;
grid-template-columns: repeat(12, 1fr);
position: relative;
margin-top: 1rem;
}
.icon-loader[hidden],
.icon-list[hidden] {
display: none;
}
.icon-list-item {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: var(--sl-border-radius-circle);
font-size: 24px;
width: 2em;
height: 2em;
margin: 0 auto;
cursor: pointer;
transition: var(--sl-transition-medium) all;
}
.icon-list-item:hover {
background-color: var(--sl-color-primary-95);
color: var(--sl-color-primary-50);
}
.icon-list[data-type="outline"] .icon-list-item[data-name$="-fill"] {
display: none;
}
.icon-list[data-type="fill"] .icon-list-item:not([data-name$="-fill"]) {
display: none;
}
.icon-copy-input {
position: absolute;
opacity: 0;
pointer-events: none;
}
@media screen and (max-width: 1000px) {
.icon-search-controls {
display: block;
}
.icon-search-controls sl-select {
margin-left: 0;
margin-top: 1rem;
}
.icon-list {
grid-template-columns: repeat(8, 1fr);
}
.icon-list-item {
font-size: 20px;
}
}
@media screen and (max-width: 500px) {
.icon-list {
grid-template-columns: repeat(4, 1fr);
}
}
</style>
[component-metadata:sl-icon]

Wyświetl plik

@ -0,0 +1,140 @@
# Input
[component-header:sl-input]
Inputs collect data from the user.
```html preview
<sl-input></sl-input>
```
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form.md) instead.
## Examples
### Labels
Use the `label` attribute to give the input an accessible label.
```html preview
<sl-input label="Name"></sl-input>
<br>
<sl-input type="email" label="Email" placeholder="bob@example.com"></sl-input>
```
### Help Text
Add descriptive help text to an input with the `help-text` slot.
```html preview
<sl-input label="Nickname">
<div slot="help-text">What would you like people to call you?</div>
</sl-input>
```
### Placeholder
Use the `placeholder` attribute to add a placeholder.
```html preview
<sl-input placeholder="Type something"></sl-input>
```
### Size
Use the `size` attribute to change an input's size.
```html preview
<sl-input placeholder="Small" size="small"></sl-input>
<br>
<sl-input placeholder="Medium" size="medium"></sl-input>
<br>
<sl-input placeholder="Large" size="large"></sl-input>
```
### Pill
Use the `pill` prop to give inputs rounded edges.
```html preview
<sl-input placeholder="Small" size="small" pill></sl-input>
<br>
<sl-input placeholder="Medium" size="medium" pill></sl-input>
<br>
<sl-input placeholder="Large" size="large" pill></sl-input>
```
### Prefix & Suffix Icons
Use the `prefix` and `suffix` slots to add icons.
```html preview
<sl-input placeholder="Small" size="small">
<sl-icon name="tag" slot="prefix"></sl-icon>
<sl-icon name="gear" slot="suffix"></sl-icon>
</sl-input>
<br>
<sl-input placeholder="Medium" size="medium">
<sl-icon name="tag" slot="prefix"></sl-icon>
<sl-icon name="gear" slot="suffix"></sl-icon>
</sl-input>
<br>
<sl-input placeholder="Large" size="large">
<sl-icon name="tag" slot="prefix"></sl-icon>
<sl-icon name="gear" slot="suffix"></sl-icon>
</sl-input>
```
### Clearable
Add the `clearable` prop to add a clear button when the input has content.
```html preview
<sl-input placeholder="Clearable" size="small" clearable></sl-input>
<br>
<sl-input placeholder="Clearable" size="medium" clearable></sl-input>
<br>
<sl-input placeholder="Clearable" size="large" clearable></sl-input>
```
### Toggle Password
Add the `toggle-password` prop to add a toggle button that will show the password when activated.
```html preview
<sl-input type="password" placeholder="Password Toggle" size="small" toggle-password></sl-input>
<br>
<sl-input type="password" placeholder="Password Toggle" size="medium" toggle-password></sl-input>
<br>
<sl-input type="password" placeholder="Password Toggle" size="large" toggle-password></sl-input>
```
### Disabled
Use the `disabled` attribute to disable an input.
```html preview
<sl-input placeholder="Disabled" size="small" disabled></sl-input>
<br>
<sl-input placeholder="Disabled" size="medium" disabled></sl-input>
<br>
<sl-input placeholder="Disabled" size="large" disabled></sl-input>
```
### Validation
Show a valid or invalid state by setting the `valid` and `invalid` attributes, respectively. Help text can be used to provide feedback for validation and will be styled accordingly.
```html preview
<sl-input label="Valid" valid>
<div slot="help-text">This is a valid input</div>
</sl-input>
<br>
<sl-input label="Invalid" invalid>
<div slot="help-text">This is an invalid input</div>
</sl-input>
```
[component-metadata:sl-input]

Wyświetl plik

@ -0,0 +1,22 @@
# 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 var(--sl-color-gray-90); 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]

Wyświetl plik

@ -0,0 +1,29 @@
# Menu Item
[component-header:sl-menu-item]
Menu items provide options for the user to pick from in a menu.
```html preview
<sl-menu
style="max-width: 200px; border: solid 1px var(--sl-color-gray-90); 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-menu-item checked>Checked</sl-menu-item>
<sl-menu-item disabled>Disabled</sl-menu-item>
<sl-menu-divider></sl-menu-divider>
<sl-menu-item>
Prefix Icon
<sl-icon slot="prefix" name="gift"></sl-icon>
</sl-menu-item>
<sl-menu-item>
Suffix Icon
<sl-icon slot="suffix" name="heart"></sl-icon>
</sl-menu-item>
</sl-menu>
```
[component-metadata:sl-menu-item]

Wyświetl plik

@ -0,0 +1,23 @@
# Menu Label
[component-header:sl-menu-label]
Menu labels are used to describe a group of menu items.
```html preview
<sl-menu
style="max-width: 200px; border: solid 1px var(--sl-color-gray-90); border-radius: var(--sl-border-radius-medium);"
>
<sl-menu-label>Fruits</sl-menu-label>
<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-menu-label>Vegetables</sl-menu-label>
<sl-menu-item value="broccoli">Broccoli</sl-menu-item>
<sl-menu-item value="carrot">Carrot</sl-menu-item>
<sl-menu-item value="zucchini">Zucchini</sl-menu-item>
</sl-menu>
```
[component-metadata:sl-menu-label]

Wyświetl plik

@ -0,0 +1,23 @@
# Menu
[component-header:sl-menu]
Menus provide a list of options for the user.
Use [menu items](/components/menu-item.md), [menu dividers](/components/menu-divider.md), and [menu labels](/components/menu-label.md) to compose a menu.
```html preview
<sl-menu
style="max-width: 200px; border: solid 1px var(--sl-color-gray-90); 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-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>
```
[component-metadata:sl-menu]

Wyświetl plik

@ -0,0 +1,52 @@
# Progress Bar
[component-header:sl-progress-bar]
Progress bars are used to show the progress of a determinate operation.
```html preview
<sl-progress-bar percentage="50"></sl-progress-bar>
```
## Examples
### Custom Height
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>
```
### Labels
Use the default slot to show a label.
```html preview
<sl-progress-bar percentage="50" class="progress-bar-labels">50%</sl-progress-bar>
<br>
<sl-button circle><sl-icon name="dash"></sl-icon></sl-button>
<sl-button circle><sl-icon name="plus"></sl-icon></sl-button>
<script>
const progressBar = document.querySelector('.progress-bar-labels');
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}%`;
});
subtractButton.addEventListener('click', () => {
const percentage = Math.max(0, progressBar.percentage - 10)
progressBar.percentage = percentage;
progressBar.textContent = `${percentage}%`;
});
</script>
```
[component-metadata:sl-progress-bar]

Wyświetl plik

@ -0,0 +1,71 @@
# Progress Ring
[component-header:sl-progress-ring]
Progress rings are used to show the progress of a determinate operation in a circular fashion.
```html preview
<sl-progress-ring percentage="50"></sl-progress-ring>
```
## Examples
### Size
Use the `size` attribute to set the diameter of the progress ring.
```html preview
<sl-progress-ring percentage="50" size="200"></sl-progress-ring>
```
### Stroke Width
Use the `stroke-width` attribute to set the width of the progress ring's indicator.
```html preview
<sl-progress-ring percentage="50" stroke-width="10"></sl-progress-ring>
```
### Colors
To change the color, use the `--track-color` and `--indicator-color` custom properties.
```html preview
<sl-progress-ring
percentage="50"
style="--track-color: #ffe2c6; --indicator-color: tomato;"
></sl-progress-ring>
```
### Labels
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>
<br>
<sl-button circle><sl-icon name="dash"></sl-icon></sl-button>
<sl-button circle><sl-icon name="plus"></sl-icon></sl-button>
<script>
const progressRing = document.querySelector('.progress-ring-labels');
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}%`;
});
subtractButton.addEventListener('click', () => {
const percentage = Math.max(0, progressRing.percentage - 10)
progressRing.percentage = percentage;
progressRing.textContent = `${percentage}%`;
});
</script>
```
[component-metadata:sl-progress-ring]

Wyświetl plik

@ -0,0 +1,42 @@
# Radio
[component-header:sl-radio]
Radios allow the user to select one option from a group of many.
```html preview
<sl-radio>Radio</sl-radio>
```
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form.md) instead.
## Examples
### Checked
Use the `checked` attribute to activate the radio.
```html preview
<sl-radio checked>Checked</sl-radio>
```
### Disabled
Use the `disabled` attribute to disable the radio.
```html preview
<sl-radio disabled>Disabled</sl-radio>
```
### Grouping Radios
Radios are grouped based on their `name` attribute and scoped to the nearest form.
```html preview
<sl-radio name="option" checked>Option 1</sl-radio><br>
<sl-radio name="option">Option 2</sl-radio><br>
<sl-radio name="option">Option 3</sl-radio><br>
<sl-radio name="option">Option 4</sl-radio>
```
[component-metadata:sl-radio]

Wyświetl plik

@ -0,0 +1,52 @@
# Range
[component-header:sl-range]
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>
```
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form.md) instead.
## Examples
### Disabled
Use the `disabled` prop to disable a slider.
```html preview
<sl-range min="0" max="100" step="1" disabled></sl-range>
```
### Tooltip Placement
By default, the tooltip is shown on top. Set `tooltip` to `bottom` to show it below the slider.
```html preview
<sl-range min="0" max="100" step="1" tooltip="bottom"></sl-range>
```
### Disable the Tooltip
To disable the tooltip, set `tooltip` to `none`.
```html preview
<sl-range min="0" max="100" step="1" tooltip="none"></sl-range>
```
### Custom Tooltip Formatter
You can change the tooltip's content by setting the `tooltipFormatter` prop to a function that accepts the range's value as an argument.
```html preview
<sl-range min="0" max="100" step="1" class="range-with-custom-formatter"></sl-range>
<script>
const range = document.querySelector('.range-with-custom-formatter');
range.tooltipFormatter = value => `Total - ${value}%`;
</script>
```
[component-metadata:sl-range]

Wyświetl plik

@ -0,0 +1,159 @@
# Select
[component-header:sl-select]
Selects allow you to choose one or more items from a dropdown menu.
```html preview
<sl-select placeholder="Select one">
<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-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>
</sl-select>
```
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form.md) instead.
## Examples
### Labels
Use the `label` attribute to give the select an accessible label.
```html preview
<sl-select label="Select one">
<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>
```
### Help Text
Add descriptive help text to an input with the `help-text` slot.
```html preview
<sl-select label="Experience">
<sl-menu-item value="option-1">Novice</sl-menu-item>
<sl-menu-item value="option-2">Intermediate</sl-menu-item>
<sl-menu-item value="option-3">Advanced</sl-menu-item>
<div slot="help-text">Please tell us your skill level.</div>
</sl-select>
```
### Multiple
To allow multiple options to be selected, use the `multiple` attribute.
```html preview
<sl-select placeholder="Select a few" multiple>
<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-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>
</sl-select>
```
### Size
Use the `size` attribute to change a select's size.
```html preview
<sl-select placeholder="Small" size="small" multiple>
<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>
<br>
<sl-select placeholder="Medium" size="medium" multiple>
<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>
<br>
<sl-select placeholder="Large" size="large" multiple>
<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` prop to give selects rounded edges.
```html preview
<sl-select label="Select one" pill multiple>
<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>
```
### Groups
Options can be grouped visually using menu labels and menu dividers.
```html preview
<sl-select placeholder="Select one">
<sl-menu-label>Group 1</sl-menu-label>
<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-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>
<sl-menu-item value="option-6">Option 6</sl-menu-item>
</sl-select>
```
### Disabled
Use the `disabled` prop to disable a select.
```html preview
<sl-select placeholder="Disabled" disabled>
<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>
```
### Validation
Show a valid or invalid state by setting the `valid` and `invalid` attributes, respectively. Help text can be used to provide feedback for validation and will be styled accordingly.
```html preview
<sl-select placeholder="Valid" valid>
<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>
<div slot="help-text">This is a valid selection!</div>
</sl-select>
<br>
<sl-select placeholder="Invalid" invalid>
<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>
<div slot="help-text">This is not a valid selection!</div>
</sl-select>
```
[component-metadata:sl-select]

Wyświetl plik

@ -0,0 +1,39 @@
# Spinner
[component-header:sl-spinner]
Spinners are used to show the progress of an indeterminate operation.
```html preview
<sl-spinner></sl-spinner>
```
## Examples
### 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.
```html preview
<sl-spinner></sl-spinner>
<sl-spinner style="font-size: 2rem;"></sl-spinner>
<sl-spinner style="font-size: 3rem;"></sl-spinner>
```
### Stroke Width
The width of the spinner can be changed by setting the `--stroke-width` custom property.
```html preview
<sl-spinner style="font-size: 2rem; --stroke-width: 6px;"></sl-spinner>
```
### Color
The spinner's color can be changed by setting the `--color` custom property.
```html preview
<sl-spinner style="font-size: 2rem; --color: tomato;"></sl-spinner>
```
[component-metadata:sl-spinner]

Wyświetl plik

@ -0,0 +1,32 @@
# Switch
[component-header:sl-switch]
Switches allow the user to toggle an option on or off.
```html preview
<sl-switch>Switch</sl-switch>
```
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form.md) instead.
## Examples
### Checked
Use the `checked` attribute to activate the switch.
```html preview
<sl-switch checked>Checked</sl-switch>
```
### Disabled
Use the `disabled` attribute to disable the switch.
```html preview
<sl-switch disabled>Disabled</sl-switch>
```
[component-metadata:sl-switch]

Wyświetl plik

@ -0,0 +1,129 @@
# Tab Group
[component-header:sl-tab-group]
Tab groups organize content into a container that shows one section at a time.
Tab groups make use of [tabs](/components/tab.md) and [tab panels](/components/tab-panel.md). Each tab must be slotted into the `nav` slot and its `panel` must refer to a tab panel of the same name.
```html preview
<sl-tab-group>
<sl-tab slot="nav" panel="general">General</sl-tab>
<sl-tab slot="nav" panel="custom">Custom</sl-tab>
<sl-tab slot="nav" panel="advanced">Advanced</sl-tab>
<sl-tab slot="nav" panel="disabled" disabled>Disabled</sl-tab>
<sl-tab-panel name="general">This is the general tab panel.</sl-tab-panel>
<sl-tab-panel name="custom">This is the custom tab panel.</sl-tab-panel>
<sl-tab-panel name="advanced">This is the advanced tab panel.</sl-tab-panel>
<sl-tab-panel name="disabled">This is a disabled tab panel.</sl-tab-panel>
</sl-tab-group>
```
## Examples
### Tabs on Bottom
Tabs can be shown on the bottom by setting `placement` to `bottom`.
```html preview
<sl-tab-group placement="bottom">
<sl-tab slot="nav" panel="general">General</sl-tab>
<sl-tab slot="nav" panel="custom">Custom</sl-tab>
<sl-tab slot="nav" panel="advanced">Advanced</sl-tab>
<sl-tab slot="nav" panel="disabled" disabled>Disabled</sl-tab>
<sl-tab-panel name="general">This is the general tab panel.</sl-tab-panel>
<sl-tab-panel name="custom">This is the custom tab panel.</sl-tab-panel>
<sl-tab-panel name="advanced">This is the advanced tab panel.</sl-tab-panel>
<sl-tab-panel name="disabled">This is a disabled tab panel.</sl-tab-panel>
</sl-tab-group>
```
### Tabs on Left
Tabs can be shown on the left by setting `placement` to `left`.
```html preview
<sl-tab-group placement="left">
<sl-tab slot="nav" panel="general">General</sl-tab>
<sl-tab slot="nav" panel="custom">Custom</sl-tab>
<sl-tab slot="nav" panel="advanced">Advanced</sl-tab>
<sl-tab slot="nav" panel="disabled" disabled>Disabled</sl-tab>
<sl-tab-panel name="general">This is the general tab panel.</sl-tab-panel>
<sl-tab-panel name="custom">This is the custom tab panel.</sl-tab-panel>
<sl-tab-panel name="advanced">This is the advanced tab panel.</sl-tab-panel>
<sl-tab-panel name="disabled">This is a disabled tab panel.</sl-tab-panel>
</sl-tab-group>
```
### Tabs on Right
Tabs can be shown on the right by setting `placement` to `right`.
```html preview
<sl-tab-group placement="right">
<sl-tab slot="nav" panel="general">General</sl-tab>
<sl-tab slot="nav" panel="custom">Custom</sl-tab>
<sl-tab slot="nav" panel="advanced">Advanced</sl-tab>
<sl-tab slot="nav" panel="disabled" disabled>Disabled</sl-tab>
<sl-tab-panel name="general">This is the general tab panel.</sl-tab-panel>
<sl-tab-panel name="custom">This is the custom tab panel.</sl-tab-panel>
<sl-tab-panel name="advanced">This is the advanced tab panel.</sl-tab-panel>
<sl-tab-panel name="disabled">This is a disabled tab panel.</sl-tab-panel>
</sl-tab-group>
```
### Scrolling Tabs
When there are more tabs than horizontal space allows, the nav will be scrollable.
```html preview
<sl-tab-group>
<sl-tab slot="nav" panel="tab-1">Tab 1</sl-tab>
<sl-tab slot="nav" panel="tab-2">Tab 2</sl-tab>
<sl-tab slot="nav" panel="tab-3">Tab 3</sl-tab>
<sl-tab slot="nav" panel="tab-4">Tab 4</sl-tab>
<sl-tab slot="nav" panel="tab-5">Tab 5</sl-tab>
<sl-tab slot="nav" panel="tab-6">Tab 6</sl-tab>
<sl-tab slot="nav" panel="tab-7">Tab 7</sl-tab>
<sl-tab slot="nav" panel="tab-8">Tab 8</sl-tab>
<sl-tab slot="nav" panel="tab-9">Tab 9</sl-tab>
<sl-tab slot="nav" panel="tab-10">Tab 10</sl-tab>
<sl-tab slot="nav" panel="tab-11">Tab 11</sl-tab>
<sl-tab slot="nav" panel="tab-12">Tab 12</sl-tab>
<sl-tab slot="nav" panel="tab-13">Tab 13</sl-tab>
<sl-tab slot="nav" panel="tab-14">Tab 14</sl-tab>
<sl-tab slot="nav" panel="tab-15">Tab 15</sl-tab>
<sl-tab slot="nav" panel="tab-16">Tab 16</sl-tab>
<sl-tab slot="nav" panel="tab-17">Tab 17</sl-tab>
<sl-tab slot="nav" panel="tab-18">Tab 18</sl-tab>
<sl-tab slot="nav" panel="tab-19">Tab 19</sl-tab>
<sl-tab slot="nav" panel="tab-20">Tab 20</sl-tab>
<sl-tab-panel name="tab-1">Tab panel 1</sl-tab-panel>
<sl-tab-panel name="tab-2">Tab panel 2</sl-tab-panel>
<sl-tab-panel name="tab-3">Tab panel 3</sl-tab-panel>
<sl-tab-panel name="tab-4">Tab panel 4</sl-tab-panel>
<sl-tab-panel name="tab-5">Tab panel 5</sl-tab-panel>
<sl-tab-panel name="tab-6">Tab panel 6</sl-tab-panel>
<sl-tab-panel name="tab-7">Tab panel 7</sl-tab-panel>
<sl-tab-panel name="tab-8">Tab panel 8</sl-tab-panel>
<sl-tab-panel name="tab-9">Tab panel 9</sl-tab-panel>
<sl-tab-panel name="tab-10">Tab panel 10</sl-tab-panel>
<sl-tab-panel name="tab-11">Tab panel 11</sl-tab-panel>
<sl-tab-panel name="tab-12">Tab panel 12</sl-tab-panel>
<sl-tab-panel name="tab-13">Tab panel 13</sl-tab-panel>
<sl-tab-panel name="tab-14">Tab panel 14</sl-tab-panel>
<sl-tab-panel name="tab-15">Tab panel 15</sl-tab-panel>
<sl-tab-panel name="tab-16">Tab panel 16</sl-tab-panel>
<sl-tab-panel name="tab-17">Tab panel 17</sl-tab-panel>
<sl-tab-panel name="tab-18">Tab panel 18</sl-tab-panel>
<sl-tab-panel name="tab-19">Tab panel 19</sl-tab-panel>
<sl-tab-panel name="tab-20">Tab panel 20</sl-tab-panel>
</sl-tab-group>
```
[component-metadata:sl-tab-group]

Wyświetl plik

@ -0,0 +1,23 @@
# Tab Panel
[component-header:sl-tab-panel]
Tab panels are used inside tab groups to display content.
```html preview
<sl-tab-group>
<sl-tab slot="nav" panel="general">General</sl-tab>
<sl-tab slot="nav" panel="custom">Custom</sl-tab>
<sl-tab slot="nav" panel="advanced">Advanced</sl-tab>
<sl-tab slot="nav" panel="disabled" disabled>Disabled</sl-tab>
<sl-tab-panel name="general">This is the general tab panel.</sl-tab-panel>
<sl-tab-panel name="custom">This is the custom tab panel.</sl-tab-panel>
<sl-tab-panel name="advanced">This is the advanced tab panel.</sl-tab-panel>
<sl-tab-panel name="disabled">This is a disabled tab panel.</sl-tab-panel>
</sl-tab-group>
```
?> Additional demonstrations can be found in the [tab group examples](/components/tab-group.md).
[component-metadata:sl-tab-panel]

Wyświetl plik

@ -0,0 +1,15 @@
# Tab
[component-header:sl-tab]
Tabs are used inside tab groups to represent tab panels.
```html preview
<sl-tab>Tab</sl-tab>
<sl-tab active>Active</sl-tab>
<sl-tab disabled>Disabled</sl-tab>
```
?> Additional demonstrations can be found in the [tab group examples](/components/tab-group.md).
[component-metadata:sl-tab]

Wyświetl plik

@ -0,0 +1,47 @@
# Tag
[component-header:sl-tag]
Tags are used as labels to organize things or to indicate a selection.
```html preview
<sl-tag type="primary">Primary</sl-tag>
<sl-tag type="success">Success</sl-tag>
<sl-tag type="info">Info</sl-tag>
<sl-tag type="warning">Warning</sl-tag>
<sl-tag type="danger">Danger</sl-tag>
```
## Examples
### Size
Use the `size` prop to change a tab's size.
```html preview
<sl-tag size="small">Small</sl-tag>
<sl-tag size="medium">Medium</sl-tag>
<sl-tag size="large">Large</sl-tag>
```
### Pill
Use the `pill` prop to give tabs rounded edges.
```html preview
<sl-tag size="small" pill>Small</sl-tag>
<sl-tag size="medium" pill>Medium</sl-tag>
<sl-tag size="large" pill>Large</sl-tag>
```
### Clearable
Use the `clearable` attribute to add a clear button to the tag.
```html preview
<sl-tag size="small" clearable>Small</sl-tag>
<sl-tag size="medium" clearable>Medium</sl-tag>
<sl-tag size="large" clearable>Large</sl-tag>
```
[component-metadata:sl-tag]

Wyświetl plik

@ -0,0 +1,89 @@
# Textarea
[component-header:sl-textarea]
Textareas collect data from the user and allow multiple lines of text.
```html preview
<sl-textarea></sl-textarea>
```
?> This component doesn't work with standard forms. Use [`<sl-form>`](/components/form.md) instead.
## Examples
### Labels
Use the `label` attribute to give the textarea an accessible label.
```html preview
<sl-textarea label="Comments"></sl-textarea>
```
### Help Text
Add descriptive help text to a textarea with the `help-text` slot.
```html preview
<sl-textarea label="Feedback">
<div slot="help-text">Please tell us what you think.</div>
</sl-textarea>
```
### Rows
Use the `rows` attribute to change the number of text rows that get shown.
```html preview
<sl-textarea rows="2"></sl-textarea>
```
### Placeholders
Use the `placeholder` attribute to add a placeholder.
```html preview
<sl-textarea placeholder="Type something"></sl-textarea>
```
### Disabled
Use the `disabled` attribute to disable an input.
```html preview
<sl-textarea placeholder="Textarea" disabled></sl-textarea>
```
### Validation
Show a valid or invalid state by setting the `valid` and `invalid` attributes, respectively. Help text can be used to provide feedback for validation and will be styled accordingly.
```html preview
<sl-textarea label="Valid" valid>
<div slot="help-text">This is a valid textarea.</div>
</sl-textarea>
<br>
<sl-textarea label="Invalid" invalid>
<div slot="help-text">This is an invalid textarea.</div>
</sl-textarea>
```
### Prevent Resizing
By default, textareas can be resized vertically by the user. To prevent resizing, set the `resize` attribute to `none`.
```html preview
<sl-textarea resize="none"></sl-textarea>
```
### Expand with Content
Textareas will automatically resize to expand to fit their content when `resize` is set to `auto`.
```html preview
<sl-textarea resize="auto"></sl-textarea>
```
[component-metadata:sl-textarea]

Wyświetl plik

@ -0,0 +1,166 @@
# Tooltip
[component-header:sl-tooltip]
Tooltips display additional information based on a specific action.
A tooltip's target is its _first child element_, so you should only wrap one element inside of the tooltip. If you need the tooltip to show up for multiple elements, nest them inside a container first.
Tooltip's use `display: contents` so they won't interfere with how elements are positioned in a flex or grid layout.
```html preview
<sl-tooltip content="This is a tooltip">
<sl-button>Hover Me</sl-button>
</sl-tooltip>
```
## Examples
### Placement
Use the `placement` attribute to set the preferred placement of the tooltip.
```html preview
<div class="tooltip-placement-example">
<div class="tooltip-placement-example-row">
<sl-tooltip content="top-start" placement="top-start">
<sl-button></sl-button>
</sl-tooltip>
<sl-tooltip content="top" placement="top">
<sl-button></sl-button>
</sl-tooltip>
<sl-tooltip content="top-end" placement="top-end">
<sl-button></sl-button>
</sl-tooltip>
</div>
<div class="tooltip-placement-example-row">
<sl-tooltip content="left-start" placement="left-start">
<sl-button></sl-button>
</sl-tooltip>
<sl-tooltip content="right-start" placement="right-start" style="margin-left: 400px;">
<sl-button></sl-button>
</sl-tooltip>
</div>
<div class="tooltip-placement-example-row">
<sl-tooltip content="left" placement="left">
<sl-button></sl-button>
</sl-tooltip>
<sl-tooltip content="right" placement="right">
<sl-button></sl-button>
</sl-tooltip>
</div>
<div class="tooltip-placement-example-row">
<sl-tooltip content="left-end" placement="left-end">
<sl-button></sl-button>
</sl-tooltip>
<sl-tooltip content="right-end" placement="right-end">
<sl-button></sl-button>
</sl-tooltip>
</div>
<div class="tooltip-placement-example-row">
<sl-tooltip content="bottom-start" placement="bottom-start">
<sl-button></sl-button>
</sl-tooltip>
<sl-tooltip content="bottom" placement="bottom">
<sl-button></sl-button>
</sl-tooltip>
<sl-tooltip content="bottom-end" placement="bottom-end">
<sl-button></sl-button>
</sl-tooltip>
</div>
</div>
<style>
.tooltip-placement-example {
width: 250px;
}
.tooltip-placement-example-row::after {
content: '';
display: table;
clear: both;
}
.tooltip-placement-example sl-button {
float: left;
margin-right: 0.25rem;
margin-bottom: 0.25rem;
}
.tooltip-placement-example [placement='top-start'] sl-button,
.tooltip-placement-example [placement='bottom-start'] sl-button {
margin-left: calc(40px + 0.25rem);
}
.tooltip-placement-example [placement^='right'] sl-button {
margin-left: calc((40px * 3) + (0.25rem * 3));
}
</style>
```
### Click Trigger
Set the `trigger` attribute to `click` to toggle the tooltip on click instead of hover.
```html preview
<sl-tooltip content="Click again to dismiss" trigger="click">
<sl-button>Click to Toggle</sl-button>
</sl-tooltip>
```
### Manual Trigger
Tooltips can be controller programmatically by setting the `trigger` attribute to `manual`. Use the `open` prop to control when the tooltip is shown.
```html preview
<sl-button style="margin-right: 4rem;">Toggle Manually</sl-button>
<sl-tooltip content="This is an avatar" trigger="manual" class="manual-tooltip">
<sl-avatar></sl-avatar>
</sl-tooltip>
<script>
const tooltip = document.querySelector('.manual-tooltip');
const toggle = tooltip.previousElementSibling;
toggle.addEventListener('click', () => (tooltip.open = !tooltip.open));
</script>
```
### Remove Arrows
You can control the size of tooltip arrows by overriding the `--sl-tooltip-arrow-size` design token.
```html preview
<div style="--sl-tooltip-arrow-size: 0;">
<sl-tooltip content="This is a tooltip">
<sl-button>Above</sl-button>
</sl-tooltip>
<sl-tooltip content="This is a tooltip" placement="bottom">
<sl-button>Below</sl-button>
</sl-tooltip>
</div>
```
To override it globally, set it in a root block in your stylesheet after `shoelace.css` is loaded.
```css
:root {
--sl-tooltip-arrow-size: 0;
}
```
[component-metadata:sl-tooltip]

Wyświetl plik

@ -0,0 +1,123 @@
# Customizing
Shoelace components can be customized at a high level through design tokens. This gives you control over theme colors and general styling. For more advanced customizations, you can make use of component parts and custom properties to target individual components.
## Design Tokens
Shoelace makes use of several design tokens to provide a consistent appearance across components. You can customize them and use them in your own application with pure CSS — no preprocessor required.
Design tokens offer a high-level way to customize the library with minimal effort. There are no component-specific variables, however, as design tokens are intended to be generic and highly reusable. To customize an individual component, refer to the section entitled [Component parts](#component-parts).
Design tokens are CSS custom properties ("CSS variables") that are defined in the `:root` block of `shoelace.css`. This stylesheet is imported when you install Shoelace, so design tokens are available on your page at that point. Because design tokens are global, they're always prefixed with `--sl` to avoid collisions with other libraries.
To customize a design token, simply override it in your stylesheet using a `:root` block.
```css
:root {
/* Changes the primary color to a shade of orange at 90% saturation */
--sl-color-primary-hue: 30;
--sl-color-primary-saturation: 90%;
}
```
Design tokens are described further along in this documentation. For a complete list, refer to `shoelace.scss` in the project's [source code](https://github.com/shoelace-style/shoelace/blob/master/src/styles/shoelace.scss).
!> **Never modify variables directly in `shoelace.css`** because your changes will be overwritten when you upgrade the library. Even if you don't plan on upgrading, it's always better to override design tokens in your own stylesheet for better maintainability.
## Component Parts
Whereas design tokens offer a high-level way to customize the library, component parts offer a low-level way to customize individual components. Again, this is done with pure CSS — no preprocessor required.
Shoelace components use a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to encapsulate their styles and behaviors. As a result, you can't simply target their internals with the usual CSS selectors. Instead, components expose "parts" that can be targetted with the [CSS part selector](https://developer.mozilla.org/en-US/docs/Web/CSS/::part), or `::part()`.
Here's an example that modifies buttons with the `tomato-button` class.
```html preview
<sl-button class="tomato-button">
Tomato Button
</sl-button>
<style>
.tomato-button::part(base) {
background: white;
border: solid 1px tomato;
}
.tomato-button::part(base):hover {
background: rgba(255, 99, 71, .1);
}
.tomato-button::part(base):active {
background: rgba(255, 99, 71, .2);
}
.tomato-button::part(base):focus {
box-shadow: 0 0 0 3px rgba(255, 99, 71, .33);
}
.tomato-button::part(label) {
color: tomato;
}
</style>
```
At first glance, this approach might seem a bit verbose or even limiting, but it comes with a few important advantages:
- Customizations can be made to components with explicit selectors, such as `::part(icon)`, rather than implicit selectors, such as `.button > div > span + .icon`, that are much more fragile.
- The internal structure of a component will likely change as it evolves. By exposing component parts through an API, the internals can be reworked without fear of breaking customizations as long as its parts remain intact.
- It encourages us to think more about how components are designed and how customizations should be allowed before users can take advantage of them. Once we opt a part into the component's API, it's guaranteed to be supported and can't be removed until a major version of the library is released.
Most (but not all) components expose parts. You can find them in each component's API documention under the "CSS Parts" section.
### Custom Properties
For convenience, some components expose CSS custom properties you can override. These are not design tokens, nor do they have the same `--sl-` prefix since they're scoped to a component.
You can set custom properties on a component in your stylesheet.
```css
sl-avatar {
--size: 6rem;
}
```
This will also work if you need to target a subset of components with a specific class.
```css
sl-avatar.your-class {
--size: 6rem;
}
```
Alternatively, you can set them inline directly on the element.
```html
<sl-avatar style="--size: 6rem;"></sl-avatar>
```
Not all components expose CSS custom properties. For those that do, they can be found in the component's API documentation.
## Writing a Theme
Customizing Shoelace is fairly easy, but you can take things a step further and create a full-blown theme if you want. A theme is nothing more than a stylesheet that uses the APIs described above to customize Shoelace's design tokens and components.
It's a good practice to include `shoelace.css` in your app and add your theme's stylesheet directly below it. That way, when an update introduces a new design token, your theme will still work with the default design token value.
### Submitting a Theme
**I am very interested in offering well-designed themes to complement this library.** To submit a theme for review, please open an issue on GitHub with the theme attached. Once approved, your theme will be showcased in the project's documentation (that section is coming soon).
Themes that are in high demand include:
- Dark mode ([details](https://github.com/shoelace-style/shoelace/issues/98))
- High contrast ([details](https://github.com/shoelace-style/shoelace/issues/99))
**I am willing to contribute a minimum of $200 USD to commission each of the themes listed above.**
Please note the following requirements before submitting a theme.
- Themes must be complete and of high quality
- Themes must be available under the same open source license as Shoelace
- If a theme is not original, the derivative work must have a license that is compatible with Shoelace's license

Wyświetl plik

@ -0,0 +1,35 @@
# Installation
You can use Shoelace via CDN or by installing it locally.
## CDN Installation (Recommended)
The easiest way to install Shoelace is with the CDN. A lightweight loader will be added to your page that registers components asynchronously as you use them. It's like magic. ✨
Just add the following tags to your page.
```html
<link rel="stylesheet" href="https://unpkg.com/@shoelace-style/shoelace@%VERSION%/dist/shoelace/shoelace.css">
<script type="module" src="https://unpkg.com/@shoelace-style/shoelace@%VERSION%/dist/shoelace/shoelace.esm.js"></script>
```
Now you can [start using Shoelace components!](/getting-started/usage.md)
## Local Installation
If you don't want to use the CDN, you can install Shoelace locally with the following command.
```sh
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 `/assets/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="/assets/shoelace/shoelace.css">
<script type="module" src="/assets/shoelace/shoelace.esm.js"></script>
```
Now you can [start using Shoelace components!](/getting-started/usage.md)

Wyświetl plik

@ -0,0 +1,107 @@
<img class="logo" src="/assets/images/wordmark.svg" alt="Shoelace" data-no-zoom>
A forward-thinking library of web components.
- Works with all frameworks 🧩
- Works with CDNs 🚛
- Fully customizable with CSS 🎨
- Open source 😸
Designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska).
## Quick Start
Add the following code to your page.
```html
<link rel="stylesheet" href="https://unpkg.com/@shoelace-style/shoelace@%VERSION%/dist/shoelace/shoelace.css">
<script type="module" src="https://unpkg.com/@shoelace-style/shoelace@%VERSION%/dist/shoelace/shoelace.esm.js"></script>
```
Now you have access to all of Shoelace's components! Try adding a button:
```html
<sl-button>Click me</sl-button>
```
See the [installation instructions](getting-started/installation.md) for more details and other ways to install Shoelace.
## New to Web Components?
**TL;DR** – we finally have a way to create [our own HTML elements](https://html.spec.whatwg.org/multipage/custom-elements.html) and use them in any framework we want!
Thanks to the popularity of frameworks such as Angular, Vue, and React, component-driven development has become a part of our every day lives. Components help us encapsulate styles and behaviors into reusable building blocks. They make a lot of sense in terms of design, development, and testing.
Unfortunately, _framework-specific_ components fail us in a number of ways:
- You can only use them in the framework they're designed for 🔒
- Their lifespan is limited to that of the framework's ⏳
- New framework versions can lead to breaking changes, requiring substantial effort to update components 😭
Web components solve these problems. They're [supported by all modern browsers](https://caniuse.com/#feat=custom-elementsv1), they're framework-agnostic, and they're [part of the standard](https://developer.mozilla.org/en-US/docs/Web/Web_Components), so we know they'll be supported for many years to come.
This is the technology that Shoelace is built on.
## What Problems Does This Solve?
Shoelace provides a collection of professionally designed, every day UI components built on a framework-agnostic technology. Why spend hundreds of hours or more building a design system from scratch? Why make a component library that only works with one framework?
With Shoelace, you can:
- Start building things faster (no need to roll your own buttons)
- Build multiple apps with different frameworks that all share the same UI
- Skip having to learn a new component library every time you switch frameworks
If your organization is looking to build a design system, [Shoelace will save you thousands of dollars](https://medium.com/eightshapes-llc/and-you-thought-buttons-were-easy-26eb5b5c1871).* All the foundational components you need are right here, ready to be customized for your brand. And since it's built on web standards, browsers will continue to support it for many years to come.
Whether you use Shoelace as a starting point for your organization's design system or for a fun personal project, there's no limit to what you can do with it.
<small>*Please consider giving back some of what you save by [supporting this project with a sponsorship](https://github.com/sponsors/claviska).</small>
## Browser Support
Shoelace is tested in the latest two versions of the following browsers.
<img src="/assets/images/chrome.png" alt="Chrome" width="64" height="64" data-no-zoom>
<img src="/assets/images/edge.png" alt="Edge" width="64" height="64" data-no-zoom>
<img src="/assets/images/firefox.png" alt="Firefox" width="64" height="64" data-no-zoom>
<img src="/assets/images/opera.png" alt="Opera" width="64" height="64" data-no-zoom>
<img src="/assets/images/safari.png" alt="Safari" width="64" height="64" data-no-zoom>
Critical bug fixes in earlier versions will be addressed based on their severity and impact.
If you need to support IE11 or pre-Chromium Edge, this library isn't for you. Although web components can (to some degree) be polyfilled for legacy browsers, supporting them is outside the scope of this project. If you're using Shoelace in such a browser, you're gonna have a bad time. ⛷
## License
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.
👇 Your support is very much appreciated! 👇
<a class="repo-button repo-button--sponsor" href="https://github.com/sponsors/claviska" rel="noopener" target="_blank">
<sl-icon name="heart"></sl-icon> Become a sponsor
</a>
<a class="repo-button repo-button--github" href="https://github.com/shoelace-style/shoelace/stargazers" rel="noopener" target="_blank">
<sl-icon src="/assets/images/github.svg"></sl-icon> Star
</a>
<a class="repo-button repo-button--twitter" href="https://twitter.com/shoelace_style" rel="noopener" target="_blank">
<sl-icon src="/assets/images/twitter.svg"></sl-icon> Follow
</a>
## Attribution
Special thanks to the following projects and individuals that helped make Shoelace possible.
- Components are compiled by [Stencil](https://stenciljs.com/)
- Documentation is powered by [Docsify](https://docsify.js.org/)
- Theme colors and form controls are inspired by [Element](element.eleme.io)
- Icons are courtesy of [Bootstrap Icons](https://icons.getbootstrap.com/)
- Positioning of menus, tooltips, et al is handled by [Popper.js](https://popper.js.org/)
- CDN services are provided by [unpkg](https://unpkg.com/)
- The Shoelace logo was designed with a single shoelace by [Adam K Olson](https://twitter.com/adamkolson)

Wyświetl plik

@ -0,0 +1,41 @@
# Roadmap
The roadmap tracks the status of components and features that are planned for development.
## 2.1 🤔
Version 2.1 is still in the planning phase. To request a feature, please [submit an issue](https://github.com/shoelace-style/shoelace/issues) on GitHub. Make sure to search for existing issues and vote using 👍 to add your support!
?> Is there a feature you really want to see here? Sponsoring Shoelace is the best way to prioritize its development. [Learn more](https://github.com/sponsors/claviska)
## 2.0 🚀
- [x] Alert
- [x] Avatar
- [x] Button
- [x] Checkbox
- [x] Color Picker
- [x] Details
- [x] Dialog
- [x] Drawer
- [x] Dropdown
- [x] Form
- [x] Icon
- [x] Input
- [x] Menu
- [x] Menu Divider
- [x] Menu Item
- [x] Menu Label
- [x] Progress Bar
- [x] Progress Ring
- [x] Radio
- [x] Range
- [x] Select
- [x] Spinner
- [x] Switch
- [x] Tab Group
- [x] Tab
- [x] Tab Panel
- [x] Tag
- [x] Textarea
- [x] Tooltip

Wyświetl plik

@ -0,0 +1,220 @@
# Usage
Shoelace components are just regular HTML elements, or "custom elements" to be precise. You can use them like any other element. Each component has detailed documentation that describes its full API, including properties, events, methods, and more.
## Web Component Basics
### Properties
Many components have properties ("props") that can be set using attributes. For example, buttons accept a `size` attribute that dictates the button's size.
```html
<sl-button size="small">Click me</sl-button>
```
Some props are booleans, so they only have true/false values. To activate a boolean prop, add the corresponding attribute without a value.
```html
<sl-button disabled>Click me</sl-button>
```
In rare cases, a prop may require an array, an object, or a function. For example, to customize the color picker's list of preset swatches, you set the `swatches` prop to an array of colors. This can be done with JavaScript.
```html
<sl-color-picker></sl-color-picker>
<script>
const colorPicker = document.querySelector('sl-color-picker');
colorPicker.swatches = ['red', 'orange', 'yellow', 'green', 'blue', 'purple'];
</script>
```
Refer to a component's documentation for a complete list of its properties.
### Events
You can listen for standard events such as `click`, `mouseover`, etc. as you normally would. In addition, some components emit custom events. These work the same way as standard events, but are prefixed with `sl` to prevent collisions with standard events and other libraries.
```html
<sl-checkbox>Check me</sl-checkbox>
<script>
const checkbox = document.querySelector('sl-checkbox');
checkbox.addEventListener('slChange', event => {
console.log(event.target.checked ? 'checked' : 'not checked');
});
</script>
```
Refer to a component's documentation for a complete list of its custom events.
### Methods
Some components have methods you can call to trigger various behaviors. For example, you can set focus on a Shoelace input using the `setFocus()` method.
```html
<sl-input></sl-input>
<script>
const input = document.querySelector('sl-input');
input.setFocus();
</script>
```
Refer to a component's documentation for a complete list of its methods and their arguments.
### Slots
Many components use slots to accept content inside of them. The most common slot is the _default_ slot, which includes any content inside the component that doesn't have a `slot` attribute.
For example, a button's default slot is used to populate its label.
```html
<sl-button>Click me</sl-button>
```
Some components also have _named_ slots. A named slot can be populated by adding a child element with the appropriate `slot` attribute. Notice how the icon below has the `slot="prefix"` attribute? This tells the component to place the icon into its `prefix` slot.
```html
<sl-button>
<sl-icon slot="prefix" name="gear"></sl-icon>
Settings
</sl-button>
```
The location of a named slot doesn't matter. You can put it anywhere inside the component and the browser will move it to the right place automatically!
Refer to a component's documentation for a complete list of available slots.
### Don't Use Self-closing Tags
Custom elements cannot have self-closing tags. Similar to `<script>` and `<textarea>`, you must always include the full closing tag.
```html
<!-- Don't do this -->
<sl-input />
<!-- Always do this -->
<sl-input></sl-input>
```
### Differences from Native Elements
You might expect similarly named elements to share the same API as native HTML elements. This is not always the case. Shoelace components **are not** designed to be one-to-one replacements for their HTML counterparts.
For example, `<button>` and `<sl-button>` both have a `type` attribute, but it does different things (the former controls whether the button submits a form and the latter controls the button's appearance). Similarly, you can't call `focus()` on a Shoelace input — you need to use the component's `setFocus()` method instead. There are technical reasons for some of these design decisions that are outside the scope of this page.
?> **Don't make assumptions about a component's API!** To prevent unexpected behaviors, please take the time to review the documentation and make sure you understand what each property, method, and event is intended to do.
## React
React [doesn't play nice](https://custom-elements-everywhere.com/#react) with custom elements — it's a bit finicky about props.
> React passes all data to Custom Elements in the form of HTML attributes. For primitive data this is fine, but the system breaks down when passing rich data, like objects or arrays. In these instances you end up with stringified values like `some-attr="[object Object]"` which can't actually be used.
Event handling can also be cumbersome.
> Because React implements its own synthetic event system, it cannot listen for DOM events coming from Custom Elements without the use of a workaround. Developers will need to reference their Custom Elements using a ref and manually attach event listeners with addEventListener. This makes working with Custom Elements cumbersome.
Fortunately, there's a utility that will wrap Shoelace components so you can use them as if they were React components. 👇
?> If you're starting a new project, consider using [Preact](https://preactjs.com/) as an alternative. It shares the same API as React and [handles custom elements quite well](https://custom-elements-everywhere.com/#preact).
### Wrapping Components
You can use [this utility](https://www.npmjs.com/package/@shoelace-style/react-wrapper) to wrap Shoelace components so they work like like regular React components. To install it, use this command.
```sh
npm install @shoelace-style/react-wrapper
```
Now you can "import" Shoelace components as React components! Remember to [install Shoelace](/getting-started/installation.md) as well, otherwise this won't work as intended.
```js
import wrapCustomElement from '@shoelace-style/react-wrapper';
const ShoelaceButton = wrapCustomElement('sl-button');
return <ShoelaceButton type="primary">Click me</ShoelaceButton>;
```
A reference ("ref") to the underlying custom element is exposed through the `element` property so you can access it directly. This is useful for calling methods.
```jsx
<ShoelaceButton
ref={el => this.button = el}
onClick={() => this.button.element.current.removeFocus()}
>
Click me
</ShoelaceButton>
```
## Vue
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-/];
new Vue({ ... });
```
### Two-way Binding
One caveat is there's currently [no support for v-model on custom elements](https://github.com/vuejs/vue/issues/7830), but you can still achieve two-way binding manually.
```html
<!-- This doesn't work -->
<sl-input v-model="name">
<!-- This works, but it's a bit longer -->
<sl-input :value="name" @input="name = $event.target.value">
```
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.
```sh
npm install @shoelace-style/vue-sl-model
```
Next, import the directive and enable it like this.
```js
import ShoelaceModelDirective from '@shoelace-style/vue-sl-model';
Vue.config.ignoredElements = [/^sl-/];
Vue.use(ShoelaceModelDirective);
// Your init here
new Vue({ ... });
```
Now you can use the `v-sl-model` directive to keep your data in sync!
```html
<sl-input v-sl-model="name">
```
## Angular
Angular [plays nice](https://custom-elements-everywhere.com/#angular) with custom elements. Just make sure to apply the custom elements schema as shown below.
```js
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
bootstrap: [AppComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}
```

87
docs/index.html 100644
Wyświetl plik

@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Shoelace: A forward-thinking library of web components.</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Stencil Component Starter" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify/themes/pure.css" />
<link rel="stylesheet" href="/assets/styles/docs.css" />
<link rel="stylesheet" href="/assets/styles/demos.css" />
<link rel="stylesheet" href="/assets/plugins/code-block/code-block.css" />
<link rel="icon" href="/assets/images/logo.svg" type="image/x-icon" />
<!-- Import Shoelace -->
<link rel="stylesheet" href="/dist/shoelace/shoelace.css" />
<script type="module" src="/dist/shoelace/shoelace.esm.js"></script>
<!-- Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-6412891-16"></script>
<script>
if (!window.ShoelaceDevServer) {
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'UA-6412891-16');
}
</script>
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
alias: {
'/.*/_sidebar.md': '/_sidebar.md'
},
auto2top: true,
copyCode: {
buttonText: 'Copy Code',
errorText: 'Failed to copy',
successText: 'Copied'
},
coverpage: false,
executeScript: true,
homepage: '/getting-started/overview.md',
loadSidebar: true,
logo: '/assets/images/wordmark.svg',
maxLevel: 3,
subMaxLevel: 2,
name: 'Shoelace',
notFoundPage: '404.md',
pagination: {
previousText: 'Previous',
nextText: 'Next',
crossChapter: true,
crossChapterText: false
},
repo: 'https://github.com/shoelace-style/shoelace/',
routerMode: window.ShoelaceDevServer ? 'hash' : 'history',
search: {
maxAge: 86400000, // Expiration time, the default one day
paths: 'auto',
placeholder: 'Search',
noData: 'No Results',
depth: 3,
namespace: 'shoelace-docs'
},
themeColor: '#049dff'
};
</script>
<script src="https://unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="https://unpkg.com/docsify/lib/plugins/search.min.js"></script>
<script src="https://unpkg.com/docsify-copy-code"></script>
<script src="https://unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"></script>
<script src="https://unpkg.com/docsify/lib/plugins/zoom-image.min.js"></script>
<script src="https://unpkg.com/prismjs@1.19.0/components/prism-bash.min.js"></script>
<script src="https://unpkg.com/prismjs@1.19.0/components/prism-jsx.min.js"></script>
<script src="/assets/plugins/code-block/code-block.js"></script>
<script src="/assets/plugins/metadata/metadata.js"></script>
<script src="/assets/plugins/sidebar/sidebar.js"></script>
</body>
</html>

Wyświetl plik

@ -0,0 +1,12 @@
# Border Radius Tokens
Border radius tokens are used to give sharp edges a more subtle, rounded effect. They use rem units so they scale with the base font size. The pixel values displayed are based on a 16px font size.
| Token | Value | Example |
| ---------------------------- | -------------- | -------------------------------------------------------------------------------------------------------- |
| `--sl-border-radius-small` | 0.125rem (2px) | <div class="border-radius-demo" style="border-radius: var(--sl-border-radius-small);"></div> |
| `--sl-border-radius-medium` | 0.25rem (4px) | <div class="border-radius-demo" style="border-radius: var(--sl-border-radius-medium);"></div> |
| `--sl-border-radius-large` | 0.5rem (8px) | <div class="border-radius-demo" style="border-radius: var(--sl-border-radius-large);"></div> |
| `--sl-border-radius-x-large` | 1rem (16px) | <div class="border-radius-demo" style="border-radius: var(--sl-border-radius-x-large);"></div> |
| `--sl-border-radius-circle` | 50% | <div class="border-radius-demo" style="border-radius: var(--sl-border-radius-circle);"></div> |
| `--sl-border-radius-pill` | 9999px | <div class="border-radius-demo" style="border-radius: var(--sl-border-radius-pill); width: 6rem;"></div> |

Wyświetl plik

@ -0,0 +1,165 @@
# Color Tokens
Color tokens are used to maintain consistent color use throughout your app.
## Theme Colors
Theme colors are based on HSL values rather than hex or RGB. This technique lets us generate more consistent palettes for every theme color, ranging from 5% to 95% lightness. There are no 0% or 100% values for theme colors. Use `--sl-color-black` and `--sl-color-white` instead.
Theme colors include primary, gray, success, info, warning, and danger. They are used extensively throughout the library to maintain a consistent appearance across components.
To customize a theme color, change its respective hue, saturation, and text tokens. This will update all colors in the palette — there's no need to update individual palette colors. In fact, doing so is strongly discouraged.
```css
--sl-color-primary-hue: 203;
--sl-color-primary-saturation: 100%;
--sl-color-primary-text: var(--sl-color-white);
```
?> Color palettes are comprised of CSS custom properties ("CSS variables"), so you can update them live in your app and see the changes reflect instantly.
## Primary
| Token | Example |
| ----------------------- | ------------------------------------------------------------------------------------ |
| `--sl-color-primary-5` | <div class="color-demo" style="background-color: var(--sl-color-primary-5);"></div> |
| `--sl-color-primary-10` | <div class="color-demo" style="background-color: var(--sl-color-primary-10);"></div> |
| `--sl-color-primary-15` | <div class="color-demo" style="background-color: var(--sl-color-primary-15);"></div> |
| `--sl-color-primary-20` | <div class="color-demo" style="background-color: var(--sl-color-primary-20);"></div> |
| `--sl-color-primary-25` | <div class="color-demo" style="background-color: var(--sl-color-primary-25);"></div> |
| `--sl-color-primary-30` | <div class="color-demo" style="background-color: var(--sl-color-primary-30);"></div> |
| `--sl-color-primary-35` | <div class="color-demo" style="background-color: var(--sl-color-primary-35);"></div> |
| `--sl-color-primary-40` | <div class="color-demo" style="background-color: var(--sl-color-primary-40);"></div> |
| `--sl-color-primary-45` | <div class="color-demo" style="background-color: var(--sl-color-primary-45);"></div> |
| `--sl-color-primary-50` | <div class="color-demo" style="background-color: var(--sl-color-primary-50);"></div> |
| `--sl-color-primary-55` | <div class="color-demo" style="background-color: var(--sl-color-primary-55);"></div> |
| `--sl-color-primary-60` | <div class="color-demo" style="background-color: var(--sl-color-primary-60);"></div> |
| `--sl-color-primary-65` | <div class="color-demo" style="background-color: var(--sl-color-primary-65);"></div> |
| `--sl-color-primary-70` | <div class="color-demo" style="background-color: var(--sl-color-primary-70);"></div> |
| `--sl-color-primary-75` | <div class="color-demo" style="background-color: var(--sl-color-primary-75);"></div> |
| `--sl-color-primary-80` | <div class="color-demo" style="background-color: var(--sl-color-primary-80);"></div> |
| `--sl-color-primary-85` | <div class="color-demo" style="background-color: var(--sl-color-primary-85);"></div> |
| `--sl-color-primary-90` | <div class="color-demo" style="background-color: var(--sl-color-primary-90);"></div> |
| `--sl-color-primary-95` | <div class="color-demo" style="background-color: var(--sl-color-primary-95);"></div> |
## Gray
| Token | Example |
| -------------------- | --------------------------------------------------------------------------------- |
| `--sl-color-black` | <div class="color-demo" style="background-color: var(--sl-color-black);"></div> |
| `--sl-color-gray-5` | <div class="color-demo" style="background-color: var(--sl-color-gray-5);"></div> |
| `--sl-color-gray-10` | <div class="color-demo" style="background-color: var(--sl-color-gray-10);"></div> |
| `--sl-color-gray-15` | <div class="color-demo" style="background-color: var(--sl-color-gray-15);"></div> |
| `--sl-color-gray-20` | <div class="color-demo" style="background-color: var(--sl-color-gray-20);"></div> |
| `--sl-color-gray-25` | <div class="color-demo" style="background-color: var(--sl-color-gray-25);"></div> |
| `--sl-color-gray-30` | <div class="color-demo" style="background-color: var(--sl-color-gray-30);"></div> |
| `--sl-color-gray-35` | <div class="color-demo" style="background-color: var(--sl-color-gray-35);"></div> |
| `--sl-color-gray-40` | <div class="color-demo" style="background-color: var(--sl-color-gray-40);"></div> |
| `--sl-color-gray-45` | <div class="color-demo" style="background-color: var(--sl-color-gray-45);"></div> |
| `--sl-color-gray-50` | <div class="color-demo" style="background-color: var(--sl-color-gray-50);"></div> |
| `--sl-color-gray-55` | <div class="color-demo" style="background-color: var(--sl-color-gray-55);"></div> |
| `--sl-color-gray-60` | <div class="color-demo" style="background-color: var(--sl-color-gray-60);"></div> |
| `--sl-color-gray-65` | <div class="color-demo" style="background-color: var(--sl-color-gray-65);"></div> |
| `--sl-color-gray-70` | <div class="color-demo" style="background-color: var(--sl-color-gray-70);"></div> |
| `--sl-color-gray-75` | <div class="color-demo" style="background-color: var(--sl-color-gray-75);"></div> |
| `--sl-color-gray-80` | <div class="color-demo" style="background-color: var(--sl-color-gray-80);"></div> |
| `--sl-color-gray-85` | <div class="color-demo" style="background-color: var(--sl-color-gray-85);"></div> |
| `--sl-color-gray-90` | <div class="color-demo" style="background-color: var(--sl-color-gray-90);"></div> |
| `--sl-color-gray-95` | <div class="color-demo" style="background-color: var(--sl-color-gray-95);"></div> |
| `--sl-color-white` | <div class="color-demo" style="background-color: var(--sl-color-white);"></div> |
## Success
| Token | Example |
| ----------------------- | ------------------------------------------------------------------------------------ |
| `--sl-color-success-5` | <div class="color-demo" style="background-color: var(--sl-color-success-5);"></div> |
| `--sl-color-success-10` | <div class="color-demo" style="background-color: var(--sl-color-success-10);"></div> |
| `--sl-color-success-15` | <div class="color-demo" style="background-color: var(--sl-color-success-15);"></div> |
| `--sl-color-success-20` | <div class="color-demo" style="background-color: var(--sl-color-success-20);"></div> |
| `--sl-color-success-25` | <div class="color-demo" style="background-color: var(--sl-color-success-25);"></div> |
| `--sl-color-success-30` | <div class="color-demo" style="background-color: var(--sl-color-success-30);"></div> |
| `--sl-color-success-35` | <div class="color-demo" style="background-color: var(--sl-color-success-35);"></div> |
| `--sl-color-success-40` | <div class="color-demo" style="background-color: var(--sl-color-success-40);"></div> |
| `--sl-color-success-45` | <div class="color-demo" style="background-color: var(--sl-color-success-45);"></div> |
| `--sl-color-success-50` | <div class="color-demo" style="background-color: var(--sl-color-success-50);"></div> |
| `--sl-color-success-55` | <div class="color-demo" style="background-color: var(--sl-color-success-55);"></div> |
| `--sl-color-success-60` | <div class="color-demo" style="background-color: var(--sl-color-success-60);"></div> |
| `--sl-color-success-65` | <div class="color-demo" style="background-color: var(--sl-color-success-65);"></div> |
| `--sl-color-success-70` | <div class="color-demo" style="background-color: var(--sl-color-success-70);"></div> |
| `--sl-color-success-75` | <div class="color-demo" style="background-color: var(--sl-color-success-75);"></div> |
| `--sl-color-success-80` | <div class="color-demo" style="background-color: var(--sl-color-success-80);"></div> |
| `--sl-color-success-85` | <div class="color-demo" style="background-color: var(--sl-color-success-85);"></div> |
| `--sl-color-success-90` | <div class="color-demo" style="background-color: var(--sl-color-success-90);"></div> |
| `--sl-color-success-95` | <div class="color-demo" style="background-color: var(--sl-color-success-95);"></div> |
## Info
| Token | Example |
| -------------------- | --------------------------------------------------------------------------------- |
| `--sl-color-info-5` | <div class="color-demo" style="background-color: var(--sl-color-info-5);"></div> |
| `--sl-color-info-10` | <div class="color-demo" style="background-color: var(--sl-color-info-10);"></div> |
| `--sl-color-info-15` | <div class="color-demo" style="background-color: var(--sl-color-info-15);"></div> |
| `--sl-color-info-20` | <div class="color-demo" style="background-color: var(--sl-color-info-20);"></div> |
| `--sl-color-info-25` | <div class="color-demo" style="background-color: var(--sl-color-info-25);"></div> |
| `--sl-color-info-30` | <div class="color-demo" style="background-color: var(--sl-color-info-30);"></div> |
| `--sl-color-info-35` | <div class="color-demo" style="background-color: var(--sl-color-info-35);"></div> |
| `--sl-color-info-40` | <div class="color-demo" style="background-color: var(--sl-color-info-40);"></div> |
| `--sl-color-info-45` | <div class="color-demo" style="background-color: var(--sl-color-info-45);"></div> |
| `--sl-color-info-50` | <div class="color-demo" style="background-color: var(--sl-color-info-50);"></div> |
| `--sl-color-info-55` | <div class="color-demo" style="background-color: var(--sl-color-info-55);"></div> |
| `--sl-color-info-60` | <div class="color-demo" style="background-color: var(--sl-color-info-60);"></div> |
| `--sl-color-info-65` | <div class="color-demo" style="background-color: var(--sl-color-info-65);"></div> |
| `--sl-color-info-70` | <div class="color-demo" style="background-color: var(--sl-color-info-70);"></div> |
| `--sl-color-info-75` | <div class="color-demo" style="background-color: var(--sl-color-info-75);"></div> |
| `--sl-color-info-80` | <div class="color-demo" style="background-color: var(--sl-color-info-80);"></div> |
| `--sl-color-info-85` | <div class="color-demo" style="background-color: var(--sl-color-info-85);"></div> |
| `--sl-color-info-90` | <div class="color-demo" style="background-color: var(--sl-color-info-90);"></div> |
| `--sl-color-info-95` | <div class="color-demo" style="background-color: var(--sl-color-info-95);"></div> |
## Warning
| Token | Example |
| ----------------------- | ------------------------------------------------------------------------------------ |
| `--sl-color-warning-5` | <div class="color-demo" style="background-color: var(--sl-color-warning-5);"></div> |
| `--sl-color-warning-10` | <div class="color-demo" style="background-color: var(--sl-color-warning-10);"></div> |
| `--sl-color-warning-15` | <div class="color-demo" style="background-color: var(--sl-color-warning-15);"></div> |
| `--sl-color-warning-20` | <div class="color-demo" style="background-color: var(--sl-color-warning-20);"></div> |
| `--sl-color-warning-25` | <div class="color-demo" style="background-color: var(--sl-color-warning-25);"></div> |
| `--sl-color-warning-30` | <div class="color-demo" style="background-color: var(--sl-color-warning-30);"></div> |
| `--sl-color-warning-35` | <div class="color-demo" style="background-color: var(--sl-color-warning-35);"></div> |
| `--sl-color-warning-40` | <div class="color-demo" style="background-color: var(--sl-color-warning-40);"></div> |
| `--sl-color-warning-45` | <div class="color-demo" style="background-color: var(--sl-color-warning-45);"></div> |
| `--sl-color-warning-50` | <div class="color-demo" style="background-color: var(--sl-color-warning-50);"></div> |
| `--sl-color-warning-55` | <div class="color-demo" style="background-color: var(--sl-color-warning-55);"></div> |
| `--sl-color-warning-60` | <div class="color-demo" style="background-color: var(--sl-color-warning-60);"></div> |
| `--sl-color-warning-65` | <div class="color-demo" style="background-color: var(--sl-color-warning-65);"></div> |
| `--sl-color-warning-70` | <div class="color-demo" style="background-color: var(--sl-color-warning-70);"></div> |
| `--sl-color-warning-75` | <div class="color-demo" style="background-color: var(--sl-color-warning-75);"></div> |
| `--sl-color-warning-80` | <div class="color-demo" style="background-color: var(--sl-color-warning-80);"></div> |
| `--sl-color-warning-85` | <div class="color-demo" style="background-color: var(--sl-color-warning-85);"></div> |
| `--sl-color-warning-90` | <div class="color-demo" style="background-color: var(--sl-color-warning-90);"></div> |
| `--sl-color-warning-95` | <div class="color-demo" style="background-color: var(--sl-color-warning-95);"></div> |
## Danger
| Token | Example |
| ---------------------- | ----------------------------------------------------------------------------------- |
| `--sl-color-danger-5` | <div class="color-demo" style="background-color: var(--sl-color-danger-5);"></div> |
| `--sl-color-danger-10` | <div class="color-demo" style="background-color: var(--sl-color-danger-10);"></div> |
| `--sl-color-danger-15` | <div class="color-demo" style="background-color: var(--sl-color-danger-15);"></div> |
| `--sl-color-danger-20` | <div class="color-demo" style="background-color: var(--sl-color-danger-20);"></div> |
| `--sl-color-danger-25` | <div class="color-demo" style="background-color: var(--sl-color-danger-25);"></div> |
| `--sl-color-danger-30` | <div class="color-demo" style="background-color: var(--sl-color-danger-30);"></div> |
| `--sl-color-danger-35` | <div class="color-demo" style="background-color: var(--sl-color-danger-35);"></div> |
| `--sl-color-danger-40` | <div class="color-demo" style="background-color: var(--sl-color-danger-40);"></div> |
| `--sl-color-danger-45` | <div class="color-demo" style="background-color: var(--sl-color-danger-45);"></div> |
| `--sl-color-danger-50` | <div class="color-demo" style="background-color: var(--sl-color-danger-50);"></div> |
| `--sl-color-danger-55` | <div class="color-demo" style="background-color: var(--sl-color-danger-55);"></div> |
| `--sl-color-danger-60` | <div class="color-demo" style="background-color: var(--sl-color-danger-60);"></div> |
| `--sl-color-danger-65` | <div class="color-demo" style="background-color: var(--sl-color-danger-65);"></div> |
| `--sl-color-danger-70` | <div class="color-demo" style="background-color: var(--sl-color-danger-70);"></div> |
| `--sl-color-danger-75` | <div class="color-demo" style="background-color: var(--sl-color-danger-75);"></div> |
| `--sl-color-danger-80` | <div class="color-demo" style="background-color: var(--sl-color-danger-80);"></div> |
| `--sl-color-danger-85` | <div class="color-demo" style="background-color: var(--sl-color-danger-85);"></div> |
| `--sl-color-danger-90` | <div class="color-demo" style="background-color: var(--sl-color-danger-90);"></div> |
| `--sl-color-danger-95` | <div class="color-demo" style="background-color: var(--sl-color-danger-95);"></div> |

Wyświetl plik

@ -0,0 +1,11 @@
# Elevation Tokens
Elevation tokens are used to give elements the appearance of being raised off the page. Use them with the `box-shadow` property. These are especially useful for menus, popovers, and dialogs.
| Token | Example |
| --------------------- | -------------------------------------------------------------------------------- |
| `--sl-shadow-x-small` | <div class="elevation-demo" style="box-shadow: var(--sl-shadow-x-small);"></div> |
| `--sl-shadow-small` | <div class="elevation-demo" style="box-shadow: var(--sl-shadow-small);"></div> |
| `--sl-shadow-medium` | <div class="elevation-demo" style="box-shadow: var(--sl-shadow-medium);"></div> |
| `--sl-shadow-large` | <div class="elevation-demo" style="box-shadow: var(--sl-shadow-large);"></div> |
| `--sl-shadow-x-large` | <div class="elevation-demo" style="box-shadow: var(--sl-shadow-x-large);"></div> |

Wyświetl plik

@ -0,0 +1,16 @@
# Spacing Tokens
Spacing tokens are used to provide consistent spacing between components and content throughout your app.
| 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-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> |

Wyświetl plik

@ -0,0 +1,11 @@
# Transition Tokens
Transition tokens are used to provide consistent transitions throughout your app.
| Token | Value | Example |
| ------------------------ | ------ | --------------------------------------------------------------------------------------------- |
| `--sl-transition-x-slow` | 1000ms | <div class="transition-demo" style="transition-duration: var(--sl-transition-x-slow);"></div> |
| `--sl-transition-slow` | 500ms | <div class="transition-demo" style="transition-duration: var(--sl-transition-slow);"></div> |
| `--sl-transition-medium` | 250ms | <div class="transition-demo" style="transition-duration: var(--sl-transition-medium);"></div> |
| `--sl-transition-fast` | 150ms | <div class="transition-demo" style="transition-duration: var(--sl-transition-fast);"></div> |
| `--sl-transition-x-fast` | 50ms | <div class="transition-demo" style="transition-duration: var(--sl-transition-x-fast);"></div> |

Wyświetl plik

@ -0,0 +1,54 @@
# Typography Tokens
Typography tokens are used to maintain a consistent set of font styles throughout your app.
## Font Family
The default font stack is designed to be simple and highly available on as many devices as possible.
| Token | Value | Example |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `--sl-font-sans` | -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' | <span style="font-family: var(--sl-font-sans)">The quick brown fox jumped over the lazy dog.</span> |
| `--sl-font-serif` | Georgia, 'Times New Roman', serif | <span style="font-family: var(--sl-font-serif)">The quick brown fox jumped over the lazy dog.</span> |
| `--sl-font-mono` | Menlo, Monaco, 'Courier New', monospace | <span style="font-family: var(--sl-font-mono)">The quick brown fox jumped over the lazy dog.</span> |
## Font Size
Font sizes use `rem` units so they scale with the base font size. The pixel values displayed are based on a 16px font size.
| 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-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> |
## Font Weight
| Token | Value | Example |
| --------------------------- | ----- | --------------------------------------------------------------------------------------------------------------- |
| `--sl-font-weight-light` | 300 | <span style="font-weight: var(--sl-font-weight-light);">The quick brown fox jumped over the lazy dog.</span> |
| `--sl-font-weight-normal` | 400 | <span style="font-weight: var(--sl-font-weight-normal);">The quick brown fox jumped over the lazy dog.</span> |
| `--sl-font-weight-semibold` | 500 | <span style="font-weight: var(--sl-font-weight-semibold);">The quick brown fox jumped over the lazy dog.</span> |
| `--sl-font-weight-bold` | 700 | <span style="font-weight: var(--sl-font-weight-bold);">The quick brown fox jumped over the lazy dog.</span> |
## 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> |
## 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> |

Wyświetl plik

@ -0,0 +1,10 @@
# Z-Index Tokens
Z-indexes are used to stack components in a logical manner.
| Token | Value |
| ---------------------------- | ----- |
| `--sl-z-index-drawer` | 700 |
| `--sl-z-index-dialog` | 800 |
| `--sl-z-index-dropdown` | 900 |
| `--sl-z-index-tooltip` | 1000 |

14
make-dist.js 100644
Wyświetl plik

@ -0,0 +1,14 @@
const chalk = require('chalk');
const copy = require('recursive-copy');
const del = require('del');
(async () => {
try {
// Create the docs distribution
console.log(chalk.cyan('Creating docs distribution 📚\n'));
await del('./docs/dist');
await copy('./dist', './docs/dist');
} catch (err) {
console.error(err);
}
})();

60
make-icons.js 100644
Wyświetl plik

@ -0,0 +1,60 @@
const Promise = require('bluebird');
const promisify = require('util').promisify;
const chalk = require('chalk');
const copy = require('recursive-copy');
const del = require('del');
const download = require('download');
const fm = require('front-matter');
const fs = require('fs').promises;
const glob = promisify(require('glob'));
const path = require('path');
let numIcons = 0;
(async () => {
try {
const version = require('./node_modules/bootstrap-icons/package.json').version;
const srcPath = `./temp/icons-${version}`;
const url = `https://github.com/twbs/icons/archive/v${version}.zip`;
// Download the source from GitHub (since not everything is published to NPM)
console.log(chalk.cyan(`\nDownloading and extracting Bootstrap Icons ${version}... 📦\n`));
await del(['./src/components/icon/icons', './temp']);
await download(url, './temp', { extract: true });
// Copy icons
console.log(chalk.cyan(`Copying icons and license... 🚛\n`));
await Promise.all([
copy(`${srcPath}/icons`, './src/components/icon/icons'),
copy(`${srcPath}/LICENSE.md`, './src/components/icon/icons/LICENSE.md'),
copy(`${srcPath}/bootstrap-icons.svg`, './docs/assets/icons/sprite.svg', { overwrite: true })
]);
// Generate metadata
console.log(chalk.cyan(`Generating icon metadata... 🏷\n`));
const files = await glob(`${srcPath}/docs/content/icons/**/*.md`);
const metadata = await Promise.map(files, async file => {
const name = path.basename(file, path.extname(file));
const data = fm(await fs.readFile(file, 'utf8')).attributes;
numIcons++;
return {
name,
title: data.title,
categories: data.categories,
tags: data.tags
};
});
await fs.writeFile('./src/components/icon/icons/icons.json', JSON.stringify(metadata, null, 2), 'utf8');
// More cleanup
console.log(chalk.cyan(`Cleaning up... 🧹\n`));
await del('./temp');
console.log(chalk.green(`Successfully processed ${numIcons} icons! ✨\n`));
} catch (err) {
console.error(err);
}
})();

7539
package-lock.json wygenerowano 100644

Plik diff jest za duży Load Diff

78
package.json 100644
Wyświetl plik

@ -0,0 +1,78 @@
{
"name": "@shoelace-style/shoelace",
"version": "2.0.0-beta.3",
"description": "A forward-thinking library of web components.",
"main": "dist/index.js",
"module": "dist/index.mjs",
"es2015": "dist/esm/index.mjs",
"es2017": "dist/esm/index.mjs",
"types": "dist/types/index.d.ts",
"collection": "dist/collection/collection-manifest.json",
"collection:main": "dist/collection/index.js",
"files": [
"dist/",
"loader/"
],
"repository": {
"type": "git",
"url": "git://github.com/shoelace-style/shoelace.git"
},
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/claviska"
},
"scripts": {
"build": "stencil build --docs",
"dev": "stencil build --dev --docs --watch --serve --port 4001 --no-open",
"lint": "eslint src/**/*{.ts,.tsx}",
"make-dist": "node make-dist.js",
"make-icons": "node make-icons.js",
"prettier": "npx prettier --write --loglevel warn .",
"postbuild": "npm run make-dist",
"postinstall": "npm run make-icons",
"prebuild": "npm run prettier && npm run lint && npm run make-icons",
"serve": "node dev-server.js",
"start": "concurrently --kill-others \"npm run dev\" \"npm run serve\"",
"test.watch": "stencil test --spec --e2e --watchAll",
"test": "stencil test --spec --e2e",
"version": "npm run build"
},
"devDependencies": {
"@stencil/eslint-plugin": "^0.3.1",
"@typescript-eslint/eslint-plugin": "^2.28.0",
"@typescript-eslint/parser": "^2.28.0",
"bluebird": "^3.7.2",
"bootstrap-icons": "^1.0.0-alpha5",
"browser-sync": "^2.26.7",
"chalk": "^4.0.0",
"concurrently": "^5.1.0",
"del": "^5.1.0",
"download": "^8.0.0",
"eslint": "^6.8.0",
"eslint-plugin-react": "^7.19.0",
"express": "^4.17.1",
"front-matter": "^4.0.2",
"glob": "^7.1.6",
"http-proxy": "^1.18.1",
"http-proxy-middleware": "^1.0.4",
"husky": "^4.2.5",
"prettier": "2.0.5",
"recursive-copy": "^2.0.10",
"through2": "^3.0.1",
"workbox-build": "4.3.1"
},
"license": "MIT",
"dependencies": {
"@popperjs/core": "^2.1.1",
"@sphinxxxx/color-conversion": "^2.2.2",
"@stencil/core": "^1.14.0",
"@stencil/sass": "^1.1.1",
"color": "^3.1.2",
"resize-observer-polyfill": "^1.5.1"
},
"husky": {
"hooks": {
"pre-commit": "npm run prettier && npm run lint"
}
}
}

17
prettier.config.js 100644
Wyświetl plik

@ -0,0 +1,17 @@
module.exports = {
arrowParens: 'avoid',
bracketSpacing: true,
htmlWhitespaceSensitivity: 'css',
insertPragma: false,
jsxBracketSameLine: false,
jsxSingleQuote: false,
printWidth: 120,
proseWrap: 'preserve',
quoteProps: 'as-needed',
requirePragma: false,
semi: true,
singleQuote: true,
tabWidth: 2,
trailingComma: 'none',
useTabs: false
};

2062
src/components.d.ts vendored 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,120 @@
@import 'component';
:host {
display: block;
border-radius: var(--sl-border-radius-medium);
&[hidden] {
display: none;
}
}
.alert {
position: relative;
display: flex;
align-items: stretch;
background-color: var(--sl-color-white);
border: solid 1px var(--sl-color-gray-90);
border-top-width: 3px;
border-radius: var(--sl-border-radius-medium);
font-family: var(--sl-font-sans);
font-size: var(--sl-font-size-small);
font-weight: var(--sl-font-weight-normal);
line-height: 1.6;
color: var(--sl-color-gray-30);
opacity: 0;
transition: var(--sl-transition-medium) opacity ease;
}
.alert--open {
opacity: 1;
}
.alert__icon {
flex: 0 0 auto;
display: flex;
align-items: center;
font-size: var(--sl-font-size-large);
::slotted(*) {
margin-left: var(--sl-spacing-large);
}
}
.alert--primary {
border-top-color: var(--sl-color-primary-50);
.alert__icon {
color: var(--sl-color-primary-50);
}
}
.alert--success {
border-top-color: var(--sl-color-success-50);
.alert__icon {
color: var(--sl-color-success-50);
}
}
.alert--info {
border-top-color: var(--sl-color-info-50);
.alert__icon {
color: var(--sl-color-info-50);
}
}
.alert--warning {
border-top-color: var(--sl-color-warning-50);
.alert__icon {
color: var(--sl-color-warning-50);
}
}
.alert--danger {
border-top-color: var(--sl-color-danger-50);
.alert__icon {
color: var(--sl-color-danger-50);
}
}
.alert__message {
flex: 1 1 auto;
padding: var(--sl-spacing-large);
overflow: hidden;
}
.alert__close {
flex: 0 0 auto;
display: flex;
align-items: center;
background: none;
border: none;
border-radius: var(--sl-border-radius-small);
font-family: inherit;
font-size: var(--sl-font-size-large);
font-weight: inherit;
color: var(--sl-color-gray-50);
padding: 0 var(--sl-spacing-large);
cursor: pointer;
transition: var(--sl-transition-fast) color;
-webkit-appearance: none;
&:hover,
&:focus,
&:active {
color: var(--sl-color-primary-50);
}
&:focus {
outline: none;
}
}
.focus-visible .alert__close:focus {
box-shadow: 0 0 0 var(--sl-focus-ring-width)
hsla(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%, var(--sl-focus-ring-alpha));
}

Wyświetl plik

@ -0,0 +1,153 @@
import { Component, Element, Event, EventEmitter, Host, Method, Prop, Watch, h } from '@stencil/core';
import { focusVisible } from '../../utilities/focus-visible';
/**
* @since 1.0
* @status stable
*
* @slot - The alert's content.
* @slot icon - An icon to show in the alert.
* @slot close-icon - An icon to use in lieu of the default close icon.
*
* @part base - The component's base wrapper.
* @part icon - The container that wraps the alert icon.
* @part message - The alert message.
* @part close-button - The close button.
*/
@Component({
tag: 'sl-alert',
styleUrl: 'alert.scss',
shadow: true
})
export class Tab {
constructor() {
this.handleCloseClick = this.handleCloseClick.bind(this);
this.handleTransitionEnd = this.handleTransitionEnd.bind(this);
}
alert: HTMLElement;
@Element() host: HTMLSlAlertElement;
/** Indicates whether or not the alert is open. You can use this in lieu of the show/hide methods. */
@Prop({ mutable: true, reflect: true }) open = false;
/** Set to true to make the alert closable. */
@Prop() closable = false;
/** The type of alert. */
@Prop() type: 'primary' | 'success' | 'info' | 'warning' | 'danger' = 'primary';
@Watch('open')
handleOpenChange() {
this.open ? this.show() : this.hide();
}
/** Emitted when the alert opens. Calling `event.preventDefault()` will prevent it from being opened. */
@Event() slShow: EventEmitter;
/** Emitted after the alert opens and all transitions are complete. */
@Event() slAfterShow: EventEmitter;
/** Emitted when the alert closes. Calling `event.preventDefault()` will prevent it from being closed. */
@Event() slHide: EventEmitter;
/** Emitted after the alert closes and all transitions are complete. */
@Event() slAfterHide: EventEmitter;
componentDidLoad() {
focusVisible.observe(this.alert);
// Show on init if open
if (this.open) {
this.show();
}
}
componentDidUnload() {
focusVisible.unobserve(this.alert);
}
/** Shows the alert. */
@Method()
async show() {
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
}
this.host.hidden = false;
this.host.clientWidth; // force a reflow
this.open = true;
}
/** Hides the alert */
@Method()
async hide() {
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
}
this.open = false;
}
handleCloseClick() {
this.hide();
}
handleTransitionEnd(event: TransitionEvent) {
const target = event.target as HTMLElement;
// Ensure we only emit one event when the target element is no longer visible
if (event.propertyName === 'opacity' && target.classList.contains('alert')) {
this.host.hidden = !this.open;
this.open ? this.slAfterShow.emit() : this.slAfterHide.emit();
}
}
render() {
return (
<Host hidden>
<div
ref={el => (this.alert = el)}
part="base"
class={{
alert: true,
'alert--open': this.open,
'alert--closable': this.closable,
// States
'alert--primary': this.type === 'primary',
'alert--success': this.type === 'success',
'alert--info': this.type === 'info',
'alert--warning': this.type === 'warning',
'alert--danger': this.type === 'danger'
}}
role="alert"
aria-hidden={!this.open}
onTransitionEnd={this.handleTransitionEnd}
>
<span part="icon" class="alert__icon">
<slot name="icon" />
</span>
<span part="message" class="alert__message">
<slot />
</span>
{this.closable && (
<button part="close-button" class="alert__close" type="button" onClick={this.handleCloseClick}>
<slot name="close-icon">
<sl-icon name="x" />
</slot>
</button>
)}
</div>
</Host>
);
}
}

Wyświetl plik

@ -0,0 +1,65 @@
@import 'component';
/**
* @prop --background-color: The avatar's background color.
* @prop --size: The size of the avatar.
*/
:host {
display: inline-block;
--size: 3rem;
}
.avatar {
display: inline-flex;
align-items: center;
justify-content: center;
position: relative;
width: var(--size);
height: var(--size);
background-color: var(--sl-color-gray-80);
font-family: var(--sl-font-sans);
font-size: calc(var(--size) * 0.5);
font-weight: var(--sl-font-weight-normal);
color: var(--sl-color-white);
overflow: hidden;
user-select: none;
vertical-align: middle;
}
.avatar--circle {
border-radius: var(--sl-border-radius-circle);
}
.avatar--rounded {
border-radius: var(--sl-border-radius-medium);
}
.avatar--square {
border-radius: 0;
}
.avatar__icon {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.avatar__initials {
line-height: 1;
text-transform: uppercase;
}
.avatar__image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}

Wyświetl plik

@ -0,0 +1,76 @@
import { Component, Prop, State, h } from '@stencil/core';
/**
* @since 1.0
* @status stable
*
* @slot icon - The default icon to use when no image or initials are present.
*
* @part base - The component's base wrapper.
* @part icon - The container that wraps the avatar icon.
* @part initials - The container that wraps the avatar initials.
* @part image - The avatar image.
*/
@Component({
tag: 'sl-avatar',
styleUrl: 'avatar.scss',
shadow: true
})
export class Avatar {
constructor() {
this.handleImageError = this.handleImageError.bind(this);
}
@State() hasError = false;
/** The image source to use for the avatar. */
@Prop() image = '';
/** Alternative text for the image. */
@Prop() alt = '';
/** Initials to use as a fallback when no image is available (1-2 characters max recommended). */
@Prop() initials = '';
/** Initials to use as a fallback when no image is available (1-2 characters max recommended). */
@Prop() shape: 'circle' | 'square' | 'rounded' = 'circle';
handleImageError() {
this.hasError = true;
}
render() {
return (
<div
part="base"
class={{
avatar: true,
'avatar--circle': this.shape === 'circle',
'avatar--rounded': this.shape === 'rounded',
'avatar--square': this.shape === 'square'
}}
role="image"
aria-label={this.alt}
>
{!this.initials && (
<div part="icon" class="avatar__icon">
<slot name="icon">
<sl-icon name="person-fill" />
</slot>
</div>
)}
{this.initials && (
<div part="initials" class="avatar__initials">
{this.initials}
</div>
)}
{this.image && !this.hasError && (
<img part="image" class="avatar__image" src={this.image} onError={this.handleImageError} />
)}
</div>
);
}
}

Wyświetl plik

@ -0,0 +1,51 @@
@import 'component';
:host {
display: inline-flex;
border-radius: var(--sl-border-radius-pill);
pointer-events: none;
}
.badge {
display: inline-flex;
align-items: center;
justify-content: center;
font-size: var(--sl-font-size-x-small);
font-weight: var(--sl-font-weight-semibold);
letter-spacing: var(--sl-letter-spacing-normal);
line-height: 1;
border-radius: inherit;
white-space: nowrap;
padding: 4px 8px;
user-select: none;
cursor: inherit;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Type modifiers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.badge--primary {
background-color: var(--sl-color-primary-50);
color: var(--sl-color-white);
}
.badge--success {
background-color: var(--sl-color-success-50);
color: var(--sl-color-white);
}
.badge--info {
background-color: var(--sl-color-info-50);
color: var(--sl-color-white);
}
.badge--warning {
background-color: var(--sl-color-warning-50);
color: var(--sl-color-white);
}
.badge--danger {
background-color: var(--sl-color-danger-50);
color: var(--sl-color-white);
}

Wyświetl plik

@ -0,0 +1,46 @@
import { Component, Prop, h } from '@stencil/core';
/**
* @since 1.0
* @status experimental
*
* @slot - The badge's content.
*
* @part base - The base wrapper
*/
@Component({
tag: 'sl-badge',
styleUrl: 'badge.scss',
shadow: true
})
export class Badge {
badge: HTMLElement;
hasSlot: boolean;
/** The badge's type. */
@Prop() type: 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'text' = 'primary';
render() {
return (
<span
ref={el => (this.badge = el)}
part="base"
class={{
badge: true,
// Types
'badge--primary': this.type === 'primary',
'badge--success': this.type === 'success',
'badge--info': this.type === 'info',
'badge--warning': this.type === 'warning',
'badge--danger': this.type === 'danger',
'badge--text': this.type === 'text'
}}
role="status"
>
<slot />
</span>
);
}
}

Wyświetl plik

@ -0,0 +1,396 @@
@import 'component';
:host {
display: inline-block;
width: auto;
cursor: pointer;
}
.button {
display: inline-flex;
align-items: stretch;
justify-content: center;
width: inherit;
border-style: solid;
border-width: var(--sl-input-border-width);
font-family: var(--sl-input-font-family);
font-weight: var(--sl-font-weight-semibold);
user-select: none;
white-space: nowrap;
vertical-align: middle;
transition: var(--sl-transition-fast) background-color, var(--sl-transition-fast) color,
var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow;
cursor: inherit;
&::-moz-focus-inner {
border: 0;
}
&:focus {
outline: none;
}
&[disabled] {
opacity: 0.5;
cursor: not-allowed;
}
// Clicks on icons shouldn't prevent the button from gaining focus
::slotted(sl-icon) {
pointer-events: none;
}
}
.button__prefix,
.button__suffix {
flex: 0 0 auto;
display: flex;
align-items: center;
}
.button__prefix ::slotted(:first-child) {
margin-left: calc(-1 * var(--sl-spacing-x-small));
margin-right: var(--sl-spacing-x-small);
}
.button__suffix ::slotted(:last-child) {
margin-left: var(--sl-spacing-x-small);
margin-right: calc(-1 * var(--sl-spacing-x-small));
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Standard buttons
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.button {
&.button--default {
background-color: var(--sl-color-white);
border-color: var(--sl-color-gray-80);
color: var(--sl-color-gray-40);
&:hover:not(:disabled) {
background-color: var(--sl-color-primary-95);
border-color: var(--sl-color-primary-80);
color: var(--sl-color-primary-40);
}
&:focus:not(:disabled) {
background-color: var(--sl-color-primary-95);
border-color: var(--sl-color-primary-70);
color: var(--sl-color-primary-40);
box-shadow: 0 0 0 var(--sl-focus-ring-width)
hsla(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%, var(--sl-focus-ring-alpha));
}
&:active:not(:disabled) {
background-color: var(--sl-color-primary-95);
border-color: var(--sl-color-primary-50);
color: var(--sl-color-primary-30);
}
}
&.button--primary {
background-color: var(--sl-color-primary-50);
border-color: var(--sl-color-primary-50);
color: var(--sl-color-primary-text);
&:hover:not(:disabled) {
background-color: var(--sl-color-primary-60);
border-color: var(--sl-color-primary-60);
color: var(--sl-color-primary-text);
}
&:focus:not(:disabled) {
background-color: var(--sl-color-primary-60);
border-color: var(--sl-color-primary-60);
color: var(--sl-color-primary-text);
box-shadow: 0 0 0 var(--sl-focus-ring-width)
hsla(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%, var(--sl-focus-ring-alpha));
}
&:active:not(:disabled) {
background-color: var(--sl-color-primary-50);
border-color: var(--sl-color-primary-50);
color: var(--sl-color-primary-text);
}
}
&.button--success {
background-color: var(--sl-color-success-50);
border-color: var(--sl-color-success-50);
color: var(--sl-color-success-text);
&:hover:not(:disabled) {
background-color: var(--sl-color-success-60);
border-color: var(--sl-color-success-60);
color: var(--sl-color-success-text);
}
&:focus:not(:disabled) {
background-color: var(--sl-color-success-60);
border-color: var(--sl-color-success-60);
color: var(--sl-color-success-text);
box-shadow: 0 0 0 var(--sl-focus-ring-width)
hsla(var(--sl-color-success-hue), var(--sl-color-success-saturation), 50%, var(--sl-focus-ring-alpha));
}
&:active:not(:disabled) {
background-color: var(--sl-color-success-50);
border-color: var(--sl-color-success-50);
color: var(--sl-color-success-text);
}
}
&.button--info {
background-color: var(--sl-color-info-50);
border-color: var(--sl-color-info-50);
color: var(--sl-color-info-text);
&:hover:not(:disabled) {
background-color: var(--sl-color-info-60);
border-color: var(--sl-color-info-60);
color: var(--sl-color-info-text);
}
&:focus:not(:disabled) {
background-color: var(--sl-color-info-60);
border-color: var(--sl-color-info-60);
color: var(--sl-color-info-text);
box-shadow: 0 0 0 var(--sl-focus-ring-width)
hsla(var(--sl-color-info-hue), var(--sl-color-info-saturation), 50%, var(--sl-focus-ring-alpha));
}
&:active:not(:disabled) {
background-color: var(--sl-color-info-50);
border-color: var(--sl-color-info-50);
color: var(--sl-color-info-text);
}
}
&.button--warning {
background-color: var(--sl-color-warning-50);
border-color: var(--sl-color-warning-50);
color: var(--sl-color-warning-text);
&:hover:not(:disabled) {
background-color: var(--sl-color-warning-60);
border-color: var(--sl-color-warning-60);
color: var(--sl-color-warning-text);
}
&:focus:not(:disabled) {
background-color: var(--sl-color-warning-60);
border-color: var(--sl-color-warning-60);
color: var(--sl-color-warning-text);
box-shadow: 0 0 0 var(--sl-focus-ring-width)
hsla(var(--sl-color-warning-hue), var(--sl-color-warning-saturation), 50%, var(--sl-focus-ring-alpha));
}
&:active:not(:disabled) {
background-color: var(--sl-color-warning-50);
border-color: var(--sl-color-warning-50);
color: var(--sl-color-warning-text);
}
}
&.button--danger {
background-color: var(--sl-color-danger-50);
border-color: var(--sl-color-danger-50);
color: var(--sl-color-danger-text);
&:hover:not(:disabled) {
background-color: var(--sl-color-danger-60);
border-color: var(--sl-color-danger-60);
color: var(--sl-color-danger-text);
}
&:focus:not(:disabled) {
background-color: var(--sl-color-danger-60);
border-color: var(--sl-color-danger-60);
color: var(--sl-color-danger-text);
box-shadow: 0 0 0 var(--sl-focus-ring-width)
hsla(var(--sl-color-danger-hue), var(--sl-color-danger-saturation), 50%, var(--sl-focus-ring-alpha));
}
&:active:not(:disabled) {
background-color: var(--sl-color-danger-50);
border-color: var(--sl-color-danger-50);
color: var(--sl-color-danger-text);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Text buttons
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.button--text {
background-color: transparent;
border-color: transparent;
color: var(--sl-color-primary-50);
&:hover:not(:disabled) {
background-color: transparent;
border-color: transparent;
color: var(--sl-color-primary-60);
}
&:focus:not(:disabled) {
background-color: transparent;
border-color: transparent;
color: var(--sl-color-primary-60);
box-shadow: 0 0 0 var(--sl-focus-ring-width)
hsla(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%, var(--sl-focus-ring-alpha));
}
&:active:not(:disabled) {
background-color: transparent;
border-color: transparent;
color: var(--sl-color-primary-40);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Size modifiers
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.button--small {
font-size: var(--sl-button-font-size-small);
height: var(--sl-input-height-small);
line-height: calc(var(--sl-input-height-small) - var(--sl-input-border-width) * 2);
border-radius: var(--sl-input-border-radius-small);
padding: 0 var(--sl-spacing-medium);
}
.button--medium {
font-size: var(--sl-button-font-size-medium);
height: var(--sl-input-height-medium);
line-height: calc(var(--sl-input-height-medium) - var(--sl-input-border-width) * 2);
border-radius: var(--sl-input-border-radius-medium);
padding: 0 var(--sl-spacing-large);
}
.button--large {
font-size: var(--sl-button-font-size-large);
height: var(--sl-input-height-large);
line-height: calc(var(--sl-input-height-large) - var(--sl-input-border-width) * 2);
border-radius: var(--sl-input-border-radius-large);
padding: 0 var(--sl-spacing-x-large);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Pill modifier
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.button--pill {
&.button--small {
border-radius: var(--sl-input-height-small);
}
&.button--medium {
border-radius: var(--sl-input-height-medium);
}
&.button--large {
border-radius: var(--sl-input-height-large);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Circle modifier
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.button--circle {
padding-left: 0;
padding-right: 0;
.button__label {
display: flex;
align-items: center;
justify-content: center;
}
&.button--small {
width: var(--sl-input-height-small);
border-radius: 50%;
}
&.button--medium {
width: var(--sl-input-height-medium);
border-radius: 50%;
}
&.button--large {
width: var(--sl-input-height-large);
border-radius: 50%;
}
.button__prefix,
.button__suffix,
.button__caret {
display: none;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Block modifier
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Caret modifier
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.button--caret {
.button__suffix {
display: none;
}
.button__caret {
display: flex;
align-items: center;
margin-left: var(--sl-spacing-xx-small);
margin-right: calc(-1 * var(--sl-spacing-xx-small));
svg {
width: 1em;
height: 1em;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Loading modifier
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.button--loading {
position: relative;
cursor: wait;
.button__prefix,
.button__label,
.button__suffix,
.button__caret {
visibility: hidden;
}
sl-spinner {
--indicator-color: currentColor;
--stroke-width: 1px;
position: absolute;
height: 1em;
width: 1em;
top: calc(50% - 0.5em);
left: calc(50% - 0.5em);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Badges
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.button ::slotted(sl-badge) {
position: absolute;
top: 0;
right: 0;
transform: translateY(-50%) translateX(50%);
}

Wyświetl plik

@ -0,0 +1,165 @@
import { Component, Event, EventEmitter, Method, Prop, State, h } from '@stencil/core';
/**
* @since 1.0
* @status stable
*
* @slot - The button's label.
* @slot prefix - Used to prepend an icon or similar element to the button.
* @slot suffix - Used to append an icon or similar element to the button.
*
* @part base - The component's base wrapper.
* @part prefix - The prefix container.
* @part label - The button's label.
* @part suffix - The suffix container.
* @part caret - The button's caret.
*/
@Component({
tag: 'sl-button',
styleUrl: 'button.scss',
shadow: true
})
export class Button {
constructor() {
this.handleBlur = this.handleBlur.bind(this);
this.handleFocus = this.handleFocus.bind(this);
this.handleClick = this.handleClick.bind(this);
}
button: HTMLButtonElement;
@State() hasFocus = false;
/** The button's type. */
@Prop() type: 'default' | 'primary' | 'success' | 'info' | 'warning' | 'danger' | 'text' = 'default';
/** The button's size. */
@Prop() size: 'small' | 'medium' | 'large' = 'medium';
/** Set to true to draw the button with a caret for use with dropdowns, popovers, etc. */
@Prop() caret = false;
/** Set to true to disable the button. */
@Prop() disabled = false;
/** Set to true to draw the button in a loading state. */
@Prop() loading = false;
/** An optional name for the button. */
@Prop() name: string;
/** Set to true to draw a pill-style button with rounded edges. */
@Prop() pill = false;
/** Set to true to draw a circle button. */
@Prop() circle = false;
/** An optional value for the button. */
@Prop() value: string;
/** Indicates if activating the button should submit the form. */
@Prop() submit = false;
/** Emitted when the button loses focus. */
@Event() slBlur: EventEmitter;
/** Emitted when the button gains focus. */
@Event() slFocus: EventEmitter;
/** Sets focus on the button. */
@Method()
async setFocus() {
this.button.focus();
}
/** Removes focus from the button. */
@Method()
async removeFocus() {
this.button.blur();
}
handleBlur() {
this.hasFocus = false;
this.slBlur.emit();
}
handleFocus() {
this.hasFocus = true;
this.slFocus.emit();
}
handleClick(event: MouseEvent) {
if (this.disabled || this.loading) {
event.preventDefault();
event.stopPropagation();
}
}
render() {
return (
<button
ref={el => (this.button = el)}
part="base"
class={{
button: true,
// Types
'button--default': this.type === 'default',
'button--primary': this.type === 'primary',
'button--success': this.type === 'success',
'button--info': this.type === 'info',
'button--warning': this.type === 'warning',
'button--danger': this.type === 'danger',
'button--text': this.type === 'text',
// Sizes
'button--small': this.size === 'small',
'button--medium': this.size === 'medium',
'button--large': this.size === 'large',
// Modifiers
'button--caret': this.caret,
'button--circle': this.circle,
'button--disabled': this.disabled,
'button--focused': this.hasFocus,
'button--loading': this.loading,
'button--pill': this.pill
}}
name={this.name}
value={this.value}
disabled={this.disabled}
type={this.submit ? 'submit' : 'button'}
onBlur={this.handleBlur}
onFocus={this.handleFocus}
onClick={this.handleClick}
>
<span part="prefix" class="button__prefix">
<slot name="prefix" />
</span>
<span part="label" class="button__label">
<slot />
</span>
<span part="suffix" class="button__suffix">
<slot name="suffix" />
</span>
{this.caret && (
<span part="caret" class="button__caret">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</span>
)}
{this.loading && <sl-spinner />}
</button>
);
}
}

Wyświetl plik

@ -0,0 +1,99 @@
@import 'component';
:host {
display: inline-block;
cursor: pointer;
}
.checkbox {
display: inline-flex;
align-items: center;
font-family: var(--sl-input-font-family);
font-size: var(--sl-input-font-size-medium);
font-weight: var(--sl-input-font-weight);
color: var(--sl-input-color);
vertical-align: middle;
cursor: inherit;
}
.checkbox__control {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--sl-toggle-size);
height: var(--sl-toggle-size);
border: solid var(--sl-input-border-width) var(--sl-input-border-color);
border-radius: 2px;
background-color: var(--sl-input-background-color);
color: var(--sl-color-white);
transition: var(--sl-transition-fast) border-color, var(--sl-transition-fast) background-color,
var(--sl-transition-fast) color, var(--sl-transition-fast) box-shadow;
input[type='checkbox'] {
position: absolute;
opacity: 0;
padding: 0;
margin: 0;
pointer-events: none;
-webkit-appearance: none;
}
.checkbox__icon {
display: inline-flex;
width: var(--sl-toggle-size);
height: var(--sl-toggle-size);
svg {
width: 100%;
height: 100%;
}
}
}
// Hover
.checkbox:not(.checkbox--checked):not(.checkbox--disabled) .checkbox__control:hover {
border-color: var(--sl-input-border-color-hover);
background-color: var(--sl-input-background-color-hover);
}
// Focus
.checkbox.checkbox--focused:not(.checkbox--checked):not(.checkbox--disabled) .checkbox__control {
border-color: var(--sl-input-border-color-focus);
background-color: var(--sl-input-background-color-focus);
box-shadow: var(--sl-focus-ring-box-shadow);
}
// Checked/indeterminate
.checkbox--checked .checkbox__control,
.checkbox--indeterminate .checkbox__control {
border-color: var(--sl-color-primary-50);
background-color: var(--sl-color-primary-50);
}
// Checked/indeterminate + hover
.checkbox.checkbox--checked:not(.checkbox--disabled) .checkbox__control:hover,
.checkbox.checkbox--indeterminate:not(.checkbox--disabled) .checkbox__control:hover {
border-color: var(--sl-color-primary-60);
background-color: var(--sl-color-primary-60);
}
// Checked/indeterminate + focus
.checkbox.checkbox--checked:not(.checkbox--disabled).checkbox--focused .checkbox__control,
.checkbox.checkbox--indeterminate:not(.checkbox--disabled).checkbox--focused .checkbox__control {
border-color: var(--sl-color-primary-60);
background-color: var(--sl-color-primary-60);
box-shadow: var(--sl-focus-ring-box-shadow);
}
// Disabled
.checkbox--disabled {
opacity: 0.5;
cursor: not-allowed;
}
.checkbox__label {
line-height: var(--sl-toggle-size);
margin-left: 0.5em;
user-select: none;
}

Wyświetl plik

@ -0,0 +1,172 @@
import { Component, Event, EventEmitter, Method, Prop, State, Watch, h } from '@stencil/core';
let id = 0;
/**
* @since 1.0
* @status stable
*
* @slot - The checkbox's label.
*
* @part base - The component's base wrapper.
* @part control - The checkbox control.
* @part checked-icon - The container the wraps the checked icon.
* @part indeterminate-icon - The container that wraps the indeterminate icon.
* @part label - The checkbox label.
*/
@Component({
tag: 'sl-checkbox',
styleUrl: 'checkbox.scss',
shadow: true
})
export class Checkbox {
constructor() {
this.handleClick = this.handleClick.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.handleFocus = this.handleFocus.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
}
inputId = `checkbox-${++id}`;
labelId = `checkbox-label-${id}`;
input: HTMLInputElement;
@State() hasFocus = false;
/** The checkbox's name attribute. */
@Prop() name: string;
/** The checkbox's value attribute. */
@Prop() value: string;
/** Set to true to disable the checkbox. */
@Prop() disabled = false;
/** Set to true to draw the checkbox in a checked state. */
@Prop({ mutable: true }) checked = false;
/** Set to true to draw the checkbox in an indeterminate state. */
@Prop({ mutable: true }) indeterminate = false;
/** Emitted when the control loses focus. */
@Event() slBlur: EventEmitter;
/** Emitted when the control's checked state changes. */
@Event() slChange: EventEmitter;
/** Emitted when the control gains focus. */
@Event() slFocus: EventEmitter;
@Watch('checked')
@Watch('indeterminate')
handleCheckedChange() {
this.input.checked = this.checked;
this.input.indeterminate = this.indeterminate;
this.slChange.emit();
}
componentDidLoad() {
this.input.indeterminate = this.indeterminate;
}
/** Sets focus on the checkbox. */
@Method()
async setFocus() {
this.input.focus();
}
/** Removes focus from the checkbox. */
@Method()
async removeFocus() {
this.input.blur();
}
handleClick() {
this.checked = this.input.checked;
this.indeterminate = this.input.indeterminate;
}
handleBlur() {
this.hasFocus = false;
this.slBlur.emit();
}
handleFocus() {
this.hasFocus = true;
this.slFocus.emit();
}
handleMouseDown(event: MouseEvent) {
// Prevent clicks on the label from briefly blurring the input
event.preventDefault();
this.input.focus();
}
render() {
return (
<label
part="base"
class={{
checkbox: true,
'checkbox--checked': this.checked,
'checkbox--disabled': this.disabled,
'checkbox--focused': this.hasFocus,
'checkbox--indeterminate': this.indeterminate
}}
htmlFor={this.inputId}
role="checkbox"
onMouseDown={this.handleMouseDown}
>
<span part="control" class="checkbox__control">
{this.checked && (
<span part="checked-icon" class="checkbox__icon">
<svg viewBox="0 0 16 16">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g stroke="currentColor" stroke-width="2">
<g transform="translate(3.428571, 3.428571)">
<path d="M0,5.71428571 L3.42857143,9.14285714"></path>
<path d="M9.14285714,0 L3.42857143,9.14285714"></path>
</g>
</g>
</g>
</svg>
</span>
)}
{!this.checked && this.indeterminate && (
<span part="indeterminate-icon" class="checkbox__icon">
<svg viewBox="0 0 16 16">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round">
<g stroke="currentColor" stroke-width="2">
<g transform="translate(2.285714, 6.857143)">
<path d="M10.2857143,1.14285714 L1.14285714,1.14285714"></path>
</g>
</g>
</g>
</svg>
</span>
)}
<input
ref={el => (this.input = el)}
id={this.inputId}
type="checkbox"
name={this.name}
value={this.value}
checked={this.checked}
disabled={this.disabled}
aria-labeledby={this.labelId}
onClick={this.handleClick}
onBlur={this.handleBlur}
onFocus={this.handleFocus}
/>
</span>
<span part="label" id={this.labelId} class="checkbox__label">
<slot />
</span>
</label>
);
}
}

Wyświetl plik

@ -0,0 +1,297 @@
@import 'component';
/**
* @prop --grid-width: The width of the color grid.
* @prop --grid-height: The height of the color grid.
* @prop --grid-handle-size: The size of the color grid's handle.
* @prop --slider-height: The height of the hue and alpha sliders.
* @prop --slider-handle-size: The diameter of the slider's handle.
*/
:host {
display: inline-block;
--grid-width: 260px;
--grid-height: 200px;
--grid-handle-size: 12px;
--slider-height: 10px;
--slider-handle-size: 12px;
}
.color-picker {
width: var(--grid-width);
font-family: var(--sl-font-sans);
font-size: var(--sl-font-size-medium);
font-weight: var(--sl-font-weight-normal);
color: var(--color);
background-color: var(--sl-color-white);
border-radius: var(--sl-border-radius-medium);
user-select: none;
}
.color-picker--inline {
border: solid 1px var(--sl-color-gray-90);
box-shadow: var(--sl-shadow-small);
}
.color-picker__grid {
position: relative;
height: var(--grid-height);
background-image: linear-gradient(
to bottom,
hsl(0, 0%, 100%) 0%,
hsla(0, 0%, 100%, 0) 50%,
hsla(0, 0%, 0%, 0) 50%,
hsl(0, 0%, 0%) 100%
),
linear-gradient(to right, hsl(0, 0%, 50%) 0%, hsla(0, 0%, 50%, 0) 100%);
border-top-left-radius: var(--sl-border-radius-medium);
border-top-right-radius: var(--sl-border-radius-medium);
cursor: crosshair;
}
.color-picker__grid-handle {
position: absolute;
width: var(--grid-handle-size);
height: var(--grid-handle-size);
border-radius: 50%;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25), inset 0 0 0 1px rgba(0, 0, 0, 0.25);
border: solid 2px white;
margin-top: calc(var(--grid-handle-size) / -2);
margin-left: calc(var(--grid-handle-size) / -2);
&:focus {
outline: none;
box-shadow: 0 0 0 1px hsl(var(--sl-focus-ring-hue), var(--sl-focus-ring-saturation), var(--sl-focus-ring-lightness)),
inset 0 0 0 1px hsl(var(--sl-focus-ring-hue), var(--sl-focus-ring-saturation), var(--sl-focus-ring-lightness)),
var(--sl-focus-ring-box-shadow);
}
}
.color-picker__controls {
padding: var(--sl-spacing-small);
display: flex;
align-items: center;
}
.color-picker__sliders {
flex: 1 1 auto;
}
.color-picker__slider {
position: relative;
height: var(--slider-height);
border-radius: var(--sl-border-radius-pill);
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
&:not(:last-of-type) {
margin-bottom: var(--sl-spacing-small);
}
}
.color-picker__slider-handle {
position: absolute;
top: calc(50% - var(--slider-handle-size) / 2);
width: var(--slider-handle-size);
height: var(--slider-handle-size);
background-color: white;
border-radius: 50%;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
margin-left: calc(var(--slider-handle-size) / -2);
&:focus {
outline: none;
box-shadow: 0 0 0 1px hsl(var(--sl-color-primary-hue), var(--sl-color-primary-saturation), 50%),
var(--sl-focus-ring-box-shadow);
}
}
.color-picker__hue {
background-image: linear-gradient(
to right,
rgb(255, 0, 0) 0%,
rgb(255, 255, 0) 17%,
rgb(0, 255, 0) 33%,
rgb(0, 255, 255) 50%,
rgb(0, 0, 255) 67%,
rgb(255, 0, 255) 83%,
rgb(255, 0, 0) 100%
);
}
.color-picker__alpha {
.color-picker__alpha-gradient {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
}
}
.color-picker__preview {
flex: 0 0 auto;
position: relative;
width: var(--sl-input-height-small);
height: var(--sl-input-height-small);
border-radius: 50%;
margin-left: var(--sl-spacing-medium);
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
background-color: currentColor;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
}
}
.color-picker__preview-color {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
border: solid 1px rgba(0, 0, 0, 0.125);
}
.color-picker__user-input {
display: flex;
padding: 0 var(--sl-spacing-small) var(--sl-spacing-small) var(--sl-spacing-small);
sl-input {
flex: 1 1 auto;
}
sl-button {
flex: 0 0 auto;
margin-left: var(--sl-spacing-medium);
}
}
.color-picker__swatches {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-gap: 6px;
justify-items: center;
border-top: solid 1px var(--sl-color-gray-90);
padding: var(--sl-spacing-small);
}
.color-picker__swatch {
flex: 0 0 auto;
position: relative;
width: 20px;
height: 20px;
border-radius: 2px;
.color-picker__swatch-color {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: solid 1px rgba(0, 0, 0, 0.125);
border-radius: inherit;
cursor: pointer;
}
&:focus {
outline: none;
box-shadow: var(--sl-focus-ring-box-shadow);
}
}
.color-picker__transparent-bg {
background-image: linear-gradient(45deg, #eee 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #eee 75%),
linear-gradient(45deg, transparent 75%, #eee 75%), linear-gradient(45deg, #eee 25%, transparent 25%);
background-size: 10px 10px;
background-position: 0 0, 0 0, -5px -5px, 5px 5px;
}
.color-picker--disabled {
opacity: 0.5;
cursor: not-allowed;
.color-picker__grid,
.color-picker__grid-handle,
.color-picker__slider,
.color-picker__slider-handle,
.color-picker__preview,
.color-picker__swatch,
.color-picker__swatch-color {
pointer-events: none;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Color dropdown
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
.color-dropdown::part(panel) {
overflow: visible;
}
.color-dropdown__trigger {
display: inline-block;
position: relative;
background-color: transparent;
border: none;
cursor: pointer;
transition: var(--sl-transition-fast) box-shadow;
-webkit-appearance: none;
&.color-dropdown__trigger--small {
width: var(--sl-input-height-small);
height: var(--sl-input-height-small);
border-radius: var(--sl-border-radius-circle);
}
&.color-dropdown__trigger--medium {
width: var(--sl-input-height-medium);
height: var(--sl-input-height-medium);
border-radius: var(--sl-border-radius-circle);
}
&.color-dropdown__trigger--large {
width: var(--sl-input-height-large);
height: var(--sl-input-height-large);
border-radius: var(--sl-border-radius-circle);
}
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: inherit;
background-color: currentColor;
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
transition: inherit;
}
&:focus {
outline: none;
}
&:focus:not(.color-dropdown__trigger--disabled) {
box-shadow: var(--sl-focus-ring-box-shadow);
outline: none;
&::before {
box-shadow: inset 0 0 0 1px var(--sl-color-primary-50);
}
}
&.color-dropdown__trigger--disabled {
opacity: 0.5;
cursor: not-allowed;
}
}

Wyświetl plik

@ -0,0 +1,777 @@
import { Component, Element, Event, EventEmitter, Prop, State, Watch, h } from '@stencil/core';
import color from 'color';
import { clamp } from '../../utilities/math';
/**
* @since 1.0
* @status stable
*
* @part base - The component's base wrapper.
* @part swatches - The container that holds swatches.
* @part swatch - Each individual swatch.
* @part grid - The color grid.
* @part grid-handle - The color grid's handle.
* @part slider - Hue and opacity sliders.
* @part slider-handle - Hue and opacity slider handles.
* @part preview - The preview color.
* @part input - The text input.
* @part copy-button - The copy button.
*/
@Component({
tag: 'sl-color-picker',
styleUrl: 'color-picker.scss',
shadow: true
})
export class ColorPicker {
constructor() {
this.handleAlphaDrag = this.handleAlphaDrag.bind(this);
this.handleAlphaInput = this.handleAlphaInput.bind(this);
this.handleAlphaKeyDown = this.handleAlphaKeyDown.bind(this);
this.handleCopy = this.handleCopy.bind(this);
this.handleDocumentKeyDown = this.handleDocumentKeyDown.bind(this);
this.handleDocumentMouseDown = this.handleDocumentMouseDown.bind(this);
this.handleDrag = this.handleDrag.bind(this);
this.handleDropdownAfterHide = this.handleDropdownAfterHide.bind(this);
this.handleDropdownAfterShow = this.handleDropdownAfterShow.bind(this);
this.handleDropdownHide = this.handleDropdownHide.bind(this);
this.handleDropdownShow = this.handleDropdownShow.bind(this);
this.handleGridDrag = this.handleGridDrag.bind(this);
this.handleGridKeyDown = this.handleGridKeyDown.bind(this);
this.handleHueDrag = this.handleHueDrag.bind(this);
this.handleHueInput = this.handleHueInput.bind(this);
this.handleHueKeyDown = this.handleHueKeyDown.bind(this);
this.handleLightnessInput = this.handleLightnessInput.bind(this);
this.handleSaturationInput = this.handleSaturationInput.bind(this);
this.handleTextInputChange = this.handleTextInputChange.bind(this);
this.handleTextInputKeyDown = this.handleTextInputKeyDown.bind(this);
}
bypassValueParse = false;
copyButton: HTMLSlButtonElement;
dropdown: HTMLSlDropdownElement;
lastValueEmitted: string;
menu: HTMLElement;
textInput: HTMLSlInputElement;
trigger: HTMLElement;
@Element() host: HTMLSlColorPickerElement;
@State() textInputValue = '';
@State() hue = 0;
@State() saturation = 100;
@State() lightness = 100;
@State() alpha = 100;
@State() showCopyCheckmark = false;
/** The current color. */
@Prop({ mutable: true, reflect: true }) value = '#ffffff';
/**
* The format to use for the display value. If opacity is enabled, these will translate to HEXA, RGBA, and HSLA
* respectively. The color picker will always accept user input in any format (including CSS color names) and convert
* it to the desired format.
*/
@Prop() format: 'hex' | 'rgb' | 'hsl' = 'hex';
/** Set to true to render the color picker inline rather than inside a dropdown. */
@Prop() inline = false;
/** When `inline` is true, this determines the size of the color picker's trigger. */
@Prop() size: 'small' | 'medium' | 'large' = 'medium';
/** Set to true to disable the color picker. */
@Prop() disabled = false;
/** Whether to show the opacity slider. */
@Prop() opacity = false;
/** By default, the value will be set in lowercase. Set this to true to set it in uppercase instead. */
@Prop() uppercase = false;
/**
* An array of predefined color swatches to display. Can include any format the color picker can parse, including
* HEX(A), RGB(A), HSL(A), and CSS color names.
*/
@Prop() swatches = [
'#d0021b',
'#f5a623',
'#f8e71c',
'#8b572a',
'#7ed321',
'#417505',
'#bd10e0',
'#9013fe',
'#4a90e2',
'#50e3c2',
'#b8e986',
'#000',
'#444',
'#888',
'#ccc',
'#fff'
];
/** Emitted when the color picker's value changes. */
@Event() slChange: EventEmitter;
/** Emitted when the color picker opens. Calling `event.preventDefault()` will prevent it from being opened. */
@Event() slShow: EventEmitter;
/** Emitted after the color picker opens and all transitions are complete. */
@Event() slAfterShow: EventEmitter;
/** Emitted when the color picker closes. Calling `event.preventDefault()` will prevent it from being closed. */
@Event() slHide: EventEmitter;
/** Emitted after the color picker closes and all transitions are complete. */
@Event() slAfterHide: EventEmitter;
@Watch('value')
handleValueChange(newValue: string, oldValue: string) {
if (!this.bypassValueParse) {
const newColor = this.parseColor(newValue);
if (newColor) {
this.textInputValue = this.value;
this.hue = newColor.hsla.h;
this.saturation = newColor.hsla.s;
this.lightness = newColor.hsla.l;
this.alpha = newColor.hsla.a * 100;
} else {
this.textInputValue = oldValue;
}
}
if (this.value !== this.lastValueEmitted) {
this.slChange.emit();
this.lastValueEmitted = this.value;
}
}
componentWillLoad() {
if (!this.setColor(this.value)) {
this.setColor(`#ffff`);
}
this.textInputValue = this.value;
this.lastValueEmitted = this.value;
this.syncValues();
}
handleCopy() {
this.textInput.select().then(() => {
document.execCommand('copy');
this.copyButton.setFocus();
this.showCopyCheckmark = true;
setTimeout(() => (this.showCopyCheckmark = false), 1000);
});
}
handleHueInput(event: Event) {
const target = event.target as HTMLInputElement;
this.hue = clamp(Number(target.value), 0, 360);
}
handleSaturationInput(event: Event) {
const target = event.target as HTMLInputElement;
this.saturation = clamp(Number(target.value), 0, 100);
}
handleLightnessInput(event: Event) {
const target = event.target as HTMLInputElement;
this.lightness = clamp(Number(target.value), 0, 100);
}
handleAlphaInput(event: Event) {
const target = event.target as HTMLInputElement;
this.alpha = clamp(Number(target.value), 0, 100);
}
handleAlphaDrag(event: any) {
const container = this.host.shadowRoot.querySelector('.color-picker__slider.color-picker__alpha') as HTMLElement;
const handle = container.querySelector('.color-picker__slider-handle') as HTMLElement;
const { width } = container.getBoundingClientRect();
handle.focus();
event.preventDefault();
this.handleDrag(event, container, x => {
this.alpha = clamp((x / width) * 100, 0, 100);
this.syncValues();
});
}
handleHueDrag(event: any) {
const container = this.host.shadowRoot.querySelector('.color-picker__slider.color-picker__hue') as HTMLElement;
const handle = container.querySelector('.color-picker__slider-handle') as HTMLElement;
const { width } = container.getBoundingClientRect();
handle.focus();
event.preventDefault();
this.handleDrag(event, container, x => {
this.hue = clamp((x / width) * 360, 0, 360);
this.syncValues();
});
}
handleGridDrag(event: any) {
const grid = this.host.shadowRoot.querySelector('.color-picker__grid') as HTMLElement;
const handle = grid.querySelector('.color-picker__grid-handle') as HTMLElement;
const { width, height } = grid.getBoundingClientRect();
handle.focus();
event.preventDefault();
this.handleDrag(event, grid, (x, y) => {
this.saturation = clamp((x / width) * 100, 0, 100);
this.lightness = clamp(100 - (y / height) * 100, 0, 100);
this.syncValues();
});
}
handleDrag(event: any, container: HTMLElement, onMove: (x: number, y: number) => void) {
if (this.disabled) {
return false;
}
const move = (event: any) => {
const dims = container.getBoundingClientRect();
const offsetX = dims.left + container.ownerDocument.defaultView.pageXOffset;
const offsetY = dims.top + container.ownerDocument.defaultView.pageYOffset;
const x = (event.changedTouches ? event.changedTouches[0].pageX : event.pageX) - offsetX;
const y = (event.changedTouches ? event.changedTouches[0].pageY : event.pageY) - offsetY;
onMove(x, y);
};
// Move on init
move(event);
const stop = () => {
document.removeEventListener('mousemove', move);
document.removeEventListener('touchmove', move);
document.removeEventListener('mouseup', stop);
document.removeEventListener('touchend', stop);
};
document.addEventListener('mousemove', move);
document.addEventListener('touchmove', move);
document.addEventListener('mouseup', stop);
document.addEventListener('touchend', stop);
}
handleAlphaKeyDown(event: KeyboardEvent) {
const increment = event.shiftKey ? 10 : 1;
if (event.key === 'ArrowLeft') {
event.preventDefault();
this.alpha = clamp(this.alpha - increment, 0, 100);
this.syncValues();
}
if (event.key === 'ArrowRight') {
event.preventDefault();
this.alpha = clamp(this.alpha + increment, 0, 100);
this.syncValues();
}
if (event.key === 'Home') {
event.preventDefault();
this.alpha = 0;
this.syncValues();
}
if (event.key === 'End') {
event.preventDefault();
this.alpha = 100;
this.syncValues();
}
}
handleHueKeyDown(event: KeyboardEvent) {
const increment = event.shiftKey ? 10 : 1;
if (event.key === 'ArrowLeft') {
event.preventDefault();
this.hue = clamp(this.hue - increment, 0, 360);
this.syncValues();
}
if (event.key === 'ArrowRight') {
event.preventDefault();
this.hue = clamp(this.hue + increment, 0, 360);
this.syncValues();
}
if (event.key === 'Home') {
event.preventDefault();
this.hue = 0;
this.syncValues();
}
if (event.key === 'End') {
event.preventDefault();
this.hue = 360;
this.syncValues();
}
}
handleGridKeyDown(event: KeyboardEvent) {
const increment = event.shiftKey ? 10 : 1;
if (event.key === 'ArrowLeft') {
event.preventDefault();
this.saturation = clamp(this.saturation - increment, 0, 100);
this.syncValues();
}
if (event.key === 'ArrowRight') {
event.preventDefault();
this.saturation = clamp(this.saturation + increment, 0, 100);
this.syncValues();
}
if (event.key === 'ArrowUp') {
event.preventDefault();
this.lightness = clamp(this.lightness + increment, 0, 100);
this.syncValues();
}
if (event.key === 'ArrowDown') {
event.preventDefault();
this.lightness = clamp(this.lightness - increment, 0, 100);
this.syncValues();
}
}
handleTextInputChange(event: CustomEvent) {
const target = event.target as HTMLInputElement;
this.setColor(target.value);
target.value = this.value;
event.stopPropagation();
}
handleTextInputKeyDown(event: KeyboardEvent) {
if (event.key === 'Enter') {
this.setColor(this.textInput.value);
this.textInput.value = this.value;
setTimeout(() => this.textInput.select());
}
}
handleDocumentKeyDown(event: KeyboardEvent) {
// Close when pressing escape or tab
if (event.key === 'Escape') {
this.dropdown.hide();
}
// Close when tabbing out of the color picker
if (event.key === 'Tab') {
setTimeout(() => {
if (document.activeElement && document.activeElement.closest('sl-color-picker') !== this.host) {
this.dropdown.hide();
}
});
}
}
handleDocumentMouseDown(event: MouseEvent) {
const target = event.target as HTMLElement;
// Close when clicking outside of the dropdown
if (target.closest('sl-color-picker') !== this.host) {
this.dropdown.hide();
}
}
handleDropdownShow(event: CustomEvent) {
event.stopPropagation();
this.slShow.emit();
}
handleDropdownAfterShow(event: CustomEvent) {
event.stopPropagation();
this.slAfterShow.emit();
}
handleDropdownHide(event: CustomEvent) {
event.stopPropagation();
this.slHide.emit();
}
handleDropdownAfterHide(event: CustomEvent) {
event.stopPropagation();
this.slAfterHide.emit();
}
normalizeColorString(colorString: string) {
//
// The color module we're using doesn't parse % values for the alpha channel in RGBA and HSLA. It also doesn't parse
// hex colors when the # is missing. This pre-parser tries to normalize these edge cases to provide a better
// experience for users who type in color values.
//
if (/rgba?/.test(colorString)) {
const rgba = colorString
.replace(/[^\d.%]/g, ' ')
.split(' ')
.map(val => val.trim())
.filter(val => val.length);
if (rgba.length < 4) {
rgba[3] = '1';
}
if (rgba[3].indexOf('%') > -1) {
rgba[3] = (Number(rgba[3].replace(/%/g, '')) / 100).toString();
}
return `rgba(${rgba[0]}, ${rgba[1]}, ${rgba[2]}, ${rgba[3]})`;
}
if (/hsla?/.test(colorString)) {
const hsla = colorString
.replace(/[^\d.%]/g, ' ')
.split(' ')
.map(val => val.trim())
.filter(val => val.length);
if (hsla.length < 4) {
hsla[3] = '1';
}
if (hsla[3].indexOf('%') > -1) {
hsla[3] = (Number(hsla[3].replace(/%/g, '')) / 100).toString();
}
return `hsla(${hsla[0]}, ${hsla[1]}, ${hsla[2]}, ${hsla[3]})`;
}
if (/^[0-9a-f]+$/.test(colorString)) {
return `#${colorString}`;
}
return colorString;
}
parseColor(colorString: string) {
function toHex(value: number) {
const hex = Math.round(value).toString(16);
return hex.length === 1 ? `0${hex}` : hex;
}
let parsed: any;
// The color module has a weak parser, so we normalize certain things to make the user experience better
colorString = this.normalizeColorString(colorString);
try {
parsed = color(colorString);
} catch {
return false;
}
const hsl = {
h: parsed.hsl().color[0],
s: parsed.hsl().color[1],
l: parsed.hsl().color[2],
a: parsed.hsl().valpha
};
const rgb = {
r: parsed.rgb().color[0],
g: parsed.rgb().color[1],
b: parsed.rgb().color[2],
a: parsed.rgb().valpha
};
const hex = {
r: toHex(parsed.rgb().color[0]),
g: toHex(parsed.rgb().color[1]),
b: toHex(parsed.rgb().color[2]),
a: toHex(parsed.rgb().valpha * 255)
};
return {
hsl: {
h: hsl.h,
s: hsl.s,
l: hsl.l,
string: this.setLetterCase(`hsl(${Math.round(hsl.h)}, ${Math.round(hsl.s)}%, ${Math.round(hsl.l)}%)`)
},
hsla: {
h: hsl.h,
s: hsl.s,
l: hsl.l,
a: hsl.a,
string: this.setLetterCase(
`hsla(${Math.round(hsl.h)}, ${Math.round(hsl.s)}%, ${Math.round(hsl.l)}%, ${Number(
hsl.a.toFixed(2).toString()
)})`
)
},
rgb: {
r: rgb.r,
g: rgb.g,
b: rgb.b,
string: this.setLetterCase(`rgb(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)})`)
},
rgba: {
r: rgb.r,
g: rgb.g,
b: rgb.b,
a: rgb.a,
string: this.setLetterCase(
`rgba(${Math.round(rgb.r)}, ${Math.round(rgb.g)}, ${Math.round(rgb.b)}, ${Number(
rgb.a.toFixed(2).toString()
)})`
)
},
hex: this.setLetterCase(`#${hex.r}${hex.g}${hex.b}`),
hexa: this.setLetterCase(`#${hex.r}${hex.g}${hex.b}${hex.a}`)
};
}
setColor(colorString: string) {
const newColor = this.parseColor(colorString);
if (!newColor) {
return false;
}
this.hue = newColor.hsla.h;
this.saturation = newColor.hsla.s;
this.lightness = newColor.hsla.l;
this.alpha = this.opacity ? newColor.hsla.a * 100 : 100;
this.syncValues();
return true;
}
setLetterCase(string: string) {
return this.uppercase ? string.toUpperCase() : string.toLowerCase();
}
syncValues() {
const currentColor = this.parseColor(
`hsla(${this.hue}, ${this.saturation}%, ${this.lightness}%, ${this.alpha / 100})`
);
if (!currentColor) {
return false;
}
// Update the value
if (this.format === 'hsl') {
this.textInputValue = this.opacity ? currentColor.hsla.string : currentColor.hsl.string;
} else if (this.format === 'rgb') {
this.textInputValue = this.opacity ? currentColor.rgba.string : currentColor.rgb.string;
} else {
this.textInputValue = this.opacity ? currentColor.hexa : currentColor.hex;
}
// Setting this.value will trigger the watcher which parses the new color. We want to bypass that behavior because
// a) we've already done it in this function and b) conversion/rounding can lead to values changing slightly.
this.bypassValueParse = true;
this.value = this.textInputValue;
this.bypassValueParse = false;
}
render() {
const x = this.saturation;
const y = 100 - this.lightness;
const ColorPicker = () => {
return (
<div
part="base"
class={{
'color-picker': true,
'color-picker--inline': this.inline,
'color-picker--disabled': this.disabled
}}
aria-disabled={this.disabled}
>
<div
part="grid"
class="color-picker__grid"
style={{
backgroundColor: `hsl(${this.hue}deg, 100%, 50%)`
}}
onMouseDown={this.handleGridDrag}
onTouchStart={this.handleGridDrag}
>
<span
part="grid-handle"
class="color-picker__grid-handle"
style={{
top: `${y}%`,
left: `${x}%`
}}
role="slider"
aria-label="HSL"
aria-valuetext={`hsl(${Math.round(this.hue)}, ${Math.round(this.saturation)}%, ${Math.round(
this.lightness
)}%)`}
tabIndex={this.disabled ? null : 0}
onKeyDown={this.handleGridKeyDown}
/>
</div>
<div class="color-picker__controls">
<div class="color-picker__sliders">
<div
part="slider"
class="color-picker__hue color-picker__slider"
onMouseDown={this.handleHueDrag}
onTouchStart={this.handleHueDrag}
>
<span
part="slider-handle"
class="color-picker__slider-handle"
style={{
left: `${this.hue === 0 ? 0 : 100 / (360 / this.hue)}%`
}}
role="slider"
aria-label="hue"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="360"
aria-valuenow={Math.round(this.hue)}
tabIndex={this.disabled ? null : 0}
onKeyDown={this.handleHueKeyDown}
/>
</div>
{this.opacity && (
<div
part="slider"
class="color-picker__alpha color-picker__slider color-picker__transparent-bg"
onMouseDown={this.handleAlphaDrag}
onTouchStart={this.handleAlphaDrag}
>
<div
class="color-picker__alpha-gradient"
style={{
backgroundImage: `linear-gradient(
to right,
hsl(${this.hue}deg, ${this.saturation}%, ${this.lightness}%, 0%) 0%,
hsl(${this.hue}deg, ${this.saturation}%, ${this.lightness}%) 100%
)`
}}
/>
<span
part="slider-handle"
class="color-picker__slider-handle"
style={{
left: `${this.alpha}%`
}}
role="slider"
aria-label="alpha"
aria-orientation="horizontal"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow={Math.round(this.alpha)}
tabIndex={this.disabled ? null : 0}
onKeyDown={this.handleAlphaKeyDown}
/>
</div>
)}
</div>
<div
part="preview"
class="color-picker__preview color-picker__transparent-bg"
style={{
color: `hsla(${this.hue}deg, ${this.saturation}%, ${this.lightness}%, ${this.alpha / 100})`
}}
/>
</div>
<div class="color-picker__user-input">
<sl-input
ref={el => (this.textInput = el)}
part="input"
size="small"
type="text"
pattern="[a-fA-F\d]+"
value={this.textInputValue}
disabled={this.disabled}
onKeyDown={this.handleTextInputKeyDown}
onSlChange={this.handleTextInputChange}
/>
<sl-button
ref={el => (this.copyButton = el)}
part="copy-button"
slot="suffix"
class="color-picker__copy-button"
size="small"
circle
onClick={this.handleCopy}
>
<sl-icon name={this.showCopyCheckmark ? 'check2' : 'clipboard'} />
</sl-button>
</div>
{this.swatches && (
<div part="swatches" class="color-picker__swatches">
{this.swatches.map(swatch => (
<div
part="swatch"
class="color-picker__swatch color-picker__transparent-bg"
tabIndex={this.disabled ? null : 0}
role="button"
aria-label={swatch}
onClick={() => !this.disabled && this.setColor(swatch)}
onKeyDown={event => !this.disabled && event.key === 'Enter' && this.setColor(swatch)}
>
<div class="color-picker__swatch-color" style={{ backgroundColor: swatch }} />
</div>
))}
</div>
)}
</div>
);
};
// Render inline
if (this.inline) {
return <ColorPicker />;
}
// Render as a dropdown
return (
<sl-dropdown
ref={el => (this.dropdown = el)}
class="color-dropdown"
aria-disabled={this.disabled}
containingElement={this.host}
onSlShow={this.handleDropdownShow}
onSlAfterShow={this.handleDropdownAfterShow}
onSlHide={this.handleDropdownHide}
onSlAfterHide={this.handleDropdownAfterHide}
>
<button
ref={el => (this.trigger = el)}
slot="trigger"
class={{
'color-dropdown__trigger': true,
'color-dropdown__trigger--disabled': this.disabled,
'color-dropdown__trigger--small': this.size === 'small',
'color-dropdown__trigger--medium': this.size === 'medium',
'color-dropdown__trigger--large': this.size === 'large',
'color-picker__transparent-bg': true
}}
style={{
color: `hsla(${this.hue}deg, ${this.saturation}%, ${this.lightness}%, ${this.alpha / 100})`
}}
type="button"
/>
<ColorPicker />
</sl-dropdown>
);
}
}

Wyświetl plik

@ -0,0 +1,85 @@
@import 'component';
/**
* @prop --hide-duration: The length of the hide transition.
* @prop --hide-timing-function: The timing function (easing) to use for the hide transition.
* @prop --show-duration: The length of the show transition.
* @prop --show-timing-function: The timing function (easing) to use for the show transition.
*/
:host {
display: block;
--hide-duration: var(--sl-transition-medium);
--hide-timing-function: ease;
--show-duration: var(--sl-transition-medium);
--show-timing-function: ease;
}
.details {
border: solid 1px var(--sl-color-gray-90);
border-radius: var(--sl-border-radius-medium);
}
.details--disabled {
opacity: 0.5;
}
.details__header {
display: flex;
align-items: center;
border-radius: inherit;
padding: var(--sl-spacing-medium);
user-select: none;
cursor: pointer;
&:focus {
outline: none;
}
}
.focus-visible .details__header:focus {
box-shadow: var(--sl-focus-ring-box-shadow);
}
.details--disabled .details__header {
cursor: not-allowed;
&:focus {
outline: none;
box-shadow: none;
}
}
.details__summary {
flex: 1 1 auto;
display: flex;
align-items: center;
}
.details__summary-icon {
flex: 0 0 auto;
display: flex;
align-items: center;
transition: var(--sl-transition-medium) transform ease;
}
.details--open .details__summary-icon {
transform: rotate(90deg);
}
.details__body {
height: 0;
overflow: hidden;
transition-property: height;
transition-duration: var(--hide-duration);
transition-timing-function: var(--hide-timing-function);
}
.details--open .details__body {
transition-duration: var(--show-duration);
transition-timing-function: var(--show-timing-function);
}
.details__content {
padding: var(--sl-spacing-medium);
}

Wyświetl plik

@ -0,0 +1,193 @@
import { Component, Event, EventEmitter, Method, Prop, Watch, h } from '@stencil/core';
import { focusVisible } from '../../utilities/focus-visible';
let id = 0;
/**
* @since 1.0
* @status stable
*
* @slot - The details' content.
* @slot summary - The details' summary. Alternatively, you can use the summary prop.
*
* @part base - The component's base wrapper.
* @part summary - The details summary.
* @part summary-icon - The expand/collapse summary icon.
* @part content - The details content.
*/
@Component({
tag: 'sl-details',
styleUrl: 'details.scss',
shadow: true
})
export class Details {
constructor() {
this.handleBodyTransitionEnd = this.handleBodyTransitionEnd.bind(this);
this.handleSummaryClick = this.handleSummaryClick.bind(this);
this.handleSummaryKeyDown = this.handleSummaryKeyDown.bind(this);
}
details: HTMLElement;
header: HTMLElement;
id = `details-${++id}`;
body: HTMLElement;
/** Indicates whether or not the details is open. You can use this in lieu of the show/hide methods. */
@Prop({ mutable: true, reflect: true }) open = false;
/** The summary to show in the details header. */
@Prop() summary = '';
/** Set to true to prevent the user from toggling the details. */
@Prop() disabled = false;
@Watch('open')
handleOpenChange() {
this.open ? this.show() : this.hide();
}
/** Emitted when the details opens. Calling `event.preventDefault()` will prevent it from being opened. */
@Event() slShow: EventEmitter;
/** Emitted after the details opens and all transitions are complete. */
@Event() slAfterShow: EventEmitter;
/** Emitted when the details closes. Calling `event.preventDefault()` will prevent it from being closed. */
@Event() slHide: EventEmitter;
/** Emitted after the details closes and all transitions are complete. */
@Event() slAfterHide: EventEmitter;
componentDidLoad() {
focusVisible.observe(this.details);
// Show on init if open
if (this.open) {
this.show();
}
}
componentDidUnload() {
focusVisible.observe(this.details);
}
/** Shows the alert. */
@Method()
async show() {
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
}
this.body.style.height = `${this.body.scrollHeight}px`;
this.body.style.overflow = 'hidden';
this.open = true;
}
/** Hides the alert */
@Method()
async hide() {
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
}
// We can't transition out of `height: auto`, so let's set it to the current height first
this.body.style.height = `${this.body.scrollHeight}px`;
this.body.style.overflow = 'hidden';
requestAnimationFrame(() => {
this.body.clientWidth; // force a reflow
this.body.style.height = '0';
});
this.open = false;
}
handleBodyTransitionEnd(event: TransitionEvent) {
const target = event.target as HTMLElement;
// Ensure we only emit one event when the target element is no longer visible
if (event.propertyName === 'height' && target.classList.contains('details__body')) {
this.body.style.overflow = this.open ? 'visible' : 'hidden';
this.body.style.height = this.open ? 'auto' : '0';
this.open ? this.slAfterShow.emit() : this.slAfterHide.emit();
}
}
handleSummaryClick() {
if (!this.disabled) {
this.open ? this.hide() : this.show();
this.header.focus();
}
}
handleSummaryKeyDown(event: KeyboardEvent) {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.open ? this.hide() : this.show();
}
if (event.key === 'ArrowUp' || event.key === 'ArrowLeft') {
event.preventDefault();
this.hide();
}
if (event.key === 'ArrowDown' || event.key === 'ArrowRight') {
event.preventDefault();
this.show();
}
}
render() {
return (
<div
ref={el => (this.details = el)}
part="base"
class={{
details: true,
'details--open': this.open,
'details--disabled': this.disabled
}}
>
<header
ref={el => (this.header = el)}
id={`${this.id}-header`}
class="details__header"
role="button"
aria-expanded={this.open}
aria-controls={`${this.id}-content`}
aria-disabled={this.disabled}
tabIndex={this.disabled ? -1 : 0}
onClick={this.handleSummaryClick}
onKeyDown={this.handleSummaryKeyDown}
>
<div part="summary" class="details__summary">
<slot name="summary">{this.summary}</slot>
</div>
<span part="summary-icon" class="details__summary-icon">
<sl-icon name="chevron-right" />
</span>
</header>
<div ref={el => (this.body = el)} class="details__body" onTransitionEnd={this.handleBodyTransitionEnd}>
<div
part="content"
id={`${this.id}-content`}
class="details__content"
role="region"
aria-labeledby={`${this.id}-header`}
>
<slot />
</div>
</div>
</div>
);
}
}

Wyświetl plik

@ -0,0 +1,130 @@
@import 'component';
/**
* @prop --width: The preferred width of the dialog. Note that the dialog will shrink to accommodate smaller screens.
*/
:host {
--width: 31rem;
display: contents;
}
.dialog {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: var(--sl-z-index-dialog);
&[hidden] {
display: none;
}
}
.dialog__panel {
display: flex;
flex-direction: column;
z-index: 2;
width: var(--width);
max-width: calc(100vw - var(--sl-spacing-xx-large));
max-height: calc(100vh - var(--sl-spacing-xx-large));
background-color: var(--sl-color-white);
border-radius: var(--sl-border-radius-medium);
box-shadow: var(--sl-shadow-x-large);
opacity: 0;
transform: scale(0.8);
transition: var(--sl-transition-medium) opacity, var(--sl-transition-medium) transform;
&:focus {
outline: none;
}
}
// Ensure there's enough vertical padding for phones that don't update vh when chrome appears (e.g. iPhone)
@media screen and (max-width: 420px) {
.dialog__panel {
max-height: calc(80vh);
}
}
.dialog--open .dialog__panel {
display: flex;
opacity: 1;
transform: scale(1);
}
.dialog__header {
display: flex;
}
.dialog__title {
flex: 1 1 auto;
font-size: var(--sl-font-size-large);
line-height: var(--sl-line-height-dense);
padding: var(--sl-spacing-large);
}
.dialog__close {
flex: 0 0 auto;
display: flex;
align-items: center;
background: none;
border: none;
border-radius: var(--sl-border-radius-small);
font-family: inherit;
font-size: var(--sl-font-size-x-large);
font-weight: inherit;
color: var(--sl-color-gray-50);
padding: 0 var(--sl-spacing-large);
cursor: pointer;
transition: var(--sl-transition-fast) color;
-webkit-appearance: none;
&:hover,
&:focus,
&:active {
color: var(--sl-color-primary-50);
}
&:focus {
outline: none;
}
}
.focus-visible .dialog__close:focus {
box-shadow: var(--sl-focus-ring-box-shadow);
}
.dialog__body {
padding: var(--sl-spacing-large);
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.dialog__footer {
text-align: right;
padding: var(--sl-spacing-large);
::slotted(sl-button:not(:first-of-type)) {
margin-left: var(--sl-spacing-x-small);
}
}
.dialog__overlay {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: var(--sl-overlay-background-color);
opacity: 0;
transition: var(--sl-transition-medium) opacity;
}
.dialog--open .dialog__overlay {
opacity: 1;
}

Wyświetl plik

@ -0,0 +1,219 @@
import { Component, Element, Event, EventEmitter, Method, Prop, Watch, h } from '@stencil/core';
import { lockBodyScrolling, unlockBodyScrolling } from '../../utilities/scroll';
import { focusVisible } from '../../utilities/focus-visible';
let id = 0;
/**
* @since 1.0
* @status stable
*
* @slot - The dialog's content.
* @slot footer - The dialog's footer, usually one or more buttons representing various options.
*
* @part base - The component's base wrapper.
* @part overlay - The overlay.
* @part panel - The dialog panel (where the dialog and its is rendered).
* @part header - The dialog header.
* @part title - The dialog title.
* @part close-button - The close button.
* @part body - The dialog body.
* @part footer - The dialog footer.
*
*/
@Component({
tag: 'sl-dialog',
styleUrl: 'dialog.scss',
shadow: true
})
export class Dialog {
constructor() {
this.handleDocumentFocusIn = this.handleDocumentFocusIn.bind(this);
this.handleCloseClick = this.handleCloseClick.bind(this);
this.handleTransitionEnd = this.handleTransitionEnd.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleOverlayClick = this.handleOverlayClick.bind(this);
}
panel: HTMLElement;
dialog: HTMLElement;
id = `dialog-${++id}`;
@Element() host: HTMLSlDialogElement;
/** Indicates whether or not the dialog is open. You can use this in lieu of the show/hide methods. */
@Prop({ mutable: true, reflect: true }) open = false;
/**
* The dialog's label as displayed in the header. You should always include a relevant label even when using
* `no-header`, as it is required for proper accessibility.
*/
@Prop() label = '';
/**
* Set to true to disable the header. This will also remove the default close button, so please ensure you provide an
* easy, accessible way for users to dismiss the dialog.
*/
@Prop() noHeader = false;
/** Set to true to disable the footer. */
@Prop() noFooter = false;
@Watch('open')
handleOpenChange() {
this.open ? this.show() : this.hide();
}
/** Emitted when the dialog opens. Calling `event.preventDefault()` will prevent it from being opened. */
@Event() slShow: EventEmitter;
/** Emitted after the dialog opens and all transitions are complete. */
@Event() slAfterShow: EventEmitter;
/** Emitted when the dialog closes. Calling `event.preventDefault()` will prevent it from being closed. */
@Event() slHide: EventEmitter;
/** Emitted after the dialog closes and all transitions are complete. */
@Event() slAfterHide: EventEmitter;
/** Emitted when the overlay is clicked. Calling `event.preventDefault()` will prevent the dialog from closing. */
@Event() slOverlayDismiss: EventEmitter;
componentDidLoad() {
focusVisible.observe(this.dialog);
// Show on init if open
if (this.open) {
this.show();
}
}
componentDidUnload() {
focusVisible.unobserve(this.dialog);
unlockBodyScrolling(this.host);
}
/** Shows the dialog */
@Method()
async show() {
const slShow = this.slShow.emit();
if (slShow.defaultPrevented) {
return false;
}
this.dialog.hidden = false;
this.host.clientWidth; // force a reflow
this.open = true;
lockBodyScrolling(this.host);
document.addEventListener('focusin', this.handleDocumentFocusIn);
}
/** Hides the dialog */
@Method()
async hide() {
const slHide = this.slHide.emit();
if (slHide.defaultPrevented) {
return false;
}
this.open = false;
unlockBodyScrolling(this.host);
document.removeEventListener('focusin', this.handleDocumentFocusIn);
}
handleCloseClick() {
this.hide();
}
handleDocumentFocusIn(event: Event) {
const target = event.target as HTMLElement;
if (target.closest('sl-dialog') !== this.host) {
this.panel.focus();
}
}
handleKeyDown(event: KeyboardEvent) {
if (event.key === 'Escape') {
this.hide();
}
}
handleOverlayClick() {
const slOverlayDismiss = this.slOverlayDismiss.emit();
if (!slOverlayDismiss.defaultPrevented) {
this.hide();
}
}
handleTransitionEnd(event: TransitionEvent) {
const target = event.target as HTMLElement;
// Ensure we only emit one event when the target element is no longer visible
if (event.propertyName === 'opacity' && target.classList.contains('dialog__panel')) {
this.dialog.hidden = !this.open;
this.open ? this.slAfterShow.emit() : this.slAfterHide.emit();
if (this.open) {
this.panel.focus();
}
}
}
render() {
return (
<div
ref={el => (this.dialog = el)}
part="base"
class={{
dialog: true,
'dialog--open': this.open
}}
onKeyDown={this.handleKeyDown}
onTransitionEnd={this.handleTransitionEnd}
hidden
>
<div part="overlay" class="dialog__overlay" onClick={this.handleOverlayClick} />
<div
ref={el => (this.panel = el)}
part="panel"
class="dialog__panel"
role="dialog"
aria-modal="true"
aria-hidden={!this.open}
aria-label={this.noHeader ? this.label : null}
aria-labeledby={!this.noHeader ? `${this.id}-title` : null}
tabIndex={0}
>
{!this.noHeader && (
<header part="header" class="dialog__header">
<span part="title" class="dialog__title" id={`${this.id}-title`}>
{/* If there's no label, use an invisible character to prevent the heading from collapsing */}
{this.label || String.fromCharCode(65279)}
</span>
<button part="close-button" class="dialog__close" type="button" onClick={this.handleCloseClick}>
<sl-icon name="x"></sl-icon>
</button>
</header>
)}
<div part="body" class="dialog__body">
<slot />
</div>
{!this.noFooter && (
<footer part="footer" class="dialog__footer">
<slot name="footer" />
</footer>
)}
</div>
</div>
);
}
}

Wyświetl plik

@ -0,0 +1,167 @@
@import 'component';
/**
* @prop --size: The preferred size of the drawer. This will be applied to the drawer's width or height depending on its
* `placement`. Note that the drawer will shrink to accommodate smaller screens.
*/
:host {
--size: 25rem;
display: contents;
}
.drawer {
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: hidden;
&[hidden] {
display: none;
}
}
.drawer--contained {
position: absolute;
z-index: initial;
}
.drawer--fixed {
position: fixed;
z-index: var(--sl-z-index-drawer);
}
.drawer__panel {
position: absolute;
display: flex;
flex-direction: column;
z-index: 2;
max-width: 100%;
max-height: 100%;
background-color: var(--sl-color-white);
box-shadow: var(--sl-shadow-x-large);
transition: var(--sl-transition-medium) transform;
overflow: auto;
pointer-events: all;
&:focus {
outline: none;
}
}
.drawer--top .drawer__panel {
top: 0;
left: 0;
width: 100%;
height: var(--size);
transform: translate(0, -100%);
}
.drawer--right .drawer__panel {
top: 0;
right: 0;
width: var(--size);
height: 100%;
transform: translate(100%, 0);
}
.drawer--bottom .drawer__panel {
bottom: 0;
left: 0;
width: 100%;
height: var(--size);
transform: translate(0, 100%);
}
.drawer--left .drawer__panel {
top: 0;
left: 0;
width: var(--size);
height: 100%;
transform: translate(-100%, 0);
}
.drawer--open .drawer__panel {
transform: translate(0, 0);
}
.drawer__header {
display: flex;
}
.drawer__title {
flex: 1 1 auto;
font-size: var(--sl-font-size-large);
line-height: var(--sl-line-height-dense);
padding: var(--sl-spacing-large);
}
.drawer__close {
flex: 0 0 auto;
display: flex;
align-items: center;
background: none;
border: none;
border-radius: var(--sl-border-radius-small);
font-family: inherit;
font-size: var(--sl-font-size-x-large);
font-weight: inherit;
color: var(--sl-color-gray-50);
padding: 0 var(--sl-spacing-large);
cursor: pointer;
transition: var(--sl-transition-fast) color;
-webkit-appearance: none;
&:hover,
&:focus,
&:active {
color: var(--sl-color-primary-50);
}
&:focus {
outline: none;
}
}
.focus-visible .drawer__close:focus {
box-shadow: var(--sl-focus-ring-box-shadow);
}
.drawer__body {
flex: 1 1 auto;
padding: var(--sl-spacing-large);
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.drawer__footer {
text-align: right;
padding: var(--sl-spacing-large);
::slotted(sl-button:not(:last-of-type)) {
margin-right: var(--sl-spacing-x-small);
}
}
.drawer__overlay {
display: block;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: var(--sl-overlay-background-color);
opacity: 0;
transition: var(--sl-transition-medium) opacity;
pointer-events: all;
}
.drawer--contained .drawer__overlay {
position: absolute;
}
.drawer--open .drawer__overlay {
opacity: 1;
}

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